summaryrefslogtreecommitdiff
path: root/apps/plugins/mikmod/mdriver.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/mikmod/mdriver.c')
-rw-r--r--apps/plugins/mikmod/mdriver.c965
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
52extern int fprintf(FILE *, const char *, ...);
53#endif
54
55static MDRIVER *firstdriver=NULL;
56MIKMODAPI MDRIVER *md_driver=NULL;
57extern MODULE *pf; /* modfile being played */
58
59/* Initial global settings */
60MIKMODAPI UWORD md_device = 0; /* autodetect */
61MIKMODAPI UWORD md_mixfreq = 44100;
62MIKMODAPI UWORD md_mode = DMODE_STEREO | DMODE_16BITS |
63 DMODE_SURROUND |DMODE_SOFT_MUSIC |
64 DMODE_SOFT_SNDFX;
65MIKMODAPI UBYTE md_pansep = 128; /* 128 == 100% (full left/right) */
66MIKMODAPI UBYTE md_reverb = 0; /* no reverb */
67MIKMODAPI UBYTE md_volume = 128; /* global sound volume (0-128) */
68MIKMODAPI UBYTE md_musicvolume = 128; /* volume of song */
69MIKMODAPI 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;
77static volatile int isplaying=0, initialized = 0;
78static UBYTE *sfxinfo;
79static int sfxpool;
80
81static SAMPLE **md_sample = NULL;
82
83/* Previous driver in use */
84static 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. */
88static 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. */
122static 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. */
156ULONG 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
166ULONG 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
177MIKMODAPI 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
201void _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
221MIKMODAPI 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
233MIKMODAPI 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
253MIKMODAPI 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
269SWORD 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
285void MD_SampleUnload(SWORD handle)
286{
287 md_driver->SampleUnload(handle);
288}
289
290MIKMODAPI 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
302MIKMODAPI 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
316void 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
332MIKMODAPI void Voice_SetVolume(SBYTE voice,UWORD vol)
333{
334 MUTEX_LOCK(vars);
335 Voice_SetVolume_internal(voice,vol);
336 MUTEX_UNLOCK(vars);
337}
338
339MIKMODAPI 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
351void 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
359MIKMODAPI void Voice_SetFrequency(SBYTE voice,ULONG frq)
360{
361 MUTEX_LOCK(vars);
362 Voice_SetFrequency_internal(voice,frq);
363 MUTEX_UNLOCK(vars);
364}
365
366MIKMODAPI 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
378void 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
389MIKMODAPI 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
401MIKMODAPI 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
413void 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
429MIKMODAPI 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
438void 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
447MIKMODAPI void Voice_Stop(SBYTE voice)
448{
449 MUTEX_LOCK(vars);
450 Voice_Stop_internal(voice);
451 MUTEX_UNLOCK(vars);
452}
453
454int Voice_Stopped_internal(SBYTE voice)
455{
456 if((voice<0)||(voice>=md_numchn)) return 0;
457 return(md_driver->VoiceStopped(voice));
458}
459
460MIKMODAPI 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
471MIKMODAPI 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
487MIKMODAPI 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
499extern MikMod_callback_t vc_callback;
500
501MIKMODAPI void VC_SetCallback(MikMod_callback_t callback)
502{
503 vc_callback = callback;
504}
505
506static 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
564MIKMODAPI 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
577void 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
592MIKMODAPI 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. */
603static 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
637MIKMODAPI 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. */
651int 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
699MIKMODAPI 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
710int 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
721MIKMODAPI 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
732void MikMod_DisableOutput_internal(void)
733{
734 if(isplaying && md_driver) {
735 isplaying = 0;
736 md_driver->PlayStop();
737 }
738}
739
740MIKMODAPI void MikMod_DisableOutput(void)
741{
742 MUTEX_LOCK(vars);
743 MikMod_DisableOutput_internal();
744 MUTEX_UNLOCK(vars);
745}
746
747int MikMod_Active_internal(void)
748{
749 return isplaying;
750}
751
752MIKMODAPI 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. */
768SBYTE 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
807MIKMODAPI 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
818MIKMODAPI 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
839INIT_MUTEX(vars);
840INIT_MUTEX(lists);
841
842MIKMODAPI 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
869MIKMODAPI void MikMod_Unlock(void)
870{
871 MUTEX_UNLOCK(lists);
872 MUTEX_UNLOCK(vars);
873}
874
875MIKMODAPI void MikMod_Lock(void)
876{
877 MUTEX_LOCK(vars);
878 MUTEX_LOCK(lists);
879}
880
881/*========== Parameter extraction helper */
882
883CHAR *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... */
920int 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 */
942int 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: */