mdriver.c
上传用户:wstnjxml
上传日期:2014-04-03
资源大小:7248k
文件大小:21k
源码类别:

Windows CE

开发平台:

C/C++

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