Subversion Repositories Kolibri OS

Rev

Rev 9133 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. //
  2. //      ID Engine
  3. //      ID_SD.c - Sound Manager for Wolfenstein 3D
  4. //      v1.2
  5. //      By Jason Blochowiak
  6. //
  7.  
  8. //
  9. //      This module handles dealing with generating sound on the appropriate
  10. //              hardware
  11. //
  12. //      Depends on: User Mgr (for parm checking)
  13. //
  14. //      Globals:
  15. //              For User Mgr:
  16. //                      SoundBlasterPresent - SoundBlaster card present?
  17. //                      AdLibPresent - AdLib card present?
  18. //                      SoundMode - What device is used for sound effects
  19. //                              (Use SM_SetSoundMode() to set)
  20. //                      MusicMode - What device is used for music
  21. //                              (Use SM_SetMusicMode() to set)
  22. //                      DigiMode - What device is used for digitized sound effects
  23. //                              (Use SM_SetDigiDevice() to set)
  24. //
  25. //              For Cache Mgr:
  26. //                      NeedsDigitized - load digitized sounds?
  27. //                      NeedsMusic - load music?
  28. //
  29.  
  30. #include "wl_def.h"
  31. #include "SDL_mixer/SDL_mixer.h"
  32. #if defined(GP2X_940)
  33. #include "gp2x/fmopl.h"
  34. #else
  35. #include "mame/fmopl.h"
  36. #endif
  37.  
  38. #pragma hdrstop
  39.  
  40. #define ORIGSAMPLERATE 7042
  41.  
  42. typedef struct
  43. {
  44.         char RIFF[4];
  45.         longword filelenminus8;
  46.         char WAVE[4];
  47.         char fmt_[4];
  48.         longword formatlen;
  49.         word val0x0001;
  50.         word channels;
  51.         longword samplerate;
  52.         longword bytespersec;
  53.         word bytespersample;
  54.         word bitspersample;
  55. } headchunk;
  56.  
  57. typedef struct
  58. {
  59.         char chunkid[4];
  60.         longword chunklength;
  61. } wavechunk;
  62.  
  63. typedef struct
  64. {
  65.     uint32_t startpage;
  66.     uint32_t length;
  67. } digiinfo;
  68.  
  69. static Mix_Chunk *SoundChunks[ STARTMUSIC - STARTDIGISOUNDS];
  70. static byte      *SoundBuffers[STARTMUSIC - STARTDIGISOUNDS];
  71.  
  72. globalsoundpos channelSoundPos[MIX_CHANNELS];
  73.  
  74. //      Global variables
  75.         boolean         AdLibPresent,
  76.                         SoundBlasterPresent,SBProPresent,
  77.                         SoundPositioned;
  78.         SDMode          SoundMode;
  79.         SMMode          MusicMode;
  80.         SDSMode         DigiMode;
  81. static  byte          **SoundTable;
  82.         int             DigiMap[LASTSOUND];
  83.         int             DigiChannel[STARTMUSIC - STARTDIGISOUNDS];
  84.  
  85. //      Internal variables
  86. boolean                         SD_Started;
  87. static  boolean                 nextsoundpos;
  88. static  soundnames              SoundNumber;
  89. static  soundnames              DigiNumber;
  90. static  word                    SoundPriority;
  91. static  word                    DigiPriority;
  92. static  int                     LeftPosition;
  93. static  int                     RightPosition;
  94.  
  95.         word                    NumDigi;
  96. static  digiinfo               *DigiList;
  97. static  boolean                 DigiPlaying;
  98.  
  99. //      PC Sound variables
  100. static  volatile byte           pcLastSample;
  101. static  byte * volatile         pcSound;
  102. static  longword                pcLengthLeft;
  103.  
  104. //      AdLib variables
  105. static  byte * volatile         alSound;
  106. static  byte                    alBlock;
  107. static  longword                alLengthLeft;
  108. static  longword                alTimeCount;
  109. static  Instrument              alZeroInst;
  110.  
  111. //      Sequencer variables
  112. static  volatile boolean        sqActive;
  113. static  word                   *sqHack;
  114. static  word                   *sqHackPtr;
  115. static  int                     sqHackLen;
  116. static  int                     sqHackSeqLen;
  117. static  longword                sqHackTime;
  118.  
  119.  
  120. static void SDL_SoundFinished(void)
  121. {
  122.         SoundNumber   = (soundnames)0;
  123.         SoundPriority = 0;
  124. }
  125.  
  126.  
  127. #ifdef NOTYET
  128.  
  129. void SDL_turnOnPCSpeaker(word timerval);
  130. #pragma aux SDL_turnOnPCSpeaker = \
  131.         "mov    al,0b6h" \
  132.         "out    43h,al" \
  133.         "mov    al,bl" \
  134.         "out    42h,al" \
  135.         "mov    al,bh" \
  136.         "out    42h,al" \
  137.         "in     al,61h" \
  138.         "or     al,3"   \
  139.         "out    61h,al" \
  140.         parm [bx] \
  141.         modify exact [al]
  142.  
  143. void SDL_turnOffPCSpeaker();
  144. #pragma aux SDL_turnOffPCSpeaker = \
  145.         "in     al,61h" \
  146.         "and    al,0fch" \
  147.         "out    61h,al" \
  148.         modify exact [al]
  149.  
  150. void SDL_setPCSpeaker(byte val);
  151. #pragma aux SDL_setPCSpeaker = \
  152.         "in     al,61h" \
  153.         "and    al,0fch" \
  154.         "or     al,ah" \
  155.         "out    61h,al" \
  156.         parm [ah] \
  157.         modify exact [al]
  158.  
  159. void inline SDL_DoFX()
  160. {
  161.         if(pcSound)
  162.         {
  163.                 if(*pcSound!=pcLastSample)
  164.                 {
  165.                         pcLastSample=*pcSound;
  166.  
  167.                         if(pcLastSample)
  168.                                 SDL_turnOnPCSpeaker(pcLastSample*60);
  169.                         else
  170.                                 SDL_turnOffPCSpeaker();
  171.                 }
  172.                 pcSound++;
  173.                 pcLengthLeft--;
  174.                 if(!pcLengthLeft)
  175.                 {
  176.                         pcSound=0;
  177.                         SoundNumber=(soundnames)0;
  178.                         SoundPriority=0;
  179.                         SDL_turnOffPCSpeaker();
  180.                 }
  181.         }
  182.  
  183.         // [adlib sound stuff removed...]
  184. }
  185.  
  186. static void SDL_DigitizedDoneInIRQ(void);
  187.  
  188. void inline SDL_DoFast()
  189. {
  190.         count_fx++;
  191.         if(count_fx>=5)
  192.         {
  193.                 count_fx=0;
  194.  
  195.                 SDL_DoFX();
  196.  
  197.                 count_time++;
  198.                 if(count_time>=2)
  199.                 {
  200.                         TimeCount++;
  201.                         count_time=0;
  202.                 }
  203.         }
  204.  
  205.         // [adlib music and soundsource stuff removed...]
  206.  
  207.         TimerCount+=TimerDivisor;
  208.         if(*((word *)&TimerCount+1))
  209.         {
  210.                 *((word *)&TimerCount+1)=0;
  211.                 t0OldService();
  212.         }
  213.         else
  214.         {
  215.                 outp(0x20,0x20);
  216.         }
  217. }
  218.  
  219. // Timer 0 ISR for 7000Hz interrupts
  220. void __interrupt SDL_t0ExtremeAsmService(void)
  221. {
  222.         if(pcindicate)
  223.         {
  224.                 if(pcSound)
  225.                 {
  226.                         SDL_setPCSpeaker(((*pcSound++)&0x80)>>6);
  227.                         pcLengthLeft--;
  228.                         if(!pcLengthLeft)
  229.                         {
  230.                                 pcSound=0;
  231.                                 SDL_turnOffPCSpeaker();
  232.                                 SDL_DigitizedDoneInIRQ();
  233.                         }
  234.                 }
  235.         }
  236.         extreme++;
  237.         if(extreme>=10)
  238.         {
  239.                 extreme=0;
  240.                 SDL_DoFast();
  241.         }
  242.         else
  243.                 outp(0x20,0x20);
  244. }
  245.  
  246. // Timer 0 ISR for 700Hz interrupts
  247. void __interrupt SDL_t0FastAsmService(void)
  248. {
  249.         SDL_DoFast();
  250. }
  251.  
  252. // Timer 0 ISR for 140Hz interrupts
  253. void __interrupt SDL_t0SlowAsmService(void)
  254. {
  255.         count_time++;
  256.         if(count_time>=2)
  257.         {
  258.                 TimeCount++;
  259.                 count_time=0;
  260.         }
  261.  
  262.         SDL_DoFX();
  263.  
  264.         TimerCount+=TimerDivisor;
  265.         if(*((word *)&TimerCount+1))
  266.         {
  267.                 *((word *)&TimerCount+1)=0;
  268.                 t0OldService();
  269.         }
  270.         else
  271.                 outp(0x20,0x20);
  272. }
  273.  
  274. void SDL_IndicatePC(boolean ind)
  275. {
  276.         pcindicate=ind;
  277. }
  278.  
  279. ///////////////////////////////////////////////////////////////////////////
  280. //
  281. //      SDL_SetTimer0() - Sets system timer 0 to the specified speed
  282. //
  283. ///////////////////////////////////////////////////////////////////////////
  284. static void
  285. SDL_SetTimer0(word speed)
  286. {
  287. #ifndef TPROF   // If using Borland's profiling, don't screw with the timer
  288. //      _asm pushfd
  289.         _asm cli
  290.  
  291.         outp(0x43,0x36);                                // Change timer 0
  292.         outp(0x40,(byte)speed);
  293.         outp(0x40,speed >> 8);
  294.         // Kludge to handle special case for digitized PC sounds
  295.         if (TimerDivisor == (1192030 / (TickBase * 100)))
  296.                 TimerDivisor = (1192030 / (TickBase * 10));
  297.         else
  298.                 TimerDivisor = speed;
  299.  
  300. //      _asm popfd
  301.         _asm    sti
  302. #else
  303.         TimerDivisor = 0x10000;
  304. #endif
  305. }
  306.  
  307. ///////////////////////////////////////////////////////////////////////////
  308. //
  309. //      SDL_SetIntsPerSec() - Uses SDL_SetTimer0() to set the number of
  310. //              interrupts generated by system timer 0 per second
  311. //
  312. ///////////////////////////////////////////////////////////////////////////
  313. static void
  314. SDL_SetIntsPerSec(word ints)
  315. {
  316.         TimerRate = ints;
  317.         SDL_SetTimer0(1192030 / ints);
  318. }
  319.  
  320. static void
  321. SDL_SetTimerSpeed(void)
  322. {
  323.         word    rate;
  324.         void (_interrupt *isr)(void);
  325.  
  326.         if ((DigiMode == sds_PC) && DigiPlaying)
  327.         {
  328.                 rate = TickBase * 100;
  329.                 isr = SDL_t0ExtremeAsmService;
  330.         }
  331.         else if ((MusicMode == smm_AdLib) || ((DigiMode == sds_SoundSource) && DigiPlaying)     )
  332.         {
  333.                 rate = TickBase * 10;
  334.                 isr = SDL_t0FastAsmService;
  335.         }
  336.         else
  337.         {
  338.                 rate = TickBase * 2;
  339.                 isr = SDL_t0SlowAsmService;
  340.         }
  341.  
  342.         if (rate != TimerRate)
  343.         {
  344.                 _dos_setvect(8,isr);
  345.                 SDL_SetIntsPerSec(rate);
  346.                 TimerRate = rate;
  347.         }
  348. }
  349.  
  350. //
  351. //      PC Sound code
  352. //
  353.  
  354. ///////////////////////////////////////////////////////////////////////////
  355. //
  356. //      SDL_PCPlaySample() - Plays the specified sample on the PC speaker
  357. //
  358. ///////////////////////////////////////////////////////////////////////////
  359. #ifdef  _MUSE_
  360. void
  361. #else
  362. static void
  363. #endif
  364. SDL_PCPlaySample(byte *data,longword len,boolean inIRQ)
  365. {
  366.         if(!inIRQ)
  367.         {
  368. //              _asm    pushfd
  369.                 _asm    cli
  370.         }
  371.  
  372.         SDL_IndicatePC(true);
  373.  
  374.         pcLengthLeft = len;
  375.         pcSound = (volatile byte *)data;
  376.  
  377.         if(!inIRQ)
  378.         {
  379. //              _asm    popfd
  380.                 _asm    sti
  381.         }
  382. }
  383.  
  384. ///////////////////////////////////////////////////////////////////////////
  385. //
  386. //      SDL_PCStopSample() - Stops a sample playing on the PC speaker
  387. //
  388. ///////////////////////////////////////////////////////////////////////////
  389. #ifdef  _MUSE_
  390. void
  391. #else
  392. static void
  393. #endif
  394. SDL_PCStopSampleInIRQ(void)
  395. {
  396.         pcSound = 0;
  397.  
  398.         SDL_IndicatePC(false);
  399.  
  400.         _asm    in      al,0x61                 // Turn the speaker off
  401.         _asm    and     al,0xfd                 // ~2
  402.         _asm    out     0x61,al
  403. }
  404.  
  405. ///////////////////////////////////////////////////////////////////////////
  406. //
  407. //      SDL_PCPlaySound() - Plays the specified sound on the PC speaker
  408. //
  409. ///////////////////////////////////////////////////////////////////////////
  410. #ifdef  _MUSE_
  411. void
  412. #else
  413. static void
  414. #endif
  415. SDL_PCPlaySound(PCSound *sound)
  416. {
  417. //      _asm    pushfd
  418.         _asm    cli
  419.  
  420.         pcLastSample = -1;
  421.         pcLengthLeft = sound->common.length;
  422.         pcSound = sound->data;
  423.  
  424. //      _asm    popfd
  425.         _asm    sti
  426. }
  427.  
  428. ///////////////////////////////////////////////////////////////////////////
  429. //
  430. //      SDL_PCStopSound() - Stops the current sound playing on the PC Speaker
  431. //
  432. ///////////////////////////////////////////////////////////////////////////
  433. #ifdef  _MUSE_
  434. void
  435. #else
  436. static void
  437. #endif
  438. SDL_PCStopSound(void)
  439. {
  440. //      _asm    pushfd
  441.         _asm    cli
  442.  
  443.         pcSound = 0;
  444.  
  445.         _asm    in      al,0x61                 // Turn the speaker off
  446.         _asm    and     al,0xfd                 // ~2
  447.         _asm    out     0x61,al
  448.  
  449. //      _asm    popfd
  450.         _asm    sti
  451. }
  452.  
  453. ///////////////////////////////////////////////////////////////////////////
  454. //
  455. //      SDL_ShutPC() - Turns off the pc speaker
  456. //
  457. ///////////////////////////////////////////////////////////////////////////
  458. static void
  459. SDL_ShutPC(void)
  460. {
  461. //      _asm    pushfd
  462.         _asm    cli
  463.  
  464.         pcSound = 0;
  465.  
  466.         _asm    in      al,0x61                 // Turn the speaker & gate off
  467.         _asm    and     al,0xfc                 // ~3
  468.         _asm    out     0x61,al
  469.  
  470. //      _asm    popfd
  471.         _asm    sti
  472. }
  473.  
  474. #endif
  475.  
  476. void
  477. SD_StopDigitized(void)
  478. {
  479.     DigiPlaying = false;
  480.     DigiNumber = (soundnames) 0;
  481.     DigiPriority = 0;
  482.     SoundPositioned = false;
  483.     if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
  484.         SDL_SoundFinished();
  485.  
  486.     switch (DigiMode)
  487.     {
  488.         case sds_PC:
  489. //            SDL_PCStopSampleInIRQ();
  490.             break;
  491.         case sds_SoundBlaster:
  492. //            SDL_SBStopSampleInIRQ();
  493.             Mix_HaltChannel(-1);
  494.             break;
  495.     }
  496. }
  497.  
  498. int SD_GetChannelForDigi(int which)
  499. {
  500.     if(DigiChannel[which] != -1) return DigiChannel[which];
  501.  
  502.     int channel = Mix_GroupAvailable(1);
  503.     if(channel == -1) channel = Mix_GroupOldest(1);
  504.     if(channel == -1)           // All sounds stopped in the meantime?
  505.         return Mix_GroupAvailable(1);
  506.     return channel;
  507. }
  508.  
  509. void SD_SetPosition(int channel, int leftpos, int rightpos)
  510. {
  511.     if((leftpos < 0) || (leftpos > 15) || (rightpos < 0) || (rightpos > 15)
  512.             || ((leftpos == 15) && (rightpos == 15)))
  513.         Quit("SD_SetPosition: Illegal position");
  514.  
  515.     switch (DigiMode)
  516.     {
  517.         case sds_SoundBlaster:
  518. //            SDL_PositionSBP(leftpos,rightpos);
  519.             Mix_SetPanning(channel, ((15 - leftpos) << 4) + 15,
  520.                 ((15 - rightpos) << 4) + 15);
  521.             break;
  522.     }
  523. }
  524.  
  525. Sint16 GetSample(float csample, byte *samples, int size)
  526. {
  527.     float s0=0, s1=0, s2=0;
  528.     int cursample = (int) csample;
  529.     float sf = csample - (float) cursample;
  530.  
  531.     if(cursample-1 >= 0) s0 = (float) (samples[cursample-1] - 128);
  532.     s1 = (float) (samples[cursample] - 128);
  533.     if(cursample+1 < size) s2 = (float) (samples[cursample+1] - 128);
  534.  
  535.     float val = s0*sf*(sf-1)/2 - s1*(sf*sf-1) + s2*(sf+1)*sf/2;
  536.     int32_t intval = (int32_t) (val * 256);
  537.     if(intval < -32768) intval = -32768;
  538.     else if(intval > 32767) intval = 32767;
  539.     return (Sint16) intval;
  540. }
  541.  
  542. void SD_PrepareSound(int which)
  543. {
  544.     if(DigiList == NULL)
  545.         Quit("SD_PrepareSound(%i): DigiList not initialized!\n", which);
  546.  
  547.     int page = DigiList[which].startpage;
  548.     int size = DigiList[which].length;
  549.  
  550.     byte *origsamples = PM_GetSound(page);
  551.     if(origsamples + size >= PM_GetEnd())
  552.         Quit("SD_PrepareSound(%i): Sound reaches out of page file!\n", which);
  553.  
  554.     int destsamples = (int) ((float) size * (float) param_samplerate
  555.         / (float) ORIGSAMPLERATE);
  556.  
  557.     byte *wavebuffer = (byte *) malloc(sizeof(headchunk) + sizeof(wavechunk)
  558.         + destsamples * 2);     // dest are 16-bit samples
  559.     if(wavebuffer == NULL)
  560.         Quit("Unable to allocate wave buffer for sound %i!\n", which);
  561.  
  562.     headchunk head = {{'R','I','F','F'}, 0, {'W','A','V','E'},
  563.         {'f','m','t',' '}, 0x10, 0x0001, 1, param_samplerate, param_samplerate*2, 2, 16};
  564.     wavechunk dhead = {{'d', 'a', 't', 'a'}, destsamples*2};
  565.     head.filelenminus8 = sizeof(head) + destsamples*2;  // (sizeof(dhead)-8 = 0)
  566.     memcpy(wavebuffer, &head, sizeof(head));
  567.     memcpy(wavebuffer+sizeof(head), &dhead, sizeof(dhead));
  568.  
  569.     // alignment is correct, as wavebuffer comes from malloc
  570.     // and sizeof(headchunk) % 4 == 0 and sizeof(wavechunk) % 4 == 0
  571.     Sint16 *newsamples = (Sint16 *)(void *) (wavebuffer + sizeof(headchunk)
  572.         + sizeof(wavechunk));
  573.     float cursample = 0.F;
  574.     float samplestep = (float) ORIGSAMPLERATE / (float) param_samplerate;
  575.     for(int i=0; i<destsamples; i++, cursample+=samplestep)
  576.     {
  577.         newsamples[i] = GetSample((float)size * (float)i / (float)destsamples,
  578.             origsamples, size);
  579.     }
  580.     SoundBuffers[which] = wavebuffer;
  581.  
  582.     SoundChunks[which] = Mix_LoadWAV_RW(SDL_RWFromMem(wavebuffer,
  583.         sizeof(headchunk) + sizeof(wavechunk) + destsamples * 2), 1);
  584. }
  585.  
  586. int SD_PlayDigitized(word which,int leftpos,int rightpos)
  587. {
  588.     if (!DigiMode)
  589.         return 0;
  590.  
  591.     if (which >= NumDigi)
  592.         Quit("SD_PlayDigitized: bad sound number %i", which);
  593.  
  594.     int channel = SD_GetChannelForDigi(which);
  595.     SD_SetPosition(channel, leftpos,rightpos);
  596.  
  597.     DigiPlaying = true;
  598.  
  599.     Mix_Chunk *sample = SoundChunks[which];
  600.     if(sample == NULL)
  601.     {
  602.         printf("SoundChunks[%i] is NULL!\n", which);
  603.         return 0;
  604.     }
  605.  
  606.     if(Mix_PlayChannel(channel, sample, 0) == -1)
  607.     {
  608.         printf("Unable to play sound: %s\n", Mix_GetError());
  609.         return 0;
  610.     }
  611.  
  612.     return channel;
  613. }
  614.  
  615. void SD_ChannelFinished(int channel)
  616. {
  617.     channelSoundPos[channel].valid = 0;
  618. }
  619.  
  620. void
  621. SD_SetDigiDevice(SDSMode mode)
  622. {
  623.     boolean devicenotpresent;
  624.  
  625.     if (mode == DigiMode)
  626.         return;
  627.  
  628.     SD_StopDigitized();
  629.  
  630.     devicenotpresent = false;
  631.     switch (mode)
  632.     {
  633.         case sds_SoundBlaster:
  634.             if (!SoundBlasterPresent)
  635.                 devicenotpresent = true;
  636.             break;
  637.     }
  638.  
  639.     if (!devicenotpresent)
  640.     {
  641.         DigiMode = mode;
  642.  
  643. #ifdef NOTYET
  644.         SDL_SetTimerSpeed();
  645. #endif
  646.     }
  647. }
  648.  
  649. void
  650. SDL_SetupDigi(void)
  651. {
  652.     // Correct padding enforced by PM_Startup()
  653.     word *soundInfoPage = (word *) (void *) PM_GetPage(ChunksInFile-1);
  654.     NumDigi = (word) PM_GetPageSize(ChunksInFile - 1) / 4;
  655.  
  656.     DigiList = (digiinfo *) malloc(NumDigi * sizeof(digiinfo));
  657.     int i;
  658.     for(i = 0; i < NumDigi; i++)
  659.     {
  660.         // Calculate the size of the digi from the sizes of the pages between
  661.         // the start page and the start page of the next sound
  662.  
  663.         DigiList[i].startpage = soundInfoPage[i * 2];
  664.         if((int) DigiList[i].startpage >= ChunksInFile - 1)
  665.         {
  666.             NumDigi = i;
  667.             break;
  668.         }
  669.  
  670.         int lastPage;
  671.         if(i < NumDigi - 1)
  672.         {
  673.             lastPage = soundInfoPage[i * 2 + 2];
  674.             if(lastPage == 0 || lastPage + PMSoundStart > ChunksInFile - 1) lastPage = ChunksInFile - 1;
  675.             else lastPage += PMSoundStart;
  676.         }
  677.         else lastPage = ChunksInFile - 1;
  678.  
  679.         int size = 0;
  680.         for(int page = PMSoundStart + DigiList[i].startpage; page < lastPage; page++)
  681.             size += PM_GetPageSize(page);
  682.  
  683.         // Don't include padding of sound info page, if padding was added
  684.         if(lastPage == ChunksInFile - 1 && PMSoundInfoPagePadded) size--;
  685.  
  686.         // Patch lower 16-bit of size with size from sound info page.
  687.         // The original VSWAP contains padding which is included in the page size,
  688.         // but not included in the 16-bit size. So we use the more precise value.
  689.         if((size & 0xffff0000) != 0 && (size & 0xffff) < soundInfoPage[i * 2 + 1])
  690.             size -= 0x10000;
  691.         size = (size & 0xffff0000) | soundInfoPage[i * 2 + 1];
  692.  
  693.         DigiList[i].length = size;
  694.     }
  695.  
  696.     for(i = 0; i < LASTSOUND; i++)
  697.     {
  698.         DigiMap[i] = -1;
  699.         DigiChannel[i] = -1;
  700.     }
  701. }
  702.  
  703. //      AdLib Code
  704.  
  705. ///////////////////////////////////////////////////////////////////////////
  706. //
  707. //      SDL_ALStopSound() - Turns off any sound effects playing through the
  708. //              AdLib card
  709. //
  710. ///////////////////////////////////////////////////////////////////////////
  711. static void
  712. SDL_ALStopSound(void)
  713. {
  714.     alSound = 0;
  715.     alOut(alFreqH + 0, 0);
  716. }
  717.  
  718. static void
  719. SDL_AlSetFXInst(Instrument *inst)
  720. {
  721.     byte c,m;
  722.  
  723.     m = 0;      // modulator cell for channel 0
  724.     c = 3;      // carrier cell for channel 0
  725.     alOut(m + alChar,inst->mChar);
  726.     alOut(m + alScale,inst->mScale);
  727.     alOut(m + alAttack,inst->mAttack);
  728.     alOut(m + alSus,inst->mSus);
  729.     alOut(m + alWave,inst->mWave);
  730.     alOut(c + alChar,inst->cChar);
  731.     alOut(c + alScale,inst->cScale);
  732.     alOut(c + alAttack,inst->cAttack);
  733.     alOut(c + alSus,inst->cSus);
  734.     alOut(c + alWave,inst->cWave);
  735.  
  736.     // Note: Switch commenting on these lines for old MUSE compatibility
  737. //    alOutInIRQ(alFeedCon,inst->nConn);
  738.     alOut(alFeedCon,0);
  739. }
  740.  
  741. ///////////////////////////////////////////////////////////////////////////
  742. //
  743. //      SDL_ALPlaySound() - Plays the specified sound on the AdLib card
  744. //
  745. ///////////////////////////////////////////////////////////////////////////
  746. static void
  747. SDL_ALPlaySound(AdLibSound *sound)
  748. {
  749.     Instrument      *inst;
  750.     byte            *data;
  751.  
  752.     SDL_ALStopSound();
  753.  
  754.     alLengthLeft = sound->common.length;
  755.     data = sound->data;
  756.     alBlock = ((sound->block & 7) << 2) | 0x20;
  757.     inst = &sound->inst;
  758.  
  759.     if (!(inst->mSus | inst->cSus))
  760.     {
  761.         Quit("SDL_ALPlaySound() - Bad instrument");
  762.     }
  763.  
  764.     SDL_AlSetFXInst(inst);
  765.     alSound = (byte *)data;
  766. }
  767.  
  768. ///////////////////////////////////////////////////////////////////////////
  769. //
  770. //      SDL_ShutAL() - Shuts down the AdLib card for sound effects
  771. //
  772. ///////////////////////////////////////////////////////////////////////////
  773. static void
  774. SDL_ShutAL(void)
  775. {
  776.     alSound = 0;
  777.     alOut(alEffects,0);
  778.     alOut(alFreqH + 0,0);
  779.     SDL_AlSetFXInst(&alZeroInst);
  780. }
  781.  
  782. ///////////////////////////////////////////////////////////////////////////
  783. //
  784. //      SDL_CleanAL() - Totally shuts down the AdLib card
  785. //
  786. ///////////////////////////////////////////////////////////////////////////
  787. static void
  788. SDL_CleanAL(void)
  789. {
  790.     int     i;
  791.  
  792.     alOut(alEffects,0);
  793.     for (i = 1; i < 0xf5; i++)
  794.         alOut(i, 0);
  795. }
  796.  
  797. ///////////////////////////////////////////////////////////////////////////
  798. //
  799. //      SDL_StartAL() - Starts up the AdLib card for sound effects
  800. //
  801. ///////////////////////////////////////////////////////////////////////////
  802. static void
  803. SDL_StartAL(void)
  804. {
  805.     alOut(alEffects, 0);
  806.     SDL_AlSetFXInst(&alZeroInst);
  807. }
  808.  
  809. ///////////////////////////////////////////////////////////////////////////
  810. //
  811. //      SDL_DetectAdLib() - Determines if there's an AdLib (or SoundBlaster
  812. //              emulating an AdLib) present
  813. //
  814. ///////////////////////////////////////////////////////////////////////////
  815. static boolean
  816. SDL_DetectAdLib(void)
  817. {
  818.     for (int i = 1; i <= 0xf5; i++)       // Zero all the registers
  819.         alOut(i, 0);
  820.  
  821.     alOut(1, 0x20);             // Set WSE=1
  822. //    alOut(8, 0);                // Set CSM=0 & SEL=0
  823.  
  824.     return true;
  825. }
  826.  
  827. ////////////////////////////////////////////////////////////////////////////
  828. //
  829. //      SDL_ShutDevice() - turns off whatever device was being used for sound fx
  830. //
  831. ////////////////////////////////////////////////////////////////////////////
  832. static void
  833. SDL_ShutDevice(void)
  834. {
  835.     switch (SoundMode)
  836.     {
  837.         case sdm_PC:
  838. //            SDL_ShutPC();
  839.             break;
  840.         case sdm_AdLib:
  841.             SDL_ShutAL();
  842.             break;
  843.     }
  844.     SoundMode = sdm_Off;
  845. }
  846.  
  847. ///////////////////////////////////////////////////////////////////////////
  848. //
  849. //      SDL_CleanDevice() - totally shuts down all sound devices
  850. //
  851. ///////////////////////////////////////////////////////////////////////////
  852. static void
  853. SDL_CleanDevice(void)
  854. {
  855.     if ((SoundMode == sdm_AdLib) || (MusicMode == smm_AdLib))
  856.         SDL_CleanAL();
  857. }
  858.  
  859. ///////////////////////////////////////////////////////////////////////////
  860. //
  861. //      SDL_StartDevice() - turns on whatever device is to be used for sound fx
  862. //
  863. ///////////////////////////////////////////////////////////////////////////
  864. static void
  865. SDL_StartDevice(void)
  866. {
  867.     switch (SoundMode)
  868.     {
  869.         case sdm_AdLib:
  870.             SDL_StartAL();
  871.             break;
  872.     }
  873.     SoundNumber = (soundnames) 0;
  874.     SoundPriority = 0;
  875. }
  876.  
  877. //      Public routines
  878.  
  879. ///////////////////////////////////////////////////////////////////////////
  880. //
  881. //      SD_SetSoundMode() - Sets which sound hardware to use for sound effects
  882. //
  883. ///////////////////////////////////////////////////////////////////////////
  884. boolean
  885. SD_SetSoundMode(SDMode mode)
  886. {
  887.     boolean result = false;
  888.     word    tableoffset;
  889.  
  890.     SD_StopSound();
  891.  
  892.     if ((mode == sdm_AdLib) && !AdLibPresent)
  893.         mode = sdm_PC;
  894.  
  895.     switch (mode)
  896.     {
  897.         case sdm_Off:
  898.             tableoffset = STARTADLIBSOUNDS;
  899.             result = true;
  900.             break;
  901.         case sdm_PC:
  902.             tableoffset = STARTPCSOUNDS;
  903.             result = true;
  904.             break;
  905.         case sdm_AdLib:
  906.             tableoffset = STARTADLIBSOUNDS;
  907.             if (AdLibPresent)
  908.                 result = true;
  909.             break;
  910.         default:
  911.             Quit("SD_SetSoundMode: Invalid sound mode %i", mode);
  912.             return false;
  913.     }
  914.     SoundTable = &audiosegs[tableoffset];
  915.  
  916.     if (result && (mode != SoundMode))
  917.     {
  918.         SDL_ShutDevice();
  919.         SoundMode = mode;
  920.         SDL_StartDevice();
  921.     }
  922.  
  923.     return(result);
  924. }
  925.  
  926. ///////////////////////////////////////////////////////////////////////////
  927. //
  928. //      SD_SetMusicMode() - sets the device to use for background music
  929. //
  930. ///////////////////////////////////////////////////////////////////////////
  931. boolean
  932. SD_SetMusicMode(SMMode mode)
  933. {
  934.     boolean result = false;
  935.  
  936.     SD_FadeOutMusic();
  937.     while (SD_MusicPlaying())
  938.         SDL_Delay(5);
  939.  
  940.     switch (mode)
  941.     {
  942.         case smm_Off:
  943.             result = true;
  944.             break;
  945.         case smm_AdLib:
  946.             if (AdLibPresent)
  947.                 result = true;
  948.             break;
  949.     }
  950.  
  951.     if (result)
  952.         MusicMode = mode;
  953.  
  954. //    SDL_SetTimerSpeed();
  955.  
  956.     return(result);
  957. }
  958.  
  959. int numreadysamples = 0;
  960. byte *curAlSound = 0;
  961. byte *curAlSoundPtr = 0;
  962. longword curAlLengthLeft = 0;
  963. int soundTimeCounter = 5;
  964. int samplesPerMusicTick;
  965.  
  966. void SDL_IMFMusicPlayer(void *udata, Uint8 *stream, int len)
  967. {
  968.     int stereolen = len>>1;
  969.     int sampleslen = stereolen>>1;
  970.     INT16 *stream16 = (INT16 *) (void *) stream;    // expect correct alignment
  971.  
  972.     while(1)
  973.     {
  974.         if(numreadysamples)
  975.         {
  976.             if(numreadysamples<sampleslen)
  977.             {
  978.                 YM3812UpdateOne(0, stream16, numreadysamples);
  979.                 stream16 += numreadysamples*2;
  980.                 sampleslen -= numreadysamples;
  981.             }
  982.             else
  983.             {
  984.                 YM3812UpdateOne(0, stream16, sampleslen);
  985.                 numreadysamples -= sampleslen;
  986.                 return;
  987.             }
  988.         }
  989.         soundTimeCounter--;
  990.         if(!soundTimeCounter)
  991.         {
  992.             soundTimeCounter = 5;
  993.             if(curAlSound != alSound)
  994.             {
  995.                 curAlSound = curAlSoundPtr = alSound;
  996.                 curAlLengthLeft = alLengthLeft;
  997.             }
  998.             if(curAlSound)
  999.             {
  1000.                 if(*curAlSoundPtr)
  1001.                 {
  1002.                     alOut(alFreqL, *curAlSoundPtr);
  1003.                     alOut(alFreqH, alBlock);
  1004.                 }
  1005.                 else alOut(alFreqH, 0);
  1006.                 curAlSoundPtr++;
  1007.                 curAlLengthLeft--;
  1008.                 if(!curAlLengthLeft)
  1009.                 {
  1010.                     curAlSound = alSound = 0;
  1011.                     SoundNumber = (soundnames) 0;
  1012.                     SoundPriority = 0;
  1013.                     alOut(alFreqH, 0);
  1014.                 }
  1015.             }
  1016.         }
  1017.         if(sqActive)
  1018.         {
  1019.             do
  1020.             {
  1021.                 if(sqHackTime > alTimeCount) break;
  1022.                 sqHackTime = alTimeCount + *(sqHackPtr+1);
  1023.                 alOut(*(byte *) sqHackPtr, *(((byte *) sqHackPtr)+1));
  1024.                 sqHackPtr += 2;
  1025.                 sqHackLen -= 4;
  1026.             }
  1027.             while(sqHackLen>0);
  1028.             alTimeCount++;
  1029.             if(!sqHackLen)
  1030.             {
  1031.                 sqHackPtr = sqHack;
  1032.                 sqHackLen = sqHackSeqLen;
  1033.                 sqHackTime = 0;
  1034.                 alTimeCount = 0;
  1035.             }
  1036.         }
  1037.         numreadysamples = samplesPerMusicTick;
  1038.     }
  1039. }
  1040.  
  1041. ///////////////////////////////////////////////////////////////////////////
  1042. //
  1043. //      SD_Startup() - starts up the Sound Mgr
  1044. //              Detects all additional sound hardware and installs my ISR
  1045. //
  1046. ///////////////////////////////////////////////////////////////////////////
  1047. void
  1048. SD_Startup(void)
  1049. {
  1050.     int     i;
  1051.  
  1052.     if (SD_Started)
  1053.         return;
  1054.  
  1055.     if(Mix_OpenAudio(param_samplerate, AUDIO_S16, 2, param_audiobuffer))
  1056.     {
  1057.         printf("Unable to open audio: %s\n", Mix_GetError());
  1058.         return;
  1059.     }
  1060.  
  1061.     Mix_ReserveChannels(2);  // reserve player and boss weapon channels
  1062.     Mix_GroupChannels(2, MIX_CHANNELS-1, 1); // group remaining channels
  1063.  
  1064.     // Init music
  1065.  
  1066.     samplesPerMusicTick = param_samplerate / 700;    // SDL_t0FastAsmService played at 700Hz
  1067.  
  1068.     if(YM3812Init(1,3579545,param_samplerate))
  1069.     {
  1070.         printf("Unable to create virtual OPL!!\n");
  1071.     }
  1072.  
  1073.     for(i=1;i<0xf6;i++)
  1074.         YM3812Write(0,i,0);
  1075.  
  1076.     YM3812Write(0,1,0x20); // Set WSE=1
  1077. //    YM3812Write(0,8,0); // Set CSM=0 & SEL=0           // already set in for statement
  1078.  
  1079.     Mix_HookMusic(SDL_IMFMusicPlayer, 0);
  1080.     Mix_ChannelFinished(SD_ChannelFinished);
  1081.     AdLibPresent = true;
  1082.     SoundBlasterPresent = true;
  1083.  
  1084.     alTimeCount = 0;
  1085.  
  1086.     SD_SetSoundMode(sdm_Off);
  1087.     SD_SetMusicMode(smm_Off);
  1088.  
  1089.     SDL_SetupDigi();
  1090.  
  1091.     SD_Started = true;
  1092. }
  1093.  
  1094. ///////////////////////////////////////////////////////////////////////////
  1095. //
  1096. //      SD_Shutdown() - shuts down the Sound Mgr
  1097. //              Removes sound ISR and turns off whatever sound hardware was active
  1098. //
  1099. ///////////////////////////////////////////////////////////////////////////
  1100. void
  1101. SD_Shutdown(void)
  1102. {
  1103.     if (!SD_Started)
  1104.         return;
  1105.  
  1106.     SD_MusicOff();
  1107.     SD_StopSound();
  1108.  
  1109.     for(int i = 0; i < STARTMUSIC - STARTDIGISOUNDS; i++)
  1110.     {
  1111.         if(SoundChunks[i]) Mix_FreeChunk(SoundChunks[i]);
  1112.         if(SoundBuffers[i]) free(SoundBuffers[i]);
  1113.     }
  1114.  
  1115.     free(DigiList);
  1116.  
  1117.     SD_Started = false;
  1118.     #ifdef _KOLIBRI
  1119.     Mix_CloseAudio();
  1120.     #endif
  1121. }
  1122.  
  1123. ///////////////////////////////////////////////////////////////////////////
  1124. //
  1125. //      SD_PositionSound() - Sets up a stereo imaging location for the next
  1126. //              sound to be played. Each channel ranges from 0 to 15.
  1127. //
  1128. ///////////////////////////////////////////////////////////////////////////
  1129. void
  1130. SD_PositionSound(int leftvol,int rightvol)
  1131. {
  1132.     LeftPosition = leftvol;
  1133.     RightPosition = rightvol;
  1134.     nextsoundpos = true;
  1135. }
  1136.  
  1137. ///////////////////////////////////////////////////////////////////////////
  1138. //
  1139. //      SD_PlaySound() - plays the specified sound on the appropriate hardware
  1140. //
  1141. ///////////////////////////////////////////////////////////////////////////
  1142. boolean
  1143. SD_PlaySound(soundnames sound)
  1144. {
  1145.     boolean         ispos;
  1146.     SoundCommon     *s;
  1147.     int             lp,rp;
  1148.  
  1149.     lp = LeftPosition;
  1150.     rp = RightPosition;
  1151.     LeftPosition = 0;
  1152.     RightPosition = 0;
  1153.  
  1154.     ispos = nextsoundpos;
  1155.     nextsoundpos = false;
  1156.  
  1157.     if (sound == -1 || (DigiMode == sds_Off && SoundMode == sdm_Off))
  1158.         return 0;
  1159.  
  1160.     s = (SoundCommon *) SoundTable[sound];
  1161.  
  1162.     if ((SoundMode != sdm_Off) && !s)
  1163.             Quit("SD_PlaySound() - Uncached sound");
  1164.  
  1165.     if ((DigiMode != sds_Off) && (DigiMap[sound] != -1))
  1166.     {
  1167.         if ((DigiMode == sds_PC) && (SoundMode == sdm_PC))
  1168.         {
  1169. #ifdef NOTYET
  1170.             if (s->priority < SoundPriority)
  1171.                 return 0;
  1172.  
  1173.             SDL_PCStopSound();
  1174.  
  1175.             SD_PlayDigitized(DigiMap[sound],lp,rp);
  1176.             SoundPositioned = ispos;
  1177.             SoundNumber = sound;
  1178.             SoundPriority = s->priority;
  1179. #else
  1180.             return 0;
  1181. #endif
  1182.         }
  1183.         else
  1184.         {
  1185. #ifdef NOTYET
  1186.             if (s->priority < DigiPriority)
  1187.                 return(false);
  1188. #endif
  1189.  
  1190.             int channel = SD_PlayDigitized(DigiMap[sound], lp, rp);
  1191.             SoundPositioned = ispos;
  1192.             DigiNumber = sound;
  1193.             DigiPriority = s->priority;
  1194.             return channel + 1;
  1195.         }
  1196.  
  1197.         return(true);
  1198.     }
  1199.  
  1200.     if (SoundMode == sdm_Off)
  1201.         return 0;
  1202.  
  1203.     if (!s->length)
  1204.         Quit("SD_PlaySound() - Zero length sound");
  1205.     if (s->priority < SoundPriority)
  1206.         return 0;
  1207.  
  1208.     switch (SoundMode)
  1209.     {
  1210.         case sdm_PC:
  1211. //            SDL_PCPlaySound((PCSound *)s);
  1212.             break;
  1213.         case sdm_AdLib:
  1214.             SDL_ALPlaySound((AdLibSound *)s);
  1215.             break;
  1216.     }
  1217.  
  1218.     SoundNumber = sound;
  1219.     SoundPriority = s->priority;
  1220.  
  1221.     return 0;
  1222. }
  1223.  
  1224. ///////////////////////////////////////////////////////////////////////////
  1225. //
  1226. //      SD_SoundPlaying() - returns the sound number that's playing, or 0 if
  1227. //              no sound is playing
  1228. //
  1229. ///////////////////////////////////////////////////////////////////////////
  1230.  
  1231. word
  1232. SD_SoundPlaying(void)
  1233. {
  1234.     boolean result = false;
  1235.  
  1236.     switch (SoundMode)
  1237.     {
  1238.         case sdm_PC:
  1239.             result = pcSound? true : false;
  1240.             break;
  1241.         case sdm_AdLib:
  1242.             result = alSound? true : false;
  1243.             break;
  1244.     }
  1245.  
  1246.     if (result)
  1247.         return(SoundNumber);
  1248.     else
  1249.         return(false);
  1250. }
  1251.  
  1252. ///////////////////////////////////////////////////////////////////////////
  1253. //
  1254. //      SD_StopSound() - if a sound is playing, stops it
  1255. //
  1256. ///////////////////////////////////////////////////////////////////////////
  1257. void
  1258. SD_StopSound(void)
  1259. {
  1260.     if (DigiPlaying)
  1261.         SD_StopDigitized();
  1262.  
  1263.     switch (SoundMode)
  1264.     {
  1265.         case sdm_PC:
  1266. //            SDL_PCStopSound();
  1267.             break;
  1268.         case sdm_AdLib:
  1269.             SDL_ALStopSound();
  1270.             break;
  1271.     }
  1272.  
  1273.     SoundPositioned = false;
  1274.  
  1275.     SDL_SoundFinished();
  1276. }
  1277.  
  1278. ///////////////////////////////////////////////////////////////////////////
  1279. //
  1280. //      SD_WaitSoundDone() - waits until the current sound is done playing
  1281. //
  1282. ///////////////////////////////////////////////////////////////////////////
  1283. void
  1284. SD_WaitSoundDone(void)
  1285. {
  1286.     while (SD_SoundPlaying())
  1287.         SDL_Delay(5);
  1288. }
  1289.  
  1290. ///////////////////////////////////////////////////////////////////////////
  1291. //
  1292. //      SD_MusicOn() - turns on the sequencer
  1293. //
  1294. ///////////////////////////////////////////////////////////////////////////
  1295. void
  1296. SD_MusicOn(void)
  1297. {
  1298.     sqActive = true;
  1299. }
  1300.  
  1301. ///////////////////////////////////////////////////////////////////////////
  1302. //
  1303. //      SD_MusicOff() - turns off the sequencer and any playing notes
  1304. //      returns the last music offset for music continue
  1305. //
  1306. ///////////////////////////////////////////////////////////////////////////
  1307. int
  1308. SD_MusicOff(void)
  1309. {
  1310.     word    i;
  1311.  
  1312.     sqActive = false;
  1313.     switch (MusicMode)
  1314.     {
  1315.         case smm_AdLib:
  1316.             alOut(alEffects, 0);
  1317.             for (i = 0;i < sqMaxTracks;i++)
  1318.                 alOut(alFreqH + i + 1, 0);
  1319.             break;
  1320.     }
  1321.  
  1322.     return (int) (sqHackPtr-sqHack);
  1323. }
  1324.  
  1325. ///////////////////////////////////////////////////////////////////////////
  1326. //
  1327. //      SD_StartMusic() - starts playing the music pointed to
  1328. //
  1329. ///////////////////////////////////////////////////////////////////////////
  1330. void
  1331. SD_StartMusic(int chunk)
  1332. {
  1333.     SD_MusicOff();
  1334.  
  1335.     if (MusicMode == smm_AdLib)
  1336.     {
  1337.         int32_t chunkLen = CA_CacheAudioChunk(chunk);
  1338.         sqHack = (word *)(void *) audiosegs[chunk];     // alignment is correct
  1339.         if(*sqHack == 0) sqHackLen = sqHackSeqLen = chunkLen;
  1340.         else sqHackLen = sqHackSeqLen = *sqHack++;
  1341.         sqHackPtr = sqHack;
  1342.         sqHackTime = 0;
  1343.         alTimeCount = 0;
  1344.         SD_MusicOn();
  1345.     }
  1346. }
  1347.  
  1348. void
  1349. SD_ContinueMusic(int chunk, int startoffs)
  1350. {
  1351.     SD_MusicOff();
  1352.  
  1353.     if (MusicMode == smm_AdLib)
  1354.     {
  1355.         int32_t chunkLen = CA_CacheAudioChunk(chunk);
  1356.         sqHack = (word *)(void *) audiosegs[chunk];     // alignment is correct
  1357.         if(*sqHack == 0) sqHackLen = sqHackSeqLen = chunkLen;
  1358.         else sqHackLen = sqHackSeqLen = *sqHack++;
  1359.         sqHackPtr = sqHack;
  1360.  
  1361.         if(startoffs >= sqHackLen)
  1362.         {
  1363.             Quit("SD_StartMusic: Illegal startoffs provided!");
  1364.         }
  1365.  
  1366.         // fast forward to correct position
  1367.         // (needed to reconstruct the instruments)
  1368.  
  1369.         for(int i = 0; i < startoffs; i += 2)
  1370.         {
  1371.             byte reg = *(byte *)sqHackPtr;
  1372.             byte val = *(((byte *)sqHackPtr) + 1);
  1373.             if(reg >= 0xb1 && reg <= 0xb8) val &= 0xdf;           // disable play note flag
  1374.             else if(reg == 0xbd) val &= 0xe0;                     // disable drum flags
  1375.  
  1376.             alOut(reg,val);
  1377.             sqHackPtr += 2;
  1378.             sqHackLen -= 4;
  1379.         }
  1380.         sqHackTime = 0;
  1381.         alTimeCount = 0;
  1382.  
  1383.         SD_MusicOn();
  1384.     }
  1385. }
  1386.  
  1387. ///////////////////////////////////////////////////////////////////////////
  1388. //
  1389. //      SD_FadeOutMusic() - starts fading out the music. Call SD_MusicPlaying()
  1390. //              to see if the fadeout is complete
  1391. //
  1392. ///////////////////////////////////////////////////////////////////////////
  1393. void
  1394. SD_FadeOutMusic(void)
  1395. {
  1396.     switch (MusicMode)
  1397.     {
  1398.         case smm_AdLib:
  1399.             // DEBUG - quick hack to turn the music off
  1400.             SD_MusicOff();
  1401.             break;
  1402.     }
  1403. }
  1404.  
  1405. ///////////////////////////////////////////////////////////////////////////
  1406. //
  1407. //      SD_MusicPlaying() - returns true if music is currently playing, false if
  1408. //              not
  1409. //
  1410. ///////////////////////////////////////////////////////////////////////////
  1411. boolean
  1412. SD_MusicPlaying(void)
  1413. {
  1414.     boolean result;
  1415.  
  1416.     switch (MusicMode)
  1417.     {
  1418.         case smm_AdLib:
  1419.             result = sqActive;
  1420.             break;
  1421.         default:
  1422.             result = false;
  1423.             break;
  1424.     }
  1425.  
  1426.     return(result);
  1427. }
  1428.