|
372
|
1 /*
|
|
|
2 pygame - Python Game Library
|
|
|
3 Copyright (C) 2000-2001 Pete Shinners
|
|
|
4
|
|
|
5 This library is free software; you can redistribute it and/or
|
|
|
6 modify it under the terms of the GNU Library General Public
|
|
|
7 License as published by the Free Software Foundation; either
|
|
|
8 version 2 of the License, or (at your option) any later version.
|
|
|
9
|
|
|
10 This library is distributed in the hope that it will be useful,
|
|
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
13 Library General Public License for more details.
|
|
|
14
|
|
|
15 You should have received a copy of the GNU Library General Public
|
|
|
16 License along with this library; if not, write to the Free
|
|
|
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
18
|
|
|
19 Pete Shinners
|
|
|
20 pete@shinners.org
|
|
|
21 */
|
|
|
22
|
|
|
23 #include"pygame.h"
|
|
|
24 #include"mixer.h"
|
|
|
25 #include<Numeric/arrayobject.h>
|
|
|
26 #include<SDL_byteorder.h>
|
|
|
27
|
|
|
28
|
|
|
29
|
|
|
30
|
|
|
31 /*DOC*/ static char doc_samples[] =
|
|
|
32 /*DOC*/ "pygame.sndarray.samples(Surface) -> Array\n"
|
|
|
33 /*DOC*/ "get a reference to the sound samples\n"
|
|
|
34 /*DOC*/ "\n"
|
|
|
35 /*DOC*/ "This will return an array that directly references the samples\n"
|
|
|
36 /*DOC*/ "in the array.\n"
|
|
|
37 /*DOC*/ ;
|
|
|
38
|
|
|
39 static PyObject* sndarray_samples(PyObject* self, PyObject* arg)
|
|
|
40 {
|
|
|
41 int dim[2], numdims, type, formatbytes;
|
|
|
42 PyObject *array, *chunkobj;
|
|
|
43 Mix_Chunk* chunk;
|
|
|
44 Uint16 format;
|
|
|
45 int numchannels;
|
|
|
46
|
|
|
47 if(!PyArg_ParseTuple(arg, "O!", &PySound_Type, &chunkobj))
|
|
|
48 return NULL;
|
|
|
49 chunk = PySound_AsChunk(chunkobj);
|
|
|
50
|
|
|
51 if(!Mix_QuerySpec(NULL, &format, &numchannels))
|
|
|
52 return RAISE(PyExc_SDLError, "Mixer not initialized");
|
|
|
53
|
|
|
54 formatbytes = (abs(format)&0xff)/8;
|
|
|
55 if(format == AUDIO_S8)
|
|
|
56 type = PyArray_CHAR;
|
|
|
57 else if(format == AUDIO_U8)
|
|
|
58 type = PyArray_UBYTE;
|
|
|
59 else if(formatbytes == 2)
|
|
|
60 type = PyArray_SHORT;
|
|
|
61 else
|
|
|
62 return RAISE(PyExc_TypeError, "Unpresentable audio format");
|
|
|
63
|
|
|
64 numdims = (numchannels>1)?2:1;
|
|
|
65 dim[0] = chunk->alen / (formatbytes*numchannels);
|
|
|
66 dim[1] = numchannels;
|
|
|
67
|
|
|
68 array = PyArray_FromDimsAndData(numdims, dim, type, chunk->abuf);
|
|
|
69 if(array)
|
|
|
70 {
|
|
|
71 Py_INCREF(chunkobj);
|
|
|
72 ((PyArrayObject*)array)->base = chunkobj;
|
|
|
73 ((PyArrayObject*)array)->flags |= SAVESPACE;
|
|
|
74 }
|
|
|
75 return array;
|
|
|
76 }
|
|
|
77
|
|
|
78 /*DOC*/ static char doc_array[] =
|
|
|
79 /*DOC*/ "pygame.sndarray.array(Sound) -> Array\n"
|
|
|
80 /*DOC*/ "get an array copied from a sound\n"
|
|
|
81 /*DOC*/ "\n"
|
|
|
82 /*DOC*/ "Creates an array with a copy of the sound data.\n"
|
|
|
83 /*DOC*/ ;
|
|
|
84
|
|
|
85 PyObject* sndarray_array(PyObject* self, PyObject* arg)
|
|
|
86 {
|
|
|
87 PyObject *array, *arraycopy=NULL;
|
|
|
88
|
|
|
89 /*we'll let numeric do the copying for us*/
|
|
|
90 array = sndarray_samples(self, arg);
|
|
|
91 if(array)
|
|
|
92 {
|
|
373
|
93 arraycopy = PyArray_Copy((PyArrayObject*)array);
|
|
372
|
94 Py_DECREF(array);
|
|
|
95 }
|
|
|
96 return arraycopy;
|
|
|
97 }
|
|
|
98
|
|
|
99
|
|
|
100 /*DOC*/ static char doc_make_sound[] =
|
|
|
101 /*DOC*/ "pygame.sndarray.make_sound(array) -> Sound\n"
|
|
|
102 /*DOC*/ "create a new Sound object from array data\n"
|
|
|
103 /*DOC*/ "\n"
|
|
|
104 /*DOC*/ "Create a new playable Sound object from array data\n"
|
|
|
105 /*DOC*/ "the Sound will be a copy of the array samples.\n"
|
|
|
106 /*DOC*/ "\n"
|
|
373
|
107 /*DOC*/ "The array must be 1-dimensional for mono sound, and.\n"
|
|
|
108 /*DOC*/ "2-dimensional for stereo.\n"
|
|
372
|
109 /*DOC*/ ;
|
|
|
110
|
|
|
111 PyObject* sndarray_make_sound(PyObject* self, PyObject* arg)
|
|
|
112 {
|
|
|
113 PyObject *arrayobj;
|
|
|
114 PyArrayObject *array;
|
|
|
115 Mix_Chunk *chunk;
|
|
|
116 Uint16 format;
|
|
374
|
117 int numchannels, mixerbytes;
|
|
448
|
118 int loop1, loop2, step1, step2, length, length2=0;
|
|
372
|
119 Uint8 *src, *dst;
|
|
|
120
|
|
|
121 if(!PyArg_ParseTuple(arg, "O!", &PyArray_Type, &arrayobj))
|
|
|
122 return NULL;
|
|
|
123 array = (PyArrayObject*)arrayobj;
|
|
|
124
|
|
|
125 if(!Mix_QuerySpec(NULL, &format, &numchannels))
|
|
|
126 return RAISE(PyExc_SDLError, "Mixer not initialized");
|
|
373
|
127 if(array->descr->type_num > PyArray_LONG)
|
|
|
128 return RAISE(PyExc_ValueError, "Invalid array datatype for sound");
|
|
372
|
129
|
|
|
130 if(format==AUDIO_S8 || format==AUDIO_U8)
|
|
373
|
131 mixerbytes = 1;
|
|
|
132 else
|
|
|
133 mixerbytes = 2;
|
|
372
|
134
|
|
|
135 /*test array dimensions*/
|
|
|
136 if(numchannels==1)
|
|
|
137 {
|
|
|
138 if(array->nd != 1)
|
|
|
139 return RAISE(PyExc_ValueError, "Array must be 1-dimensional for mono mixer");
|
|
|
140 }
|
|
|
141 else
|
|
|
142 {
|
|
|
143 if(array->nd != 2)
|
|
|
144 return RAISE(PyExc_ValueError, "Array must be 2-dimensional for stereo mixer");
|
|
|
145 if(array->dimensions[1] != numchannels)
|
|
|
146 return RAISE(PyExc_ValueError, "Array depth must match number of mixer channels");
|
|
|
147 }
|
|
373
|
148 length = array->dimensions[0];
|
|
|
149 if(array->nd == 2)
|
|
|
150 length2 = array->dimensions[1];
|
|
|
151
|
|
372
|
152 /*create chunk, we are screwed if SDL_mixer ever does more than malloc/free*/
|
|
|
153 chunk = (Mix_Chunk *)malloc(sizeof(Mix_Chunk));
|
|
|
154 if ( chunk == NULL )
|
|
|
155 return RAISE(PyExc_MemoryError, "Cannot allocate chunk\n");
|
|
|
156 /*let's hope Mix_Chunk never changes also*/
|
|
373
|
157 chunk->alen = mixerbytes * length * numchannels;
|
|
372
|
158 chunk->abuf = (Uint8*)malloc(chunk->alen);
|
|
|
159 chunk->allocated = 1;
|
|
|
160 chunk->volume = 128;
|
|
373
|
161
|
|
372
|
162 if(array->nd == 1)
|
|
|
163 {
|
|
|
164 step1 = array->strides[0];
|
|
|
165 src = (Uint8*)array->data;
|
|
|
166 dst = (Uint8*)chunk->abuf;
|
|
373
|
167 if(mixerbytes == 1)
|
|
372
|
168 {
|
|
373
|
169 switch(array->descr->elsize)
|
|
372
|
170 {
|
|
373
|
171 case 1:
|
|
|
172 for(loop1=0; loop1<length; loop1++, dst+=1, src+=step1)
|
|
|
173 *(Uint8*)dst = (Uint8)*((Uint8*)src);
|
|
|
174 break;
|
|
|
175 case 2:
|
|
|
176 for(loop1=0; loop1<length; loop1++, dst+=1, src+=step1)
|
|
|
177 *(Uint8*)dst = (Uint8)*((Uint16*)src);
|
|
|
178 break;
|
|
|
179 case 4:
|
|
|
180 for(loop1=0; loop1<length; loop1++, dst+=1, src+=step1)
|
|
|
181 *(Uint8*)dst = (Uint8)*((Uint32*)src);
|
|
|
182 break;
|
|
372
|
183 }
|
|
|
184 }
|
|
|
185 else
|
|
|
186 {
|
|
373
|
187 switch(array->descr->elsize)
|
|
372
|
188 {
|
|
373
|
189 case 1:
|
|
|
190 for(loop1=0; loop1<length; loop1++, dst+=2, src+=step1)
|
|
|
191 *(Uint16*)dst = (Uint16)((*((Uint8*)src))<<8);
|
|
|
192 break;
|
|
|
193 case 2:
|
|
|
194 for(loop1=0; loop1<length; loop1++, dst+=2, src+=step1)
|
|
|
195 *(Uint16*)dst = (Uint16)*((Uint16*)src);
|
|
|
196 break;
|
|
|
197 case 4:
|
|
|
198 for(loop1=0; loop1<length; loop1++, dst+=2, src+=step1)
|
|
|
199 *(Uint16*)dst = (Uint16)*((Uint32*)src);
|
|
|
200 break;
|
|
372
|
201 }
|
|
|
202 }
|
|
|
203 }
|
|
|
204 else
|
|
|
205 {
|
|
|
206 step1 = array->strides[0];
|
|
|
207 step2 = array->strides[1];
|
|
|
208 dst = (Uint8*)chunk->abuf;
|
|
373
|
209 if(mixerbytes == 1)
|
|
372
|
210 {
|
|
373
|
211 for(loop1=0; loop1<length; loop1++)
|
|
372
|
212 {
|
|
|
213 src = (Uint8*)array->data + loop1*step1;
|
|
373
|
214 switch(array->descr->elsize)
|
|
372
|
215 {
|
|
373
|
216 case 1:
|
|
|
217 for(loop2=0; loop2<length2; loop1++, dst+=1, src+=step2)
|
|
|
218 *(Uint8*)dst = (Uint8)*((Uint8*)src);
|
|
|
219 break;
|
|
|
220 case 2:
|
|
|
221 for(loop1=0; loop1<length; loop1++, dst+=1, src+=step2)
|
|
|
222 *(Uint8*)dst = (Uint8)*((Uint16*)src);
|
|
|
223 break;
|
|
|
224 case 4:
|
|
|
225 for(loop1=0; loop1<length; loop1++, dst+=1, src+=step2)
|
|
|
226 *(Uint8*)dst = (Uint8)*((Uint32*)src);
|
|
|
227 break;
|
|
372
|
228 }
|
|
|
229 }
|
|
|
230 }
|
|
|
231 else
|
|
|
232 {
|
|
373
|
233 for(loop1 = 0; loop1 < length; loop1++)
|
|
372
|
234 {
|
|
|
235 src = (Uint8*)array->data + loop1*step1;
|
|
373
|
236 switch(array->descr->elsize)
|
|
372
|
237 {
|
|
373
|
238 case 1:
|
|
|
239 for(loop2=0; loop2<length2; loop1++, dst+=1, src+=step2)
|
|
|
240 *(Uint16*)dst = (Uint16)(*((Uint8*)src)<<8);
|
|
|
241 break;
|
|
|
242 case 2:
|
|
|
243 for(loop1=0; loop1<length; loop1++, dst+=1, src+=step2)
|
|
|
244 *(Uint16*)dst = (Uint16)*((Uint16*)src);
|
|
|
245 break;
|
|
|
246 case 4:
|
|
|
247 for(loop1=0; loop1<length; loop1++, dst+=1, src+=step2)
|
|
|
248 *(Uint16*)dst = (Uint16)*((Uint32*)src);
|
|
|
249 break;
|
|
372
|
250 }
|
|
|
251 }
|
|
|
252 }
|
|
|
253 }
|
|
373
|
254
|
|
372
|
255 return PySound_New(chunk);
|
|
|
256 }
|
|
|
257
|
|
|
258
|
|
|
259
|
|
|
260 static PyMethodDef sndarray_builtins[] =
|
|
|
261 {
|
|
|
262 { "samples", sndarray_samples, 1, doc_samples },
|
|
|
263 { "array", sndarray_array, 1, doc_array },
|
|
|
264 { "make_sound", sndarray_make_sound, 1, doc_make_sound },
|
|
|
265
|
|
|
266 { NULL, NULL }
|
|
|
267 };
|
|
|
268
|
|
|
269
|
|
|
270
|
|
|
271
|
|
|
272
|
|
|
273 /*DOC*/ static char doc_pygame_sndarray_MODULE[] =
|
|
|
274 /*DOC*/ "Contains routines for mixing numeric arrays with\n"
|
|
|
275 /*DOC*/ "sounds\n"
|
|
|
276 /*DOC*/ ;
|
|
|
277
|
|
|
278 PYGAME_EXPORT
|
|
|
279 void initsndarray(void)
|
|
|
280 {
|
|
|
281 PyObject *module, *dict;
|
|
|
282
|
|
|
283 /* create the module */
|
|
|
284 module = Py_InitModule3("sndarray", sndarray_builtins, doc_pygame_sndarray_MODULE);
|
|
|
285 dict = PyModule_GetDict(module);
|
|
|
286
|
|
|
287 /*imported needed apis*/
|
|
|
288 import_pygame_base();
|
|
|
289 import_pygame_mixer();
|
|
|
290 import_array();
|
|
|
291 }
|
|
|
292
|
|
|
293
|
|
|
294
|