Mercurial > hg > dmlib
annotate jssmix.c @ 158:255da2a698fe
Improve loop handling in the mixer.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 06 Oct 2012 05:30:22 +0300 |
parents | 0c9438a2c72a |
children | fe0c7ae05776 |
rev | line source |
---|---|
0 | 1 /* |
2 * miniJSS - Mixing device and channel handling | |
3 * Programmed and designed by Matti 'ccr' Hamalainen | |
4 * (C) Copyright 2006-2012 Tecnic Software productions (TNSP) | |
5 */ | |
6 #include "jssmix.h" | |
7 #include <string.h> | |
8 | |
9 | |
10 #ifdef DM_USE_C | |
11 #define JMIXER_HEADER | |
49
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
36
diff
changeset
|
12 #include "jmix_c_in.c" |
0 | 13 #undef JMIXER_HEADER |
14 #endif | |
15 | |
16 #undef DM_USE_SIMD | |
17 | |
18 #ifdef DM_USE_SIMD | |
19 #define JMIXER_HEADER | |
49
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
36
diff
changeset
|
20 #include "jmix_mmx_in.c" |
0 | 21 #undef JMIXER_HEADER |
22 #endif | |
23 | |
24 | |
25 typedef struct | |
26 { | |
27 int mixerID; | |
28 int outFormat; | |
29 int outChannels; | |
51
36e2f910219c
A non-working implementation of floating point audio mixing.
Matti Hamalainen <ccr@tnsp.org>
parents:
49
diff
changeset
|
30 |
36e2f910219c
A non-working implementation of floating point audio mixing.
Matti Hamalainen <ccr@tnsp.org>
parents:
49
diff
changeset
|
31 int (*jvmMixChannel_FW)(JSSMixer *, JSSChannel *, JMIXER_ADDBUF_TYPE *, const int, const Sint32); |
36e2f910219c
A non-working implementation of floating point audio mixing.
Matti Hamalainen <ccr@tnsp.org>
parents:
49
diff
changeset
|
32 int (*jvmMixChannel_BW)(JSSMixer *, JSSChannel *, JMIXER_ADDBUF_TYPE *, const int, const Sint32); |
36e2f910219c
A non-working implementation of floating point audio mixing.
Matti Hamalainen <ccr@tnsp.org>
parents:
49
diff
changeset
|
33 void (*jvmPostProcess)(JMIXER_ADDBUF_TYPE *, void *, const int); |
0 | 34 } JSSMixingRoutine; |
35 | |
36 | |
37 /* This table should be sorted from fastest to slowest, e.g. MMX/x86 | |
38 * optimized routines first, pure C versions last. | |
39 */ | |
40 static JSSMixingRoutine jvmMixRoutines[] = | |
41 { | |
42 #ifdef DM_USE_SIMD | |
43 { JMIX_MMX, JSS_AUDIO_U8, JSS_AUDIO_MONO, jvmMix_Mono_MMX_FW, jvmMix_Mono_MMX_BW, jvmPostProcess_U8_MMX }, | |
44 { JMIX_MMX, JSS_AUDIO_S8, JSS_AUDIO_MONO, jvmMix_Mono_MMX_FW, jvmMix_Mono_MMX_BW, jvmPostProcess_S8_MMX }, | |
45 { JMIX_MMX, JSS_AUDIO_U8, JSS_AUDIO_STEREO, jvmMix_Stereo_MMX_FW, jvmMix_Stereo_MMX_BW, jvmPostProcess_U8_MMX }, | |
46 { JMIX_MMX, JSS_AUDIO_S8, JSS_AUDIO_STEREO, jvmMix_Stereo_MMX_FW, jvmMix_Stereo_MMX_BW, jvmPostProcess_S8_MMX }, | |
47 | |
48 { JMIX_MMX, JSS_AUDIO_U16, JSS_AUDIO_MONO, jvmMix_Mono_MMX_FW, jvmMix_Mono_MMX_BW, jvmPostProcess_U16_MMX }, | |
49 { JMIX_MMX, JSS_AUDIO_S16, JSS_AUDIO_MONO, jvmMix_Mono_MMX_FW, jvmMix_Mono_MMX_BW, jvmPostProcess_S16_MMX }, | |
50 { JMIX_MMX, JSS_AUDIO_U16, JSS_AUDIO_STEREO, jvmMix_Stereo_MMX_FW, jvmMix_Stereo_MMX_BW, jvmPostProcess_U16_MMX }, | |
51 { JMIX_MMX, JSS_AUDIO_S16, JSS_AUDIO_STEREO, jvmMix_Stereo_MMX_FW, jvmMix_Stereo_MMX_BW, jvmPostProcess_S16_MMX }, | |
52 #endif | |
53 | |
54 #ifdef DM_USE_C | |
55 { JMIX_C, JSS_AUDIO_U8, JSS_AUDIO_MONO, jvmMix_Mono_C_FW, jvmMix_Mono_C_BW, jvmPostProcess_U8_C }, | |
56 { JMIX_C, JSS_AUDIO_S8, JSS_AUDIO_MONO, jvmMix_Mono_C_FW, jvmMix_Mono_C_BW, jvmPostProcess_S8_C }, | |
57 { JMIX_C, JSS_AUDIO_U8, JSS_AUDIO_STEREO, jvmMix_Stereo_C_FW, jvmMix_Stereo_C_BW, jvmPostProcess_U8_C }, | |
58 { JMIX_C, JSS_AUDIO_S8, JSS_AUDIO_STEREO, jvmMix_Stereo_C_FW, jvmMix_Stereo_C_BW, jvmPostProcess_S8_C }, | |
59 | |
60 { JMIX_C, JSS_AUDIO_U16, JSS_AUDIO_MONO, jvmMix_Mono_C_FW, jvmMix_Mono_C_BW, jvmPostProcess_U16_C }, | |
61 { JMIX_C, JSS_AUDIO_S16, JSS_AUDIO_MONO, jvmMix_Mono_C_FW, jvmMix_Mono_C_BW, jvmPostProcess_S16_C }, | |
62 { JMIX_C, JSS_AUDIO_U16, JSS_AUDIO_STEREO, jvmMix_Stereo_C_FW, jvmMix_Stereo_C_BW, jvmPostProcess_U16_C }, | |
63 { JMIX_C, JSS_AUDIO_S16, JSS_AUDIO_STEREO, jvmMix_Stereo_C_FW, jvmMix_Stereo_C_BW, jvmPostProcess_S16_C }, | |
64 #endif | |
65 }; | |
66 | |
67 static const int jvmNMixRoutines = sizeof(jvmMixRoutines) / sizeof(jvmMixRoutines[0]); | |
68 | |
69 | |
70 static int jvmFindMixRoutine(int outFormat, int outChannels, int mixerID) | |
71 { | |
72 int i; | |
73 | |
74 for (i = 0; i < jvmNMixRoutines; i++) | |
75 { | |
76 if (jvmMixRoutines[i].outFormat == outFormat && | |
77 jvmMixRoutines[i].outChannels == outChannels && | |
78 (mixerID == JMIX_AUTO || jvmMixRoutines[i].mixerID == mixerID)) | |
79 return i; | |
80 } | |
81 | |
82 return -1; | |
83 } | |
84 | |
85 | |
86 JSSMixer *jvmInit(const int outFormat, const int outChannels, const int outFreq, const int mixerID) | |
87 { | |
88 JSSMixer *mixer; | |
49
033c660c25f5
Restructure module playing, removing 8bit sample mixing (output can still be
Matti Hamalainen <ccr@tnsp.org>
parents:
36
diff
changeset
|
89 int mixerIdx; |
0 | 90 |
91 // Check settings | |
92 if (outChannels < 1) | |
93 { | |
94 JSSERROR(DMERR_INVALID_ARGS, NULL, | |
95 "Invalid number of channels %d\n", outChannels); | |
96 } | |
97 | |
98 if (outFreq < 4000) | |
99 { | |
100 JSSERROR(DMERR_INVALID_ARGS, NULL, | |
101 "Invalid mixing frequency %d\n", outFreq); | |
102 } | |
103 | |
104 /* Select mixing routines: | |
105 * Here we try to choose the most fitting mixing routines | |
106 * from the compiled in routines, unless caller is forcing | |
107 * us to select specific ones. | |
108 */ | |
109 if (mixerID == JMIX_AUTO) | |
110 { | |
111 mixerIdx = jvmFindMixRoutine(outFormat, outChannels, JMIX_SSE); | |
112 if (mixerIdx < 0) | |
113 mixerIdx = jvmFindMixRoutine(outFormat, outChannels, JMIX_MMX); | |
114 if (mixerIdx < 0) | |
115 mixerIdx = jvmFindMixRoutine(outFormat, outChannels, JMIX_AUTO); | |
116 } | |
117 else | |
118 { | |
119 mixerIdx = jvmFindMixRoutine(outFormat, outChannels, mixerID); | |
120 } | |
121 | |
122 if (mixerIdx < 0) | |
123 { | |
124 JSSERROR(DMERR_INVALID_ARGS, NULL, | |
125 "Could not find mixing routine for outFormat=%d, outChannels=%d, outFreq=%d.\n", | |
126 outFormat, outChannels, outFreq); | |
127 return NULL; | |
128 } | |
129 | |
130 // Allocate a mixer device structure | |
131 mixer = dmMalloc0(sizeof(JSSMixer)); | |
132 if (mixer == NULL) | |
133 { | |
134 JSSERROR(DMERR_MALLOC, NULL, | |
135 "Could not allocate mixing device structure.\n"); | |
136 } | |
137 | |
138 // Initialize variables | |
139 #ifdef JSS_SUP_THREADS | |
140 mixer->mutex = dmCreateMutex(); | |
141 #endif | |
142 mixer->outFormat = outFormat; | |
143 mixer->outFreq = outFreq; | |
144 mixer->outChannels = outChannels; | |
145 | |
146 mixer->jvmMixChannel_FW = jvmMixRoutines[mixerIdx].jvmMixChannel_FW; | |
147 mixer->jvmMixChannel_BW = jvmMixRoutines[mixerIdx].jvmMixChannel_BW; | |
148 mixer->jvmPostProcess = jvmMixRoutines[mixerIdx].jvmPostProcess; | |
149 | |
150 // Allocate addBuffer | |
151 mixer->addBufSize = outChannels * outFreq; | |
53
a83f7c4d9e08
No need to allocate with dmCalloc, when a plain dmMalloc is fine.
Matti Hamalainen <ccr@tnsp.org>
parents:
52
diff
changeset
|
152 mixer->addBuffer = dmMalloc(mixer->addBufSize * sizeof(JMIXER_ADDBUF_TYPE)); |
0 | 153 if (mixer->addBuffer == NULL) |
154 { | |
155 JSSERROR(DMERR_MALLOC, NULL, | |
156 "Could not allocate mixing addition buffer.\n"); | |
157 } | |
158 | |
159 return mixer; | |
160 } | |
161 | |
162 | |
163 int jvmClose(JSSMixer * mixer) | |
164 { | |
165 if (mixer == NULL) | |
166 return DMERR_NULLPTR; | |
167 | |
168 // Deallocate resources | |
169 #ifdef JSS_SUP_THREADS | |
170 dmDestroyMutex(mixer->mutex); | |
171 #endif | |
172 dmFree(mixer->addBuffer); | |
173 | |
174 memset(mixer, 0, sizeof(JSSMixer)); | |
175 dmFree(mixer); | |
176 | |
177 return DMERR_OK; | |
178 } | |
179 | |
180 | |
181 int jvmGetSampleSize(JSSMixer *mixer) | |
182 { | |
183 int sampSize = 1; | |
184 assert(mixer); | |
185 | |
186 switch (mixer->outChannels) | |
187 { | |
188 case JSS_AUDIO_STEREO: | |
189 case JSS_AUDIO_MONO: | |
190 sampSize = mixer->outChannels; | |
191 break; | |
192 default: | |
193 JSSERROR(DMERR_INVALID_ARGS, -1, | |
194 "outChannels=%d not stereo or mono!\n", mixer->outChannels); | |
195 break; | |
196 } | |
197 | |
198 switch (mixer->outFormat) | |
199 { | |
200 case JSS_AUDIO_U16: sampSize *= sizeof(Uint16); break; | |
201 case JSS_AUDIO_S16: sampSize *= sizeof(Sint16); break; | |
54 | 202 case JSS_AUDIO_U8: sampSize *= sizeof(Uint8); break; |
203 case JSS_AUDIO_S8: sampSize *= sizeof(Sint8); break; | |
0 | 204 default: |
205 JSSERROR(DMERR_INVALID_ARGS, -1, | |
206 "outFormat=%d is not supported!\n", mixer->outFormat); | |
207 } | |
208 | |
209 return sampSize; | |
210 } | |
211 | |
212 | |
213 int jvmGetSampleRes(JSSMixer *mixer) | |
214 { | |
54 | 215 int sampRes = 0; |
0 | 216 |
217 assert(mixer); | |
218 | |
219 switch (mixer->outFormat) | |
220 { | |
221 case JSS_AUDIO_U16: case JSS_AUDIO_S16: sampRes = 16; break; | |
54 | 222 case JSS_AUDIO_U8: case JSS_AUDIO_S8: sampRes = 8; break; |
0 | 223 default: |
224 JSSERROR(DMERR_INVALID_ARGS, -1, | |
225 "outFormat=%d is not supported!\n", mixer->outFormat); | |
226 } | |
227 | |
228 return sampRes; | |
229 } | |
230 | |
231 | |
51
36e2f910219c
A non-working implementation of floating point audio mixing.
Matti Hamalainen <ccr@tnsp.org>
parents:
49
diff
changeset
|
232 static void jvmMixChannel(JSSMixer *mixer, JSSChannel *chn, JMIXER_ADDBUF_TYPE *addBuffer, const int mixLength) |
0 | 233 { |
234 int mixDone = mixLength, mixResult; | |
51
36e2f910219c
A non-working implementation of floating point audio mixing.
Matti Hamalainen <ccr@tnsp.org>
parents:
49
diff
changeset
|
235 JMIXER_ADDBUF_TYPE *ab = addBuffer; |
0 | 236 |
237 if (!chn->chPlaying || chn->chMute) | |
238 return; | |
239 | |
240 DBG("%s(%p, %d)\n", __FUNCTION__, chn, mixLength); | |
241 | |
242 while (mixDone > 0) | |
243 { | |
244 if (chn->chDirection) | |
245 { | |
246 // Channel is playing FORWARDS | |
247 if (chn->chFlags & jsfLooped) | |
248 { | |
249 // Sample is looped | |
250 if (chn->chFlags & jsfBiDi) | |
251 { | |
252 // Bi-directional loop | |
253 if (FP_GETH(chn->chPos) >= chn->chLoopE) | |
254 { | |
158
255da2a698fe
Improve loop handling in the mixer.
Matti Hamalainen <ccr@tnsp.org>
parents:
141
diff
changeset
|
255 DMFixedPoint end; |
255da2a698fe
Improve loop handling in the mixer.
Matti Hamalainen <ccr@tnsp.org>
parents:
141
diff
changeset
|
256 FP_SETHL(end, chn->chLoopE + chn->chLoopE, 0); |
255da2a698fe
Improve loop handling in the mixer.
Matti Hamalainen <ccr@tnsp.org>
parents:
141
diff
changeset
|
257 FP_SUB_R(chn->chPos, end, chn->chPos); |
0 | 258 chn->chDirection = FALSE; |
259 } | |
260 } | |
261 else | |
262 { | |
263 // Normal forward loop | |
264 if (FP_GETH(chn->chPos) >= chn->chLoopE) | |
265 { | |
158
255da2a698fe
Improve loop handling in the mixer.
Matti Hamalainen <ccr@tnsp.org>
parents:
141
diff
changeset
|
266 DMFixedPoint diff, end; |
255da2a698fe
Improve loop handling in the mixer.
Matti Hamalainen <ccr@tnsp.org>
parents:
141
diff
changeset
|
267 FP_SETHL(end, chn->chLoopE, 0); |
255da2a698fe
Improve loop handling in the mixer.
Matti Hamalainen <ccr@tnsp.org>
parents:
141
diff
changeset
|
268 FP_SUB_R(diff, chn->chPos, end); |
255da2a698fe
Improve loop handling in the mixer.
Matti Hamalainen <ccr@tnsp.org>
parents:
141
diff
changeset
|
269 FP_SETHL(chn->chPos, chn->chLoopS, 0); |
255da2a698fe
Improve loop handling in the mixer.
Matti Hamalainen <ccr@tnsp.org>
parents:
141
diff
changeset
|
270 FP_ADD(chn->chPos, diff); |
0 | 271 } |
272 } | |
273 } | |
274 else | |
275 { | |
276 // Normal (non-looped) sample | |
277 if (FP_GETH(chn->chPos) >= chn->chSize) | |
278 { | |
279 chn->chPlaying = FALSE; | |
280 return; | |
281 } | |
282 } | |
283 } | |
284 else | |
285 { | |
286 // Channel is playing BACKWARDS | |
287 if (chn->chFlags & jsfLooped) | |
288 { | |
289 // Sample is looped | |
290 if (chn->chFlags & jsfBiDi) | |
291 { | |
292 // Bi-directional loop | |
293 if (FP_GETH(chn->chPos) <= chn->chLoopS) | |
294 { | |
158
255da2a698fe
Improve loop handling in the mixer.
Matti Hamalainen <ccr@tnsp.org>
parents:
141
diff
changeset
|
295 DMFixedPoint start; |
255da2a698fe
Improve loop handling in the mixer.
Matti Hamalainen <ccr@tnsp.org>
parents:
141
diff
changeset
|
296 FP_SETHL(start, chn->chLoopS + chn->chLoopS, 0); |
255da2a698fe
Improve loop handling in the mixer.
Matti Hamalainen <ccr@tnsp.org>
parents:
141
diff
changeset
|
297 FP_SUB_R(chn->chPos, start, chn->chPos); |
0 | 298 chn->chDirection = TRUE; |
299 } | |
300 } | |
301 else | |
302 { | |
303 // Normal forward loop | |
304 if (FP_GETH(chn->chPos) <= chn->chLoopS) | |
305 { | |
158
255da2a698fe
Improve loop handling in the mixer.
Matti Hamalainen <ccr@tnsp.org>
parents:
141
diff
changeset
|
306 DMFixedPoint diff; |
255da2a698fe
Improve loop handling in the mixer.
Matti Hamalainen <ccr@tnsp.org>
parents:
141
diff
changeset
|
307 FP_SETHL(diff, chn->chLoopE - chn->chLoopS, 0); |
255da2a698fe
Improve loop handling in the mixer.
Matti Hamalainen <ccr@tnsp.org>
parents:
141
diff
changeset
|
308 FP_ADD(chn->chPos, diff); |
0 | 309 } |
310 } | |
311 } | |
312 else | |
313 { | |
314 // Normal (non-looped) sample | |
315 if (FP_GETH(chn->chPos) <= 0) | |
316 { | |
317 chn->chPlaying = FALSE; | |
318 return; | |
319 } | |
320 } | |
321 } | |
322 | |
323 // Call the mixing innerloop functions | |
324 if (chn->chDirection) | |
325 { | |
326 DBG("MIX_FW[%p : %d : ", ab, mixDone); | |
327 if (chn->chFlags & jsfLooped) | |
328 { | |
329 DBG("%d (%x)] {loop}\n", chn->chLoopE, chn->chLoopE); | |
330 mixResult = mixer->jvmMixChannel_FW((void *) mixer, chn, | |
331 ab, mixDone, chn->chLoopE); | |
332 } | |
333 else | |
334 { | |
335 DBG("%d (%x)]\n", chn->chSize, chn->chSize); | |
336 mixResult = mixer->jvmMixChannel_FW((void *) mixer, chn, | |
337 ab, mixDone, chn->chSize); | |
338 } | |
339 } | |
340 else | |
341 { | |
342 DBG("MIX_BW[%p : %d : ", ab, mixDone); | |
343 if (chn->chFlags & jsfLooped) | |
344 { | |
345 DBG("%d (%x)] {loop}\n", chn->chLoopS, chn->chLoopS); | |
346 mixResult = mixer->jvmMixChannel_BW(mixer, chn, | |
347 ab, mixDone, chn->chLoopS); | |
348 } | |
349 else | |
350 { | |
351 DBG("%d (%x)]\n", 0, 0); | |
352 mixResult = mixer->jvmMixChannel_BW(mixer, chn, | |
353 ab, mixDone, 0); | |
354 } | |
355 } | |
356 | |
357 mixDone -= mixResult; | |
358 ab += mixResult * mixer->outChannels; | |
359 } | |
360 | |
361 #ifdef JSS_DEBUG | |
362 if (mixDone < 0) | |
363 JSSWARNING(DMERR_BOUNDS,, "mixDone < 0 in mixing logic loop.\n"); | |
364 #endif | |
365 } | |
366 | |
367 | |
368 void jvmRenderAudio(JSSMixer *mixer, void *mixBuffer, const int mixLength) | |
369 { | |
370 int i, blockLength, mixLeft; | |
51
36e2f910219c
A non-working implementation of floating point audio mixing.
Matti Hamalainen <ccr@tnsp.org>
parents:
49
diff
changeset
|
371 JMIXER_ADDBUF_TYPE *ab; |
0 | 372 |
373 JSS_LOCK(mixer); | |
374 | |
375 assert(mixer != NULL); | |
376 assert(mixBuffer != NULL); | |
377 assert(mixLength > 0); | |
52 | 378 assert(mixLength * mixer->outChannels <= mixer->addBufSize); |
0 | 379 |
380 // Clear mixer->addBuffer | |
51
36e2f910219c
A non-working implementation of floating point audio mixing.
Matti Hamalainen <ccr@tnsp.org>
parents:
49
diff
changeset
|
381 memset(mixer->addBuffer, 0, mixLength * mixer->outChannels * sizeof(JMIXER_ADDBUF_TYPE)); |
0 | 382 |
383 ab = mixer->addBuffer; | |
384 mixLeft = mixLength; | |
385 while (mixLeft > 0) | |
386 { | |
387 // Check for callbacks | |
388 blockLength = mixLeft; | |
389 | |
390 if (mixer->cbFunction) | |
391 { | |
392 if (mixer->cbCounter <= 0) | |
393 { | |
394 mixer->cbFunction(mixer, mixer->cbData); | |
395 mixer->cbCounter = mixer->cbFreq; | |
396 } | |
397 | |
398 if (mixer->cbCounter < blockLength) | |
399 blockLength = mixer->cbCounter; | |
400 } | |
401 | |
402 // Do mixing | |
403 for (i = 0; i < jsetNChannels; i++) | |
404 { | |
405 JSSChannel *chn = &(mixer->channels[i]); | |
406 if (chn->chPlaying && !chn->chMute) | |
407 jvmMixChannel(mixer, chn, ab, blockLength); | |
408 } | |
409 | |
410 /* | |
411 if (chn->chPlaying) | |
412 { | |
413 if (!chn->chMute) | |
414 jvmMixChannel(mixer, chn, ab, blockLength); | |
415 else | |
416 jvmAdvanceChannel(mixer, chn, blockLength); | |
417 } | |
418 */ | |
419 | |
420 ab += blockLength * mixer->outChannels; | |
421 mixLeft -= blockLength; | |
422 mixer->cbCounter -= blockLength; | |
423 } | |
424 | |
425 // Post-process | |
426 mixer->jvmPostProcess(mixer->addBuffer, mixBuffer, mixLength * mixer->outChannels); | |
427 | |
428 JSS_UNLOCK(mixer); | |
429 } | |
430 | |
431 | |
432 int jvmSetCallback(JSSMixer * mixer, void (*cbFunction) (void *, void *), void *cbData) | |
433 { | |
434 assert(mixer); | |
435 | |
436 if (cbFunction == NULL) | |
437 JSSERROR(DMERR_NULLPTR, DMERR_NULLPTR, "NULL pointer given as cbFunction"); | |
438 | |
439 JSS_LOCK(mixer); | |
440 | |
441 mixer->cbFunction = cbFunction; | |
442 mixer->cbData = cbData; | |
443 | |
444 JSS_UNLOCK(mixer); | |
445 | |
446 return DMERR_OK; | |
447 } | |
448 | |
449 | |
450 void jvmRemoveCallback(JSSMixer * mixer) | |
451 { | |
452 assert(mixer); | |
453 | |
454 JSS_LOCK(mixer); | |
455 | |
456 mixer->cbFunction = NULL; | |
457 mixer->cbData = NULL; | |
458 mixer->cbFreq = mixer->cbCounter = 0; | |
459 | |
460 JSS_UNLOCK(mixer); | |
461 } | |
462 | |
463 | |
464 int jvmSetCallbackFreq(JSSMixer * mixer, const int cbFreq) | |
465 { | |
466 assert(mixer); | |
467 | |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
468 if (cbFreq < 1 || cbFreq >= mixer->outFreq) |
0 | 469 JSSERROR(DMERR_INVALID_ARGS, DMERR_INVALID_ARGS, |
470 "Invalid callback frequency given (%i / %i)\n", cbFreq, mixer->outFreq); | |
471 | |
472 JSS_LOCK(mixer); | |
473 | |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
474 mixer->cbFreq = mixer->outFreq / cbFreq; |
0 | 475 mixer->cbCounter = 0; |
476 | |
477 //fprintf(stderr, "set(outFreq = %d, cbFreq = %d) = %d\n", mixer->outFreq, cbFreq, mixer->cbFreq); | |
478 | |
479 JSS_UNLOCK(mixer); | |
480 return DMERR_OK; | |
481 } | |
482 | |
483 | |
484 /* Channel manipulation routines | |
485 */ | |
486 void jvmPlay(JSSMixer * mixer, const int channel) | |
487 { | |
488 JSS_LOCK(mixer); | |
489 mixer->channels[channel].chPlaying = TRUE; | |
490 JSS_UNLOCK(mixer); | |
491 } | |
492 | |
493 | |
494 void jvmStop(JSSMixer * mixer, const int channel) | |
495 { | |
496 JSS_LOCK(mixer); | |
497 mixer->channels[channel].chPlaying = FALSE; | |
498 JSS_UNLOCK(mixer); | |
499 } | |
500 | |
501 | |
502 void jvmSetSample(JSSMixer * mixer, const int channel, | |
36
f3407a58e01e
Change DMFixedPoint types and appropriate JSS functions back to using signed
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
503 void *data, const Sint32 size, const Sint32 loopS, |
f3407a58e01e
Change DMFixedPoint types and appropriate JSS functions back to using signed
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
504 const Sint32 loopE, const int flags) |
0 | 505 { |
506 JSSChannel *c; | |
507 | |
508 JSS_LOCK(mixer); | |
509 c = &mixer->channels[channel]; | |
510 | |
54 | 511 c->chData = data; |
512 c->chSize = size; | |
513 c->chLoopS = loopS; | |
514 c->chLoopE = loopE; | |
515 c->chFlags = flags; | |
0 | 516 c->chDirection = TRUE; |
57
2edda27f951c
Silly interpolation in mixing.
Matti Hamalainen <ccr@tnsp.org>
parents:
54
diff
changeset
|
517 memset(c->chPrevL, 0, sizeof(c->chPrevL)); |
2edda27f951c
Silly interpolation in mixing.
Matti Hamalainen <ccr@tnsp.org>
parents:
54
diff
changeset
|
518 memset(c->chPrevR, 0, sizeof(c->chPrevR)); |
54 | 519 c->chPos.dw = c->chDeltaO.dw = 0; |
0 | 520 |
521 JSS_UNLOCK(mixer); | |
522 } | |
523 | |
524 | |
525 void jvmSetFreq(JSSMixer * mixer, const int channel, const int freq) | |
526 { | |
527 JSS_LOCK(mixer); | |
528 | |
529 mixer->channels[channel].chFreq = freq; | |
530 | |
531 if (mixer->outFreq > 0) | |
532 { | |
533 DMFixedPoint a, b; | |
534 FP_SETHL(a, freq, 0); | |
535 FP_CONV(b, mixer->outFreq); | |
536 FP_DIV_R(mixer->channels[channel].chDeltaO, a, b); | |
537 } | |
538 else | |
539 { | |
540 FP_SET(mixer->channels[channel].chDeltaO, 0); | |
541 } | |
542 | |
543 JSS_UNLOCK(mixer); | |
544 } | |
545 | |
546 | |
547 int jvmGetFreq(JSSMixer * mixer, const int channel) | |
548 { | |
549 int tmp; | |
550 | |
551 JSS_LOCK(mixer); | |
552 tmp = mixer->channels[channel].chFreq; | |
553 JSS_UNLOCK(mixer); | |
554 | |
555 return tmp; | |
556 } | |
557 | |
558 | |
559 void jvmSetVolume(JSSMixer * mixer, const int channel, const int volume) | |
560 { | |
561 JSS_LOCK(mixer); | |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
562 FP_SETHL(mixer->channels[channel].chVolume, volume, 0); |
139
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
563 mixer->channels[channel].chVolumeD = 0; |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
564 mixer->channels[channel].chDeltaV.dw = 0; |
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
565 JSS_UNLOCK(mixer); |
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
566 } |
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
567 |
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
568 |
139
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
569 void jvmSetVolumeRamp(JSSMixer * mixer, const int channel, const int start, const int end, const int len) |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
570 { |
139
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
571 int tmp; |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
572 DMFixedPoint a, b; |
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
573 JSS_LOCK(mixer); |
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
574 FP_SETHL(mixer->channels[channel].chVolume, start, 0); |
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
575 |
139
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
576 tmp = mixer->channels[channel].chVolumeD = |
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
577 len > 0 ? ((mixer->outFreq * len) / 1000) : mixer->cbFreq; |
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
578 |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
579 FP_SETHL(a, (end - start), 0); |
139
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
580 FP_CONV(b, tmp); |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
581 FP_DIV_R(mixer->channels[channel].chDeltaV, a, b); |
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
582 |
0 | 583 JSS_UNLOCK(mixer); |
584 } | |
585 | |
586 | |
587 int jvmGetVolume(JSSMixer * mixer, const int channel) | |
588 { | |
589 int tmp; | |
590 | |
591 JSS_LOCK(mixer); | |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
592 tmp = FP_GETH(mixer->channels[channel].chVolume); |
0 | 593 JSS_UNLOCK(mixer); |
594 | |
595 return tmp; | |
596 } | |
597 | |
598 | |
36
f3407a58e01e
Change DMFixedPoint types and appropriate JSS functions back to using signed
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
599 void jvmSetPos(JSSMixer * mixer, const int channel, const Sint32 pos) |
0 | 600 { |
601 JSS_LOCK(mixer); | |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
602 FP_SETHL(mixer->channels[channel].chPos, pos, 0); |
0 | 603 JSS_UNLOCK(mixer); |
604 } | |
605 | |
606 | |
36
f3407a58e01e
Change DMFixedPoint types and appropriate JSS functions back to using signed
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
607 Sint32 jvmGetPos(JSSMixer * mixer, const int channel) |
0 | 608 { |
36
f3407a58e01e
Change DMFixedPoint types and appropriate JSS functions back to using signed
Matti Hamalainen <ccr@tnsp.org>
parents:
34
diff
changeset
|
609 Sint32 tmp; |
0 | 610 |
611 JSS_LOCK(mixer); | |
612 tmp = FP_GETH(mixer->channels[channel].chPos); | |
613 JSS_UNLOCK(mixer); | |
614 | |
615 return tmp; | |
616 } | |
617 | |
618 | |
619 void jvmSetPan(JSSMixer * mixer, const int channel, const int panning) | |
620 { | |
621 JSS_LOCK(mixer); | |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
622 FP_SETHL(mixer->channels[channel].chPanning, panning, 0); |
139
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
623 mixer->channels[channel].chPanningD = 0; |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
624 mixer->channels[channel].chDeltaP.dw = 0; |
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
625 JSS_UNLOCK(mixer); |
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
626 } |
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
627 |
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
628 |
139
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
629 void jvmSetPanRamp(JSSMixer * mixer, const int channel, const int start, const int end, const int len) |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
630 { |
139
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
631 int tmp; |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
632 DMFixedPoint a, b; |
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
633 JSS_LOCK(mixer); |
139
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
634 |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
635 FP_SETHL(mixer->channels[channel].chPanning, start, 0); |
139
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
636 |
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
637 tmp = mixer->channels[channel].chPanningD = |
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
638 len > 0 ? ((mixer->outFreq * len) / 1000) : mixer->cbFreq; |
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
639 |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
640 FP_SETHL(a, (end - start), 0); |
139
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
641 FP_CONV(b, tmp); |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
642 FP_DIV_R(mixer->channels[channel].chDeltaP, a, b); |
139
111f3e4b57ad
Improve volume ramping functionality to allow arbitrary length ramps.
Matti Hamalainen <ccr@tnsp.org>
parents:
134
diff
changeset
|
643 |
0 | 644 JSS_UNLOCK(mixer); |
645 } | |
646 | |
647 | |
648 int jvmGetPan(JSSMixer * mixer, const int channel) | |
649 { | |
650 int tmp; | |
651 | |
652 JSS_LOCK(mixer); | |
134
1ba202b448e0
Implement volume and panning ramps (interpolation between callbacks aka "frames")
Matti Hamalainen <ccr@tnsp.org>
parents:
57
diff
changeset
|
653 tmp = FP_GETH(mixer->channels[channel].chPanning); |
0 | 654 JSS_UNLOCK(mixer); |
655 | |
656 return tmp; | |
657 } | |
658 | |
659 | |
660 void jvmMute(JSSMixer * mixer, const int channel, const BOOL mute) | |
661 { | |
662 JSS_LOCK(mixer); | |
663 mixer->channels[channel].chMute = mute; | |
664 JSS_UNLOCK(mixer); | |
665 } | |
666 | |
667 | |
141
0c9438a2c72a
Add function jvmGetMute() to get status of channel mute.
Matti Hamalainen <ccr@tnsp.org>
parents:
140
diff
changeset
|
668 BOOL jvmGetMute(JSSMixer * mixer, const int channel) |
0c9438a2c72a
Add function jvmGetMute() to get status of channel mute.
Matti Hamalainen <ccr@tnsp.org>
parents:
140
diff
changeset
|
669 { |
0c9438a2c72a
Add function jvmGetMute() to get status of channel mute.
Matti Hamalainen <ccr@tnsp.org>
parents:
140
diff
changeset
|
670 BOOL tmp; |
0c9438a2c72a
Add function jvmGetMute() to get status of channel mute.
Matti Hamalainen <ccr@tnsp.org>
parents:
140
diff
changeset
|
671 |
0c9438a2c72a
Add function jvmGetMute() to get status of channel mute.
Matti Hamalainen <ccr@tnsp.org>
parents:
140
diff
changeset
|
672 JSS_LOCK(mixer); |
0c9438a2c72a
Add function jvmGetMute() to get status of channel mute.
Matti Hamalainen <ccr@tnsp.org>
parents:
140
diff
changeset
|
673 tmp = mixer->channels[channel].chMute; |
0c9438a2c72a
Add function jvmGetMute() to get status of channel mute.
Matti Hamalainen <ccr@tnsp.org>
parents:
140
diff
changeset
|
674 JSS_UNLOCK(mixer); |
0c9438a2c72a
Add function jvmGetMute() to get status of channel mute.
Matti Hamalainen <ccr@tnsp.org>
parents:
140
diff
changeset
|
675 |
0c9438a2c72a
Add function jvmGetMute() to get status of channel mute.
Matti Hamalainen <ccr@tnsp.org>
parents:
140
diff
changeset
|
676 return tmp; |
0c9438a2c72a
Add function jvmGetMute() to get status of channel mute.
Matti Hamalainen <ccr@tnsp.org>
parents:
140
diff
changeset
|
677 } |
0c9438a2c72a
Add function jvmGetMute() to get status of channel mute.
Matti Hamalainen <ccr@tnsp.org>
parents:
140
diff
changeset
|
678 |
0c9438a2c72a
Add function jvmGetMute() to get status of channel mute.
Matti Hamalainen <ccr@tnsp.org>
parents:
140
diff
changeset
|
679 |
0 | 680 void jvmClear(JSSMixer * mixer, const int channel) |
681 { | |
682 JSS_LOCK(mixer); | |
683 memset(&mixer->channels[channel], 0, sizeof(JSSChannel)); | |
684 JSS_UNLOCK(mixer); | |
685 } | |
686 | |
687 | |
688 void jvmSetGlobalVol(JSSMixer * mixer, const int volume) | |
689 { | |
690 JSS_LOCK(mixer); | |
691 mixer->globalVol = volume; | |
692 JSS_UNLOCK(mixer); | |
693 } | |
694 | |
695 | |
696 int jvmGetGlobalVol(JSSMixer * mixer) | |
697 { | |
698 int tmp; | |
699 | |
700 JSS_LOCK(mixer); | |
701 tmp = mixer->globalVol; | |
702 JSS_UNLOCK(mixer); | |
703 | |
704 return tmp; | |
705 } |