How to read stream of .wav bytes in python
Asked Answered
B

3

13

Is there a way to read frames of .wav format binary data? I am streaming .wav binary to a python server which I want to be able to read and use from processing by pyaudio, which complains about the frame size.

Since I cannot use wave.open('filename.wav'), because I already have the binary data being streamed, is there a way to read the binary data so that I can use the readframes method in the wave python library?

EDIT: I tried streaming readframes from the client side, however pyaudio gives an error that the bytes are not in .wav format. It would be ideal however if I can get this done on the server.

Bifocal answered 10/5, 2017 at 18:13 Comment(4)
Do you mean getnframes or readframes? I don't see a getframes in the documentation.Scandent
readframes, sorry for the confusion. I tried streaming readframes from the client side, however pyaudio gives an error that the bytes are not in .wav format. It would be ideal however if I can get this done on the server side.Bifocal
You could create an object with all of the file methods that are needed by wave and pass it to wave.open: "If file is a string, open the file by that name, otherwise treat it as a seekable file-like object."Scandent
What is in your binary stream? Is it the whole content of the WAV file including headers, or is it just the plain audio samples? If latter, you can directly pass the bytes to PyAudio, you just have to make sure you pass the right amount of data and that you tell PyAudio the right data type and number of channels. BTW, PyAudio doesn't know about WAV files, and I'm pretty sure it doesn't talk about them in its error messages. You should provide the actual error message!Argyrol
S
3
from scipy.io import wavfile
fs, data = wavfile.read('your file path')
Sarcoma answered 11/7, 2020 at 9:36 Comment(0)
P
3

As @Vishesh Mangla pointed out use librosa a great library for audio signals

import librosa

sr = librosa.get_samplerate('/path/to/file.wav')

# Set the frame parameters to be equivalent to the librosa defaults
# in the file's native sampling rate
frame_length = (2048 * sr) // 22050
hop_length = (512 * sr) // 22050

# Stream the data, working on 128 frames at a time
stream = librosa.stream('path/to/file.wav',
                        block_length=128,
                        frame_length=frame_length,
                        hop_length=hop_length)

chromas = []
for y in stream:
   chroma_block = librosa.feature.chroma_stft(y=y, sr=sr,
                                              n_fft=frame_length,
                                              hop_length=hop_length,
                                              center=False)
   chromas.append(chromas)

In this example, each audio fragment y will consist of 128 frames worth of samples, or more specifically, len(y) == frame_length + (block_length - 1) * hop_length. Each fragment y will overlap with the subsequent fragment by frame_length - hop_length samples, which ensures that stream processing will provide equivalent results to if the entire sequence was processed in one step (assuming padding / centering is disabled).

For more details about the streaming interface, refer to librosa.core.stream.

Plop answered 17/7, 2020 at 13:58 Comment(0)
K
1

Answering to my own bounty, there is an elegant solution that I borrow from this more general context relating to getting a virtual file object.

import io
audio = wave.open(io.BytesIO(bytes))

This will enable all of wave's API, at least the subset I use for the same scenario as the original question, for a python bytes object. For example with the audio variable from above you can now:

format=self.audio.get_format_from_width(
   audio.getsampwidth()),
   channels=audio.getnchannels(),
   rate=audio.getframerate(),
   frames_per_buffer=self.chunk_size,
   output=True)

Since it seems the wave library does not directly support anything but a disk file object, this is a nice workaround and at least it hinges on a standard python library (io) that provides just what we need to bridge the gap in the API.

Kinaesthesia answered 11/7, 2020 at 9:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.