Не получается записать двухканальный волновой файл в сыром Python (без волнового модуля) - PullRequest
0 голосов
/ 27 февраля 2019

Я пытаюсь немного узнать о звуковом программировании, поэтому я решил посмотреть, смогу ли я выяснить, как создать синусоидальную волну и записать ее в файл .wav.Из ссылки здесь я понял, что каждый канал просто чередуется в блоке данных в конце файла.Тем не менее, мой сгенерированный файл WAV, кажется, играет только в левом каналеЯ также сравнил свой выходной сигнал с истинным значением 440 Гц A и заметил, что он на октаву ниже ожидаемого.

Я предполагаю, что происходит то, что программы, которые я использую для прослушивания файла, интерпретируют данные какодин канал, и, поскольку каждый образец дублируется один раз, воспроизводится волна с 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()

1 Ответ

0 голосов
/ 28 февраля 2019

Отличный способ изучения файлов wav.
Размер выборки из 16 бит означает, что каждый канал равен 16 битам.Вы берете значение выборки вашей синусоидальной волны, упаковываете его в 4 байта (32 бита), так что вы получите что-то вроде XX00, где XX - правильное значение 16 бит для первого канала, затем 00 для второго канала, так что второй каналимеет только нули.После этого - вы снова записываете то же значение, поэтому дублируете данные предыдущего образца, и поэтому ваша частота неверна: enter image description here Измените цикл 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))))

To -

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 байта за раз, то есть один канал, а затем снова будете записывать то же значение для второго канала.Частота не 440 Гц, а 500 Гц - я считаю, что это связано с округлением чисел.

...