Search code examples
pythonpyaudio

pyaudio simple audioplayer with "start at" functionality


I'm writing a simple player in python using the pyaudio Library, with some basic functionalities, such start play, pause and start position. I started working on the first example of the Documentation:

import pyaudio
import wave
import sys

CHUNK = 1024

if len(sys.argv) < 2:
    print("Plays a wave file.\n\nUsage: %s filename.wav" % sys.argv[0])
    sys.exit(-1)

wf = wave.open(sys.argv[1], 'rb')

# instantiate PyAudio (1)
p = pyaudio.PyAudio()

# open stream (2)
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
                channels=wf.getnchannels(),
                rate=wf.getframerate(),
                output=True)

# read data
data = wf.readframes(CHUNK)

# play stream (3)
while len(data) > 0:
    stream.write(data)
    data = wf.readframes(CHUNK)

# stop stream (4)
stream.stop_stream()
stream.close()

# close PyAudio (5)
p.terminate()

It works perfectly but I really wouldn't know where to add a frame offset to start the playback at a specific frame. I saw that there are different libraries available, but PyAudio allows me to read the raw data from the file in real time, and I need this functionality. Do you have any suggestions?


Solution

  • You just have to count how many bytes to move in the audio.

    nbytes = wf.getsampwidth()  # Gives the number of bytes per sample for 1 channel
    nchannels = wf.getnchannels()  # Number of channels
    sample_rate = wf.getframerate()  # Number of samples per second  44100 is 44100 samples per second
    
    nbytes_per_sample_per_channel = nbytes * nchannels
    nbytes_per_second = nbytes_per_sample_per_channel * sample_rate
    
    skip_seconds = 5  # Skip 5 seconds
    
    wf.readframes(int(skip_seconds * nbytes_per_second))  # Read data that you want to skip
    

    Start playing the file after the offset was read

    # read data
    data = wf.readframes(CHUNK)
    
    # play stream (3)
    while len(data) > 0:
        stream.write(data)
        data = wf.readframes(CHUNK)
    
    # stop stream (4)
    stream.stop_stream()
    stream.close()
    
    # close PyAudio (5)
    p.terminate()