Commits

Anonymous committed eca6857

Added doppler shift support to openal contexts.
Implemented experimental get_samples() method for capture devices.

Comments (0)

Files changed (8)

 	$(top_srcdir)/lib/freetype \
 	$(top_srcdir)/lib/math \
 	$(top_srcdir)/lib/midi \
+	$(top_srcdir)/lib/openal \
 	$(top_srcdir)/lib/sdl \
 	$(top_srcdir)/lib/sdlext \
 	$(top_srcdir)/lib/sdlgfx \

src/base/streamwrapper.c

 {
     capi[PYGAME_STREAMWRAPPER_FIRSTSLOT] = (void *)CPyStreamWrapper_New;
     capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+1] = (void *)CPyStreamWrapper_Free;
-    capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+2] = (void *)CPyStreamWrapper_Read_Threaded;
+    capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+2] =
+        (void *)CPyStreamWrapper_Read_Threaded;
     capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+3] = (void *)CPyStreamWrapper_Read;
-    capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+4] = (void *)CPyStreamWrapper_Write_Threaded;
+    capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+4] =
+        (void *)CPyStreamWrapper_Write_Threaded;
     capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+5] = (void *)CPyStreamWrapper_Write;
-    capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+6] = (void *)CPyStreamWrapper_Seek_Threaded;
+    capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+6] =
+        (void *)CPyStreamWrapper_Seek_Threaded;
     capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+7] = (void *)CPyStreamWrapper_Seek;
-    capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+8] = (void *)CPyStreamWrapper_Tell_Threaded;
+    capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+8] =
+        (void *)CPyStreamWrapper_Tell_Threaded;
     capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+9] = (void *)CPyStreamWrapper_Tell;
-    capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+10] = (void *)CPyStreamWrapper_Close_Threaded;
+    capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+10] =
+        (void *)CPyStreamWrapper_Close_Threaded;
     capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+11] = (void *)CPyStreamWrapper_Close;
     capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+12] = (void *)IsReadableStreamObj;
     capi[PYGAME_STREAMWRAPPER_FIRSTSLOT+13] = (void *)IsWriteableStreamObj;

src/openal/capturedevice.c

 #define PYGAME_OPENALCAPTUREDEVICE_INTERNAL
 
 #include "openalmod.h"
+#include "pgbase.h"
 #include "pgopenal.h"
 
+static int _getbytesfromformat (ALenum format);
+static int _getchannelsfromformat (ALenum format);
+
 static PyObject* _capturedevice_new (PyTypeObject *type, PyObject *args,
     PyObject *kwds);
 static int _capturedevice_init (PyObject *self, PyObject *args, PyObject *kwds);
 }
 
 /* CaptureDevice methods */
+static int
+_getbytesfromformat (ALenum format)
+{
+    switch (format)
+    {
+    case AL_FORMAT_MONO8:
+    case AL_FORMAT_STEREO8:
+    case AL_FORMAT_QUAD8_LOKI:
+    case AL_FORMAT_QUAD8:
+    case AL_FORMAT_51CHN8:
+    case AL_FORMAT_61CHN8:
+    case AL_FORMAT_71CHN8:
+        return 1;
+    case AL_FORMAT_MONO16:
+    case AL_FORMAT_STEREO16:
+    case AL_FORMAT_QUAD16_LOKI:
+    case AL_FORMAT_QUAD16:
+    case AL_FORMAT_51CHN16:
+    case AL_FORMAT_61CHN16:
+    case AL_FORMAT_71CHN16:
+        return 2;
+    case AL_FORMAT_MONO_FLOAT32:
+    case AL_FORMAT_STEREO_FLOAT32:
+    case AL_FORMAT_QUAD32:
+    case AL_FORMAT_51CHN32:
+    case AL_FORMAT_61CHN32:
+    case AL_FORMAT_71CHN32:
+        return 4;
+    default:
+        return -1;
+    }
+}
+
+static int
+_getchannelsfromformat (ALenum format)
+{
+    switch (format)
+    {
+    case AL_FORMAT_MONO8:
+    case AL_FORMAT_MONO16:
+    case AL_FORMAT_MONO_FLOAT32:
+        return 1;
+    case AL_FORMAT_STEREO8:
+    case AL_FORMAT_STEREO16:
+    case AL_FORMAT_STEREO_FLOAT32:
+        return 2;
+    case AL_FORMAT_QUAD8_LOKI:
+    case AL_FORMAT_QUAD16_LOKI:
+    case AL_FORMAT_QUAD8:
+    case AL_FORMAT_QUAD16:
+    case AL_FORMAT_QUAD32:
+        return 4;
+    case AL_FORMAT_51CHN8:
+    case AL_FORMAT_51CHN16:
+    case AL_FORMAT_51CHN32:
+        return 6;
+    case AL_FORMAT_61CHN8:
+    case AL_FORMAT_61CHN16:
+    case AL_FORMAT_61CHN32:
+        return 7;
+    case AL_FORMAT_71CHN8:
+    case AL_FORMAT_71CHN16:
+    case AL_FORMAT_71CHN32:
+        return 8;
+    default:
+        return -1;
+    }
+}
+
 static PyObject*
 _capturedevice_start (PyObject* self)
 {
 static PyObject*
 _capturedevice_getsamples (PyObject* self, PyObject *args)
 {
-    PyObject *buffer = NULL;
-    long offset = 0;
+    PyObject *retval, *buffer = NULL;
     ALCvoid *buf;
-    ALCsizei count;
+    ALCsizei count, total;
+    int channels, bytesize;
+    PyCaptureDevice *pydevice = (PyCaptureDevice*) self;
+    ALCdevice *device = PyCaptureDevice_AsDevice (self);
     
-    if (!PyArg_ParseTuple (args, "|Ol:get_samples", &buffer, &offset))
+    if (!PyArg_ParseTuple (args, "|O:get_samples", &buffer))
         return NULL;
+
+    if (buffer && !IsWriteableStreamObj (buffer))
+    {
+        PyErr_SetString (PyExc_ValueError, "buffer is not writeable");
+        return NULL;
+    }
     
     CLEAR_ALCERROR_STATE ();
-    alcGetIntegerv (PyCaptureDevice_AsDevice (self), ALC_CAPTURE_SAMPLES,
-        (ALCsizei)(sizeof (ALCsizei)), &count);
-    if (SetALCErrorException (alcGetError (PyCaptureDevice_AsDevice(self)), 0))
+    alcGetIntegerv (device, ALC_CAPTURE_SAMPLES, (ALCsizei)(sizeof (ALCsizei)),
+        &count);
+    if (SetALCErrorException (alcGetError (device), 0))
         return NULL;
     if (count == 0)
         Py_RETURN_NONE;
     
+    /* The default for a good ring buffer size is something like the following
+     *
+     * single sample bytesize:
+     *      frequency * channels * format
+     */
+    
+    channels = _getchannelsfromformat (pydevice->format);
+    bytesize = _getbytesfromformat (pydevice->format);
+    if (channels == -1 || bytesize == -1)
+    {
+        PyErr_SetString (PyExc_RuntimeError, "unsupported OpenAL format");
+        return NULL;
+    }
+
+    total = count * channels * bytesize;
+    buf = PyMem_Malloc (total);
+    if (!buf)
+        return NULL;
+
     alcCaptureSamples (PyCaptureDevice_AsDevice (self), &buf, count);
     if (SetALCErrorException (alcGetError (PyCaptureDevice_AsDevice(self)), 0))
         return NULL;
 
-    Py_RETURN_NONE;
+    if (buffer)
+    {
+        pguint32 written;
+        CPyStreamWrapper *wrapper = CPyStreamWrapper_New (buffer);
+        if (!wrapper)
+        {
+            PyMem_Free (buf);
+            return NULL;
+        }
+        if (!CPyStreamWrapper_Write (buffer, buf, count, bytesize * channels,
+                &written))
+        {
+            PyMem_Free (buf);
+            CPyStreamWrapper_Free (buffer);
+            return NULL;
+        }
+        CPyStreamWrapper_Free (buffer);
+        return PyLong_FromUnsignedLong ((unsigned long) written);
+    }
+
+    /* No buffer provided - create a byte array */
+    retval = Bytes_FromStringAndSize ((const char*) buf, total);
+    PyMem_Free (buf);
+    if (!retval)
+        return NULL;
+    return retval;
 }
 
 /* C API */
 static PyObject* _context_enable (PyObject *self, PyObject *args);
 static PyObject* _context_disable (PyObject *self, PyObject *args);
 static PyObject* _context_isenabled (PyObject *self, PyObject *args);
+static PyObject* _context_getprop (PyObject *self, PyObject *args);
 
 static PyObject* _context_iscurrent (PyObject* self, void *closure);
 static PyObject* _context_getlistener (PyObject* self, void *closure);
 static PyObject* _context_getdevice (PyObject* self, void *closure);
+static PyObject* _context_getdistancemodel (PyObject* self, void *closure);
+static int _context_setdistancemodel (PyObject* self, PyObject *value,
+    void *closure);
+static PyObject* _context_getdopplerfactor (PyObject* self, void *closure);
+static int _context_setdopplerfactor (PyObject* self, PyObject *value,
+    void *closure);
+static PyObject* _context_getspeedofsound (PyObject* self, void *closure);
+static int _context_setspeedofsound (PyObject* self, PyObject *value,
+    void *closure);
 
 /**
  */
     { "enable", (PyCFunction) _context_enable, METH_O, "" },
     { "disable", (PyCFunction) _context_disable, METH_O, "" },
     { "is_enabled", (PyCFunction) _context_isenabled, METH_O, "" },
+    /*{ "get_prop", (PyCFunction) _context_getprop, METH_VARARGS, "" },*/
     { NULL, NULL, 0, NULL }
 };
 
     { "is_current", _context_iscurrent, NULL, NULL, NULL },
     { "device", _context_getdevice, NULL, NULL, NULL },
     { "listener", _context_getlistener, NULL, NULL, NULL },
+    { "distance_model", _context_getdistancemodel, _context_setdistancemodel,
+      NULL, NULL },
+    { "doppler_factor", _context_getdopplerfactor, _context_setdopplerfactor,
+      NULL, NULL }, 
+    { "speed_of_sound", _context_getspeedofsound, _context_setspeedofsound,
+      NULL, NULL },
     { NULL, NULL, NULL, NULL, NULL }
 };
 
     return ctxt->listener;
 }
 
+static PyObject*
+_context_getdistancemodel (PyObject* self, void *closure)
+{
+    ALint model;
+    
+    ASSERT_CONTEXT_IS_CURRENT (self, NULL);
+    CLEAR_ALERROR_STATE ();
+    model = alGetInteger (AL_DISTANCE_MODEL);
+    if (SetALErrorException (alGetError (), 0))
+        return NULL;
+    return PyInt_FromLong ((long)model);
+}
+
+static int
+_context_setdistancemodel (PyObject* self, PyObject *value, void *closure)
+{
+    int model;
+    
+    ASSERT_CONTEXT_IS_CURRENT (self, -1);
+    
+    if (!IntFromObj (value, &model))
+        return -1;
+    CLEAR_ALERROR_STATE ();
+    alDistanceModel ((ALenum)model);
+    if (SetALErrorException (alGetError (), 0))
+        return -1;
+    return 0;
+}
+
+static PyObject*
+_context_getdopplerfactor (PyObject* self, void *closure)
+{
+    ALfloat factor;
+    
+    ASSERT_CONTEXT_IS_CURRENT (self, NULL);
+    CLEAR_ALERROR_STATE ();
+    factor = alGetFloat (AL_DOPPLER_FACTOR);
+    if (SetALErrorException (alGetError (), 0))
+        return NULL;
+    return PyFloat_FromDouble ((double)factor);
+}
+
+static int
+_context_setdopplerfactor (PyObject* self, PyObject *value, void *closure)
+{
+    double factor;
+    
+    ASSERT_CONTEXT_IS_CURRENT (self, -1);
+    
+    if (!DoubleFromObj (value, &factor))
+        return -1;
+    CLEAR_ALERROR_STATE ();
+    alDopplerFactor ((ALfloat)factor);
+    if (SetALErrorException (alGetError (), 0))
+        return -1;
+    return 0;
+}
+
+static PyObject*
+_context_getspeedofsound (PyObject* self, void *closure)
+{
+    ALfloat speed;
+    
+    ASSERT_CONTEXT_IS_CURRENT (self, NULL);
+    CLEAR_ALERROR_STATE ();
+    speed = alGetFloat (AL_SPEED_OF_SOUND);
+    if (SetALErrorException (alGetError (), 0))
+        return NULL;
+    return PyFloat_FromDouble ((double)speed);
+}
+
+static int
+_context_setspeedofsound (PyObject* self, PyObject *value, void *closure)
+{
+    double speed;
+    
+    ASSERT_CONTEXT_IS_CURRENT (self, -1);
+    
+    if (!DoubleFromObj (value, &speed))
+        return -1;
+    CLEAR_ALERROR_STATE ();
+    alSpeedOfSound ((ALfloat)speed);
+    if (SetALErrorException (alGetError (), 0))
+        return -1;
+    return 0;
+}
+
+
 /* Context methods */
 static PyObject*
 _context_makecurrent (PyObject *self)
     Py_RETURN_NONE;
 }
 
-
 static PyObject*
 _context_enable (PyObject *self, PyObject *args)
 {
     Py_RETURN_FALSE;
 }
 
+static PyObject*
+_context_getprop (PyObject *self, PyObject *args)
+{
+    /* TODO */
+    Py_RETURN_NONE;
+}
+
 void
 context_export_capi (void **capi)
 {
 
 static PyObject* _device_hasextension (PyObject *self, PyObject *args);
 static PyObject* _device_geterror (PyObject* self);
+static PyObject* _device_getenumvalue (PyObject *self, PyObject *args);
 
 static PyObject* _device_getname (PyObject* self, void *closure);
 static PyObject* _device_getextensions (PyObject *self, void *closure);
 static PyMethodDef _device_methods[] = {
     { "has_extension", _device_hasextension, METH_VARARGS, NULL },
     { "get_error", (PyCFunction)_device_geterror, METH_NOARGS, NULL },
+    { "get_enum_value", _device_getenumvalue, METH_O, NULL },
     { NULL, NULL, 0, NULL }
 };
 
     }
 }
 
+static PyObject*
+_device_getenumvalue (PyObject *self, PyObject *args)
+{
+    ALCenum val;
+    PyObject *freeme;
+    char *enumname;
+    
+    if (!ASCIIFromObj (args, &enumname, &freeme))
+        return NULL;
+    CLEAR_ALCERROR_STATE ();
+    val = alcGetEnumValue (PyDevice_AsDevice (self), (const ALchar*)enumname);
+    Py_XDECREF (freeme);
+    if (SetALCErrorException (alcGetError (PyDevice_AsDevice (self)), 0))
+        return NULL;
+    return PyInt_FromLong ((long)val);
+}
+
 /* C API */
 PyObject*
 PyDevice_New (const char* name)

src/openal/listener.c

             break;
         }
         default:
-            PyErr_SetString (PyExc_TypeError, "unsupported value");
+            PyErr_SetString (PyExc_TypeError, "unsupported type value");
             return NULL;
         }
     }

src/openal/openalmod.c

 static PyObject* _openal_quit (PyObject *self);
 static PyObject* _openal_geterror (PyObject *self);
 static PyObject* _openal_algetstring (PyObject *self, PyObject *args);
+static PyObject* _openal_getenumvalue (PyObject *self, PyObject *args);
 static PyObject* _openal_isextensionpresent (PyObject *self, PyObject *args);
 static PyObject* _openal_setcurrentcontext (PyObject *self, PyObject *args);
 static PyObject* _openal_listoutputdevices (PyObject *self);
     { "get_error", (PyCFunction)_openal_geterror, METH_NOARGS,
       ""/*DOC_BASE_GETERROR*/ },
     { "is_extension_present", _openal_isextensionpresent, METH_VARARGS, "" },
+    { "get_enum_value", _openal_getenumvalue, METH_O, "" }, 
     { "list_output_devices", (PyCFunction)_openal_listoutputdevices,
       METH_NOARGS, "" },
     { "list_capture_devices", (PyCFunction)_openal_listcapturedevices,
 }
 
 static PyObject*
+_openal_getenumvalue (PyObject *self, PyObject *args)
+{
+    ALenum val;
+    PyObject *freeme;
+    char *enumname;
+    
+    if (!ASCIIFromObj (args, &enumname, &freeme))
+        return NULL;
+    val = alGetEnumValue ((const ALchar*)enumname);
+    Py_XDECREF (freeme);
+    if (val == 0)
+    {
+        PyErr_SetString (PyExc_ValueError, "enumeration name does not exist");
+        return NULL;
+    }
+    return PyInt_FromLong ((long)val);
+}
+
+static PyObject*
 _openal_isextensionpresent (PyObject *self, PyObject *args)
 {
     char *extname = NULL;

src/openal/openalmod.h

 typedef enum
 {
     INVALID,     /* invalid type */
+    BOOL,        /* 'b'  */
     INT,         /* 'i'  */
     FLOAT,       /* 'f'  */
+    DOUBLE,      /* 'd'  */
     INT3,        /* 'i3' */
     FLOAT3,      /* 'f3' */ 
+    BOOLARRAY,   /* 'ba' */
     INTARRAY,    /* 'ia' */
-    FLOATARRAY   /* 'fa' */
+    FLOATARRAY,  /* 'fa' */
+    DOUBLEARRAY, /* 'da' */
 } PropType;
 PropType GetPropTypeFromStr (char *name);