home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 February / PCO_0299.ISO / filesbbs / linux / mikmod-3.000 / mikmod-3 / mikmod-3.1.2 / playercode / mdriver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-12-07  |  12.4 KB  |  522 lines

  1. /*    MikMod sound library
  2.     (c) 1998 Miodrag Vallat and others - see file AUTHORS for complete list
  3.  
  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., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18.  
  19. /*==============================================================================
  20.  
  21.   $Id: mdriver.c,v 1.16 1998/12/07 06:00:43 miod Exp $
  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. #include <mikmod_internals.h>
  32.  
  33. #include <string.h>
  34.  
  35. static    MDRIVER *firstdriver=NULL;
  36.         MDRIVER *md_driver=NULL;
  37. extern    MODULE *pf; /* modfile being played */
  38.  
  39.         UWORD md_device         = 0;
  40.         UWORD md_mixfreq        = 44100;
  41.         UWORD md_mode           = DMODE_STEREO | DMODE_16BITS | DMODE_SURROUND
  42.                                  |DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX;
  43.         UBYTE md_pansep         = 128; /* 128 == 100% (full left/right) */
  44.         UBYTE md_reverb         = 6; /* Reverb */
  45.         UBYTE md_volume         = 96;  /* Global sound volume (0-128) */
  46.         UBYTE md_musicvolume    = 128; /* volume of song */
  47.         UBYTE md_sndfxvolume    = 128; /* volume of sound effects */
  48.         UBYTE md_bpm            = 125;
  49.  
  50. /* Do not modify the numchn variables yourself!  use MD_SetVoices() */
  51.         UBYTE md_numchn=0,md_sngchn=0,md_sfxchn=0;
  52.         UBYTE md_hardchn=0,md_softchn=0;
  53.  
  54.         void (*md_player)(void) = Player_HandleTick;
  55. static    BOOL  isplaying=0, initialized = 0;
  56. static    UBYTE *sfxinfo;
  57. static    int sfxpool;
  58.  
  59. static    SAMPLE **md_sample = NULL;
  60.  
  61. /* Previous driver in use */
  62. static    UWORD idevice;
  63.  
  64. /* Limits the number of hardware voices to the specified amount.
  65.    This function should only be used by the low-level drivers. */
  66. static    void LimitHardVoices(int limit)
  67. {
  68.     int t = 0;
  69.  
  70.     if(!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn>limit)) md_sfxchn=limit;
  71.     if(!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn>limit)) md_sngchn=limit;
  72.  
  73.     if(!(md_mode & DMODE_SOFT_SNDFX))
  74.         md_hardchn = md_sfxchn;
  75.     else
  76.         md_hardchn = 0;
  77.  
  78.     if(!(md_mode & DMODE_SOFT_MUSIC)) md_hardchn += md_sngchn;
  79.  
  80.     while(md_hardchn>limit) {
  81.         if(++t & 1) {
  82.             if(!(md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > 4)) md_sfxchn--;
  83.         } else {
  84.             if(!(md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > 8)) md_sngchn--;
  85.         }
  86.  
  87.         if(!(md_mode & DMODE_SOFT_SNDFX))
  88.             md_hardchn = md_sfxchn;
  89.         else
  90.             md_hardchn = 0;
  91.  
  92.         if(!(md_mode & DMODE_SOFT_MUSIC))
  93.             md_hardchn += md_sngchn;
  94.     }
  95.     md_numchn = md_hardchn + md_softchn;
  96. }
  97.  
  98. /* Limits the number of hardware voices to the specified amount.
  99.    This function should only be used by the low-level drivers. */
  100. static    void LimitSoftVoices(int limit)
  101. {
  102.     int t = 0;
  103.  
  104.     if((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > limit)) md_sfxchn = limit;
  105.     if((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > limit)) md_sngchn = limit;
  106.  
  107.     if(md_mode & DMODE_SOFT_SNDFX)
  108.         md_softchn = md_sfxchn;
  109.     else
  110.         md_softchn = 0;
  111.  
  112.     if(md_mode & DMODE_SOFT_MUSIC) md_softchn += md_sngchn;
  113.  
  114.     while(md_softchn > limit) {
  115.         if(++t & 1) {
  116.             if((md_mode & DMODE_SOFT_SNDFX) && (md_sfxchn > 4)) md_sfxchn--;
  117.         } else {
  118.             if((md_mode & DMODE_SOFT_MUSIC) && (md_sngchn > 8)) md_sngchn--;
  119.         }
  120.  
  121.         if(!(md_mode & DMODE_SOFT_SNDFX))
  122.             md_softchn = md_sfxchn;
  123.         else
  124.             md_softchn = 0;
  125.  
  126.         if(!(md_mode & DMODE_SOFT_MUSIC))
  127.             md_softchn += md_sngchn;
  128.     }
  129.     md_numchn = md_hardchn + md_softchn;
  130. }
  131.  
  132. /* Note: 'type' indicates whether the returned value should be for music or for
  133.    sound effects. */
  134. ULONG MD_SampleSpace(int type)
  135. {
  136.     if(type==MD_MUSIC)
  137.         type = (md_mode & DMODE_SOFT_MUSIC) ? MD_SOFTWARE : MD_HARDWARE;
  138.     else if(type==MD_SNDFX)
  139.         type = (md_mode & DMODE_SOFT_SNDFX) ? MD_SOFTWARE : MD_HARDWARE;
  140.  
  141.     return md_driver->FreeSampleSpace(type);
  142. }
  143.  
  144. ULONG MD_SampleLength(int type,SAMPLE* s)
  145. {
  146.     if(type==MD_MUSIC)
  147.         type = (md_mode & DMODE_SOFT_MUSIC) ? MD_SOFTWARE : MD_HARDWARE;
  148.     else
  149.       if(type==MD_SNDFX)
  150.         type = (md_mode & DMODE_SOFT_SNDFX) ? MD_SOFTWARE : MD_HARDWARE;
  151.  
  152.     return md_driver->RealSampleLength(type,s);
  153. }
  154.  
  155. CHAR* MikMod_InfoDriver(void)
  156. {
  157.     int t,len=0;
  158.     MDRIVER *l;
  159.     CHAR *list=NULL;
  160.  
  161.     /* compute size of buffer */
  162.     for(l=firstdriver;l;l=l->next) len+=4+(l->next?1:0)+strlen(l->Version);
  163.  
  164.     if(len)
  165.         if((list=_mm_malloc(len*sizeof(CHAR)))) {
  166.             list[0]=0;
  167.             /* list all registered device drivers : */
  168.             for(t=1,l=firstdriver;l;l=l->next,t++)
  169.                 sprintf(list,(l->next)?"%s%2d %s\n":"%s%2d %s",list,t,l->Version);
  170.         }
  171.     return list;
  172. }
  173.  
  174. void MikMod_RegisterDriver(MDRIVER* drv)
  175. {
  176.     MDRIVER *cruise = firstdriver;
  177.  
  178.     /* if we try to register an invalid driver, or an already registered driver,
  179.        ignore this attempt */
  180.     if ((!drv)||(drv->next))
  181.         return;
  182.  
  183.     if(cruise) {
  184.         while(cruise->next) cruise=cruise->next;
  185.         cruise->next=drv;
  186.     } else
  187.         firstdriver = drv; 
  188. }
  189.  
  190. SWORD MD_SampleLoad(SAMPLOAD* s, int type)
  191. {
  192.     SWORD result;
  193.  
  194.     if(type==MD_MUSIC)
  195.         type = (md_mode & DMODE_SOFT_MUSIC) ? MD_SOFTWARE : MD_HARDWARE;
  196.     else if(type==MD_SNDFX)
  197.         type = (md_mode & DMODE_SOFT_SNDFX) ? MD_SOFTWARE : MD_HARDWARE;
  198.  
  199.     SL_Init(s);
  200.     result = md_driver->SampleLoad(s, type);
  201.     SL_Exit(s);
  202.  
  203.     return result;
  204. }
  205.  
  206. void MD_SampleUnload(SWORD handle)
  207. {
  208.     md_driver->SampleUnload(handle);
  209. }
  210.  
  211. MikMod_player_t MikMod_RegisterPlayer(MikMod_player_t player)
  212. {
  213.     MikMod_player_t oldproc=md_player;
  214.  
  215.     md_player=player;
  216.     return oldproc;
  217. }
  218.  
  219. void MikMod_Update(void)
  220. {
  221.     if(isplaying)
  222.         if((!pf)||(!pf->forbid)) md_driver->Update();
  223. }
  224.  
  225. void Voice_SetVolume(SBYTE voice,UWORD vol)
  226. {
  227.     ULONG  tmp;
  228.  
  229.     if((voice<0)||(voice>=md_numchn)) return;
  230.  
  231.     /* range checks */
  232.     if(md_musicvolume>128) md_musicvolume=128;
  233.     if(md_sndfxvolume>128) md_sndfxvolume=128;
  234.     if(md_volume>128) md_volume=128;
  235.  
  236.     tmp=(ULONG)vol*(ULONG)md_volume*
  237.          ((voice<md_sngchn)?(ULONG)md_musicvolume:(ULONG)md_sndfxvolume);
  238.     md_driver->VoiceSetVolume(voice,tmp/16384UL);
  239. }
  240.  
  241. void Voice_SetFrequency(SBYTE voice,ULONG frq)
  242. {
  243.     if((voice<0)||(voice>=md_numchn)) return;
  244.     if((md_sample[voice])&&(md_sample[voice]->divfactor))
  245.         frq/=md_sample[voice]->divfactor;
  246.     md_driver->VoiceSetFrequency(voice,frq);
  247. }
  248.  
  249. void Voice_SetPanning(SBYTE voice,ULONG pan)
  250. {
  251.     if((voice<0)||(voice>=md_numchn)) return;
  252.     if(pan!=PAN_SURROUND) {
  253. #ifdef MIKMOD_DEBUG
  254.         if((pan<0)||(pan>255))
  255.             fprintf(stderr,"\rVoice_SetPanning called with pan=%ld\n",pan);
  256. #endif
  257.         if(md_pansep>128) md_pansep=128;
  258.         if(md_mode & DMODE_REVERSE) pan=255-pan;
  259.         pan = (((SWORD)(pan-128)*md_pansep)/128)+128;
  260.     }
  261.     md_driver->VoiceSetPanning(voice, pan);
  262. }
  263.  
  264. void Voice_Play(SBYTE voice,SAMPLE* s,ULONG start)
  265. {
  266.     ULONG  repend;
  267.  
  268.     if((voice<0)||(voice>=md_numchn)||(start>=s->length)) return;
  269.  
  270.     md_sample[voice]=s;
  271.     repend=s->loopend;
  272.  
  273.     if(s->flags&SF_LOOP)
  274.         /* repend can't be bigger than size */
  275.         if(repend>s->length) repend=s->length;
  276.  
  277.     md_driver->VoicePlay(voice,s->handle,start,s->length,s->loopstart,repend,s->flags);
  278. }
  279.  
  280. void Voice_Stop(SBYTE voice)
  281. {
  282.     if((voice<0)||(voice>=md_numchn)) return;
  283.     if(voice>=md_sngchn)
  284.         /* It is a sound effects channel, so flag the voice as non-critical! */
  285.         sfxinfo[voice-md_sngchn]=0;
  286.     md_driver->VoiceStop(voice);
  287. }
  288.  
  289. BOOL Voice_Stopped(SBYTE voice)
  290. {
  291.     if((voice<0)||(voice>=md_numchn)) return 0;
  292.     return(md_driver->VoiceStopped(voice));
  293. }
  294.  
  295. SLONG Voice_GetPosition(SBYTE voice)
  296. {
  297.     if((voice<0)||(voice>=md_numchn)) return 0;
  298.     return(md_driver->VoiceGetPosition(voice));
  299. }
  300.  
  301. ULONG Voice_RealVolume(SBYTE voice)
  302. {
  303.     if((voice<0)||(voice>=md_numchn)) return 0;
  304.     return(md_driver->VoiceRealVolume(voice));
  305. }
  306.  
  307. BOOL MikMod_Init(void)
  308. {
  309.     UWORD t;
  310.  
  311.     _mm_critical = 1;
  312.  
  313.     /* if md_device==0, try to find a device number */
  314.     if(!md_device) {
  315.         for(t=1,md_driver=firstdriver;md_driver;md_driver=md_driver->next,t++)
  316.             if(md_driver->IsPresent()) break;
  317.  
  318.         if(!md_driver) {
  319.             _mm_errno = MMERR_DETECTING_DEVICE;
  320.             if(_mm_errorhandler) _mm_errorhandler();
  321.             md_driver = &drv_nos;
  322.             return 1;
  323.         }
  324.  
  325.         md_device = t;
  326.     } else {
  327.         /* if n>0 use that driver */
  328.         for(t=1,md_driver=firstdriver;(md_driver)&&(t!=md_device);md_driver=md_driver->next,t++);
  329.  
  330.         if(!md_driver) {
  331.             _mm_errno = MMERR_INVALID_DEVICE;
  332.             if(_mm_errorhandler) _mm_errorhandler();
  333.             md_driver = &drv_nos;
  334.             return 1;
  335.         }
  336.  
  337.         if(!md_driver->IsPresent()) {
  338.             _mm_errno = MMERR_DETECTING_DEVICE;
  339.             if(_mm_errorhandler) _mm_errorhandler();
  340.             md_driver = &drv_nos;
  341.             return 1;
  342.         }
  343.     }
  344.  
  345.     if(md_driver->Init()) {
  346.         MikMod_Exit();
  347.         if(_mm_errorhandler) _mm_errorhandler();
  348.         return 1;
  349.     }
  350.  
  351.     initialized=1;
  352.     _mm_critical=0;
  353.  
  354.     return 0;
  355. }
  356.  
  357. void MikMod_Exit(void)
  358. {
  359.     MikMod_DisableOutput();
  360.     md_driver->Exit();
  361.     md_numchn = md_sfxchn = md_sngchn = 0;
  362.     md_driver = &drv_nos;
  363.  
  364.     if(sfxinfo) free(sfxinfo);
  365.     if(md_sample) free(md_sample);
  366.     md_sample  = NULL;
  367.     sfxinfo    = NULL;
  368.  
  369.     initialized = 0;
  370. }
  371.  
  372. /* Reset the driver using the new global variable settings. 
  373.    If the driver has not been initialized, it will be now. */
  374. BOOL MikMod_Reset(void)
  375. {
  376.     if(!initialized) return MikMod_Init();
  377.  
  378.     if((!md_driver->Reset)||(md_device != idevice)) {
  379.         /* md_driver->Reset was NULL, or md_device was changed, so do a full
  380.            reset of the driver. */
  381.         if(isplaying) md_driver->PlayStop();
  382.         md_driver->Exit();
  383.         if(MikMod_Init()) {
  384.             MikMod_Exit();
  385.             if(_mm_errno)
  386.                 if(_mm_errorhandler) _mm_errorhandler();
  387.             return 1;
  388.         }
  389.         if(isplaying) md_driver->PlayStart();
  390.     } else {
  391.         if(md_driver->Reset()) {
  392.             MikMod_Exit();
  393.             if(_mm_errno)
  394.                 if(_mm_errorhandler) _mm_errorhandler();
  395.             return 1;
  396.         }
  397.     }
  398.     return 0;
  399. }
  400.  
  401. /* If either parameter is -1, the current set value will be retained. */
  402. BOOL MikMod_SetNumVoices(int music, int sfx)
  403. {
  404.     BOOL resume = 0;
  405.     int t, oldchn = 0;
  406.  
  407.     if((!music)&&(!sfx)) return 1;
  408.     _mm_critical = 1;
  409.     if(isplaying) {
  410.         MikMod_DisableOutput();
  411.         oldchn = md_numchn;
  412.         resume = 1;
  413.     }
  414.  
  415.     if(sfxinfo) free(sfxinfo);
  416.     if(md_sample) free(md_sample);
  417.     md_sample  = NULL;
  418.     sfxinfo    = NULL;
  419.  
  420.     if(music!=-1) md_sngchn = music;
  421.     if(sfx!=-1)   md_sfxchn = sfx;
  422.     md_numchn = md_sngchn + md_sfxchn;
  423.  
  424.     LimitHardVoices(md_driver->HardVoiceLimit);
  425.     LimitSoftVoices(md_driver->SoftVoiceLimit);
  426.  
  427.     if(md_driver->SetNumVoices()) {
  428.         MikMod_Exit();
  429.         if(_mm_errno)
  430.             if(_mm_errorhandler!=NULL) _mm_errorhandler();
  431.         md_numchn = md_softchn = md_hardchn = md_sfxchn = md_sngchn = 0;
  432.         return 1;
  433.     }
  434.  
  435.     if(md_sngchn+md_sfxchn)
  436.         md_sample=(SAMPLE**)_mm_calloc(md_sngchn+md_sfxchn,sizeof(SAMPLE*));
  437.     if(md_sfxchn)
  438.         sfxinfo = (UBYTE *)_mm_calloc(md_sfxchn,sizeof(UBYTE));
  439.  
  440.     /* make sure the player doesn't start with garbage */
  441.     for(t=oldchn;t<md_numchn;t++)  Voice_Stop(t);
  442.  
  443.     sfxpool = 0;
  444.     if(resume) MikMod_EnableOutput();
  445.     _mm_critical = 0;
  446.  
  447.     return 0;
  448. }
  449.  
  450. BOOL MikMod_EnableOutput(void)
  451. {
  452.     _mm_critical = 1;
  453.     if(!isplaying) {
  454.         if(md_driver->PlayStart()) return 1;
  455.         isplaying = 1;
  456.     }
  457.     _mm_critical = 0;
  458.     return 0;
  459. }
  460.  
  461. void MikMod_DisableOutput(void)
  462. {
  463.     if(isplaying && md_driver) {
  464.         isplaying = 0;
  465.         md_driver->PlayStop();
  466.     }
  467. }
  468.  
  469. BOOL MikMod_Active(void)
  470. {
  471.     return isplaying;
  472. }
  473.  
  474. /* Plays a sound effects sample.  Picks a voice from the number of voices
  475.    allocated for use as sound effects (loops through voices, skipping all active
  476.    criticals).
  477.  
  478.    Returns the voice that the sound is being played on.                       */
  479. SBYTE Sample_Play(SAMPLE *s,ULONG start,UBYTE flags)
  480. {
  481.     int orig=sfxpool;/* for cases where all channels are critical */
  482.     int c;
  483.  
  484.     if(!md_sfxchn) return -1;
  485.     if(s->volume>64) s->volume = 64;
  486.  
  487.     /* check the first location after sfxpool */
  488.     do {
  489.         if(sfxinfo[sfxpool]&SFX_CRITICAL) {
  490.             if(md_driver->VoiceStopped(c=sfxpool+md_sngchn)) {
  491.                 sfxinfo[sfxpool]=flags;
  492.                 Voice_Play(c, s, start);
  493.                 md_driver->VoiceSetVolume(c,s->volume<<2);
  494.                 Voice_SetPanning(c,s->panning);
  495.                 md_driver->VoiceSetFrequency(c,s->speed);
  496.                 sfxpool++;
  497.                 if(sfxpool>=md_sfxchn) sfxpool=0;
  498.                 return c;
  499.             }
  500.         } else {
  501.             sfxinfo[sfxpool] = flags;
  502.             Voice_Play(c=sfxpool+md_sngchn, s, start);
  503.             md_driver->VoiceSetVolume(c,s->volume<<2);
  504.             Voice_SetPanning(c,s->panning);
  505.             md_driver->VoiceSetFrequency(c,s->speed);
  506.             sfxpool++;
  507.             if(sfxpool>=md_sfxchn) sfxpool=0;
  508.             return c;
  509.         }
  510.  
  511.         sfxpool++;
  512.         if(sfxpool>=md_sfxchn) sfxpool = 0;
  513.     } while(sfxpool!=orig);
  514.  
  515.     return -1;
  516. }
  517.  
  518. long MikMod_GetVersion(void)
  519. {
  520.     return LIBMIKMOD_VERSION;
  521. }
  522.