How do you separate each channel of a two channel wav file into two different files using wavio? or another library?

mm_ picture mm_ · Jul 11, 2018 · Viewed 10.3k times · Source

The following script plays the original file ok. I try to separate each channel in the obvious way, but it does not work.

import os
import wavio
import numpy
import pyglet

file_name = "guitarup_full.wav"

# I get the file !
File = wavio.read(file_name)
rate = File.rate
# it looks good
print File.data.shape
print rate
# and then the channels:
channel_1 = File.data[:,0]
channel_2 = File.data[:,1]
wavio.write("guitar_channel_1.wav", channel_1, rate )
wavio.write("guitar_channel_2.wav", channel_2, rate )

# now we try to play:
source =  pyglet.resource.media(file_name, streaming=False)
source_ch1 =  pyglet.resource.media("guitar_channel_1.wav", streaming=False)
source_ch2 =  pyglet.resource.media("guitar_channel_2.wav", streaming=False)

#uncomment the one you want to listen.
source.play()
#source_ch1.play()
#source_ch2.play()

pyglet.app.run()

The first sounds like a guitar, the second and third like Gaussian noise. Can someone tell me what is wrong with it?

The audio file I used is: https://www.freesounds.info/global/wav.php?fileid=11

The shape of the data is: (88471, 2) rate is: 44100

Also, if I play the file in another player, I get the same: Gaussian Noise.

Note: The use of pyglet is superfluous for the problem. If you use it to investigate this issue, make sure the files are in a folder registered in the resources folder. To do that:

pyglet.resource.path.append("your_sounds_location")
pyglet.resource.reindex()

Answer

Andriy Makukha picture Andriy Makukha · Jul 13, 2018

I don't know what is wrong with the wavio code, but here's how you can separate WAV channel using standard Python module wave (which is also used by wavio) and numpy:

import wave
import numpy as np

def save_wav_channel(fn, wav, channel):
    '''
    Take Wave_read object as an input and save one of its
    channels into a separate .wav file.
    '''
    # Read data
    nch   = wav.getnchannels()
    depth = wav.getsampwidth()
    wav.setpos(0)
    sdata = wav.readframes(wav.getnframes())

    # Extract channel data (24-bit data not supported)
    typ = { 1: np.uint8, 2: np.uint16, 4: np.uint32 }.get(depth)
    if not typ:
        raise ValueError("sample width {} not supported".format(depth))
    if channel >= nch:
        raise ValueError("cannot extract channel {} out of {}".format(channel+1, nch))
    print ("Extracting channel {} out of {} channels, {}-bit depth".format(channel+1, nch, depth*8))
    data = np.fromstring(sdata, dtype=typ)
    ch_data = data[channel::nch]

    # Save channel to a separate file
    outwav = wave.open(fn, 'w')
    outwav.setparams(wav.getparams())
    outwav.setnchannels(1)
    outwav.writeframes(ch_data.tostring())
    outwav.close()

wav = wave.open(WAV_FILENAME)
save_wav_channel('ch1.wav', wav, 0)
save_wav_channel('ch2.wav', wav, 1)