如何在Python中写入立体声wav文件?

18 投票
3 回答
24652 浏览
提问于 2025-04-16 03:40

下面的代码会把一个频率为400Hz的简单正弦波写入一个单声道的WAV文件。为了让这个代码能生成一个立体声的WAV文件,我们应该怎么改呢?第二个声道的频率要不同。

import math
import wave
import struct

freq = 440.0
data_size = 40000
fname = "WaveTest.wav"
frate = 11025.0  # framerate as a float
amp = 64000.0     # multiplier for amplitude

sine_list_x = []
for x in range(data_size):
    sine_list_x.append(math.sin(2*math.pi*freq*(x/frate)))

wav_file = wave.open(fname, "w")

nchannels = 1
sampwidth = 2
framerate = int(frate)
nframes = data_size
comptype = "NONE"
compname = "not compressed"

wav_file.setparams((nchannels, sampwidth, framerate, nframes,
    comptype, compname))

for s in sine_list_x:
    # write the audio frames to file
    wav_file.writeframes(struct.pack('h', int(s*amp/2)))

wav_file.close()

3 个回答

2

另一个选择是使用SciPy和NumPy这两个库。在下面的例子中,我们会生成一个立体声的音频文件,左声道会有一个低频的音调,而右声道则会有一个高频的音调。(注意:建议使用VLC播放器来播放音频)

要安装SciPy,可以查看: https://pypi.org/project/scipy/

import numpy as np
from scipy.io import wavfile

# User input
duration=5.0
toneFrequency_left=500 #Hz (20,000 Hz max value)
toneFrequency_right=1200 #Hz (20,000 Hz max value)

# Constants
samplingFrequency=48000

# Generate Tones
time_x=np.arange(0, duration, 1.0/float(samplingFrequency))
toneLeft_y=np.cos(2.0 * np.pi * toneFrequency_left * time_x)
toneRight_y=np.cos(2.0 * np.pi * toneFrequency_right * time_x)

# A 2D array where the left and right tones are contained in their respective rows
tone_y_stereo=np.vstack((toneLeft_y, toneRight_y))

# Reshape 2D array so that the left and right tones are contained in their respective columns
tone_y_stereo=tone_y_stereo.transpose()

# Produce an audio file that contains stereo sound
wavfile.write('stereoAudio.wav', samplingFrequency, tone_y_stereo)

环境说明

使用的版本 Python 3.7.1

  • Python 3.7.1
  • SciPy 1.1.0
3

如果你想看看怎么生成一个立体声的 .wav 文件,可以参考这个 test_wave.py 模块。这个测试会生成一个全是零的文件。你可以通过插入交替的样本值来进行修改。

nchannels = 2
sampwidth = 2
framerate = 8000
nframes = 100

# ...

    def test_it(self):
        self.f = wave.open(TESTFN, 'wb')
        self.f.setnchannels(nchannels)
        self.f.setsampwidth(sampwidth)
        self.f.setframerate(framerate)
        self.f.setnframes(nframes)
        output = '\0' * nframes * nchannels * sampwidth
        self.f.writeframes(output)
        self.f.close()
11

创建一个与另一个频率/频道相对应的 sine_list_y 列表,设置 nchannels=2,然后在输出循环中使用 for s, t in zip(sine_list_x, sine_list_y): 作为开头部分,接着在循环体中调用两次 writeframes -- 一次用于 s,一次用于 t。换句话说,两个频道的对应音频帧在文件中是“交替”存储的。

例如,可以参考 这个页面,里面详细描述了所有可能的WAV文件格式,我引用如下:

多频道数字音频样本 是以交错的波形数据存储的, 这意味着多频道(比如 立体声和环绕声)波形文件的音频 样本是通过循环每个频道的音频 样本来存储的,然后再 进入下一个样本时间。 这样做是为了让音频文件 可以在整个文件读取完之前 播放或流式传输。这在从磁盘 播放大型文件时非常方便 (因为可能无法完全放入 内存)或通过互联网流式传输文件时也很有用。下面图表中的值 将按照它们在 值列中列出的顺序(从上到下)存储在WAV文件中。

接下来的表格清楚地显示了频道的样本是如何左、右、左、右交替的……

撰写回答