How to write stereo wav files in Python?
Asked Answered
H

3

18

The following code writes a simple sine at frequency 400Hz to a mono WAV file. How should this code be changed in order to produce a stereo WAV file. The second channel should be in a different frequency.

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()
Have answered 3/9, 2010 at 15:41 Comment(1)
Set nchannels = 2 for a start ;)Healall
U
11

Build a parallel sine_list_y list with the other frequency / channel, set nchannels=2, and in the output loop use for s, t in zip(sine_list_x, sine_list_y): as the header clause, and a body with two writeframes calls -- one for s, one for t. IOW, corresponding frames for the two channels "alternate" in the file.

See e.g. this page for a thorough description of all possible WAV file formats, and I quote:

Multi-channel digital audio samples are stored as interlaced wave data which simply means that the audio samples of a multi-channel (such as stereo and surround) wave file are stored by cycling through the audio samples for each channel before advancing to the next sample time. This is done so that the audio files can be played or streamed before the entire file can be read. This is handy when playing a large file from disk (that may not completely fit into memory) or streaming a file over the Internet. The values in the diagram below would be stored in a Wave file in the order they are listed in the Value column (top to bottom).

and the following table clearly shows the channels' samples going left, right, left, right, ...

Untrue answered 3/9, 2010 at 15:47 Comment(0)
B
3

For an example producing a stereo .wav file, see the test_wave.py module. The test produces an all-zero file. You can modify by inserting alternating sample values.

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()
Baber answered 3/9, 2010 at 15:56 Comment(0)
B
2

Another option is to use the SciPy and NumPy libraries. In the below example, we produce a stereo wave file where the left channel has a low-frequency tone while the right channel has a higher-frequency tone. (Note: Use VLC player to play the audio)

To install SciPy, see: 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)

Environment Notes

Version Used Python 3.7.1

  • Python 3.7.1
  • SciPy 1.1.0
Bassett answered 18/5, 2020 at 20:52 Comment(2)
When I try to play the audio file your code generates, both Windows media player and Groove music player throw an unsupported codec error: 0xc00d5212. Which player did you use?Mail
@Naktis, I only tested with VLC player and Apple Quicktime. Also, I just tested that the generated file plays as expected when using VLC player on a Windows machine. You can download VLC player for free here: videolan.orgBassett

© 2022 - 2024 — McMap. All rights reserved.