PyAudio and Decibel change and panning

1.5k Views Asked by At

I have a pretty basic pyaudio code that plays a wav file.

    open_wave = wave.open("tone_silence/l0r1d0_500.wavc",'rb')

    pyAudio_session = pyaudio.PyAudio()

    def callback(in_data, frame_count, time_info, status):
        data = open_wave.readframes(frame_count)
        return (data, pyaudio.paContinue)
    pyAudio_stream = pyAudio_session.open(
        format = pyAudio_session.get_format_from_width(open_wave.getsampwidth()),
        channels = open_wave.getnchannels(),
        rate = open_wave.getframerate(),
        output = True,
        stream_callback=callback)

    while pyAudio_stream.is_active():
        time.sleep(0.1)

    pyAudio_stream.stop_stream()
    pyAudio_stream.close()
    print("Stopped")
    pyAudio_session.terminate()

I have searched every corner of the internet to find a way such that I can change the Decibel level of the stream and pan the stereo output to a specific channel (left speaker only/right speaker only) as per need. But I could not find any method.

I cannot shift to pydub (which actually has this features) because it does not let me close the stream at any time; it plays the full audio and cannot be closed abruptly.

1

There are 1 best solutions below

0
On

While pydub does not have a direct way to stop audioSegment play, According to this documentation, it breaks the audio in to half-second chunks to facilitate keyboard interrupts.

Thus if we take audio and run through a while loop within a try-except block, we should be able to break the play using "Ctrl + c"

Here is a working sample code that pans audio to left or right channel as per documentation from here and then uses above logic to stop playing upon "Ctrl + c"

from pydub import AudioSegment
from pydub.playback import play

song = AudioSegment.from_wav("music.wav")

# pan the sound 15% to the right
panned_right = song.pan(+0.15)

# pan the sound 50% to the left
panned_left = song.pan(-0.50)

#Play panned left audio
while True:
    try:
        play(panned_left)
    except KeyboardInterrupt:
        print "Stopping playing"
        break

We get IDLE session prompt back upon breaking from play loop. You can tailor that your needs.

Output:
Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>> 
Stopping playing
>>> 

This gives you ease of using built-in panning methods within pydub and also a hack to interrupt play-back mid-stream. Hope this help you with your problem.

EDIT-1
Above solution may run into problem that while loop will play indefinitely (if you don't break it.). It's may be good for testing only.

Another option is to use python multiprocess module to spawn a process that plays an audio segment and terminate it when not needed. This gives more control during playback.

Here is an example.

from multiprocessing import Process

def play_audio(seg):
    play(seg)

if __name__ == '__main__':
    p = Process(target=play_audio, args=(panned_left,))
    p.start()

When you need audio to be stopped, simply invoke p.terminate() either in IDE or in program.

Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>> 
>>> p.terminate()
>>>