Commits

Lenard Lindstrom committed b3ee3ed

Correct pygame.mixer.Sound handling of PyBUF_* buffer export flags

Comments (0)

Files changed (2)

 #define EXPORT_BUFFER HAVE_NEW_BUFPROTO
 #endif
 
+#define PyBUF_HAS_FLAG(f, F) (((f) & (F)) == (F))
+
 /* The SDL audio format constants are not defined for anything larger
    than 2 byte samples. Define our own. Low two bytes gives sample
    size in bytes. Higher bytes are flags.
 {
     Mix_Chunk *chunk = PySound_AsChunk(obj);
     int channels;
-    char *format = '\0';
-    int ndim = 1;
+    char *format;
+    int ndim = 0;
     Py_ssize_t *shape = 0;
     Py_ssize_t *strides = 0;
-    Py_ssize_t itemsize = 0;
+    Py_ssize_t itemsize;
     Py_ssize_t samples;
-    int fortran_order = (flags & PyBUF_F_CONTIGUOUS) == PyBUF_F_CONTIGUOUS;
 
-    if (flags != PyBUF_SIMPLE) {
-        if (snd_buffer_iteminfo(&format, &itemsize, &channels)) {
+    view->obj = 0;
+    if (snd_buffer_iteminfo(&format, &itemsize, &channels)) {
+        return -1;
+    }
+    if (channels != 1 &&
+        PyBUF_HAS_FLAG (flags, PyBUF_F_CONTIGUOUS)) {
+        PyErr_SetString(PyExc_BufferError,
+                        "polyphonic sound is not Fortran contiguous");
+        return -1;
+    }
+    if (PyBUF_HAS_FLAG(flags, PyBUF_ND)) {
+        ndim = channels > 1 ? 2 : 1;
+        samples = chunk->alen / (itemsize * channels);
+        shape = PyMem_New(Py_ssize_t, 2 * ndim);
+        if (!shape) {
+            PyErr_NoMemory();
             return -1;
         }
-        if ((flags & PyBUF_FORMAT) != PyBUF_FORMAT) {
-            format = 0;
-        }
-        if ((flags & PyBUF_ND) == PyBUF_ND) {
-            ndim = channels > 1 ? 2 : 1;
-            samples = chunk->alen / (itemsize * channels);
-            shape = PyMem_New(Py_ssize_t, 2 * ndim);
-            if (!shape) {
-                PyErr_NoMemory();
-                return -1;
-            }
-            if (fortran_order) {
-                shape[0] = channels;
-                shape[ndim - 1] = samples;
-            }
-            else {
-                shape[ndim - 1] = channels;
-                shape[0] = samples;
-            }
-        }
-        if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
+        shape[ndim - 1] = channels;
+        shape[0] = samples;
+        if (PyBUF_HAS_FLAG(flags, PyBUF_STRIDES)) {
             strides = shape + ndim;
-            if (fortran_order) {
-                strides[ndim - 1] = itemsize * channels;
-                strides[0] = itemsize;
-            }
-            else {
-                strides[0] = itemsize * channels;
-                strides[ndim - 1] = itemsize;
-            }
+            strides[0] = itemsize * channels;
+            strides[ndim - 1] = itemsize;
         }
     }
-
     Py_INCREF(obj);
     view->obj = obj;
     view->buf = chunk->abuf;
     view->len = (Py_ssize_t)chunk->alen;
     view->readonly = 0;
     view->itemsize = itemsize;
-    view->format = format;
+    view->format = PyBUF_HAS_FLAG(flags, PyBUF_FORMAT) ? format : 0;
     view->ndim = ndim;
     view->shape = shape;
     view->strides = strides;

test/mixer_test.py

         finally:
             mixer.quit()
 
+    if pygame.HAVE_NEWBUF:
+        def test_newbuf(self):
+            self.NEWBUF_test_newbuf()
+        if is_pygame_pkg:
+            from pygame.tests.test_utils import buftools
+        else:
+            from test.test_utils import buftools
+
+    def NEWBUF_test_newbuf(self):
+        mixer.init(22050, -16, 1)
+        try:
+            self.NEWBUF_export_check()
+        finally:
+            mixer.quit()
+        mixer.init(22050, -16, 2)
+        try:
+            self.NEWBUF_export_check()
+        finally:
+            mixer.quit()
+
+    def NEWBUF_export_check(self):
+        freq, fmt, channels = mixer.get_init()
+        if channels == 1:
+            ndim = 1
+        else:
+            ndim = 2
+        itemsize = abs(fmt) // 8
+        formats = {8: 'B', -8: 'b',
+                   16: '=H', -16: '=h',
+                   32: '=I', -32: '=i',  # 32 and 64 for future consideration
+                   64: '=Q', -64: '=q'}
+        format = formats[fmt]
+        buftools = self.buftools
+        BufferExporter = buftools.BufferExporter
+        BufferImporter = buftools.BufferImporter
+        is_lil_endian = pygame.get_sdl_byteorder() == pygame.LIL_ENDIAN
+        fsys, frev = ('<', '>') if is_lil_endian else ('>', '<')
+        shape = (10, channels)[:ndim]
+        strides = (channels * itemsize, itemsize)[2 - ndim:]
+        exp = BufferExporter(shape, format=frev + 'i')
+        snd = mixer.Sound(array=exp)
+        buflen = len(exp) * itemsize * channels
+        imp = BufferImporter(snd, buftools.PyBUF_SIMPLE)
+        self.assertEqual(imp.ndim, 0)
+        self.assertTrue(imp.format is None)
+        self.assertEqual(imp.len, buflen)
+        self.assertEqual(imp.itemsize, itemsize)
+        self.assertTrue(imp.shape is None)
+        self.assertTrue(imp.strides is None)
+        self.assertTrue(imp.suboffsets is None)
+        self.assertFalse(imp.readonly)
+        self.assertEqual(imp.buf, snd._samples_address)
+        imp = BufferImporter(snd, buftools.PyBUF_WRITABLE)
+        self.assertEqual(imp.ndim, 0)
+        self.assertTrue(imp.format is None)
+        self.assertEqual(imp.len, buflen)
+        self.assertEqual(imp.itemsize, itemsize)
+        self.assertTrue(imp.shape is None)
+        self.assertTrue(imp.strides is None)
+        self.assertTrue(imp.suboffsets is None)
+        self.assertFalse(imp.readonly)
+        self.assertEqual(imp.buf, snd._samples_address)
+        imp = BufferImporter(snd, buftools.PyBUF_FORMAT)
+        self.assertEqual(imp.ndim, 0)
+        self.assertEqual(imp.format, format)
+        self.assertEqual(imp.len, buflen)
+        self.assertEqual(imp.itemsize, itemsize)
+        self.assertTrue(imp.shape is None)
+        self.assertTrue(imp.strides is None)
+        self.assertTrue(imp.suboffsets is None)
+        self.assertFalse(imp.readonly)
+        self.assertEqual(imp.buf, snd._samples_address)
+        imp = BufferImporter(snd, buftools.PyBUF_ND)
+        self.assertEqual(imp.ndim, ndim)
+        self.assertTrue(imp.format is None)
+        self.assertEqual(imp.len, buflen)
+        self.assertEqual(imp.itemsize, itemsize)
+        self.assertEqual(imp.shape, shape)
+        self.assertTrue(imp.strides is None)
+        self.assertTrue(imp.suboffsets is None)
+        self.assertFalse(imp.readonly)
+        self.assertEqual(imp.buf, snd._samples_address)
+        imp = BufferImporter(snd, buftools.PyBUF_STRIDES)
+        self.assertEqual(imp.ndim, ndim)
+        self.assertTrue(imp.format is None)
+        self.assertEqual(imp.len, buflen)
+        self.assertEqual(imp.itemsize, itemsize)
+        self.assertEqual(imp.shape, shape)
+        self.assertEqual(imp.strides, strides)
+        self.assertTrue(imp.suboffsets is None)
+        self.assertFalse(imp.readonly)
+        self.assertEqual(imp.buf, snd._samples_address)
+        imp = BufferImporter(snd, buftools.PyBUF_FULL_RO)
+        self.assertEqual(imp.ndim, ndim)
+        self.assertEqual(imp.format, format)
+        self.assertEqual(imp.len, buflen)
+        self.assertEqual(imp.itemsize, 2)
+        self.assertEqual(imp.shape, shape)
+        self.assertEqual(imp.strides, strides)
+        self.assertTrue(imp.suboffsets is None)
+        self.assertFalse(imp.readonly)
+        self.assertEqual(imp.buf, snd._samples_address)
+        imp = BufferImporter(snd, buftools.PyBUF_FULL_RO)
+        self.assertEqual(imp.ndim, ndim)
+        self.assertEqual(imp.format, format)
+        self.assertEqual(imp.len, buflen)
+        self.assertEqual(imp.itemsize, itemsize)
+        self.assertEqual(imp.shape, exp.shape)
+        self.assertEqual(imp.strides, strides)
+        self.assertTrue(imp.suboffsets is None)
+        self.assertFalse(imp.readonly)
+        self.assertEqual(imp.buf, snd._samples_address)
+        imp = BufferImporter(snd, buftools.PyBUF_C_CONTIGUOUS)
+        self.assertEqual(imp.ndim, ndim)
+        self.assertTrue(imp.format is None)
+        self.assertEqual(imp.strides, strides)
+        imp = BufferImporter(snd, buftools.PyBUF_ANY_CONTIGUOUS)
+        self.assertEqual(imp.ndim, ndim)
+        self.assertTrue(imp.format is None)
+        self.assertEqual(imp.strides, strides)
+        if (ndim == 1):
+            imp = BufferImporter(snd, buftools.PyBUF_F_CONTIGUOUS)
+            self.assertEqual(imp.ndim, 1)
+            self.assertTrue(imp.format is None)
+            self.assertEqual(imp.strides, strides)
+        else:
+            self.assertRaises(BufferError, BufferImporter, snd,
+                              buftools.PyBUF_F_CONTIGUOUS)
+
     def test_get_raw(self):
         from ctypes import pythonapi, c_void_p, py_object
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.