Commits

marcus  committed 424ef30

Added numpy support for the sndarray module. BufferProxy now contains a length property, which indicates the length of the buffer in bytes.

  • Participants
  • Parent commits cdd953a

Comments (0)

Files changed (14)

 
 clean:
 	rm -rf build dist
+	rm -f lib/*~ src/*~ test/*~
 
 mixer src/mixer.c $(SDL) $(MIXER) $(DEBUG)
 mixer_music src/music.c $(SDL) $(MIXER) $(DEBUG)
 _numericsurfarray src/_numericsurfarray.c $(SDL) $(DEBUG)
-sndarray src/sndarray.c $(SDL) $(MIXER) $(DEBUG)
+_numericsndarray src/_numericsndarray.c $(SDL) $(MIXER) $(DEBUG)
 movie src/movie.c $(SDL) $(SMPEG) $(DEBUG)
 scrap src/scrap.c $(SDL) $(SCRAP) $(DEBUG)
 
 # BUG	= fixed a bug that was (or could have been) crashing
 #
 #
+Jan 26, 2008
+    pygame.sndarray noew can change between Numeric and numpy using the
+      new methods pygame.sndarray.use_array () and
+      pygame.sndarray.get_arraytypes ().
+
 Jan 24, 2008
-    Updated the configuration and build process under Windows. In config_msys.py
-       and config.py os.popen is replaced with the newer subprocess.Popen so
-       the MSYS will run. Calls to raw_input now show the prompt on an MSYS
-       console. In an MSYS build paths written to Setup are now Windows paths
-       for distutils. The hard coded DLL file paths have been removed from setup.py.
-       In now gets the paths from Setup. Consequently, setup.py is now VC/MinGW
+    Updated the configuration and build process under Windows. In
+       config_msys.py and config.py os.popen is replaced with the newer
+       subprocess.Popen so the MSYS will run. Calls to raw_input now
+       show the prompt on an MSYS console. In an MSYS build paths
+       written to Setup are now Windows paths for distutils. The hard
+       coded DLL file paths have been removed from setup.py.  It now
+       gets the paths from Setup. Consequently, setup.py is now VC/MinGW
        agnostic.
 
-    Added build_deps.py, an all-in-one dependency builder for Windows. Requires
-       MinGW and MSYS.
+    Added build_deps.py, an all-in-one dependency builder for
+       Windows. Requires MinGW and MSYS.
 
 Jan 8, 2008
     pygame.surfarray now can change between Numeric and numpy using the
 
 Dec 15, 2007
     Mask can now get bounding rects of set bits.
-    pygame.transform can find edges in an image, get the average surface of many
-      surfaces and also threshold an image by color.
+    pygame.transform can find edges in an image, get the average surface
+      of many surfaces and also threshold an image by color.
 
 Sep 1, 2007
     Added get_buffer() methods to Surface, and Sound - which return a new

File lib/_numpysndarray.py

+##    pygame - Python Game Library
+##    Copyright (C) 2008 Marcus von Appen
+##
+##    This library is free software; you can redistribute it and/or
+##    modify it under the terms of the GNU Library General Public
+##    License as published by the Free Software Foundation; either
+##    version 2 of the License, or (at your option) any later version.
+##
+##    This library is distributed in the hope that it will be useful,
+##    but WITHOUT ANY WARRANTY; without even the implied warranty of
+##    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+##    Library General Public License for more details.
+##
+##    You should have received a copy of the GNU Library General Public
+##    License along with this library; if not, write to the Free
+##    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+##
+##    Marcus von Appen
+##    mva@sysfault.org
+
+"""pygame module for accessing 
+"""
+
+import pygame
+import pygame.mixer as mixer 
+import numpy
+
+def array (sound):
+    """
+    """
+    # 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 = mixer.get_num_channels ()
+    data = sound.get_buffer ().raw
+
+    shape = (len (data) / channels * fmtbytes, )
+    if channels > 1:
+        shape = (shape[0], 2)
+        
+    typecode = None
+    # Signed or unsigned representation?
+    if info[1] in (pygame.AUDIO_S8, pygame.AUDIO_S16LSB, pygame.AUDIO_S16MSB):
+        typecode = (numpy.uint8, numpy.uint16, None, numpy.uint32)[fmtbytes - 1]
+    else:
+        typecode = (numpy.int8, numpy.int16, None, numpy.int32)[fmtbytes - 1]
+        
+    array = numpy.fromstring (data, typecode)
+    array.shape = shape
+    return array
+
+def samples (sound):
+    """
+    """
+    # Info is a (freq, format, stereo) tuple
+    info = pygame.mixer.get_init ()
+    if not info:
+        raise pygame.error, "Mixer not initialized"
+    fmtbytes = (abs (info[1]) & 0xff) >> 3
+    channels = mixer.get_num_channels ()
+    data = sound.get_buffer ()
+
+    shape = (data.length / channels * fmtbytes, )
+    if channels > 1:
+        shape = (shape[0], 2)
+        
+    typecode = None
+    # Signed or unsigned representation?
+    if format in (pygame.AUDIO_S8, pygame.AUDIO_S16LSB, pygame.AUDIO_S16MSB):
+        typecode = (numpy.uint8, numpy.uint16, None, numpy.uint32)[fmtbytes - 1]
+    else:
+        typecode = (numpy.int8, numpy.int16, None, numpy.int32)[fmtbytes - 1]
+        
+    array = numpy.frombuffer (data, typecode)
+    array.shape = shape
+    return array
+
+def make_sound (array):
+    """
+    """
+    # Info is a (freq, format, stereo) tuple
+    info = pygame.mixer.get_init ()
+    if not info:
+        raise pygame.error, "Mixer not initialized"
+    fmtbytes = (abs (info[1]) & 0xff) >> 3
+    channels = mixer.get_num_channels ()
+
+    shape = array.shape
+    if len (shape) != channels:
+        if channels == 1:
+            raise ValueError, "Array must be 1-dimensional for mono mixer"
+        elif channels == 2:
+            raise ValueError, "Array must be 2-dimensional for stereo mixer"
+        else:
+            raise ValueError, "Array depth must match number of mixer channels"
+    return mixer.Sound (array)

File lib/sndarray.doc

+pygame.sndarray
+pygame module for accessing sound sample data
+
+Functions to convert between Numeric or numpy arrays and Sound
+objects. This module will only be available when pygame can use the
+external numpy or Numeric package.
+
+Sound data is made of thousands of samples per second, and each sample
+is the amplitude of the wave at a particular moment in time. For
+example, in 22-kHz format, element number 5 of the array is the
+amplitude of the wave after 5/22000 seconds.
+
+Each sample is an 8-bit or 16-bit integer, depending on the data format.
+A stereo sound file has two values per sample, while a mono sound file
+only has one.
+
+Supported array systems are
+
+  numeric
+  numpy
+
+The default will be Numeric, if installed. Otherwise, numpy will be set
+as default if installed. If neither Numeric nor numpy are installed, the
+module will raise an ImportError.
+
+The array type to use can be changed at runtime using the use_array()
+method, which requires one of the above types as string.
+
+Note: numpy and Numeric are not completely compatible. Certain array
+manipulations, which work for one type, might behave differently or even
+completely break for the other.
+
+Additionally, in contrast to Numeric numpy can use unsigned 16-bit
+integers. Sounds with 16-bit data will be treated as unsigned integers,
+if the sound sample type requests this. Numeric instead always uses
+signed integers for the representation, which is important to keep in
+mind, if you use the module's functions and wonder about the values.
+<SECTION>
+
+array
+copy Sound samples into an array
+pygame.sndarray.array(Sound): return array
+
+Creates a new array for the sound data and copies the samples. The array
+will always be in the format returned from pygame.mixer.get_init().
+<END>
+
+samples
+reference Sound samples into an array
+pygame.sndarray.samples(Sound): return array
+
+Creates a new array that directly references the samples in a Sound
+object. Modifying the array will change the Sound. The array will always
+be in the format returned from pygame.mixer.get_init().
+<END>
+
+make_sound
+convert an array into a Sound object
+pygame.sndarray.make_sound(array): return Sound
+
+Create a new playable Sound object from an array. The mixer module must
+be initialized and the array format must be similar to the mixer audio
+format.
+<END>
+
+use_array
+Sets the array system to be used for sound arrays
+pygame.sndarray.use_array (arraytype): return None
+
+Uses the requested array type for the module functions.
+Currently supported array types are:
+
+  numeric 
+  numpy
+
+If the requested type is not available, a ValueError will be raised.
+
+New in pygame 1.8.
+<END>
+
+get_arraytypes
+Gets the array system types currently supported.
+pygame.sndarray.get_arraytypes (): return tuple
+
+Checks, which array systems are available and returns them as a tuple of
+strings. The values of the tuple can be used directly in the
+pygame.sndarray.use_array() method. If no supported array system could
+be found, None will be returned.
+
+New in pygame 1.8.
+<END>
+<END>

File lib/sndarray.py

+##    pygame - Python Game Library
+##    Copyright (C) 2008 Marcus von Appen
+##
+##    This library is free software; you can redistribute it and/or
+##    modify it under the terms of the GNU Library General Public
+##    License as published by the Free Software Foundation; either
+##    version 2 of the License, or (at your option) any later version.
+##
+##    This library is distributed in the hope that it will be useful,
+##    but WITHOUT ANY WARRANTY; without even the implied warranty of
+##    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+##    Library General Public License for more details.
+##
+##    You should have received a copy of the GNU Library General Public
+##    License along with this library; if not, write to the Free
+##    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+##
+##    Marcus von Appen
+##    mva@sysfault.org
+
+"""pygame module for accessing sound sample data
+
+Functions to convert between Numeric or numpy arrays and Sound
+objects. This module will only be available when pygame can use the
+external numpy or Numeric package.
+
+Sound data is made of thousands of samples per second, and each sample
+is the amplitude of the wave at a particular moment in time. For
+example, in 22-kHz format, element number 5 of the array is the
+amplitude of the wave after 5/22000 seconds.
+
+Each sample is an 8-bit or 16-bit integer, depending on the data format.
+A stereo sound file has two values per sample, while a mono sound file
+only has one.
+
+Supported array systems are
+
+  numeric
+  numpy
+
+The default will be Numeric, if installed. Otherwise, numpy will be set
+as default if installed. If neither Numeric nor numpy are installed, the
+module will raise an ImportError.
+
+The array type to use can be changed at runtime using the use_array()
+method, which requires one of the above types as string.
+
+Note: numpy and Numeric are not completely compatible. Certain array
+manipulations, which work for one type, might behave differently or even
+completely break for the other.
+
+Additionally, in contrast to Numeric numpy can use unsigned 16-bit
+integers. Sounds with 16-bit data will be treated as unsigned integers,
+if the sound sample type requests this. Numeric instead always uses
+signed integers for the representation, which is important to keep in
+mind, if you use the module's functions and wonder about the values.
+"""
+
+import pygame
+
+# Global array type setting. See use_array().
+__arraytype = None
+
+# Try to import the necessary modules.
+try:
+    import pygame._numericsndarray as numericsnd
+    __hasnumeric = True
+    __arraytype = "numeric"
+except ImportError, msg:
+    __hasnumeric = False
+
+try:
+    import pygame._numpysndarray as numpysnd
+    __hasnumpy = True
+    if not __hasnumeric:
+        __arraytype = "numpy"
+except ImportError:
+    __hasnumpy = False
+
+if not __hasnumpy and not __hasnumeric:
+    raise ImportError, "no module named numpy or Numeric found"
+
+def array (sound):
+    """pygame.sndarray.array(Sound): return array
+
+    Copy Sound samples into an array.
+
+    Creates a new array for the sound data and copies the samples. The
+    array will always be in the format returned from
+    pygame.mixer.get_init().
+    """
+    if __arraytype == "numeric":
+        return numericsnd.array (sound)
+    elif __arraytype == "numpy":
+        return numpysnd.array (sound)
+    raise NotImplementedError, "sound arrays are not supported"
+
+def samples (sound):
+    """pygame.sndarray.samples(Sound): return array
+
+    Reference Sound samples into an array.
+
+    Creates a new array that directly references the samples in a Sound
+    object. Modifying the array will change the Sound. The array will
+    always be in the format returned from pygame.mixer.get_init().
+    """
+    if __arraytype == "numeric":
+        return numericsnd.samples (sound)
+    elif __arraytype == "numpy":
+        return numpy.samples (sound)
+    raise NotImplementedError, "sound arrays are not supported"
+
+def make_sound (array):
+    """pygame.sndarray.make_sound(array): return Sound
+
+    Convert an array into a Sound object.
+    
+    Create a new playable Sound object from an array. The mixer module
+    must be initialized and the array format must be similar to the mixer
+    audio format.
+    """
+    if __arraytype == "numeric":
+        return numericnd.make_sound (array)
+    elif __arraytype == "numpy":
+        return numpy.make_sound (array)
+    raise NotImplementedError, "sound arrays are not supported"
+
+def use_array (arraytype):
+    """pygame.sndarray.use_array (arraytype): return None
+
+    Sets the array system to be used for sound arrays.
+
+    Uses the requested array type for the module functions.
+    Currently supported array types are:
+
+      numeric 
+      numpy
+
+    If the requested type is not available, a ValueError will be raised.
+    """
+    global __arraytype
+
+    arraytype = arraytype.lower ()
+    if arraytype == "numeric":
+        if __hasnumeric:
+            __arraytype = arraytype
+        else:
+            raise ValueError, "Numeric arrays are not available"
+        
+    elif arraytype == "numpy":
+        if __hasnumpy:
+            __arraytype = arraytype
+        else:
+            raise ValueError, "numpy arrays are not available"
+    else:
+        raise ValueError, "invalid array type"
+
+def get_arraytypes ():
+    """pygame.sndarray.get_arraytypes (): return tuple
+
+    Gets the array system types currently supported.
+
+    Checks, which array system types are available and returns them as a
+    tuple of strings. The values of the tuple can be used directly in
+    the use_array () method.
+
+    If no supported array system could be found, None will be returned.
+    """
+    vals = []
+    if __hasnumeric:
+        vals.append ("numeric")
+    if __hasnumpy:
+        vals.append ("numpy")
+    if len (vals) == 0:
+        return None
+    return tuple (vals)

File lib/surfarray.py

 
 import pygame
 
+# Global array type setting. See use_array().
 __arraytype = None
 
 # Try to import the necessary modules.
 if not __hasnumpy and not __hasnumeric:
     raise ImportError, "no module named numpy or Numeric found"
 
-# Global array type setting. See use_array().
-
-
 def array2d (surface):
     """pygame.surfarray.array2d (Surface): return array
 
     """
     vals = []
     if __hasnumeric:
-        vals += ["numeric"]
+        vals.append ("numeric")
     if __hasnumpy:
-        vals += ["numpy"]
+        vals.append ("numpy")
     if len (vals) == 0:
         return None
     return tuple (vals)

File src/_numericsndarray.c

+/*
+  pygame - Python Game Library
+  Copyright (C) 2000-2001  Pete Shinners
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Library General Public
+  License as published by the Free Software Foundation; either
+  version 2 of the License, or (at your option) any later version.
+
+  This library is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  Library General Public License for more details.
+
+  You should have received a copy of the GNU Library General Public
+  License along with this library; if not, write to the Free
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+  Pete Shinners
+  pete@shinners.org
+*/
+
+#include "pygame.h"
+#include "pygamedocs.h"
+#include "mixer.h"
+#include "numeric_arrayobject.h"
+#include <SDL_byteorder.h>
+
+static PyObject*
+sndarray_samples (PyObject* self, PyObject* arg)
+{
+    int dim[2], numdims, type, formatbytes;
+    PyObject *array, *chunkobj;
+    Mix_Chunk* chunk;
+    Uint16 format;
+    int numchannels;
+
+    if (!PyArg_ParseTuple (arg, "O!", &PySound_Type, &chunkobj))
+        return NULL;
+    chunk = PySound_AsChunk (chunkobj);
+
+    if (!Mix_QuerySpec (NULL, &format, &numchannels))
+        return RAISE (PyExc_SDLError, "Mixer not initialized");
+
+    formatbytes = (abs (format) & 0xff) / 8;
+    switch (format) 
+    {
+    case AUDIO_S8:
+        type = PyArray_CHAR;
+        break;
+    case AUDIO_U8:
+        type = PyArray_UBYTE;
+        break;
+    case AUDIO_S16SYS:
+        type = PyArray_SHORT;
+        break;
+    case AUDIO_U16SYS:
+        type = PyArray_USHORT;
+        break;
+    default:
+        return RAISE (PyExc_TypeError, "Unpresentable audio format");
+    }
+
+    numdims = (numchannels > 1) ? 2 : 1;
+    dim[0] = chunk->alen / (numchannels*formatbytes);
+    dim[1] = numchannels;
+    
+    array = PyArray_FromDimsAndData (numdims, dim, type, (char*)chunk->abuf);
+    if(array)
+    {
+        Py_INCREF (chunkobj);
+        ((PyArrayObject*) array)->base = chunkobj;
+        ((PyArrayObject*) array)->flags |= SAVESPACE;
+    }
+    return array;
+}
+
+PyObject*
+sndarray_array (PyObject* self, PyObject* arg)
+{
+    PyObject *array, *arraycopy=NULL;
+    
+    /*we'll let numeric do the copying for us*/
+    array = sndarray_samples (self, arg);
+    if(array)
+    {
+        arraycopy = PyArray_Copy ((PyArrayObject*) array);
+        Py_DECREF (array);
+    }
+    return arraycopy;
+}
+
+PyObject*
+sndarray_make_sound (PyObject* self, PyObject* arg)
+{
+    PyObject *arrayobj;
+    PyArrayObject *array;
+    Mix_Chunk *chunk;
+    Uint16 format;
+    int numchannels, mixerbytes;
+    int loop1, loop2, step1, step2, length, length2=0;
+    Uint8 *src, *dst;
+
+    if (!PyArg_ParseTuple (arg, "O!", &PyArray_Type, &arrayobj))
+	return NULL;
+    array = (PyArrayObject*) arrayobj;
+    
+    if (!Mix_QuerySpec (NULL, &format, &numchannels))
+        return RAISE (PyExc_SDLError, "Mixer not initialized");
+    if (array->descr->type_num > PyArray_LONG)
+        return RAISE (PyExc_ValueError, "Invalid array datatype for sound");
+    
+    if (format==AUDIO_S8 || format==AUDIO_U8)
+        mixerbytes = 1;
+    else
+        mixerbytes = 2;
+    
+    /*test array dimensions*/
+    if (numchannels == 1)
+    {
+        if (array->nd != 1)
+            return RAISE (PyExc_ValueError,
+                          "Array must be 1-dimensional for mono mixer");
+    }
+    else
+    {
+        if (array->nd != 2)
+            return RAISE (PyExc_ValueError,
+                          "Array must be 2-dimensional for stereo mixer");
+        if (array->dimensions[1] != numchannels)
+            return RAISE (PyExc_ValueError,
+                          "Array depth must match number of mixer channels");
+    }
+    length = array->dimensions[0];
+    step1 = array->strides[0];
+    if (array->nd == 2)
+    {
+        length2 = array->dimensions[1];
+	step2 = array->strides[1];
+    }
+    else 
+    {
+        length2 = 1;
+        /*since length2 == 1, this won't be used for looping*/
+	step2 = mixerbytes; 
+    }
+
+    /*create chunk, we are screwed if SDL_mixer ever does more than
+     * malloc/free*/
+    chunk = (Mix_Chunk *)malloc (sizeof (Mix_Chunk));
+    if (chunk == NULL)
+        return RAISE (PyExc_MemoryError, "Cannot allocate chunk\n");
+    /*let's hope Mix_Chunk never changes also*/
+    chunk->alen = length * numchannels * mixerbytes;
+    chunk->abuf = (Uint8*) malloc (chunk->alen);
+    chunk->allocated = 1;
+    chunk->volume = 128;
+
+    if (step1 == mixerbytes * numchannels && step2 == mixerbytes)
+    {
+        /*OPTIMIZATION: in these cases, we don't need to loop through
+         *the samples individually, because the bytes are already layed
+         *out correctly*/
+        memcpy (chunk->abuf, array->data, chunk->alen);
+    }
+    else
+    {
+        dst = (Uint8*) chunk->abuf;
+        if (mixerbytes == 1)
+        {
+            for (loop1 = 0; loop1 < length; loop1++)
+            {
+                src = (Uint8*) array->data + loop1*step1;
+                switch (array->descr->elsize)
+                {
+                case 1:
+                    for (loop2=0; loop2<length2; loop2++, dst+=1, src+=step2)
+                        *(Uint8*)dst = (Uint8)*((Uint8*)src);
+                    break;
+                case 2:
+                    for (loop2=0; loop2<length2; loop2++, dst+=1, src+=step2)
+                        *(Uint8*)dst = (Uint8)*((Uint16*)src);
+                    break;
+                case 4:
+                    for (loop2=0; loop2<length2; loop2++, dst+=1, src+=step2)
+                        *(Uint8*)dst = (Uint8)*((Uint32*)src);
+                    break;
+                }
+            }
+        }
+        else
+        {
+            for (loop1 = 0; loop1 < length; loop1++)
+            {
+                src = (Uint8*) array->data + loop1*step1;
+                switch (array->descr->elsize)
+                {
+                case 1:
+                    for (loop2=0; loop2<length2; loop2++, dst+=2, src+=step2)
+                        *(Uint16*)dst = (Uint16)(*((Uint8*)src)<<8);
+                    break;
+                case 2:
+                    for (loop2=0; loop2<length2; loop2++, dst+=2, src+=step2)
+                        *(Uint16*)dst = (Uint16)*((Uint16*)src);
+                    break;
+                case 4:
+                    for (loop2=0; loop2<length2; loop2++, dst+=2, src+=step2)
+                        *(Uint16*)dst = (Uint16)*((Uint32*)src);
+                    break;
+                }
+            }
+        }
+    }
+    
+    return PySound_New (chunk);
+}
+
+static PyMethodDef sndarray_builtins[] =
+{
+    { "samples", sndarray_samples, METH_VARARGS, DOC_PYGAMESNDARRAYSAMPLES },
+    { "array", sndarray_array, METH_VARARGS, DOC_PYGAMESNDARRAYARRAY },
+    { "make_sound", sndarray_make_sound, METH_VARARGS,
+      DOC_PYGAMESNDARRAYMAKESOUND },
+    { NULL, NULL, 0, NULL}
+};
+
+PYGAME_EXPORT
+void init_numericsndarray (void)
+{
+    PyObject *module, *dict;
+    
+    /* create the module */
+    module = Py_InitModule3 ("_numericsndarray", sndarray_builtins,
+        DOC_PYGAMESNDARRAY);
+    dict = PyModule_GetDict (module);
+        
+    /*imported needed apis*/
+    import_pygame_base ();
+    import_pygame_mixer ();
+    import_array ();
+    /*needed for Numeric in python2.3*/
+    PyImport_ImportModule ("Numeric");
+}

File src/bufferproxy.c

                                    PyObject *kwds);
 static void _bufferproxy_dealloc (PyBufferProxy *self);
 static PyObject* _bufferproxy_get_dict (PyBufferProxy *self, void *closure);
-static PyObject* _bufferproxy_get_raw (PyBufferProxy *buffer, void *closure);
+static PyObject* _bufferproxy_get_raw (PyBufferProxy *self, void *closure);
+static PyObject* _bufferproxy_get_length (PyBufferProxy *self, void *closure);
 static PyObject* _bufferproxy_repr (PyBufferProxy *self);
 static PyObject* _bufferproxy_write (PyBufferProxy *buffer, PyObject *args);
 
     { "__dict__", (getter) _bufferproxy_get_dict, NULL, NULL, NULL },
     { "raw", (getter) _bufferproxy_get_raw, NULL,
       "The raw buffer data as string", NULL },
+    { "length", (getter) _bufferproxy_get_length, NULL,
+      "The size of the buffer data.", NULL },
     { NULL, NULL, NULL, NULL, NULL }
 };
 
  * Getter for PyBufferProxy.raw.
  */
 static PyObject*
-_bufferproxy_get_raw (PyBufferProxy *buffer, void *closure)
+_bufferproxy_get_raw (PyBufferProxy *self, void *closure)
 {
-    return PyString_FromStringAndSize (buffer->buffer, buffer->length);
+    return PyString_FromStringAndSize (self->buffer, self->length);
+}
+
+/**
+ * Getter for PyBufferProxy.length
+ */
+static PyObject*
+_bufferproxy_get_length (PyBufferProxy *self, void *closure)
+{
+    return PyInt_FromLong (self->length);
 }
 
 /**** Methods ****/
     apiobj = PyCObject_FromVoidPtr (c_api, NULL);
     PyDict_SetItemString (dict, PYGAMEAPI_LOCAL_ENTRY, apiobj);
     Py_DECREF (apiobj);
-
-
 }
       DOC_SOUNDGETLENGTH },
     { "get_buffer", (PyCFunction) snd_get_buffer, METH_NOARGS,
       DOC_SOUNDGETBUFFER },
-        
     { NULL, NULL, 0, NULL }
 };
 
 {
     PyObject* file;
     char* name = NULL;
-    Mix_Chunk* chunk;
+    Mix_Chunk* chunk = NULL;
     
     ((PySoundObject*)self)->chunk = NULL;
 
     if (!PyArg_ParseTuple (arg, "O", &file))
         return -1;
 
-        
     if (!SDL_WasInit (SDL_INIT_AUDIO)) 
     {
         RAISE (PyExc_SDLError, "mixer system not initialized");
         return -1;
     }
-        
+
     if (PyString_Check (file) || PyUnicode_Check (file))
     {
-        if (!PyArg_ParseTuple (arg, "s", &name))
+        if (PyArg_ParseTuple (arg, "s", &name))
+        {
+            Py_BEGIN_ALLOW_THREADS;
+            chunk = Mix_LoadWAV (name);
+            Py_END_ALLOW_THREADS;
+        }
+    }
+    
+    if (!chunk)
+    {
+        const void *buf;
+        Py_ssize_t buflen;
+
+        if (PyObject_AsReadBuffer (file, &buf, &buflen) == -1)
             return -1;
-        Py_BEGIN_ALLOW_THREADS;
-        chunk = Mix_LoadWAV (name);
-        Py_END_ALLOW_THREADS;
+        chunk = malloc (sizeof (Mix_Chunk));
+        if (!chunk)
+        {
+            RAISE (PyExc_MemoryError, "cannot allocate chunk");
+            return -1;
+        }
+        chunk->alen = buflen;
+        chunk->abuf = malloc (buflen);
+        if (!chunk->abuf)
+        {
+            free (chunk);
+            RAISE (PyExc_MemoryError, "cannot allocate chunk");
+            return -1;
+        }
+        chunk->allocated = 1;
+        chunk->volume = 128;
+        memcpy (chunk->abuf, buf, buflen);
     }
-    else
+    
+    if (!chunk)
     {
         SDL_RWops *rw;
         if (!(rw = RWopsFromPython (file)))

File src/mixer.doc

 resampling, so the mixer should be initialized to match the values of
 your audio resources.
 
-
 NOTE: there is currently a bug on some windows machines which makes
 sound play back 'scratchy'.  There is not enough cpu in the sound 
 thread to feed the buffer to the sound api.
 the sound and when it gets played.  Try calling this before the pygame.init or 
 pygame.mixer.init calls.  pygame.mixer.pre_init(44100,-16,2, 1024 * 3)
 
-
-
 <SECTION>
-
-
 init
 initialize the mixer module
 pygame.mixer.init(frequency=22050, size=-16, stereo=2, buffer=1024): return None
 calling pygame.mixer.quit().
 <END>
 
-
-
 pre_init
 preset the mixer init arguments
 pygame.mixer.pre_init(frequency=0, size=0, stereo=0, buffersize=0): return None
 pygame.init().
 <END>
 
-
-
 quit
 uninitialize the mixer
 pygame.mixer.quit(): return None
 Sound objects may not be compatable with the mixer if it is reinitialized later.
 <END>
 
-
-
 get_init
 test if the mixer is initialized
 pygame.mixer.get_init(): return (frequency, format, stereo)
 is using. If the mixer has not been initialized this returns None
 <END>
 
-
-
 stop
 stop playback of all sound channels
 pygame.mixer.stop(): return None
 This will stop all playback of all active mixer channels.
 <END>
 
-
-
 pause
 temporarily stop playback of all sound channels
 pygame.mixer.pause(): return None
 The playback can later be resumed with pygame.mixer.unpause()
 <END>
 
-
-
 unpause
 resume paused playback of sound channels
 pygame.mixer.unpause(): return None
 This will resume all active sound channels after they have been paused.
 <END>
 
-
-
 fadeout
 fade out the volume on all sounds before stopping
 pygame.mixer.fadeout(time): return None
 argument in milliseconds. After the sound is muted the playback will stop.
 <END>
 
-
-
 set_num_channels
 set the total number of playback channels
 pygame.mixer.set_num_channels(count): return None
 sounds playing on the truncated channels are stopped.
 <END>
 
-
-
 get_num_channels
 get the total number of playback channels
 
 Returns the number of currently active playback channels.
 <END>
 
-
-
 set_reserved
 reserve channels from being automatically used
 pygame.mixer.set_reserved(count): return None
 play on.
 <END>
 
-
-
 find_channel
 find an unused channel
 pygame.mixer.find_channel(force=False): return Channel
 those channels will not be returned here.
 <END>
 
-
-
 get_busy
 test if any sound is being mixed
 pygame.mixer.get_busy(): return bool
 idle then this return False.
 <END>
 
-
-
 Sound
 Create a new Sound object from a file
 pygame.mixer.Sound(filename): return Sound
+pygame.mixer.Sound(buffer): return Sound
 pygame.mixer.Sound(object): return Sound
 
-Load a new sound buffer from a filename or from a python file object. Limited
-resampling will be performed to help the sample match the initialize arguments
-for the mixer.
+Load a new sound buffer from a filename, a python file object or a
+readable buffer object. Limited resampling will be performed to help the
+sample match the initialize arguments for the mixer.
 
 The Sound object represents actual sound sample data. Methods that change
 the state of the Sound object will the all instances of the Sound playback.
 
-The Sound can be loaded from an OGG audio file or from an uncompressed WAV.
+The Sound can be loaded from an OGG audio file or from an uncompressed
+WAV.
+
+Note: The buffer will be copied internally, no data will be shared
+between it and the Sound object.
+
+pygame.mixer.Sound(buffer) is new in pygame 1.8
 <SECTION>
 
-
-
 play
 begin sound playback
 Sound.play(loops=0, maxtime=0): return Channel
 This returns the Channel object for the channel that was selected.
 <END>
 
-
-
 stop
 stop sound playback
 Sound.stop(): return None
 This will stop the playback of this Sound on any active Channels.
 <END>
 
-
-
 fadeout
 stop sound playback after fading out
 Sound.fadeout(time): return None
 actively playing channels.
 <END>
 
-
-
 set_volume
 set the playback volume for this Sound
 Sound.set_volume(value): return None
 of this Sound. The argument is a value from 0.0 to 1.0.
 <END>
 
-
-
 get_volume
 get the playback volume
 Sound.get_volume(): return value
 Return a value from 0.0 to 1.0 representing the volume for this Sound.
 <END>
 
-
-
 get_num_channels
 count how many times this Sound is playing
 Sound.get_num_channels(): return count
 Return the number of active channels this sound is playing on.
 <END>
 
-
 get_length
 get the length of the Sound
 Sound.get_length(): return seconds
 <END>
 <END>
 
-
 Channel
 Create a Channel object for controlling playback
 pygame.mixer.Channel(id): return Channel
 channels is entirely optional since pygame can manage them by default.
 <SECTION>
 
-
-
 play
 play a Sound on a specific Channel
 Channel.play(Sound, loops=0, time=0): return None
 stop playback of the Sound after a given number of milliseconds.
 <END>
 
-
-
 stop
 stop playback on a Channel
 Channel.stop(): return None
 becomes available for new Sounds to play on it.
 <END>
 
-
-
 pause
 temporarily stop playback of a channel
 Channel.pause(): return None
 a later time with Channel.unpause()
 <END>
 
-
-
 unpause
 resume pause playback of a channel
 Channel.unpause(): return None
 Resume the playback on a paused channel.
 <END>
 
-
-
 fadeout
 stop playback after fading channel out
 Channel.fadeout(time): return None
 time argument in milliseconds.
 <END>
 
-
-
 set_volume
 set the volume of a playing channel
 Channel.set_volume(value): return None
     channel.set_volume(0.5) # Now plays at 30% (0.6 * 0.5).
 <END>
 
-
-
 get_volume
 get the volume of the playing channel
 Channel.get_volume(): return value
 The Sound object also has its own volume which is mixed with the channel.
 <END>
 
-
-
 get_busy
 check if the channel is active
 Channel.get_busy(): return bool
 idle this returns False.
 <END>
 
-
-
 get_sound
 get the currently playing Sound
 Channel.get_sound(): return Sound
 channel is idle None is returned.
 <END>
 
-
-
 queue
 queue a Sound object to follow the current
 Channel.queue(Sound): return None
 will begin playing immediately.
 <END>
 
-
-
 get_queue
 return any Sound that is queued
 Channel.get_queue(): return Sound
 the queued sound begins playback it will no longer be on the queue.
 <END>
 
-
-
 set_endevent
 have the channel send an event when playback stops
 Channel.set_endevent(): return None
 If no type argument is given then the Channel will stop sending endevents.
 <END>
 
-
-
 get_endevent
 get the event a channel sends when playback stops
 Channel.get_endevent(): return type

File src/sndarray.c

-/*
-  pygame - Python Game Library
-  Copyright (C) 2000-2001  Pete Shinners
-
-  This library is free software; you can redistribute it and/or
-  modify it under the terms of the GNU Library General Public
-  License as published by the Free Software Foundation; either
-  version 2 of the License, or (at your option) any later version.
-
-  This library is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-  Library General Public License for more details.
-
-  You should have received a copy of the GNU Library General Public
-  License along with this library; if not, write to the Free
-  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-
-  Pete Shinners
-  pete@shinners.org
-*/
-
-#include "pygame.h"
-#include "pygamedocs.h"
-#include "mixer.h"
-#include "numeric_arrayobject.h"
-#include <SDL_byteorder.h>
-
-static PyObject*
-sndarray_samples (PyObject* self, PyObject* arg)
-{
-    int dim[2], numdims, type, formatbytes;
-    PyObject *array, *chunkobj;
-    Mix_Chunk* chunk;
-    Uint16 format;
-    int numchannels;
-
-    if (!PyArg_ParseTuple (arg, "O!", &PySound_Type, &chunkobj))
-        return NULL;
-    chunk = PySound_AsChunk (chunkobj);
-
-    if (!Mix_QuerySpec (NULL, &format, &numchannels))
-        return RAISE (PyExc_SDLError, "Mixer not initialized");
-
-    formatbytes = (abs (format) & 0xff) / 8;
-    switch (format) 
-    {
-    case AUDIO_S8:
-        type = PyArray_CHAR;
-        break;
-    case AUDIO_U8:
-        type = PyArray_UBYTE;
-        break;
-    case AUDIO_S16SYS:
-        type = PyArray_SHORT;
-        break;
-    case AUDIO_U16SYS:
-        type = PyArray_USHORT;
-        break;
-    default:
-        return RAISE (PyExc_TypeError, "Unpresentable audio format");
-    }
-
-    numdims = (numchannels > 1) ? 2 : 1;
-    dim[0] = chunk->alen / (numchannels*formatbytes);
-    dim[1] = numchannels;
-    
-    array = PyArray_FromDimsAndData (numdims, dim, type, (char*)chunk->abuf);
-    if(array)
-    {
-        Py_INCREF (chunkobj);
-        ((PyArrayObject*) array)->base = chunkobj;
-        ((PyArrayObject*) array)->flags |= SAVESPACE;
-    }
-    return array;
-}
-
-PyObject*
-sndarray_array (PyObject* self, PyObject* arg)
-{
-    PyObject *array, *arraycopy=NULL;
-    
-    /*we'll let numeric do the copying for us*/
-    array = sndarray_samples (self, arg);
-    if(array)
-    {
-        arraycopy = PyArray_Copy ((PyArrayObject*) array);
-        Py_DECREF (array);
-    }
-    return arraycopy;
-}
-
-PyObject*
-sndarray_make_sound (PyObject* self, PyObject* arg)
-{
-    PyObject *arrayobj;
-    PyArrayObject *array;
-    Mix_Chunk *chunk;
-    Uint16 format;
-    int numchannels, mixerbytes;
-    int loop1, loop2, step1, step2, length, length2=0;
-    Uint8 *src, *dst;
-
-    if (!PyArg_ParseTuple (arg, "O!", &PyArray_Type, &arrayobj))
-	return NULL;
-    array = (PyArrayObject*) arrayobj;
-    
-    if (!Mix_QuerySpec (NULL, &format, &numchannels))
-        return RAISE (PyExc_SDLError, "Mixer not initialized");
-    if (array->descr->type_num > PyArray_LONG)
-        return RAISE (PyExc_ValueError, "Invalid array datatype for sound");
-    
-    if (format==AUDIO_S8 || format==AUDIO_U8)
-        mixerbytes = 1;
-    else
-        mixerbytes = 2;
-    
-    /*test array dimensions*/
-    if (numchannels == 1)
-    {
-        if (array->nd != 1)
-            return RAISE (PyExc_ValueError,
-                          "Array must be 1-dimensional for mono mixer");
-    }
-    else
-    {
-        if (array->nd != 2)
-            return RAISE (PyExc_ValueError,
-                          "Array must be 2-dimensional for stereo mixer");
-        if (array->dimensions[1] != numchannels)
-            return RAISE (PyExc_ValueError,
-                          "Array depth must match number of mixer channels");
-    }
-    length = array->dimensions[0];
-    step1 = array->strides[0];
-    if (array->nd == 2)
-    {
-        length2 = array->dimensions[1];
-	step2 = array->strides[1];
-    }
-    else 
-    {
-        length2 = 1;
-        /*since length2 == 1, this won't be used for looping*/
-	step2 = mixerbytes; 
-    }
-
-    /*create chunk, we are screwed if SDL_mixer ever does more than
-     * malloc/free*/
-    chunk = (Mix_Chunk *)malloc (sizeof (Mix_Chunk));
-    if (chunk == NULL)
-        return RAISE (PyExc_MemoryError, "Cannot allocate chunk\n");
-    /*let's hope Mix_Chunk never changes also*/
-    chunk->alen = length * numchannels * mixerbytes;
-    chunk->abuf = (Uint8*) malloc (chunk->alen);
-    chunk->allocated = 1;
-    chunk->volume = 128;
-
-    if (step1 == mixerbytes * numchannels && step2 == mixerbytes)
-    {
-        /*OPTIMIZATION: in these cases, we don't need to loop through
-         *the samples individually, because the bytes are already layed
-         *out correctly*/
-        memcpy (chunk->abuf, array->data, chunk->alen);
-    }
-    else
-    {
-        dst = (Uint8*) chunk->abuf;
-        if (mixerbytes == 1)
-        {
-            for (loop1 = 0; loop1 < length; loop1++)
-            {
-                src = (Uint8*) array->data + loop1*step1;
-                switch (array->descr->elsize)
-                {
-                case 1:
-                    for (loop2=0; loop2<length2; loop2++, dst+=1, src+=step2)
-                        *(Uint8*)dst = (Uint8)*((Uint8*)src);
-                    break;
-                case 2:
-                    for (loop2=0; loop2<length2; loop2++, dst+=1, src+=step2)
-                        *(Uint8*)dst = (Uint8)*((Uint16*)src);
-                    break;
-                case 4:
-                    for (loop2=0; loop2<length2; loop2++, dst+=1, src+=step2)
-                        *(Uint8*)dst = (Uint8)*((Uint32*)src);
-                    break;
-                }
-            }
-        }
-        else
-        {
-            for (loop1 = 0; loop1 < length; loop1++)
-            {
-                src = (Uint8*) array->data + loop1*step1;
-                switch (array->descr->elsize)
-                {
-                case 1:
-                    for (loop2=0; loop2<length2; loop2++, dst+=2, src+=step2)
-                        *(Uint16*)dst = (Uint16)(*((Uint8*)src)<<8);
-                    break;
-                case 2:
-                    for (loop2=0; loop2<length2; loop2++, dst+=2, src+=step2)
-                        *(Uint16*)dst = (Uint16)*((Uint16*)src);
-                    break;
-                case 4:
-                    for (loop2=0; loop2<length2; loop2++, dst+=2, src+=step2)
-                        *(Uint16*)dst = (Uint16)*((Uint32*)src);
-                    break;
-                }
-            }
-        }
-    }
-    
-    return PySound_New (chunk);
-}
-
-static PyMethodDef sndarray_builtins[] =
-{
-    { "samples", sndarray_samples, METH_VARARGS, DOC_PYGAMESNDARRAYSAMPLES },
-    { "array", sndarray_array, METH_VARARGS, DOC_PYGAMESNDARRAYARRAY },
-    { "make_sound", sndarray_make_sound, METH_VARARGS,
-      DOC_PYGAMESNDARRAYMAKESOUND },
-    { NULL, NULL, 0, NULL}
-};
-
-PYGAME_EXPORT
-void initsndarray (void)
-{
-    PyObject *module, *dict;
-    
-    /* create the module */
-    module = Py_InitModule3 ("sndarray", sndarray_builtins, DOC_PYGAMESNDARRAY);
-    dict = PyModule_GetDict (module);
-        
-    /*imported needed apis*/
-    import_pygame_base ();
-    import_pygame_mixer ();
-    import_array ();
-    /*needed for Numeric in python2.3*/
-    PyImport_ImportModule ("Numeric");
-}

File src/sndarray.doc

-pygame.sndarray
-pygame module for accessing sound sample data
-
-Functions to convert between Numeric arrays and Sound objects. This
-module will only be available when pygame can use the external Numeric package.
-
-Sound data is made of thousands of samples per second, and each sample is the
-amplitude of the wave at a particular moment in time. For example, in
-22-kHz format, element number 5 of the array is the amplitude of the wave
-after 5/22000 seconds.
-
-Each sample is an 8-bit or 16-bit integer, depending on the data format.
-A stereo sound file has two values per sample, while a mono sound file only has one.
-
-Numeric does not use unsigned 16-bit integers; they will be converted to
-signed 16-bit arrays.
-<SECTION>
-
-
-
-array
-copy Sound samples into an array
-pygame.sndarray.array(Sound): return array
-
-Creates a new Numeric array for the sound data and copies the samples. The
-array will always be in the format returned from pygame.mixer.get_init(). 
-<END>
-
-
-
-samples
-reference Sound samples into an array
-pygame.sndarray.samples(Sound): return array
-
-Creates a new Numeric array that directly references the samples in a 
-Sound object. Modifying the array will change the Sound. The array
-will always be in the format returned from pygame.mixer.get_init().
-<END>
-
-
-
-make_sound
-convert an array into a Sound object
-pygame.sndarray.make_sound(array): return Sound
-
-Create a new playable Sound object from a Numeric array. The mixer module
-must be initialized and the array format must be similar to the mixer audio
-format.
-<END>
-<END>

File test/scrap_test.py

 import unittest
 import pygame
-from pygame.locals import *
 import pygame.scrap as scrap
 
 class ScrapTest (unittest.TestCase):
 
     def test_scrap_mode (self):
-        scrap.set_mode (SCRAP_SELECTION)
-        scrap.set_mode (SCRAP_CLIPBOARD)
+        scrap.set_mode (pygame.SCRAP_SELECTION)
+        scrap.set_mode (pygame.SCRAP_CLIPBOARD)
         self.assertRaises (ValueError, scrap.set_mode, 1099)
 
     def test_scrap_put_text (self):
-        scrap.put (SCRAP_TEXT, "Hello world")
-        self.assertEquals (scrap.get (SCRAP_TEXT), "Hello world")
+        scrap.put (pygame.SCRAP_TEXT, "Hello world")
+        self.assertEquals (scrap.get (pygame.SCRAP_TEXT), "Hello world")
 
-        scrap.put (SCRAP_TEXT, "Another String")
-        self.assertEquals (scrap.get (SCRAP_TEXT), "Another String")
+        scrap.put (pygame.SCRAP_TEXT, "Another String")
+        self.assertEquals (scrap.get (pygame.SCRAP_TEXT), "Another String")
 
     def test_scrap_put_image (self):
         sf = pygame.image.load ("examples/data/asprite.bmp")
         string = pygame.image.tostring (sf, "RGBA")
-        scrap.put (SCRAP_BMP, string)
-        self.assertEquals (scrap.get (SCRAP_BMP), string)
+        scrap.put (pygame.SCRAP_BMP, string)
+        self.assertEquals (scrap.get (pygame.SCRAP_BMP), string)
 
     def test_scrap_put (self):
         scrap.put ("arbitrary buffer", "buf")