python audio player filtered without jitter
Question: For a project I need to

  * read WAV file
  * filter
  * play WAV file

The code below is "working" except that the sound crackles, and that is
because I can't guarantee a continue data stream to the audio output.
Filtering takes some time and that's where the sound freezes for a very short
time.

In the future I'd like to do some extra calculations on the raw audio data.
I'd like to know which method is the best to keep the sound smooth.

    
    
    import pyaudio  
    import wave  
    from scipy import signal
    from struct import *
    
    chunk = 1024
    
    f = wave.open("sample.wav","rb")  
    p = pyaudio.PyAudio()
    
    stream = p.open(format = p.get_format_from_width(f.getsampwidth()),  
                channels = f.getnchannels(),  
                rate = f.getframerate(),  
                output = True)  
    
    data = f.readframes(chunk)
    b, a = signal.butter(2, 0.01)
    
    tmp = len(data)/2
    s = '<'
    for i in range(0,tmp):
        s = s + 'h'
    
    while data != '':
        sig = signal.filtfilt(b, a, unpack(s,data))
    
        output_signal = pack(s,*sig)
        stream.write(output_signal) 
        data = f.readframes(chunk)
    
    stream.stop_stream()  
    stream.close()  
    p.terminate()   
    

Thanks in advance!


Answer: You can try splitting the producer of the data and the consumer (which is
pyaudio) in two programs, with a regular Unix pipe connecting them. The Unix
pipe plays the role of buffering. Example:

in producer.py:

    
    
    while data != '':
        sig = signal.filtfilt(b, a, unpack(s,data))
        output_signal = pack(s,*sig)
        sys.stdout.write(output_signal)      # <===
        data = f.readframes(chunk)
    

in consumer.py:

    
    
    while 1:
        data = sys.stdin.read(1024)
        if not data: break
        stream.write(data)
    

Command-line invocation:

    
    
    python producer.py | python consumer.py
    

If it works, then you can also run `python consumer.py` from inside the other
program with `os.popen()`, for example.

