source: libmikmod/vendor/current/playercode/mdriver.c@ 1454

Last change on this file since 1454 was 1454, checked in by valerius, 9 years ago

libmikmod: Import version 3.3.8 from vendor.

Source URL: https://sourceforge.net/projects/mikmod/files/libmikmod/3.3.8/libmikmod-3.3.8.tar.gz/download

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