0

I have a jupyter notebook file and a .wav file that I am working with. You can find both here:

https://github.com/diggetybo/ICA-Attachments

I have created python functions to load a .wav file and play it using an HTML interface within jupyter notebook.

I will repurpose this post slightly becuase I have resolved the load_wav function. What remains unresolved is the other function, wavPlayer. It supposed to take a numpy representation of a .wav file and render it for playback. Unfortunately, it's not working at all. All the files, despite being correctly loaded by load_wav, have the error: 'This audio content is encoded by an unsupported format.' And doesn't play. Clearly, in this link, the original author of the code had it working:

http://web.archive.org/web/20150314223948/http://shogun-toolbox.org/static/notebook/current/bss_audio.html

My guess is it's a version compatibility issue. I use Python 3.5, this tutorial was in 2.7 I think.

All I need to be able to accept an answer to this question is for someone to get a .wav file to be played by the wavPlayer function in Python 3.5 (see either link for the jupyter notebook file) My guess after a week of playing around with it is the StringIO and/or BytesIO sections of the code. I'm not an expert on those particular libraries, so I'm hoping someone can help out here.

For accessibility purposes, I'll post the function below.

import sys
import StringIO
import base64
import struct  

from IPython.display import display
from IPython.core.display import HTML

def wavPlayer(data, rate):
    """ will display html 5 player for compatible browser
    The browser need to know how to play wav through html5.
    there is no autoplay to prevent file playing when the browser opens
    Adapted from SciPy.io. and
    github.com/Carreau/posts/blob/master/07-the-sound-of-hydrogen.ipynb
    """

    buffer = StringIO.StringIO()
    buffer.write(b'RIFF')
    buffer.write(b'\x00\x00\x00\x00')
    buffer.write(b'WAVE')

    buffer.write(b'fmt ')
    if data.ndim == 1:
        noc = 1
    else:
        noc = data.shape[1]
    bits = data.dtype.itemsize * 8
    sbytes = rate*(bits // 8)*noc
    ba = noc * (bits // 8)
    buffer.write(struct.pack('<ihHIIHH', 16, 1, noc, rate, sbytes, ba, bits))

    # data chunk
    buffer.write(b'data')
    buffer.write(struct.pack('<i', data.nbytes))

    if data.dtype.byteorder == '>' or (data.dtype.byteorder == '=' and sys.byteorder == 'big'):
        data = data.byteswap()

    buffer.write(data.tostring())
    # return buffer.getvalue()
    # Determine file size and place it in correct
    # position at start of the file.
    size = buffer.tell()
    buffer.seek(4)
    buffer.write(struct.pack('<i', size-8))

    val = buffer.getvalue()

    src = """
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Simple Test</title>
    </head>

    <body>
    <audio controls="controls" style="width:600px" >
      <source controls src="data:audio/wav;base64,{base64}" type="audio/wav" />
      Your browser does not support the audio element.
    </audio>
    </body>
    """.format(base64=base64.encodestring(val))
    display(HTML(src))

Thank you

Arash Howaida
  • 2,575
  • 2
  • 19
  • 50
  • I'm aware that IPython.display.Audio('filename.wav') will work for playing the .wav, but I will eventually need to transform the audio data into linear algebra (probably using numpy). That's why the load_wav function is key, even though Jupyter has a built-in media player. Take a look at the bottom portion of the load_wav function, specifically, `data = resample(data, len(data) * ratio) return samplerate, data.astype(np.int16)` is instrumental for the rest of the notebook. But of course, it doesn't work.... yet... somebody help... – Arash Howaida Sep 19 '16 at 17:22
  • Do you know which bit of your code it's getting stuck in? – Thomas K Sep 20 '16 at 14:34
  • when I hit interrupt kernal, it usually is stuck at the resample part of the code. `data = resample(data, len(data) * ratio) return samplerate, data.astype(np.int16)` I'm guessing it must be that. I've also commented that section out and proceeded with the load_wav and it worked. However I'm not sure that omitting the resampling is ideal for the subsequent ICA audio application that will use these .wavs. – Arash Howaida Sep 20 '16 at 15:20
  • It turns out the original link isn't available anymore. It can be viewed on web archive though. If it's more convenient than viewing the material I provided in my Github repository, I will link the original notebook for robustness. http://web.archive.org/web/20150314223948/http://shogun-toolbox.org/static/notebook/current/bss_audio.html -- Note that you will need your own .wavs to follow along. – Arash Howaida Sep 20 '16 at 15:25
  • Update: I noticed an error that said expected string, got bytes in the wav player function. What I changed was: `IoString.IoString()` to `io.BytesIO()` I also changed `encodestring` to `encodebytes`I don't know if that was the right thing to do. It does at least run, but it cannot play the audio data, it says the media content is not supported. – Arash Howaida Sep 21 '16 at 05:40
  • Update 2: I did an experiment to see if the cell would ever complete. I gave it a lot of help. I had it running on my liquid cooled 4.5Ghz machine and just sat back and watched. It took 30 minutes for the load_wav function to complete. My .wav file are only 10 seconds long, and are not super high definition either. Hopefully those that are following along with my progress can shed some light on why the load_wav function is so computationally intensive, or whether or not my .wavs themselves are the issue. I'm just out of my depth, unfortunately. Doing my best though. – Arash Howaida Sep 21 '16 at 05:43
  • Update 2 (cont'd) Let me add that as part of my experiment, I had the same jupyter notebook file run on my laptop. My laptop's CPU is not as powerful as my desktops, so I tried to cut it some slack by reducing the samplerate by a factor of 100. So when my laptop got to the load_wav function, it was able to complete it in about 7 minutes. Still a long time. I'm wondering if maybe the wavfile module or the scipy signal resample is not efficient? 7 minutes of processing for 10 seconds of audio seems drastic. Of course I'm not ruling out user error. Hope these updates help elucidate the situation. – Arash Howaida Sep 21 '16 at 05:55
  • That does seem incredibly slow. I would suggest that you try profiling the code - have a look at this [relevant SO post](http://stackoverflow.com/questions/582336/how-can-you-profile-a-python-script#582337) and at the [profiling docs](https://docs.python.org/3.5/library/profile.html). – Thomas K Sep 21 '16 at 13:16
  • Great advice. It seems to be the `data = resample(data, len(data) * ratio)` line, specifically the `len(data)` part, although the .wavs are only 10 seconds long, they require a numpy array with 10's of 1000's of data elements to be expressed. It's also consistent with my experiments, lowering the samplerate, commenting out the resample section altogether. So I think I have narrowed down the issue quite a bit. I have learned that audio processing can be inefficient, so I'll try to go from there. – Arash Howaida Sep 21 '16 at 17:04
  • You might want to try asking on the [scipy-user](https://mail.scipy.org/mailman/listinfo/scipy-user) mailing list - I don't know much about audio processing, but I can't believe it's meant to be that slow. – Thomas K Sep 21 '16 at 21:10

0 Answers0