[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[pygame] Error using sndarray on mac 10.5 and 10.6



Ok, so I have a problem playing some sound files properly on Macs with 2.5 or 2.6
I am using the macports version of pygame 1.9.1 and python 2.5

The issue is some of the wav files I have created in audacity have an odd number of
Frames. Of course since these are 16bit mono PCM files  they should be even, but
these files work fine using pygame in Ubuntu. I have found that the problem lies in
_numpysndarray.py  particularly in _array_samples:

def _array_samples(sound, raw):
    # Info is a (freq, format, stereo) tuple
    info = mixer.get_init ()
    if not info:
        raise pygame.error("Mixer not initialized")
    fmtbytes = (abs (info[1]) & 0xff) >> 3
    channels = info[2]
    if raw:
        data = "" ().raw
    else:
        data = "" ()

    shape = (len (data) // fmtbytes, )
    if channels > 1:
        shape = (shape[0] // channels, channels)

    # mixer.init () does not support different formats from the ones below,
    # so MSB/LSB stuff is silently ignored.
    typecode = { 8 : numpy.uint8,   # AUDIO_U8
                 16 : numpy.uint16, # AUDIO_U16 / AUDIO_U16SYS
                 -8 : numpy.int8,   # AUDIO_S8
                 -16 : numpy.int16  # AUDUI_S16 / AUDIO_S16SYS
                 }[info[1]]
                
    array = numpy.fromstring (data, typecode)
    array.shape = shape
    return array

the line
array = numpy.fromstring (data, typecode)
gives the following error:
ValueError: string size must be a multiple of element size

As these these are 16 bit values the size should be even, though some wave files have
an extra byte at the end that needs to be dropped. Somehow the odd file work in
Linux still, but crap out in osX. I think this odd frame size problem could be easily
solved by just dropping the last odd frame.

def _array_samples(sound, raw):
    # Info is a (freq, format, stereo) tuple
    info = mixer.get_init ()
    if not info:
        raise pygame.error("Mixer not initialized")
    fmtbytes = (abs (info[1]) & 0xff) >> 3
    channels = info[2]
    if raw:
        data = "" ().raw
    else:
        data = "" ()

    shape = (len (data) // fmtbytes, )
    if channels > 1:
        shape = (shape[0] // channels, channels)

    # mixer.init () does not support different formats from the ones below,
    # so MSB/LSB stuff is silently ignored.
    typecode = { 8 : numpy.uint8,   # AUDIO_U8
                 16 : numpy.uint16, # AUDIO_U16 / AUDIO_U16SYS
                 -8 : numpy.int8,   # AUDIO_S8
                 -16 : numpy.int16  # AUDUI_S16 / AUDIO_S16SYS
                 }[info[1]]
    dl=len(data)
    if(dl%2==1):
        dl=dl-1           
    array = numpy.fromstring (data[:dl], typecode)
    array.shape = shape
    return array


I've tried this modification locally, and it indeed works for odd and even frames.
Since odd frames seem to work on some systems but not others, I think this
change should be added. Anyways, it solved my headaches and I thought I'd share.