Adding to a WAV file in Python - python

I want to add to a wav file, ideal would be from a numpy array. I tried the following code:
data = stream.read(CHUNK)
audio_numpy = numpy.frombuffer(data, dtype=numpy.int16)
scipy.io.wavfile.write(FILENAME, RATE, audio_numpy)
where stream is created by
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paInt16,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
as I heard that scipy would add to the file and not overwrite it. Unfortunately however, it overwrites the file.
How can I append to a WAV file? The input comes from the microphone.
The WAV file should be accessed from ffmpeg later, so that the WAV file should not be written in total again, as this is also inefficient.

Related

How do I pass an audio file into the microphone?

I know the question does not seems to make sense but let me explain.
So I have a voice changer software that Change the voice in real time. If i open the audacity and choose the micro of that software I can speak and record with the voice changed.
Now what I want is, I have a audio file already recorded and I want to pass that file into that same microphone (to simulate me speaking) and save the output with the voice changed in another file. I made some attemps using pyaudio but no success.
The idea here is to use a tts module in python to read a dataset I have with multiple lines, save the output in a file and then pass that output to the microphone to change the voice and save in another file. That way I can automate a creation of a new dataset with a new speaker to train a new tts. But the problem is I missing the way to pass a file to the microphone to simulate me speaking to it but instead using an audio file already recorded.
Sorry of it was confused. I made my best to explain. Hope someone can help me.
Thank you in advanced!
This is what I have but no success.
import pyaudio
import wave
# Open the audio file
wf = wave.open("my_audio_file.wav", "rb")
# Open the output file
wf_out = wave.open("my_output_file.wav", "wb")
# Set the output file's format and parameters to match the input file
wf_out.setframerate(wf.getframerate())
wf_out.setsampwidth(wf.getsampwidth())
wf_out.setnchannels(wf.getnchannels())
# Open the microphone using pyaudio
p = pyaudio.PyAudio()
# Create a stream to send the audio data to the microphone
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
channels=wf.getnchannels(),
rate=wf.getframerate(),
output=True)
# Start streaming the audio data to the microphone
stream.start_stream()
# Send the audio data to the stream and output file
data = wf.readframes(1024)
while data != "":
stream.write(data)
wf_out.writeframes(data)
data = wf.readframes(1024)
# Stop the stream
stream.stop_stream()
# Close the stream, microphone, and output file
stream.close()
p.terminate()
wf_out.close()

How to record microphone on macos with pyaudio?

I made a simple voice assistant in python with speech_recognition on Windows 10 and I wanted to copy the code for macOs too.
I downloaded PortAudio and PyAudio, the code runs fine but when i play the audio track I hear nothing :( (and the program not detect when I try to use the speech_recognition)
I guess it something with permissions and things like that... anyone have an idea?
( I also checked I use the right device index and I indeed use index 0 (The Mackbook built-in Microphone)
here is some code sample:
import pyaudio
import wave
chunk = 1024 # Record in chunks of 1024 samples
sample_format = pyaudio.paInt16 # 16 bits per sample
channels = 1
fs = 44100 # Record at 44100 samples per second
seconds = 3
filename = "output.wav"
p = pyaudio.PyAudio() # Create an interface to PortAudio
print('Recording')
stream = p.open(format=sample_format,
channels=channels,
rate=fs,
frames_per_buffer=chunk,
input=True)
frames = [] # Initialize array to store frames
# Store data in chunks for 3 seconds
for i in range(0, int(fs / chunk * seconds)):
data = stream.read(chunk)
frames.append(data)
# Stop and close the stream
stream.stop_stream()
stream.close()
# Terminate the PortAudio interface
p.terminate()
print('Finished recording')
# Save the recorded data as a WAV file
wf = wave.open(filename, 'wb')
wf.setnchannels(channels)
wf.setsampwidth(p.get_sample_size(sample_format))
wf.setframerate(fs)
wf.writeframes(b''.join(frames))
wf.close()
I found the answer!!!
The code actually worked fine all this time, the problem was that I used Visual Studio Code that for some reason messed up with the microphone permissions
Now I run the code through terminal with python [filename].py and its working great!

Updating/appending to a .wav file in Python

I have a stream of PCM audio frames coming into my Python script, and I am able to save blocks of these frames as .wav files as such:
def update_wav():
filename = "test.wav"
wav_file = wave.open(filename, "wb")
n_frames = len(audio)
wav_file.setparams((n_channels, sample_width, sample_rate, n_frames, comptype, compname))
for sample in audio:
wav_file.writeframes(struct.pack('h', int(sample * 32767.0)))
wav_file.close()
However, I'd like this to continually update as new frames come in. Is there way to writeframe in a way that appends to an existing .wav file? Right now I am only able to accomplish an overwrite.
I found a way of doing this with SciPy, it actually seems to be the default functionality for their writing method.
import scipy.io.wavfile
def update_wav():
numpy_data = numpy.array(audio, dtype=float)
scipy.io.wavfile.write("test.wav", 8000, numpy_data)

PyAudio: how to capture internal audio (not from microphone)?

Tried like this:
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
output=True,
frames_per_buffer=chunk)
all = []
for i in range(0, int(RATE / chunk * RECORD_SECONDS)):
data = stream.read(chunk)
but it throws paCanNotReadFromAnOutputOnlyStream
Using input=True it reads audio from mic, but that is not what I need.
Any help, please
Edit: I am using linux
I can also use other library, not only PyAudio. I just need to get this work
Try this: https://github.com/intxcc/pyaudio_portaudio
PyAudio isn't made to record outputs, only inputs. This fork however introduces an api that gives you the ability to do so through loopback mode. To use this, set the flag as AUDCLNT_STREAMFLAGS_LOOPBACK. Hopefully this works and good luck!

howto stream numpy array into pyaudio stream?

I'm writing a code that supposed to give some audio output to the user based on his action, and I want to generate the sound rather than having a fixed number of wav files to play. Now, what I'm doing is to generate the signal in numpy format, store the data in a wav file and then read the same file into pyaudio. I think this is redundant, however, I couldn't find a way to do that. My question is, can I stream a numpy array (or a regular list) directly into my the pyaudio to play?
If its just playback and does not need to be synchronised to anything then you can just do the following:
# Open stream with correct settings
stream = self.p.open(format=pyaudio.paFloat32,
channels=CHANNELS,
rate=48000,
output=True,
output_device_index=1
)
# Assuming you have a numpy array called samples
data = samples.astype(np.float32).tostring()
stream.write(data)
I use this method and it works fine for me. If you need to record at the same time then this won't work.
If you are just looking to generate audio tones then below code may be useful,
It does need pyaudio that can be installed as
pip install pyaudio
Sample Code
#Play a fixed frequency sound.
from __future__ import division
import math
import pyaudio
#See http://en.wikipedia.org/wiki/Bit_rate#Audio
BITRATE = 44100 #number of frames per second/frameset.
#See http://www.phy.mtu.edu/~suits/notefreqs.html
FREQUENCY = 2109.89 #Hz, waves per second, 261.63=C4-note.
LENGTH = 1.2 #seconds to play sound
NUMBEROFFRAMES = int(BITRATE * LENGTH)
RESTFRAMES = NUMBEROFFRAMES % BITRATE
WAVEDATA = ''
for x in xrange(NUMBEROFFRAMES):
WAVEDATA = WAVEDATA+chr(int(math.sin(x/((BITRATE/FREQUENCY)/math.pi))*127+128))
#fill remainder of frameset with silence
for x in xrange(RESTFRAMES):
WAVEDATA = WAVEDATA+chr(128)
p = pyaudio.PyAudio()
stream = p.open(format = p.get_format_from_width(1),
channels = 1,
rate = BITRATE,
output = True)
stream.write(WAVEDATA)
stream.stop_stream()
stream.close()
p.terminate()
Code is slightly modified from this askubuntu site
You can directly stream the data through pyaudio, there is no need to write and read a .wav file.
import pyaudio
p = pyaudio.PyAudio()
stream = p.open(format=pyaudio.paFloat32,
channels=1,
rate=44100,
frames_per_buffer=1024,
output=True,
output_device_index=1
)
samples = np.sin(np.arange(50000)/20)
stream.write(samples.astype(np.float32).tostring())
stream.close()

Categories

Resources