我试图学习一些有关音频编程的知识,所以我决定看看是否可以弄清楚如何生成一个正弦波并将其写入.wav文件。从参考文献here,我收集到每个通道只是在文件末尾的数据块中交错。但是,我生成的wav文件似乎只在左声道播放。我还将输出与真实的440hA相比较,发现它比预期的低八度。
我想像的是,我用来侦听文件的程序将数据解释为单个通道,并且由于每个样本都重复了一次,因此以预期频率的1/2播放波形。
我知道有一个Python模块可帮助编写wav文件,但这是一个教育性项目,我正在尝试学习有关编写二进制文件和wav文件格式的知识。
为什么我似乎无法在两个频道中播放此文件?任何帮助将不胜感激。
我为凌乱的代码表示歉意,一旦解决了这个最后的错误,我打算稍作重构。
import struct
import math
# Frequency Table
A4 = 440.0
#Misc inputs
waveDuration = 3
amp_16 = 32760
# Wave Header
# Chunk Descriptor
chunkID = b'\x52\x49\x46\x46' #RIFF
hFormat = b'\x57\x41\x56\x45' #WAVE
# fmtSubChunk
fChunkID = b'\x66\x6d\x74\x20' #'fmt '
fChunkSize = 16 # 16 for PCM
audioFormat = 1 # 1 for PCM
numChannels = 2
sampleRate = 48000
bitsPerSample = 16
byteRate = int(sampleRate * numChannels * bitsPerSample / 8)
blockAlign = int(numChannels * bitsPerSample / 8)
# dataSubChunk
numSamples = waveDuration * sampleRate * numChannels
dChunkID = b'\x64\x61\x74\x61' #DATA
dChunkSize = int(numSamples * bitsPerSample / 8)
chunkSize = dChunkSize + 36 + 8
# Generate Sin Wave
def generateSin(sampleRate, bitDepth, frequency, amplitude, duration):
data = [0] * sampleRate * duration
angle = frequency * 2 * math.pi
cur_sample = 0
for sample in data:
data[cur_sample] = amplitude * (math.sin(angle * cur_sample/ sampleRate))
cur_sample += 1
return data
# Write .wav file
waveFile = open('test.wav', 'wb')
# Header
waveFile.write(chunkID)
waveFile.write(struct.pack('<i', chunkSize))
waveFile.write(hFormat)
# Format Subchunk
waveFile.write(fChunkID)
waveFile.write(struct.pack('<i', fChunkSize))
waveFile.write(struct.pack('<h', audioFormat))
waveFile.write(struct.pack('<h', numChannels))
waveFile.write(struct.pack('<i', sampleRate))
waveFile.write(struct.pack('<i', byteRate))
waveFile.write(struct.pack('<h', blockAlign))
waveFile.write(struct.pack('<h', bitsPerSample))
# Data Subchunk
waveFile.write(dChunkID)
waveFile.write(struct.pack('<i', dChunkSize))
for samp in generateSin(sampleRate, bitsPerSample, A4, amp_16, 1):
waveFile.write(struct.pack('<i', int(round(samp))))
waveFile.write(struct.pack('<i', int(round(samp))))
waveFile.close()
答案 0 :(得分:0)
学习wav
文件的好方法。
16位样本大小表示每个频道为16位。您将正弦波的采样值打包为4个字节(32位),得到类似XX00的图形,其中XX是第一个通道的正确16位值,然后是第二个通道的00,因此是第二个通道只有零。之后-您再次写入相同的值,因此您复制了先前样本的数据,这就是您的频率错误的原因:
从
for
循环
for samp in generateSin(sampleRate, bitsPerSample, A4, amp_16, 1):
waveFile.write(struct.pack('<i', int(round(samp))))
waveFile.write(struct.pack('<i', int(round(samp))))
至-
for samp in generateSin(sampleRate, bitsPerSample, A4, amp_16, 1):
waveFile.write(struct.pack('<h', int(round(samp))))
waveFile.write(struct.pack('<h', int(round(samp))))
现在,您一次只写入2个字节,即一个通道,然后为第二个通道再次写入相同的值。 频率不是440Hz,而是500Hz-我相信这是由于对数字进行了四舍五入。