Clean up multiple definitions of RAM size. Remove -DMEM (make) and MEM (code), use...
[maemo-rb.git] / apps / plugins / mikmod / mdriver.c
blobe11d32539b378445e59047985a5e419b3fa6a882
1 /* MikMod sound library
2 (c) 1998, 1999, 2000, 2001 Miodrag Vallat and others - see file AUTHORS
3 for complete list.
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.
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.
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.
21 /*==============================================================================
23 $Id: mdriver.c,v 1.4 2007/12/03 20:59:05 denis111 Exp $
25 These routines are used to access the available soundcard drivers.
27 ==============================================================================*/
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
37 #if 0
38 #if defined unix || (defined __APPLE__ && defined __MACH__)
39 #include <pwd.h>
40 #include <sys/stat.h>
41 #endif
42 #endif
44 #include <string.h>
45 #ifdef HAVE_STRINGS_H
46 #include <strings.h>
47 #endif
49 #include "mikmod_internals.h"
51 #ifdef SUNOS
52 extern int fprintf(FILE *, const char *, ...);
53 #endif
55 static MDRIVER *firstdriver=NULL;
56 MIKMODAPI MDRIVER *md_driver=NULL;
57 extern MODULE *pf; /* modfile being played */
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 */
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;
76 void (*md_player)(void) = Player_HandleTick;
77 static volatile int isplaying=0, initialized = 0;
78 static UBYTE *sfxinfo;
79 static int sfxpool;
81 static SAMPLE **md_sample = NULL;
83 /* Previous driver in use */
84 static SWORD olddevice = -1;
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)
90 int t=0;
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;
95 if (!(md_mode & DMODE_SOFT_SNDFX))
96 md_hardchn=md_sfxchn;
97 else
98 md_hardchn=0;
100 if (!(md_mode & DMODE_SOFT_MUSIC)) md_hardchn += md_sngchn;
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--;
109 if (!(md_mode & DMODE_SOFT_SNDFX))
110 md_hardchn=md_sfxchn;
111 else
112 md_hardchn=0;
114 if (!(md_mode & DMODE_SOFT_MUSIC))
115 md_hardchn+=md_sngchn;
117 md_numchn=md_hardchn+md_softchn;
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)
124 int t=0;
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;
129 if (md_mode & DMODE_SOFT_SNDFX)
130 md_softchn=md_sfxchn;
131 else
132 md_softchn=0;
134 if (md_mode & DMODE_SOFT_MUSIC) md_softchn+=md_sngchn;
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--;
143 if (!(md_mode & DMODE_SOFT_SNDFX))
144 md_softchn=md_sfxchn;
145 else
146 md_softchn=0;
148 if (!(md_mode & DMODE_SOFT_MUSIC))
149 md_softchn+=md_sngchn;
151 md_numchn=md_hardchn+md_softchn;
154 /* Note: 'type' indicates whether the returned value should be for music or for
155 sound effects. */
156 ULONG MD_SampleSpace(int type)
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;
163 return md_driver->FreeSampleSpace(type);
166 ULONG MD_SampleLength(int type,SAMPLE* s)
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;
174 return md_driver->RealSampleLength(type,s);
177 MIKMODAPI CHAR* MikMod_InfoDriver(void)
179 int t;
180 size_t len=0;
181 MDRIVER *l;
182 CHAR *list=NULL;
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);
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);
197 MUTEX_UNLOCK(lists);
198 return list;
201 void _mm_registerdriver(struct MDRIVER* drv)
203 MDRIVER *cruise = firstdriver;
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;
215 cruise->next = drv;
216 } else
217 firstdriver = drv;
221 MIKMODAPI void MikMod_RegisterDriver(struct MDRIVER* drv)
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;
228 MUTEX_LOCK(lists);
229 _mm_registerdriver(drv);
230 MUTEX_UNLOCK(lists);
233 MIKMODAPI int MikMod_DriverFromAlias(CHAR *alias)
235 int rank=1;
236 MDRIVER *cruise;
238 MUTEX_LOCK(lists);
239 cruise=firstdriver;
240 while(cruise) {
241 if (cruise->Alias) {
242 if (!(strcasecmp(alias,cruise->Alias))) break;
243 rank++;
245 cruise=cruise->next;
247 if(!cruise) rank=0;
248 MUTEX_UNLOCK(lists);
250 return rank;
253 MIKMODAPI MDRIVER *MikMod_DriverByOrdinal(int ordinal)
255 MDRIVER *cruise;
257 /* Allow only driver ordinals > 0 */
258 if (!ordinal)
259 return 0;
261 MUTEX_LOCK(lists);
262 cruise = firstdriver;
263 while (cruise && --ordinal)
264 cruise = cruise->next;
265 MUTEX_UNLOCK(lists);
266 return cruise;
269 SWORD MD_SampleLoad(SAMPLOAD* s, int type)
271 SWORD result;
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;
278 SL_Init(s);
279 result=md_driver->SampleLoad(s,type);
280 SL_Exit(s);
282 return result;
285 void MD_SampleUnload(SWORD handle)
287 md_driver->SampleUnload(handle);
290 MIKMODAPI MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t player)
292 MikMod_player_t result;
294 MUTEX_LOCK(vars);
295 result=md_player;
296 md_player=player;
297 MUTEX_UNLOCK(vars);
299 return result;
302 MIKMODAPI void MikMod_Update(void)
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();
313 MUTEX_UNLOCK(vars);
316 void Voice_SetVolume_internal(SBYTE voice,UWORD vol)
318 ULONG tmp;
320 if((voice<0)||(voice>=md_numchn)) return;
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;
327 tmp=(ULONG)vol*(ULONG)md_volume*
328 ((voice<md_sngchn)?(ULONG)md_musicvolume:(ULONG)md_sndfxvolume);
329 md_driver->VoiceSetVolume(voice,tmp/16384UL);
332 MIKMODAPI void Voice_SetVolume(SBYTE voice,UWORD vol)
334 MUTEX_LOCK(vars);
335 Voice_SetVolume_internal(voice,vol);
336 MUTEX_UNLOCK(vars);
339 MIKMODAPI UWORD Voice_GetVolume(SBYTE voice)
341 UWORD result=0;
343 MUTEX_LOCK(vars);
344 if((voice>=0)&&(voice<md_numchn))
345 result=md_driver->VoiceGetVolume(voice);
346 MUTEX_UNLOCK(vars);
348 return result;
351 void Voice_SetFrequency_internal(SBYTE voice,ULONG frq)
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);
359 MIKMODAPI void Voice_SetFrequency(SBYTE voice,ULONG frq)
361 MUTEX_LOCK(vars);
362 Voice_SetFrequency_internal(voice,frq);
363 MUTEX_UNLOCK(vars);
366 MIKMODAPI ULONG Voice_GetFrequency(SBYTE voice)
368 ULONG result=0;
370 MUTEX_LOCK(vars);
371 if((voice>=0)&&(voice<md_numchn))
372 result=md_driver->VoiceGetFrequency(voice);
373 MUTEX_UNLOCK(vars);
375 return result;
378 void Voice_SetPanning_internal(SBYTE voice,ULONG pan)
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;
386 md_driver->VoiceSetPanning(voice, pan);
389 MIKMODAPI void Voice_SetPanning(SBYTE voice,ULONG pan)
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
396 MUTEX_LOCK(vars);
397 Voice_SetPanning_internal(voice,pan);
398 MUTEX_UNLOCK(vars);
401 MIKMODAPI ULONG Voice_GetPanning(SBYTE voice)
403 ULONG result=PAN_CENTER;
405 MUTEX_LOCK(vars);
406 if((voice>=0)&&(voice<md_numchn))
407 result=md_driver->VoiceGetPanning(voice);
408 MUTEX_UNLOCK(vars);
410 return result;
413 void Voice_Play_internal(SBYTE voice,SAMPLE* s,ULONG start)
415 ULONG repend;
417 if((voice<0)||(voice>=md_numchn)) return;
419 md_sample[voice]=s;
420 repend=s->loopend;
422 if(s->flags&SF_LOOP)
423 /* repend can't be bigger than size */
424 if(repend>s->length) repend=s->length;
426 md_driver->VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags);
429 MIKMODAPI void Voice_Play(SBYTE voice,SAMPLE* s,ULONG start)
431 if(start>s->length) return;
433 MUTEX_LOCK(vars);
434 Voice_Play_internal(voice,s,start);
435 MUTEX_UNLOCK(vars);
438 void Voice_Stop_internal(SBYTE voice)
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);
447 MIKMODAPI void Voice_Stop(SBYTE voice)
449 MUTEX_LOCK(vars);
450 Voice_Stop_internal(voice);
451 MUTEX_UNLOCK(vars);
454 int Voice_Stopped_internal(SBYTE voice)
456 if((voice<0)||(voice>=md_numchn)) return 0;
457 return(md_driver->VoiceStopped(voice));
460 MIKMODAPI int Voice_Stopped(SBYTE voice)
462 int result;
464 MUTEX_LOCK(vars);
465 result=Voice_Stopped_internal(voice);
466 MUTEX_UNLOCK(vars);
468 return result;
471 MIKMODAPI SLONG Voice_GetPosition(SBYTE voice)
473 SLONG result=0;
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;
482 MUTEX_UNLOCK(vars);
484 return result;
487 MIKMODAPI ULONG Voice_RealVolume(SBYTE voice)
489 ULONG result=0;
491 MUTEX_LOCK(vars);
492 if((voice>=0)&&(voice<md_numchn)&& md_driver->VoiceRealVolume)
493 result=(md_driver->VoiceRealVolume(voice));
494 MUTEX_UNLOCK(vars);
496 return result;
499 extern MikMod_callback_t vc_callback;
501 MIKMODAPI void VC_SetCallback(MikMod_callback_t callback)
503 vc_callback = callback;
506 static int _mm_init(CHAR *cmdline)
508 UWORD t;
510 _mm_critical = 1;
512 /* if md_device==0, try to find a device number */
513 if(!md_device) {
514 cmdline=NULL;
516 for(t=1,md_driver=firstdriver;md_driver;md_driver=md_driver->next,t++)
517 if(md_driver->IsPresent()) break;
519 if(!md_driver) {
520 _mm_errno = MMERR_DETECTING_DEVICE;
521 if(_mm_errorhandler) _mm_errorhandler();
522 md_driver = &drv_nos;
523 return 1;
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++;
532 if(!md_driver) {
533 _mm_errno = MMERR_INVALID_DEVICE;
534 if(_mm_errorhandler) _mm_errorhandler();
535 md_driver = &drv_nos;
536 return 1;
539 /* arguments here might be necessary for the presence check to succeed */
540 if(cmdline&&(md_driver->CommandLine))
541 md_driver->CommandLine(cmdline);
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;
551 olddevice = md_device;
552 if(md_driver->Init()) {
553 MikMod_Exit_internal();
554 if(_mm_errorhandler) _mm_errorhandler();
555 return 1;
558 initialized=1;
559 _mm_critical=0;
561 return 0;
564 MIKMODAPI int MikMod_Init(CHAR *cmdline)
566 int result;
568 MUTEX_LOCK(vars);
569 MUTEX_LOCK(lists);
570 result=_mm_init(cmdline);
571 MUTEX_UNLOCK(lists);
572 MUTEX_UNLOCK(vars);
574 return result;
577 void MikMod_Exit_internal(void)
579 MikMod_DisableOutput_internal();
580 md_driver->Exit();
581 md_numchn = md_sfxchn = md_sngchn = 0;
582 md_driver = &drv_nos;
584 if(sfxinfo) MikMod_free(sfxinfo);
585 if(md_sample) MikMod_free(md_sample);
586 md_sample = NULL;
587 sfxinfo = NULL;
589 initialized = 0;
592 MIKMODAPI void MikMod_Exit(void)
594 MUTEX_LOCK(vars);
595 MUTEX_LOCK(lists);
596 MikMod_Exit_internal();
597 MUTEX_UNLOCK(lists);
598 MUTEX_UNLOCK(vars);
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)
605 int wasplaying = 0;
607 if(!initialized) return _mm_init(cmdline);
609 if (isplaying) {
610 wasplaying = 1;
611 md_driver->PlayStop();
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;
624 } else {
625 if(md_driver->Reset()) {
626 MikMod_Exit_internal();
627 if(_mm_errno)
628 if(_mm_errorhandler) _mm_errorhandler();
629 return 1;
633 if (wasplaying) md_driver->PlayStart();
634 return 0;
637 MIKMODAPI int MikMod_Reset(CHAR *cmdline)
639 int result;
641 MUTEX_LOCK(vars);
642 MUTEX_LOCK(lists);
643 result=_mm_reset(cmdline);
644 MUTEX_UNLOCK(lists);
645 MUTEX_UNLOCK(vars);
647 return result;
650 /* If either parameter is -1, the current set value will be retained. */
651 int MikMod_SetNumVoices_internal(int music, int sfx)
653 int resume = 0;
654 int t, oldchn = 0;
656 if((!music)&&(!sfx)) return 1;
657 _mm_critical = 1;
658 if(isplaying) {
659 MikMod_DisableOutput_internal();
660 oldchn = md_numchn;
661 resume = 1;
664 if(sfxinfo) MikMod_free(sfxinfo);
665 if(md_sample) MikMod_free(md_sample);
666 md_sample = NULL;
667 sfxinfo = NULL;
669 if(music!=-1) md_sngchn = music;
670 if(sfx!=-1) md_sfxchn = sfx;
671 md_numchn = md_sngchn + md_sfxchn;
673 LimitHardVoices(md_driver->HardVoiceLimit);
674 LimitSoftVoices(md_driver->SoftVoiceLimit);
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;
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));
689 /* make sure the player doesn't start with garbage */
690 for(t=oldchn;t<md_numchn;t++) Voice_Stop_internal(t);
692 sfxpool = 0;
693 if(resume) MikMod_EnableOutput_internal();
694 _mm_critical = 0;
696 return 0;
699 MIKMODAPI int MikMod_SetNumVoices(int music, int sfx)
701 int result;
703 MUTEX_LOCK(vars);
704 result=MikMod_SetNumVoices_internal(music,sfx);
705 MUTEX_UNLOCK(vars);
707 return result;
710 int MikMod_EnableOutput_internal(void)
712 _mm_critical = 1;
713 if(!isplaying) {
714 if(md_driver->PlayStart()) return 1;
715 isplaying = 1;
717 _mm_critical = 0;
718 return 0;
721 MIKMODAPI int MikMod_EnableOutput(void)
723 int result;
725 MUTEX_LOCK(vars);
726 result=MikMod_EnableOutput_internal();
727 MUTEX_UNLOCK(vars);
729 return result;
732 void MikMod_DisableOutput_internal(void)
734 if(isplaying && md_driver) {
735 isplaying = 0;
736 md_driver->PlayStop();
740 MIKMODAPI void MikMod_DisableOutput(void)
742 MUTEX_LOCK(vars);
743 MikMod_DisableOutput_internal();
744 MUTEX_UNLOCK(vars);
747 int MikMod_Active_internal(void)
749 return isplaying;
752 MIKMODAPI int MikMod_Active(void)
754 int result;
756 MUTEX_LOCK(vars);
757 result=MikMod_Active_internal();
758 MUTEX_UNLOCK(vars);
760 return result;
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).
767 Returns the voice that the sound is being played on. */
768 SBYTE Sample_Play_internal(SAMPLE *s,ULONG start,UBYTE flags)
770 int orig=sfxpool;/* for cases where all channels are critical */
771 int c;
773 if(!md_sfxchn) return -1;
774 if(s->volume>64) s->volume = 64;
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;
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;
800 sfxpool++;
801 if(sfxpool>=md_sfxchn) sfxpool = 0;
802 } while(sfxpool!=orig);
804 return -1;
807 MIKMODAPI SBYTE Sample_Play(SAMPLE *s,ULONG start,UBYTE flags)
809 SBYTE result;
811 MUTEX_LOCK(vars);
812 result=Sample_Play_internal(s,start,flags);
813 MUTEX_UNLOCK(vars);
815 return result;
818 MIKMODAPI long MikMod_GetVersion(void)
820 return LIBMIKMOD_VERSION;
823 /*========== MT-safe stuff */
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
839 INIT_MUTEX(vars);
840 INIT_MUTEX(lists);
842 MIKMODAPI int MikMod_InitThreads(void)
844 static int firstcall=1;
845 static int result=0;
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
866 return result;
869 MIKMODAPI void MikMod_Unlock(void)
871 MUTEX_UNLOCK(lists);
872 MUTEX_UNLOCK(vars);
875 MIKMODAPI void MikMod_Lock(void)
877 MUTEX_LOCK(vars);
878 MUTEX_LOCK(lists);
881 /*========== Parameter extraction helper */
883 CHAR *MD_GetAtom(CHAR *atomname,CHAR *cmdline,int implicit)
885 CHAR *ret=NULL;
887 if(cmdline) {
888 CHAR *buf=strstr(cmdline,atomname);
890 if((buf)&&((buf==cmdline)||(*(buf-1)==','))) {
891 CHAR *ptr=buf+strlen(atomname);
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);
907 return ret;
910 #if 0
911 #if defined unix || (defined __APPLE__ && defined __MACH__)
913 /*========== Posix helper functions */
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)
922 struct stat buf;
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;
938 return 1;
941 /* Drop all root privileges we might have */
942 int MD_DropPrivileges(void)
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;
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;
960 return 0;
963 #endif
964 #endif
965 /* ex:set ts=4: */