Python Wave byte data
Question: I'm trying to read the data from a .wav file.

    
    
    import wave
    wr = wave.open("~/01 Road.wav", 'r')
    # sample width is 2 bytes
    # number of channels is 2
    wave_data = wr.readframes(1)
    print(wave_data)
    

This gives:

    
    
    b'\x00\x00\x00\x00'
    

Which is the "first frame" of the song. These 4 bytes obviously correspond to
the (2 channels * 2 byte sample width) bytes per frame, but what does each
byte correspond to?

In particular, I'm trying to convert it to a mono amplitude signal.


Answer: If you want to understand what the 'frame' is you will have to read the
**standard** of the wave file format. For instance:
<https://web.archive.org/web/20140221054954/http://home.roadrunner.com/~jgglatt/tech/wave.htm>

From that document:

> The sample points that are meant to be "played" ie, sent to a Digital to
> Analog Converter(DAC) simultaneously are collectively called a **sample
> frame**. In the example of our stereo waveform, every two sample points
> makes up another sample frame. This is illustrated below for that stereo
> example.
    
    
    sample       sample              sample
    frame 0      frame 1             frame N
     _____ _____ _____ _____         _____ _____
    | ch1 | ch2 | ch1 | ch2 | . . . | ch1 | ch2 |
    |_____|_____|_____|_____|       |_____|_____|
     _____
    |     | = one sample point
    |_____|
    

To convert to mono you could do something like this,

    
    
    import wave
    
    def stereo_to_mono(hex1, hex2):
        """average two hex string samples"""
        return hex((ord(hex1) + ord(hex2))/2)
    
    wr = wave.open('piano2.wav','r')
    
    nchannels, sampwidth, framerate, nframes, comptype, compname =  wr.getparams()
    
    ww = wave.open('piano_mono.wav','wb')
    ww.setparams((1,sampwidth,framerate,nframes,comptype,compname))
    
    frames = wr.readframes(wr.getnframes()-1)
    
    new_frames = ''
    
    for (s1, s2) in zip(frames[0::2],frames[1::2]):
        new_frames += stereo_to_mono(s1,s2)[2:].zfill(2).decode('hex')
    
    ww.writeframes(new_frames)
    

There is no clear-cut way to go from stereo to mono. You could just drop one
channel. Above, I am averaging the channels. It all depends on your
application.

