Graba audio de manera simultánea desde el micrófono y reprodúcelo con efecto en Python

Mi objective es grabar mi voz a través del micrófono de la computadora portátil y, al mismo tiempo, agregarle un efecto, en python. Lo que necesito es similar a un pedal de efectos de música donde conectas una guitarra o un micrófono y agrega reverberación, eco o distorsión, etc.

Estoy usando ‘pyaudio’ y ‘wave‘ para grabar y reproducir audio. Usar ‘scikits.audiolab’ para importar audio como una matriz y poder editar esta matriz con funciones como invertir, recortar, mosaico, etc. Esta manipulación de la matriz de audio me permite “agregar” efectos al audio original.

Tengo un problema, que no es realmente un problema, simplemente no es el efecto que quiero. Digamos que grabo la palabra “Hola”. Tengo mi función de grabación configurada para grabar durante 3 segundos. Entonces tomo esta matriz de audio y la coloco una vez. Ahora, cuando reproduzco esto, dirá hola dos veces, un efecto de retardo. PERO, hay un intervalo de tiempo de ‘espacio vacío’ entre ambos hellos, lo que sucede porque el audio todavía se está grabando DESPUÉS de que termine de saludar. Por lo tanto, cuando se repite, hay demasiado espacio vacío entre las palabras. Quiero eliminar este espacio vacío para que la reproducción diga hola hola más rápidamente.

Mi profesor recomienda enhebrar. Él dice que debo grabar y, simultáneamente, tomar las primeras 500 muestras, para decir un número. Recomienda tomar estas 500 muestras y reproducirlas mientras grabas. No estoy muy seguro de cómo implementar esto.

Mi pregunta es, cómo grabar simultáneamente, tomar las primeras 500 muestras y crear una nueva matriz con el “efecto” agregado a la grabación original.

    import scikits.audiolab as audiolab import pyaudio import wave def recordAudio(): CHUNK = 1024 FORMAT = pyaudio.paInt16 CHANNELS = 1 RATE = 44100 RECORD_SECONDS = 3 WAVE_OUTPUT_FILENAME = "audioOriginal.wav" p = pyaudio.PyAudio() stream = p.open(format=FORMAT, channels=CHANNELS, rate=RATE, input=True, frames_per_buffer=CHUNK) print("* recording:") frames = [] for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)): data = stream.read(CHUNK) frames.append(data) print("* Finished recording.") stream.stop_stream() stream.close() p.terminate() wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb') wf.setnchannels(CHANNELS) wf.setsampwidth(p.get_sample_size(FORMAT)) wf.setframerate(RATE) wf.writeframes(b''.join(frames)) wf.close() # Duplicate audio and save as Actual frames, fs, encoder = audiolab.wavread('audioOriginal.wav') audiolab.wavwrite(frames,'audioActual.wav',fs) def playAudio(): import pyaudio import wave CHUNK = 1024 wf = wave.open('audioActual.wav', 'rb') p = pyaudio.PyAudio() stream = p.open(format=p.get_format_from_width(wf.getsampwidth()), channels=wf.getnchannels(), rate=wf.getframerate(), output=True) data = wf.readframes(CHUNK) while data != '': stream.write(data) data = wf.readframes(CHUNK) stream.stop_stream() stream.close() p.terminate() def reverseAudio(): frames, fs, encoder = audiolab.wavread('audioActual.wav') audiolab.wavwrite(frames[::-1],'audioActual.wav',44100) def revert(): frames, fs, encoder = audiolab.wavread('audioOriginal.wav') audiolab.wavwrite(frames,'audioActual.wav',fs) def errorSelection(): print("\nERROR.") # no option in menu def showMenu(): print(""" 1. Record audio 2. Play audio 3. Reverse audio 4. Add delay 5. Revert to original audio T to end program. """) # Menu def main(): selecciones = {"1": recordAudio, "2": playAudio, "3": reverseAudio, "5": revert} while True: showMenu() seleccion = raw_input(u'What do you want to do? ') if "t" == seleccion: return elif "T" == seleccion: return toDo = selecciones.get(seleccion, errorSelection) toDo() if __name__ == "__main__": main() 

    Primero, el problema que usted planteó (poder mosaico de muestras de audio mientras se elimina automáticamente el espacio silencioso entre ellas) no se puede resolver con subprocesos. Debe analizar el sonido grabado para determinar dónde hay o no silencio, o simplemente permitir que el usuario especifique cuándo debe terminar la grabación. Puedes lograr esto último con un simple bucle:

    1. Abre el hardware de audio y comienza a grabar.
    2. Crear una lista vacía para almacenar trozos de audio
    3. Solicite una pequeña porción de datos de audio, agregue a la lista
    4. Compruebe que el usuario ha solicitado que finalice la grabación. Si no, vuelve a 3.
    5. Cuando haya terminado, monte los trozos en una sola matriz para reproducirlos.

    En este ejemplo simple, no hay ningún beneficio al usar subprocesos.

    El método sugerido, para grabar y reproducir simultáneamente , parece una solución a un problema diferente, uno que es mucho más complejo. En este caso, hay dos grandes dificultades:

    1. No todas las tarjetas de sonido del consumidor son capaces de grabar y reproducir simultáneamente. Busque tarjetas que digan “dúplex completo” en lugar de “dúplex medio”.
    2. Hablar por un micrófono y escucharte con una breve demora es una gran distracción. Para que esto funcione correctamente, el audio grabado debe procesarse y enviarse a la tarjeta de sonido en menos de unos 20 ms. A 44.1 kHz, esto significa que debería estar leyendo menos de 880 cuadros por ciclo de bucle, y si el procesamiento no puede continuar, tendrá huecos en la salida. Este es un problema sorprendentemente difícil a menos que tenga un software especializado para ayudarlo. Si realmente desea ir por este camino, puede consultar a Jack ( http://jackaudio.org/ ), que proporciona acceso de audio de baja latencia en la mayoría de las plataformas y también tiene una biblioteca de Python fácil ( http: // sourceforge. net / proyectos / py-jack / ). El enhebrado probablemente no sea útil en este tipo de progtwig.

    Para ampliar la respuesta de Lucas:

     for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)): data = stream.read(CHUNK) frames.append(data) 

    En tu código es donde te comprometes a un determinado tiempo de grabación. Si escribiste una función ” isSilent ” que puede determinar si un fragmento está en silencio, tu código podría cambiar a:

     while len(frames) <= 0 or not isSilent(frames[-1]): data = stream.read(CHUNK) frames.append(data) 

    Si " isSilent " es difícil de escribir o si es demasiado lento computacionalmente, puede esperar la entrada del usuario. KeyboardInterrupt es un primer truco para jugar con este método:

     try: while true: data = stream.read(CHUNK) frames.append(data) except KeyboardInterrupt: pass 

    Este es un truco, y no es la forma correcta de buscar la entrada del usuario en la producción, pero le permitirá comenzar a experimentar con esto. usted querrá encontrar o hacer una función stopButtonHasBeenPressed .

     while not stopButtonHasBeenPressed(): data = stream.read(CHUNK) frames.append(data)