how to append audio frames to wav file python - python

I have a stream of PCM audio frames coming to my python code .Is there way to write frame in a way that appends to an existing .wav file. What i have tried is i am taking 2 wav files . From 1 wav file i am reading the data and writing to a existing wav file
import numpy
import wave
import scipy.io.wavfile
with open('testing_data.wav', 'rb') as fd:
contents = fd.read()
contents1=bytearray(contents)
numpy_data = numpy.array(contents1, dtype=float)
scipy.io.wavfile.write("whatstheweatherlike.wav", 8000, numpy_data)
data is getting appended in the existing wav file but the wav file is getting corrupted when i am trying to play in a media player

With wave library you can do that with something like:
import wave
audiofile1="youraudiofile1.wav"
audiofile2="youraudiofile2.wav"
concantenated_file="youraudiofile3.wav"
frames=[]
wave0=wave.open(audiofile2,'rb')
frames.append([wave0.getparams(),wave0.readframes(wave0.getnframes())])
wave.close()
wave1=wave.open(audiofile2,'rb')
frames.append([wave1.getparams(),wave1.readframes(wave1.getnframes())])
wave1.close()
result=wave.open(concantenated_file,'wb')
result.setparams(frames[0][0])
result.writeframes(frames[0][1])
result.writeframes(frames[1][1])
result.close()
And the order of concatenation is exactly the order of the writing here :
result.writeframes(frames[0][1]) #audiofile1
result.writeframes(frames[1][1]) #audiofile2

Related

How can I convert a .wav to .mp3 in-memory?

I have a numpy array from a some.npy file that contains data of an audio file that is encoded in the .wav format.
The some.npy was created with sig = librosa.load(some_wav_file, sr=22050) and np.save('some.npy', sig).
I want to convert this numpy array as if its content was encoded with .mp3 instead.
Unfortunately, I am restricted to the use of in-memory file objects for two reasons.
I have many .npy files. They are cached in advance and it would be highly inefficient to have that much "real" I/O when actually running the application.
Conflicting access rights of people who are executing the application on a server.
First, I was looking for a way to convert the data in the numpy array directly, but there seems to be no library function. So is there a simple way to achieve this with in-memory file objects?
NOTE: I found this question How to convert MP3 to WAV in Python and its solution could be theoretically adapted but this is not in-memory.
You can read and write memory using BytesIO, like this:
import BytesIO
# Create "in-memory" buffer
memoryBuff = io.BytesIO()
And you can read and write MP3 using pydub module:
from pydub import AudioSegment
# Read a file in
sound = AudioSegment.from_wav('stereo_file.wav')
# Write to memory buffer as MP3
sound.export(memoryBuff, format='mp3')
Your MP3 data is now available at memoryBuff.getvalue()
You can convert between AudioSegments and Numpy arrays using this answer.
I finally found a working solution. This is what I wanted.
from pydub import AudioSegment
wav = np.load('some.npy')
with io.BytesIO() as inmemoryfile:
compression_format = 'mp3'
n_channels = 2 if wav.shape[0] == 2 else 1 # stereo and mono files
AudioSegment(wav.tobytes(), frame_rate=my_sample_rate, sample_width=wav.dtype.itemsize,
channels=n_channels).export(inmemoryfile, format=compression_format)
wav = np.array(AudioSegment.from_file_using_temporary_files(inmemoryfile)
.get_array_of_samples())
There exists a wrapper package (audiosegment) with which one could convert the last line to:
wav = audiosegment.AudioSegment.to_numpy_array(AudioSegment.from_file_using_temporary_files(inmemoryfile))

How to get numpy arrays output of .wav file format

I am new to Python, and I am trying to train my audio voice recognition model. I want to read a .wav file and get output of that .wav file into Numpy arrays. How can I do that?
In keeping with #Marco's comment, you can have a look at the Scipy library and, in particular, at scipy.io.
from scipy.io import wavfile
To read your file ('filename.wav'), simply do
output = wavfile.read('filename.wav')
This will output a tuple (which I named 'output'):
output[0], the sampling rate
output[1], the sample array you want to analyze
This is possible with a few lines with wave (built in) and numpy (obviously). You don't need to use librosa, scipy or soundfile. The latest gave me problems reading wav files and it's the whole reason I'm writting here now.
import numpy as np
import wave
# Start opening the file with wave
with wave.open('filename.wav') as f:
# Read the whole file into a buffer. If you are dealing with a large file
# then you should read it in blocks and process them separately.
buffer = f.readframes(f.getnframes())
# Convert the buffer to a numpy array by checking the size of the sample
# with in bytes. The output will be a 1D array with interleaved channels.
interleaved = np.frombuffer(buffer, dtype=f'int{f.getsampwidth()*8}')
# Reshape it into a 2D array separating the channels in columns.
data = np.reshape(interleaved, (-1, f.getnchannels()))
I like to pack it into a function that returns the sampling frequency and works with pathlib.Path objects. In this way it can be played using sounddevice
# play_wav.py
import sounddevice as sd
import numpy as np
import wave
from typing import Tuple
from pathlib import Path
# Utility function that reads the whole `wav` file content into a numpy array
def wave_read(filename: Path) -> Tuple[np.ndarray, int]:
with wave.open(str(filename), 'rb') as f:
buffer = f.readframes(f.getnframes())
inter = np.frombuffer(buffer, dtype=f'int{f.getsampwidth()*8}')
return np.reshape(inter, (-1, f.getnchannels())), f.getframerate()
if __name__ == '__main__':
# Play all files in the current directory
for wav_file in Path().glob('*.wav'):
print(f"Playing {wav_file}")
data, fs = wave_read(wav_file)
sd.play(data, samplerate=fs, blocking=True)

python make_chunks from an audio stream wav or mp3

I want to write a python program that write chunks from an audio file. I can write chunks from an audio file available locally using following code,
from pydub import AudioSegment
from pydub.utils import make_chunks
myaudio = AudioSegment.from_file("file1.wav" , "wav")
chunk_length_ms = 10000 # pydub calculates in millisec
chunks = make_chunks(myaudio, chunk_length_ms) #Make chunks of one sec
#Export all of the individual chunks as wav files
for i, chunk in enumerate(chunks):
chunk_name = "chunk{0}.wav".format(i)
print "exporting", chunk_name
chunk.export(chunk_name, format="wav")
The above code will create chunks with 10000 milliseconds of the audio file "file1.wav". But I want to write chunks from an audio stream, the stream could be wav or mp3. Can someone help me on this?
change the audio chunk to numpy array and use the function .get_array_of_samples()
np.array(chunk[0].get_array_of_samples())

Raspberry PI - Python - merge wav files and play

I've got Python script for merge .wav files, based on list with paths.
It's based on this code
import wave
infiles = ["sound_1.wav", "sound_2.wav"]
outfile = "sounds.wav"
data= []
for infile in infiles:
w = wave.open(infile, 'rb')
data.append( [w.getparams(), w.readframes(w.getnframes())] )
w.close()
output = wave.open(outfile, 'wb')
output.setparams(data[0][0])
output.writeframes(data[0][1])
output.writeframes(data[1][1])
output.close()
from this topic
How to join two wav files using python?
But I realized, It takes too much time to generate file. In fact I don't need to store merged data as the file on physical disk.
So question is, is there any way to read .wav files merge them and play it just from RAM memory?
EDIT: I forgot to specify, that I need to play it using Raspberry pi 3. I tried to use PyAudio which on my laptop works fine, but when I tried it in RPI the sound is slowly and crackling (I used this example https://people.csail.mit.edu/hubert/pyaudio/docs/#example-blocking-mode-audio-i-o)

pydub accessing the sampling rate(Hz) and the audio signal from an mp3 file

Just found out this interesting python package pydub which converts any audio file to mp3, wav, etc.
As far as I have read its documentation, the process is as follows:
read the mp3 audio file using from_mp3()
creates a wav file using export().
Just curious if there is a way to access the sampling rate and the audio signal(of 1-dimensional array, supposing it is a mono) directly from the mp3 file without converting it to a wav file. I am working on thousands of audio files and it might be expensive to convert all of them to wav file.
If you aren't interested in the actual audio content of the file, you may be able to use pydub.utils.mediainfo():
>>> from pydub.utils import mediainfo
>>> info = mediainfo("/path/to/file.mp3")
>>> print info['sample_rate']
44100
>>> print info['channels']
1
This uses avlib's avprobe utility, and returns all kinds of info. I suggest giving it a try :)
Should be much faster than opening each mp3 using AudioSegment.from_mp3(…)
frame_rate means sample_rate, so you can get like below;
from pydub import AudioSegment
filename = "hoge.wav"
myaudio = AudioSegment.from_file(filename)
print(myaudio.frame_rate)

Categories