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