我正在尝试将我的麦克风音频转换为 mp3 文件,然后将它们保存在磁盘上,以便我可以录制和保存音轨。
但是要播放它,pyaudio
我需要将其转换为wav
格式。
它最初记录在wav
,我正在尝试做wav -> mp3 -> wav
。
我已经把我的代码的最小调试版本放在一起,它看起来像下面这样:
import pyaudio
from array import array
from struct import pack
from sys import byteorder
from io import BytesIO
from pydub import AudioSegment
p = pyaudio.PyAudio()
stream_mic = p.open(rate=11000,
format=pyaudio.paInt16,
channels=1,
input=True,
frames_per_buffer=500)
stream_out = p.open(rate=11000,
format=pyaudio.paInt16,
channels=1,
output=True,
frames_per_buffer=500)
def is_odd(a):
return bool(a - ((a>>1)<<1))
def wav_obj(raw_data):
wavHandle = AudioSegment(data=raw_data, sample_width=2, frame_rate=11000, channels=1)
return wavHandle
def wavToMp3(audioFrame):
mp3 = BytesIO()
file_handle = audioFrame.export(mp3, format="mp3")
mp3.seek(0)
data = mp3.read()
## == Data needs to be multiple of (sample_width * channels)
## Easiest way is to strip of a trailing data,
while is_odd(len(data)):
data = data[:-1]
return AudioSegment(data=data, sample_width=2, frame_rate=11000, channels=1)
def mp3ToWav(audioFrame):
#remasteredAudioFrame = audioFrame.set_frame_rate(11000)
wav = BytesIO()
file_handle = audioFrame.export(wav, format="wav")
wav.seek(0)
return AudioSegment(data=wav.read(), sample_width=2, frame_rate=11000, channels=1)
while 1:
snd_data = array('h', stream_mic.read(500))
if byteorder == 'big':
snd_data.byteswap()
frame = array('h')
frame.extend(snd_data)
wav = wav_obj(frame)
## == convert from .wav -> .mp3 -> .wav
## just to see the loss of audio.
mp3 = wavToMp3(wav)
wav = mp3ToWav(mp3)
stream_out.write(wav.raw_data)
stream_out.stop_stream()
stream_mic.stop_stream()
stream_out.close()
stream_mic.close()
p.terminate()
这会产生可怕的静电,它会导致 100% 的音频丢失。
起初我以为是剪辑的问题,data[:-1]
但至少在我看来这不是问题。
其次,我认为帧速率可能会关闭,所以我尝试这样做set_frame_rate(11000)
,但也没有用。
注释掉这两行:
mp3 = wavToMp3(wav)
wav = mp3ToWav(mp3)
使播放声音“优美”。没有数据丢失,质量正如我定义的那样。
看在我的份上,我无法弄清楚我在哪里混合了数据压缩。
注意:如果可能,我想在内存中执行此操作,因为稍后我将处理数据以尝试创建效果等。
进步
正如@Anthon 指出的那样,我应该一个一个地隔离转换,看看两者中的哪一个失败。我通过保存wav -> mp3
到磁盘来做到这一点。
started = time()
sound = AudioSegment(data=b'', sample_width=2, frame_rate=11000, channels=1)
while 1:
snd_data = array('h', stream_mic.read(500))
if byteorder == 'big':
snd_data.byteswap()
frame = array('h')
frame.extend(snd_data)
wav = wav_obj(frame)
## == convert from .wav -> .mp3 -> .wav
## just to see the loss of audio.
mp3 = wavToMp3(wav)
sound = sound + mp3
#wav = mp3ToWav(mp3)
#stream_out.write(mp3.raw_data)
if time() - started > 1.5:
break
print(sound.raw_data)
with open('test.mp3', 'wb') as fh:
fh.write(sound.raw_data)
然后我大胆地猛烈test.mp3
地看看形成的波浪是什么样子。
果然,看起来这是不稳定的.mp3
转换。
肉眼看起来好像音频帧被拉出并单独扭曲。声音总共应该大约 1.5 秒长,但从波形来看,压缩器添加的每一帧都有暂停和延迟:
因此,我在使用该值的所有实例上将值frames_per_buffer=500
提高到:2000
stream_mic = p.open(frames_per_buffer=5000, ...)
stream_out = p.open(frames_per_buffer=5000, ...)
stream_mic.read(5000)
任何高于我的值1.5 seconds
都应该是一个足够好的值。
果然,波形看起来完全不同:
似乎有效的方法如下:
wav = wav_obj(frame)
sound = sound + wav
sound.export("test.mp3",
format="mp3",
bitrate="11k",
tags={"album": "test", "artist": "Not Ariana Grande"})
所以有些方法,wav frame -> mp3 frame -> combine several mp3 frames
不起作用。
但做wav frame -> combine several wav frames -> export to mp3
的工作。
这就是我再次陷入困境的地方。
显然,mp3
转换是不稳定的,并且它如何在每段的波形中增加失真音高。
我希望你们中的一些人在 SO 上工作过pydub
,尤其是 mp3 转换,因为我很迷茫。
这是收集的 mp3:s: