diff options
author | Frank Gevaerts <frank@gevaerts.be> | 2010-12-12 15:03:30 +0000 |
---|---|---|
committer | Frank Gevaerts <frank@gevaerts.be> | 2010-12-12 15:03:30 +0000 |
commit | 26f2bfde03420edad4de1f22cb3d515dc063b20d (patch) | |
tree | 4a8c4abaf4795f38da70a4657c1a0fb3ba9debeb /apps/plugins/mikmod/mdriver.c | |
parent | d192bdf11e06e50645ecb5726658d4b691480a9a (diff) | |
download | rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.tar.gz rockbox-26f2bfde03420edad4de1f22cb3d515dc063b20d.zip |
Add MikMod plugin, ported by Jason Yu, with some minor work by Craig Mann and William Peters (FS#8806)
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28810 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/mikmod/mdriver.c')
-rw-r--r-- | apps/plugins/mikmod/mdriver.c | 965 |
1 files changed, 965 insertions, 0 deletions
diff --git a/apps/plugins/mikmod/mdriver.c b/apps/plugins/mikmod/mdriver.c new file mode 100644 index 0000000000..e11d32539b --- /dev/null +++ b/apps/plugins/mikmod/mdriver.c | |||
@@ -0,0 +1,965 @@ | |||
1 | /* MikMod sound library | ||
2 | (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS | ||
3 | for complete list. | ||
4 | |||
5 | This library is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU Library General Public License as | ||
7 | published by the Free Software Foundation; either version 2 of | ||
8 | the License, or (at your option) any later version. | ||
9 | |||
10 | This program 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 | ||
13 | GNU 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 Software | ||
17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||
18 | 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /*============================================================================== | ||
22 | |||
23 | $Id: mdriver.c,v 1.4 2007/12/03 20:59:05 denis111 Exp $ | ||
24 | |||
25 | These routines are used to access the available soundcard drivers. | ||
26 | |||
27 | ==============================================================================*/ | ||
28 | |||
29 | #ifdef HAVE_CONFIG_H | ||
30 | #include "config.h" | ||
31 | #endif | ||
32 | |||
33 | #ifdef HAVE_UNISTD_H | ||
34 | #include <unistd.h> | ||
35 | #endif | ||
36 | |||
37 | #if 0 | ||
38 | #if defined unix || (defined __APPLE__ && defined __MACH__) | ||
39 | #include <pwd.h> | ||
40 | #include <sys/stat.h> | ||
41 | #endif | ||
42 | #endif | ||
43 | |||
44 | #include <string.h> | ||
45 | #ifdef HAVE_STRINGS_H | ||
46 | #include <strings.h> | ||
47 | #endif | ||
48 | |||
49 | #include "mikmod_internals.h" | ||
50 | |||
51 | #ifdef SUNOS | ||
52 | extern int fprintf(FILE *, const char *, ...); | ||
53 | #endif | ||
54 | |||
55 | static MDRIVER *firstdriver=NULL; | ||
56 | MIKMODAPI MDRIVER *md_driver=NULL; | ||
57 | extern MODULE *pf; /* modfile being played */ | ||
58 | |||
59 | /* Initial global settings */ | ||
60 | MIKMODAPI UWORD md_device = 0; /* autodetect */ | ||
61 | MIKMODAPI UWORD md_mixfreq = 44100; | ||
62 | MIKMODAPI UWORD md_mode = DMODE_STEREO | DMODE_16BITS | | ||
63 | DMODE_SURROUND |DMODE_SOFT_MUSIC | | ||
64 | DMODE_SOFT_SNDFX; | ||
65 | MIKMODAPI UBYTE md_pansep = 128; /* 128 == 100% (full left/right) */ | ||
66 | MIKMODAPI UBYTE md_reverb = 0; /* no reverb */ | ||
67 | MIKMODAPI UBYTE md_volume = 128; /* global sound volume (0-128) */ | ||
68 | MIKMODAPI UBYTE md_musicvolume = 128; /* volume of song */ | ||
69 | MIKMODAPI UBYTE md_sndfxvolume = 128; /* volume of sound effects */ | ||
70 | UWORD md_bpm = 125; /* tempo */ | ||
71 | |||
72 | /* Do not modify the numchn variables yourself! use MD_SetVoices() */ | ||
73 | UBYTE md_numchn=0,md_sngchn=0,md_sfxchn=0; | ||
74 | UBYTE md_hardchn=0,md_softchn=0; | ||
75 | |||
76 | void (*md_player)(void) = Player_HandleTick; | ||
77 | static volatile int isplaying=0, initialized = 0; | ||
78 | static UBYTE *sfxinfo; | ||
79 | static int sfxpool; | ||
80 | |||
81 | static SAMPLE **md_sample = NULL; | ||
82 | |||
83 | /* Previous driver in use */ | ||
84 | static SWORD olddevice = -1; | ||
85 | |||
86 | /* Limits the number of hardware voices to the specified amount. | ||
87 | This function should only be used by the low-level drivers. */ | ||
88 | static void LimitHardVoices(int limit) | ||
89 | { | ||
90 | int t=0; | ||
91 | |||
92 | if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit; | ||
93 | if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit; | ||
94 | |||
95 | if (!(md_mode & DMODE_SOFT_SNDFX)) | ||
96 | md_hardchn=md_sfxchn; | ||
97 | else | ||
98 | md_hardchn=0; | ||
99 | |||
100 | if (!(md_mode & DMODE_SOFT_MUSIC)) md_hardchn += md_sngchn; | ||
101 | |||
102 | while (md_hardchn>limit) { | ||
103 | if (++t & 1) { | ||
104 | if (!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--; | ||
105 | } else { | ||
106 | if (!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--; | ||
107 | } | ||
108 | |||
109 | if (!(md_mode & DMODE_SOFT_SNDFX)) | ||
110 | md_hardchn=md_sfxchn; | ||
111 | else | ||
112 | md_hardchn=0; | ||
113 | |||
114 | if (!(md_mode & DMODE_SOFT_MUSIC)) | ||
115 | md_hardchn+=md_sngchn; | ||
116 | } | ||
117 | md_numchn=md_hardchn+md_softchn; | ||
118 | } | ||
119 | |||
120 | /* Limits the number of hardware voices to the specified amount. | ||
121 | This function should only be used by the low-level drivers. */ | ||
122 | static void LimitSoftVoices(int limit) | ||
123 | { | ||
124 | int t=0; | ||
125 | |||
126 | if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit; | ||
127 | if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit; | ||
128 | |||
129 | if (md_mode & DMODE_SOFT_SNDFX) | ||
130 | md_softchn=md_sfxchn; | ||
131 | else | ||
132 | md_softchn=0; | ||
133 | |||
134 | if (md_mode & DMODE_SOFT_MUSIC) md_softchn+=md_sngchn; | ||
135 | |||
136 | while (md_softchn>limit) { | ||
137 | if (++t & 1) { | ||
138 | if ((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>4)) md_sfxchn--; | ||
139 | } else { | ||
140 | if ((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>8)) md_sngchn--; | ||
141 | } | ||
142 | |||
143 | if (!(md_mode & DMODE_SOFT_SNDFX)) | ||
144 | md_softchn=md_sfxchn; | ||
145 | else | ||
146 | md_softchn=0; | ||
147 | |||
148 | if (!(md_mode & DMODE_SOFT_MUSIC)) | ||
149 | md_softchn+=md_sngchn; | ||
150 | } | ||
151 | md_numchn=md_hardchn+md_softchn; | ||
152 | } | ||
153 | |||
154 | /* Note: 'type' indicates whether the returned value should be for music or for | ||
155 | sound effects. */ | ||
156 | ULONG MD_SampleSpace(int type) | ||
157 | { | ||
158 | if(type==MD_MUSIC) | ||
159 | type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE; | ||
160 | else if(type==MD_SNDFX) | ||
161 | type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE; | ||
162 | |||
163 | return md_driver->FreeSampleSpace(type); | ||
164 | } | ||
165 | |||
166 | ULONG MD_SampleLength(int type,SAMPLE* s) | ||
167 | { | ||
168 | if(type==MD_MUSIC) | ||
169 | type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE; | ||
170 | else | ||
171 | if(type==MD_SNDFX) | ||
172 | type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE; | ||
173 | |||
174 | return md_driver->RealSampleLength(type,s); | ||
175 | } | ||
176 | |||
177 | MIKMODAPI CHAR* MikMod_InfoDriver(void) | ||
178 | { | ||
179 | int t; | ||
180 | size_t len=0; | ||
181 | MDRIVER *l; | ||
182 | CHAR *list=NULL; | ||
183 | |||
184 | MUTEX_LOCK(lists); | ||
185 | /* compute size of buffer */ | ||
186 | for(l=firstdriver;l;l=l->next) | ||
187 | len+=4+(l->next?1:0)+strlen(l->Version); | ||
188 | |||
189 | if(len) | ||
190 | if((list=MikMod_malloc(len*sizeof(CHAR)))) { | ||
191 | list[0]=0; | ||
192 | /* list all registered device drivers : */ | ||
193 | for(t=1,l=firstdriver;l;l=l->next,t++) | ||
194 | sprintf(list,(l->next)?"%s%2d %s\n":"%s%2d %s", | ||
195 | list,t,l->Version); | ||
196 | } | ||
197 | MUTEX_UNLOCK(lists); | ||
198 | return list; | ||
199 | } | ||
200 | |||
201 | void _mm_registerdriver(struct MDRIVER* drv) | ||
202 | { | ||
203 | MDRIVER *cruise = firstdriver; | ||
204 | |||
205 | /* don't register a MISSING() driver */ | ||
206 | if ((drv->Name) && (drv->Version)) { | ||
207 | if (cruise) { | ||
208 | if ( cruise == drv ) | ||
209 | return; | ||
210 | while(cruise->next) { | ||
211 | cruise = cruise->next; | ||
212 | if ( cruise == drv ) | ||
213 | return; | ||
214 | } | ||
215 | cruise->next = drv; | ||
216 | } else | ||
217 | firstdriver = drv; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | MIKMODAPI void MikMod_RegisterDriver(struct MDRIVER* drv) | ||
222 | { | ||
223 | /* if we try to register an invalid driver, or an already registered driver, | ||
224 | ignore this attempt */ | ||
225 | if ((!drv)||(drv->next)||(!drv->Name)) | ||
226 | return; | ||
227 | |||
228 | MUTEX_LOCK(lists); | ||
229 | _mm_registerdriver(drv); | ||
230 | MUTEX_UNLOCK(lists); | ||
231 | } | ||
232 | |||
233 | MIKMODAPI int MikMod_DriverFromAlias(CHAR *alias) | ||
234 | { | ||
235 | int rank=1; | ||
236 | MDRIVER *cruise; | ||
237 | |||
238 | MUTEX_LOCK(lists); | ||
239 | cruise=firstdriver; | ||
240 | while(cruise) { | ||
241 | if (cruise->Alias) { | ||
242 | if (!(strcasecmp(alias,cruise->Alias))) break; | ||
243 | rank++; | ||
244 | } | ||
245 | cruise=cruise->next; | ||
246 | } | ||
247 | if(!cruise) rank=0; | ||
248 | MUTEX_UNLOCK(lists); | ||
249 | |||
250 | return rank; | ||
251 | } | ||
252 | |||
253 | MIKMODAPI MDRIVER *MikMod_DriverByOrdinal(int ordinal) | ||
254 | { | ||
255 | MDRIVER *cruise; | ||
256 | |||
257 | /* Allow only driver ordinals > 0 */ | ||
258 | if (!ordinal) | ||
259 | return 0; | ||
260 | |||
261 | MUTEX_LOCK(lists); | ||
262 | cruise = firstdriver; | ||
263 | while (cruise && --ordinal) | ||
264 | cruise = cruise->next; | ||
265 | MUTEX_UNLOCK(lists); | ||
266 | return cruise; | ||
267 | } | ||
268 | |||
269 | SWORD MD_SampleLoad(SAMPLOAD* s, int type) | ||
270 | { | ||
271 | SWORD result; | ||
272 | |||
273 | if(type==MD_MUSIC) | ||
274 | type=(md_mode & DMODE_SOFT_MUSIC)?MD_SOFTWARE:MD_HARDWARE; | ||
275 | else if(type==MD_SNDFX) | ||
276 | type=(md_mode & DMODE_SOFT_SNDFX)?MD_SOFTWARE:MD_HARDWARE; | ||
277 | |||
278 | SL_Init(s); | ||
279 | result=md_driver->SampleLoad(s,type); | ||
280 | SL_Exit(s); | ||
281 | |||
282 | return result; | ||
283 | } | ||
284 | |||
285 | void MD_SampleUnload(SWORD handle) | ||
286 | { | ||
287 | md_driver->SampleUnload(handle); | ||
288 | } | ||
289 | |||
290 | MIKMODAPI MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t player) | ||
291 | { | ||
292 | MikMod_player_t result; | ||
293 | |||
294 | MUTEX_LOCK(vars); | ||
295 | result=md_player; | ||
296 | md_player=player; | ||
297 | MUTEX_UNLOCK(vars); | ||
298 | |||
299 | return result; | ||
300 | } | ||
301 | |||
302 | MIKMODAPI void MikMod_Update(void) | ||
303 | { | ||
304 | MUTEX_LOCK(vars); | ||
305 | if(isplaying) { | ||
306 | if((!pf)||(!pf->forbid)) | ||
307 | md_driver->Update(); | ||
308 | else { | ||
309 | if (md_driver->Pause) | ||
310 | md_driver->Pause(); | ||
311 | } | ||
312 | } | ||
313 | MUTEX_UNLOCK(vars); | ||
314 | } | ||
315 | |||
316 | void Voice_SetVolume_internal(SBYTE voice,UWORD vol) | ||
317 | { | ||
318 | ULONG tmp; | ||
319 | |||
320 | if((voice<0)||(voice>=md_numchn)) return; | ||
321 | |||
322 | /* range checks */ | ||
323 | if(md_musicvolume>128) md_musicvolume=128; | ||
324 | if(md_sndfxvolume>128) md_sndfxvolume=128; | ||
325 | if(md_volume>128) md_volume=128; | ||
326 | |||
327 | tmp=(ULONG)vol*(ULONG)md_volume* | ||
328 | ((voice<md_sngchn)?(ULONG)md_musicvolume:(ULONG)md_sndfxvolume); | ||
329 | md_driver->VoiceSetVolume(voice,tmp/16384UL); | ||
330 | } | ||
331 | |||
332 | MIKMODAPI void Voice_SetVolume(SBYTE voice,UWORD vol) | ||
333 | { | ||
334 | MUTEX_LOCK(vars); | ||
335 | Voice_SetVolume_internal(voice,vol); | ||
336 | MUTEX_UNLOCK(vars); | ||
337 | } | ||
338 | |||
339 | MIKMODAPI UWORD Voice_GetVolume(SBYTE voice) | ||
340 | { | ||
341 | UWORD result=0; | ||
342 | |||
343 | MUTEX_LOCK(vars); | ||
344 | if((voice>=0)&&(voice<md_numchn)) | ||
345 | result=md_driver->VoiceGetVolume(voice); | ||
346 | MUTEX_UNLOCK(vars); | ||
347 | |||
348 | return result; | ||
349 | } | ||
350 | |||
351 | void Voice_SetFrequency_internal(SBYTE voice,ULONG frq) | ||
352 | { | ||
353 | if((voice<0)||(voice>=md_numchn)) return; | ||
354 | if((md_sample[voice])&&(md_sample[voice]->divfactor)) | ||
355 | frq/=md_sample[voice]->divfactor; | ||
356 | md_driver->VoiceSetFrequency(voice,frq); | ||
357 | } | ||
358 | |||
359 | MIKMODAPI void Voice_SetFrequency(SBYTE voice,ULONG frq) | ||
360 | { | ||
361 | MUTEX_LOCK(vars); | ||
362 | Voice_SetFrequency_internal(voice,frq); | ||
363 | MUTEX_UNLOCK(vars); | ||
364 | } | ||
365 | |||
366 | MIKMODAPI ULONG Voice_GetFrequency(SBYTE voice) | ||
367 | { | ||
368 | ULONG result=0; | ||
369 | |||
370 | MUTEX_LOCK(vars); | ||
371 | if((voice>=0)&&(voice<md_numchn)) | ||
372 | result=md_driver->VoiceGetFrequency(voice); | ||
373 | MUTEX_UNLOCK(vars); | ||
374 | |||
375 | return result; | ||
376 | } | ||
377 | |||
378 | void Voice_SetPanning_internal(SBYTE voice,ULONG pan) | ||
379 | { | ||
380 | if((voice<0)||(voice>=md_numchn)) return; | ||
381 | if(pan!=PAN_SURROUND) { | ||
382 | if(md_pansep>128) md_pansep=128; | ||
383 | if(md_mode & DMODE_REVERSE) pan=255-pan; | ||
384 | pan = (((SWORD)(pan-128)*md_pansep)/128)+128; | ||
385 | } | ||
386 | md_driver->VoiceSetPanning(voice, pan); | ||
387 | } | ||
388 | |||
389 | MIKMODAPI void Voice_SetPanning(SBYTE voice,ULONG pan) | ||
390 | { | ||
391 | #ifdef MIKMOD_DEBUG | ||
392 | if((pan!=PAN_SURROUND)&&((pan<0)||(pan>255))) | ||
393 | fprintf(stderr,"\rVoice_SetPanning called with pan=%ld\n",(long)pan); | ||
394 | #endif | ||
395 | |||
396 | MUTEX_LOCK(vars); | ||
397 | Voice_SetPanning_internal(voice,pan); | ||
398 | MUTEX_UNLOCK(vars); | ||
399 | } | ||
400 | |||
401 | MIKMODAPI ULONG Voice_GetPanning(SBYTE voice) | ||
402 | { | ||
403 | ULONG result=PAN_CENTER; | ||
404 | |||
405 | MUTEX_LOCK(vars); | ||
406 | if((voice>=0)&&(voice<md_numchn)) | ||
407 | result=md_driver->VoiceGetPanning(voice); | ||
408 | MUTEX_UNLOCK(vars); | ||
409 | |||
410 | return result; | ||
411 | } | ||
412 | |||
413 | void Voice_Play_internal(SBYTE voice,SAMPLE* s,ULONG start) | ||
414 | { | ||
415 | ULONG repend; | ||
416 | |||
417 | if((voice<0)||(voice>=md_numchn)) return; | ||
418 | |||
419 | md_sample[voice]=s; | ||
420 | repend=s->loopend; | ||
421 | |||
422 | if(s->flags&SF_LOOP) | ||
423 | /* repend can't be bigger than size */ | ||
424 | if(repend>s->length) repend=s->length; | ||
425 | |||
426 | md_driver->VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags); | ||
427 | } | ||
428 | |||
429 | MIKMODAPI void Voice_Play(SBYTE voice,SAMPLE* s,ULONG start) | ||
430 | { | ||
431 | if(start>s->length) return; | ||
432 | |||
433 | MUTEX_LOCK(vars); | ||
434 | Voice_Play_internal(voice,s,start); | ||
435 | MUTEX_UNLOCK(vars); | ||
436 | } | ||
437 | |||
438 | void Voice_Stop_internal(SBYTE voice) | ||
439 | { | ||
440 | if((voice<0)||(voice>=md_numchn)) return; | ||
441 | if(voice>=md_sngchn) | ||
442 | /* It is a sound effects channel, so flag the voice as non-critical! */ | ||
443 | sfxinfo[voice-md_sngchn]=0; | ||
444 | md_driver->VoiceStop(voice); | ||
445 | } | ||
446 | |||
447 | MIKMODAPI void Voice_Stop(SBYTE voice) | ||
448 | { | ||
449 | MUTEX_LOCK(vars); | ||
450 | Voice_Stop_internal(voice); | ||
451 | MUTEX_UNLOCK(vars); | ||
452 | } | ||
453 | |||
454 | int Voice_Stopped_internal(SBYTE voice) | ||
455 | { | ||
456 | if((voice<0)||(voice>=md_numchn)) return 0; | ||
457 | return(md_driver->VoiceStopped(voice)); | ||
458 | } | ||
459 | |||
460 | MIKMODAPI int Voice_Stopped(SBYTE voice) | ||
461 | { | ||
462 | int result; | ||
463 | |||
464 | MUTEX_LOCK(vars); | ||
465 | result=Voice_Stopped_internal(voice); | ||
466 | MUTEX_UNLOCK(vars); | ||
467 | |||
468 | return result; | ||
469 | } | ||
470 | |||
471 | MIKMODAPI SLONG Voice_GetPosition(SBYTE voice) | ||
472 | { | ||
473 | SLONG result=0; | ||
474 | |||
475 | MUTEX_LOCK(vars); | ||
476 | if((voice>=0)&&(voice<md_numchn)) { | ||
477 | if (md_driver->VoiceGetPosition) | ||
478 | result=(md_driver->VoiceGetPosition(voice)); | ||
479 | else | ||
480 | result=-1; | ||
481 | } | ||
482 | MUTEX_UNLOCK(vars); | ||
483 | |||
484 | return result; | ||
485 | } | ||
486 | |||
487 | MIKMODAPI ULONG Voice_RealVolume(SBYTE voice) | ||
488 | { | ||
489 | ULONG result=0; | ||
490 | |||
491 | MUTEX_LOCK(vars); | ||
492 | if((voice>=0)&&(voice<md_numchn)&& md_driver->VoiceRealVolume) | ||
493 | result=(md_driver->VoiceRealVolume(voice)); | ||
494 | MUTEX_UNLOCK(vars); | ||
495 | |||
496 | return result; | ||
497 | } | ||
498 | |||
499 | extern MikMod_callback_t vc_callback; | ||
500 | |||
501 | MIKMODAPI void VC_SetCallback(MikMod_callback_t callback) | ||
502 | { | ||
503 | vc_callback = callback; | ||
504 | } | ||
505 | |||
506 | static int _mm_init(CHAR *cmdline) | ||
507 | { | ||
508 | UWORD t; | ||
509 | |||
510 | _mm_critical = 1; | ||
511 | |||
512 | /* if md_device==0, try to find a device number */ | ||
513 | if(!md_device) { | ||
514 | cmdline=NULL; | ||
515 | |||
516 | for(t=1,md_driver=firstdriver;md_driver;md_driver=md_driver->next,t++) | ||
517 | if(md_driver->IsPresent()) break; | ||
518 | |||
519 | if(!md_driver) { | ||
520 | _mm_errno = MMERR_DETECTING_DEVICE; | ||
521 | if(_mm_errorhandler) _mm_errorhandler(); | ||
522 | md_driver = &drv_nos; | ||
523 | return 1; | ||
524 | } | ||
525 | |||
526 | md_device = t; | ||
527 | } else { | ||
528 | /* if n>0, use that driver */ | ||
529 | for(t=1,md_driver=firstdriver;(md_driver)&&(t!=md_device);md_driver=md_driver->next) | ||
530 | t++; | ||
531 | |||
532 | if(!md_driver) { | ||
533 | _mm_errno = MMERR_INVALID_DEVICE; | ||
534 | if(_mm_errorhandler) _mm_errorhandler(); | ||
535 | md_driver = &drv_nos; | ||
536 | return 1; | ||
537 | } | ||
538 | |||
539 | /* arguments here might be necessary for the presence check to succeed */ | ||
540 | if(cmdline&&(md_driver->CommandLine)) | ||
541 | md_driver->CommandLine(cmdline); | ||
542 | |||
543 | if(!md_driver->IsPresent()) { | ||
544 | _mm_errno = MMERR_DETECTING_DEVICE; | ||
545 | if(_mm_errorhandler) _mm_errorhandler(); | ||
546 | md_driver = &drv_nos; | ||
547 | return 1; | ||
548 | } | ||
549 | } | ||
550 | |||
551 | olddevice = md_device; | ||
552 | if(md_driver->Init()) { | ||
553 | MikMod_Exit_internal(); | ||
554 | if(_mm_errorhandler) _mm_errorhandler(); | ||
555 | return 1; | ||
556 | } | ||
557 | |||
558 | initialized=1; | ||
559 | _mm_critical=0; | ||
560 | |||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | MIKMODAPI int MikMod_Init(CHAR *cmdline) | ||
565 | { | ||
566 | int result; | ||
567 | |||
568 | MUTEX_LOCK(vars); | ||
569 | MUTEX_LOCK(lists); | ||
570 | result=_mm_init(cmdline); | ||
571 | MUTEX_UNLOCK(lists); | ||
572 | MUTEX_UNLOCK(vars); | ||
573 | |||
574 | return result; | ||
575 | } | ||
576 | |||
577 | void MikMod_Exit_internal(void) | ||
578 | { | ||
579 | MikMod_DisableOutput_internal(); | ||
580 | md_driver->Exit(); | ||
581 | md_numchn = md_sfxchn = md_sngchn = 0; | ||
582 | md_driver = &drv_nos; | ||
583 | |||
584 | if(sfxinfo) MikMod_free(sfxinfo); | ||
585 | if(md_sample) MikMod_free(md_sample); | ||
586 | md_sample = NULL; | ||
587 | sfxinfo = NULL; | ||
588 | |||
589 | initialized = 0; | ||
590 | } | ||
591 | |||
592 | MIKMODAPI void MikMod_Exit(void) | ||
593 | { | ||
594 | MUTEX_LOCK(vars); | ||
595 | MUTEX_LOCK(lists); | ||
596 | MikMod_Exit_internal(); | ||
597 | MUTEX_UNLOCK(lists); | ||
598 | MUTEX_UNLOCK(vars); | ||
599 | } | ||
600 | |||
601 | /* Reset the driver using the new global variable settings. | ||
602 | If the driver has not been initialized, it will be now. */ | ||
603 | static int _mm_reset(CHAR *cmdline) | ||
604 | { | ||
605 | int wasplaying = 0; | ||
606 | |||
607 | if(!initialized) return _mm_init(cmdline); | ||
608 | |||
609 | if (isplaying) { | ||
610 | wasplaying = 1; | ||
611 | md_driver->PlayStop(); | ||
612 | } | ||
613 | |||
614 | if((!md_driver->Reset)||(md_device != olddevice)) { | ||
615 | /* md_driver->Reset was NULL, or md_device was changed, so do a full | ||
616 | reset of the driver. */ | ||
617 | md_driver->Exit(); | ||
618 | if(_mm_init(cmdline)) { | ||
619 | MikMod_Exit_internal(); | ||
620 | if(_mm_errno) | ||
621 | if(_mm_errorhandler) _mm_errorhandler(); | ||
622 | return 1; | ||
623 | } | ||
624 | } else { | ||
625 | if(md_driver->Reset()) { | ||
626 | MikMod_Exit_internal(); | ||
627 | if(_mm_errno) | ||
628 | if(_mm_errorhandler) _mm_errorhandler(); | ||
629 | return 1; | ||
630 | } | ||
631 | } | ||
632 | |||
633 | if (wasplaying) md_driver->PlayStart(); | ||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | MIKMODAPI int MikMod_Reset(CHAR *cmdline) | ||
638 | { | ||
639 | int result; | ||
640 | |||
641 | MUTEX_LOCK(vars); | ||
642 | MUTEX_LOCK(lists); | ||
643 | result=_mm_reset(cmdline); | ||
644 | MUTEX_UNLOCK(lists); | ||
645 | MUTEX_UNLOCK(vars); | ||
646 | |||
647 | return result; | ||
648 | } | ||
649 | |||
650 | /* If either parameter is -1, the current set value will be retained. */ | ||
651 | int MikMod_SetNumVoices_internal(int music, int sfx) | ||
652 | { | ||
653 | int resume = 0; | ||
654 | int t, oldchn = 0; | ||
655 | |||
656 | if((!music)&&(!sfx)) return 1; | ||
657 | _mm_critical = 1; | ||
658 | if(isplaying) { | ||
659 | MikMod_DisableOutput_internal(); | ||
660 | oldchn = md_numchn; | ||
661 | resume = 1; | ||
662 | } | ||
663 | |||
664 | if(sfxinfo) MikMod_free(sfxinfo); | ||
665 | if(md_sample) MikMod_free(md_sample); | ||
666 | md_sample = NULL; | ||
667 | sfxinfo = NULL; | ||
668 | |||
669 | if(music!=-1) md_sngchn = music; | ||
670 | if(sfx!=-1) md_sfxchn = sfx; | ||
671 | md_numchn = md_sngchn + md_sfxchn; | ||
672 | |||
673 | LimitHardVoices(md_driver->HardVoiceLimit); | ||
674 | LimitSoftVoices(md_driver->SoftVoiceLimit); | ||
675 | |||
676 | if(md_driver->SetNumVoices()) { | ||
677 | MikMod_Exit_internal(); | ||
678 | if(_mm_errno) | ||
679 | if(_mm_errorhandler!=NULL) _mm_errorhandler(); | ||
680 | md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0; | ||
681 | return 1; | ||
682 | } | ||
683 | |||
684 | if(md_sngchn+md_sfxchn) | ||
685 | md_sample=(SAMPLE**)MikMod_calloc(md_sngchn+md_sfxchn,sizeof(SAMPLE*)); | ||
686 | if(md_sfxchn) | ||
687 | sfxinfo = (UBYTE *)MikMod_calloc(md_sfxchn,sizeof(UBYTE)); | ||
688 | |||
689 | /* make sure the player doesn't start with garbage */ | ||
690 | for(t=oldchn;t<md_numchn;t++) Voice_Stop_internal(t); | ||
691 | |||
692 | sfxpool = 0; | ||
693 | if(resume) MikMod_EnableOutput_internal(); | ||
694 | _mm_critical = 0; | ||
695 | |||
696 | return 0; | ||
697 | } | ||
698 | |||
699 | MIKMODAPI int MikMod_SetNumVoices(int music, int sfx) | ||
700 | { | ||
701 | int result; | ||
702 | |||
703 | MUTEX_LOCK(vars); | ||
704 | result=MikMod_SetNumVoices_internal(music,sfx); | ||
705 | MUTEX_UNLOCK(vars); | ||
706 | |||
707 | return result; | ||
708 | } | ||
709 | |||
710 | int MikMod_EnableOutput_internal(void) | ||
711 | { | ||
712 | _mm_critical = 1; | ||
713 | if(!isplaying) { | ||
714 | if(md_driver->PlayStart()) return 1; | ||
715 | isplaying = 1; | ||
716 | } | ||
717 | _mm_critical = 0; | ||
718 | return 0; | ||
719 | } | ||
720 | |||
721 | MIKMODAPI int MikMod_EnableOutput(void) | ||
722 | { | ||
723 | int result; | ||
724 | |||
725 | MUTEX_LOCK(vars); | ||
726 | result=MikMod_EnableOutput_internal(); | ||
727 | MUTEX_UNLOCK(vars); | ||
728 | |||
729 | return result; | ||
730 | } | ||
731 | |||
732 | void MikMod_DisableOutput_internal(void) | ||
733 | { | ||
734 | if(isplaying && md_driver) { | ||
735 | isplaying = 0; | ||
736 | md_driver->PlayStop(); | ||
737 | } | ||
738 | } | ||
739 | |||
740 | MIKMODAPI void MikMod_DisableOutput(void) | ||
741 | { | ||
742 | MUTEX_LOCK(vars); | ||
743 | MikMod_DisableOutput_internal(); | ||
744 | MUTEX_UNLOCK(vars); | ||
745 | } | ||
746 | |||
747 | int MikMod_Active_internal(void) | ||
748 | { | ||
749 | return isplaying; | ||
750 | } | ||
751 | |||
752 | MIKMODAPI int MikMod_Active(void) | ||
753 | { | ||
754 | int result; | ||
755 | |||
756 | MUTEX_LOCK(vars); | ||
757 | result=MikMod_Active_internal(); | ||
758 | MUTEX_UNLOCK(vars); | ||
759 | |||
760 | return result; | ||
761 | } | ||
762 | |||
763 | /* Plays a sound effects sample. Picks a voice from the number of voices | ||
764 | allocated for use as sound effects (loops through voices, skipping all active | ||
765 | criticals). | ||
766 | |||
767 | Returns the voice that the sound is being played on. */ | ||
768 | SBYTE Sample_Play_internal(SAMPLE *s,ULONG start,UBYTE flags) | ||
769 | { | ||
770 | int orig=sfxpool;/* for cases where all channels are critical */ | ||
771 | int c; | ||
772 | |||
773 | if(!md_sfxchn) return -1; | ||
774 | if(s->volume>64) s->volume = 64; | ||
775 | |||
776 | /* check the first location after sfxpool */ | ||
777 | do { | ||
778 | if(sfxinfo[sfxpool]&SFX_CRITICAL) { | ||
779 | if(md_driver->VoiceStopped(c=sfxpool+md_sngchn)) { | ||
780 | sfxinfo[sfxpool]=flags; | ||
781 | Voice_Play_internal(c,s,start); | ||
782 | md_driver->VoiceSetVolume(c,s->volume<<2); | ||
783 | Voice_SetPanning_internal(c,s->panning); | ||
784 | md_driver->VoiceSetFrequency(c,s->speed); | ||
785 | sfxpool++; | ||
786 | if(sfxpool>=md_sfxchn) sfxpool=0; | ||
787 | return c; | ||
788 | } | ||
789 | } else { | ||
790 | sfxinfo[sfxpool]=flags; | ||
791 | Voice_Play_internal(c=sfxpool+md_sngchn,s,start); | ||
792 | md_driver->VoiceSetVolume(c,s->volume<<2); | ||
793 | Voice_SetPanning_internal(c,s->panning); | ||
794 | md_driver->VoiceSetFrequency(c,s->speed); | ||
795 | sfxpool++; | ||
796 | if(sfxpool>=md_sfxchn) sfxpool=0; | ||
797 | return c; | ||
798 | } | ||
799 | |||
800 | sfxpool++; | ||
801 | if(sfxpool>=md_sfxchn) sfxpool = 0; | ||
802 | } while(sfxpool!=orig); | ||
803 | |||
804 | return -1; | ||
805 | } | ||
806 | |||
807 | MIKMODAPI SBYTE Sample_Play(SAMPLE *s,ULONG start,UBYTE flags) | ||
808 | { | ||
809 | SBYTE result; | ||
810 | |||
811 | MUTEX_LOCK(vars); | ||
812 | result=Sample_Play_internal(s,start,flags); | ||
813 | MUTEX_UNLOCK(vars); | ||
814 | |||
815 | return result; | ||
816 | } | ||
817 | |||
818 | MIKMODAPI long MikMod_GetVersion(void) | ||
819 | { | ||
820 | return LIBMIKMOD_VERSION; | ||
821 | } | ||
822 | |||
823 | /*========== MT-safe stuff */ | ||
824 | |||
825 | #ifdef HAVE_PTHREAD | ||
826 | #define INIT_MUTEX(name) \ | ||
827 | pthread_mutex_t _mm_mutex_##name=PTHREAD_MUTEX_INITIALIZER | ||
828 | #elif defined(__OS2__)||defined(__EMX__) | ||
829 | #define INIT_MUTEX(name) \ | ||
830 | HMTX _mm_mutex_##name | ||
831 | #elif defined(WIN32) | ||
832 | #define INIT_MUTEX(name) \ | ||
833 | HANDLE _mm_mutex_##name | ||
834 | #else | ||
835 | #define INIT_MUTEX(name) \ | ||
836 | void *_mm_mutex_##name = NULL | ||
837 | #endif | ||
838 | |||
839 | INIT_MUTEX(vars); | ||
840 | INIT_MUTEX(lists); | ||
841 | |||
842 | MIKMODAPI int MikMod_InitThreads(void) | ||
843 | { | ||
844 | static int firstcall=1; | ||
845 | static int result=0; | ||
846 | |||
847 | if (firstcall) { | ||
848 | firstcall=0; | ||
849 | #ifdef HAVE_PTHREAD | ||
850 | result=1; | ||
851 | #elif defined(__OS2__)||defined(__EMX__) | ||
852 | if(DosCreateMutexSem((PSZ)NULL,&_mm_mutex_lists,0,0) || | ||
853 | DosCreateMutexSem((PSZ)NULL,&_mm_mutex_vars,0,0)) { | ||
854 | _mm_mutex_lists=_mm_mutex_vars=(HMTX)NULL; | ||
855 | result=0; | ||
856 | } else | ||
857 | result=1; | ||
858 | #elif defined(WIN32) | ||
859 | if((!(_mm_mutex_lists=CreateMutex(NULL,FALSE,"libmikmod(lists)")))|| | ||
860 | (!(_mm_mutex_vars=CreateMutex(NULL,FALSE,"libmikmod(vars)")))) | ||
861 | result=0; | ||
862 | else | ||
863 | result=1; | ||
864 | #endif | ||
865 | } | ||
866 | return result; | ||
867 | } | ||
868 | |||
869 | MIKMODAPI void MikMod_Unlock(void) | ||
870 | { | ||
871 | MUTEX_UNLOCK(lists); | ||
872 | MUTEX_UNLOCK(vars); | ||
873 | } | ||
874 | |||
875 | MIKMODAPI void MikMod_Lock(void) | ||
876 | { | ||
877 | MUTEX_LOCK(vars); | ||
878 | MUTEX_LOCK(lists); | ||
879 | } | ||
880 | |||
881 | /*========== Parameter extraction helper */ | ||
882 | |||
883 | CHAR *MD_GetAtom(CHAR *atomname,CHAR *cmdline,int implicit) | ||
884 | { | ||
885 | CHAR *ret=NULL; | ||
886 | |||
887 | if(cmdline) { | ||
888 | CHAR *buf=strstr(cmdline,atomname); | ||
889 | |||
890 | if((buf)&&((buf==cmdline)||(*(buf-1)==','))) { | ||
891 | CHAR *ptr=buf+strlen(atomname); | ||
892 | |||
893 | if(*ptr=='=') { | ||
894 | for(buf=++ptr;(*ptr)&&((*ptr)!=',');ptr++); | ||
895 | ret=MikMod_malloc((1+ptr-buf)*sizeof(CHAR)); | ||
896 | if(ret) | ||
897 | strncpy(ret,buf,ptr-buf); | ||
898 | } else if((*ptr==',')||(!*ptr)) { | ||
899 | if(implicit) { | ||
900 | ret=MikMod_malloc((1+ptr-buf)*sizeof(CHAR)); | ||
901 | if(ret) | ||
902 | strncpy(ret,buf,ptr-buf); | ||
903 | } | ||
904 | } | ||
905 | } | ||
906 | } | ||
907 | return ret; | ||
908 | } | ||
909 | |||
910 | #if 0 | ||
911 | #if defined unix || (defined __APPLE__ && defined __MACH__) | ||
912 | |||
913 | /*========== Posix helper functions */ | ||
914 | |||
915 | /* Check if the file is a regular or nonexistant file (or a link to a such a | ||
916 | file), and that, should the calling program be setuid, the access rights are | ||
917 | reasonable. Returns 1 if it is safe to rewrite the file, 0 otherwise. | ||
918 | The goal is to prevent a setuid root libmikmod application from overriding | ||
919 | files like /etc/passwd with digital sound... */ | ||
920 | int MD_Access(CHAR *filename) | ||
921 | { | ||
922 | struct stat buf; | ||
923 | |||
924 | if(!stat(filename,&buf)) { | ||
925 | /* not a regular file ? */ | ||
926 | if(!S_ISREG(buf.st_mode)) return 0; | ||
927 | /* more than one hard link to the file ? */ | ||
928 | if(buf.st_nlink>1) return 0; | ||
929 | /* check access rights with the real user and group id */ | ||
930 | if(getuid()==buf.st_uid) { | ||
931 | if(!(buf.st_mode&S_IWUSR)) return 0; | ||
932 | } else if(getgid()==buf.st_gid) { | ||
933 | if(!(buf.st_mode&S_IWGRP)) return 0; | ||
934 | } else | ||
935 | if(!(buf.st_mode&S_IWOTH)) return 0; | ||
936 | } | ||
937 | |||
938 | return 1; | ||
939 | } | ||
940 | |||
941 | /* Drop all root privileges we might have */ | ||
942 | int MD_DropPrivileges(void) | ||
943 | { | ||
944 | if(!geteuid()) { | ||
945 | if(getuid()) { | ||
946 | /* we are setuid root -> drop setuid to become the real user */ | ||
947 | if(setuid(getuid())) return 1; | ||
948 | } else { | ||
949 | /* we are run as root -> drop all and become user 'nobody' */ | ||
950 | struct passwd *nobody; | ||
951 | int uid; | ||
952 | |||
953 | if(!(nobody=getpwnam("nobody"))) return 1; /* no such user ? */ | ||
954 | uid=nobody->pw_uid; | ||
955 | if (!uid) /* user 'nobody' has root privileges ? weird... */ | ||
956 | return 1; | ||
957 | if (setuid(uid)) return 1; | ||
958 | } | ||
959 | } | ||
960 | return 0; | ||
961 | } | ||
962 | |||
963 | #endif | ||
964 | #endif | ||
965 | /* ex:set ts=4: */ | ||