home *** CD-ROM | disk | FTP | other *** search
/ Large Pack of OldSkool DOS MOD Trackers / goattracker_2.73.zip / src / bme / bme_snd.c < prev    next >
Encoding:
C/C++ Source or Header  |  2014-07-23  |  16.8 KB  |  542 lines

  1. //
  2. // BME (Blasphemous Multimedia Engine) sound main module
  3. //
  4.  
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <stdio.h>
  8.  
  9. #include <SDL/SDL.h>
  10. #include "bme_main.h"
  11. #include "bme_cfg.h"
  12. #include "bme_win.h"
  13. #include "bme_io.h"
  14. #include "bme_err.h"
  15.  
  16. // Prototypes
  17. int snd_init(unsigned mixrate, unsigned mixmode, unsigned bufferlength, unsigned channels, int usedirectsound);
  18. void snd_uninit(void);
  19. void snd_setcustommixer(void (*custommixer)(Sint32 *dest, unsigned samples));
  20. static int snd_initmixer(void);
  21. static void snd_uninitmixer(void);
  22. static void snd_mixdata(Uint8 *dest, unsigned bytes);
  23. static void snd_mixchannels(Sint32 *dest, unsigned samples);
  24. static void snd_mixer(void *userdata, Uint8 *stream, int len);
  25.  
  26. // Lowlevel mixing functions
  27. static void snd_clearclipbuffer(Sint32 *clipbuffer, unsigned clipsamples);
  28. static void snd_mixchannel(CHANNEL *chptr, Sint32 *dest, unsigned samples);
  29. static void snd_16bit_postprocess(Sint32 *src, Sint16 *dest, unsigned samples);
  30. static void snd_8bit_postprocess(Sint32 *src, Uint8 *dest, unsigned samples);
  31.  
  32. void (*snd_player)(void) = NULL;
  33. CHANNEL *snd_channel = NULL;
  34. int snd_channels = 0;
  35. int snd_sndinitted = 0;
  36. int snd_bpmcount;
  37. int snd_bpmtempo = 125;
  38. unsigned snd_mixmode;
  39. unsigned snd_mixrate;
  40.  
  41. static void (*snd_custommixer)(Sint32 *dest, unsigned samples) = NULL;
  42. static unsigned snd_buffersize;
  43. static unsigned snd_samplesize;
  44. static unsigned snd_previouschannels = 0xffffffff;
  45. static int snd_atexit_registered = 0;
  46. static Sint32 *snd_clipbuffer = NULL;
  47. static SDL_AudioSpec desired;
  48. static SDL_AudioSpec obtained;
  49.  
  50. int snd_init(unsigned mixrate, unsigned mixmode, unsigned bufferlength, unsigned channels, int usedirectsound)
  51. {
  52.     int c;
  53.  
  54.     // Register snd_uninit as an atexit function
  55.  
  56.     if (!snd_atexit_registered)
  57.     {
  58.         atexit(snd_uninit);
  59.         snd_atexit_registered = 1;
  60.     }
  61.  
  62.     // If user wants to re-initialize, shutdown first
  63.  
  64.     snd_uninit();
  65.  
  66.     // Check for illegal config
  67.  
  68.     if ((channels < 1) || (!mixrate) || (!bufferlength))
  69.     {
  70.         bme_error = BME_ILLEGAL_CONFIG;
  71.         snd_uninit();
  72.         return BME_ERROR;
  73.     }
  74.  
  75.     desired.freq = mixrate;
  76.     desired.format = AUDIO_U8;
  77.     if (mixmode & SIXTEENBIT)
  78.     {
  79.         desired.format = AUDIO_S16SYS;
  80.     }
  81.     desired.channels = 1;
  82.     if (mixmode & STEREO) desired.channels = 2;
  83.     desired.samples = bufferlength * mixrate / 1000;
  84.     {
  85.         int bits = 0;
  86.  
  87.         for (;;)
  88.         {
  89.             desired.samples >>= 1;
  90.             if (!desired.samples) break;
  91.             bits++;
  92.         }
  93.         desired.samples = 1 << bits;    
  94.     }
  95.  
  96.     desired.callback = snd_mixer;
  97.     desired.userdata = NULL;
  98.  
  99.     // Init tempo count
  100.  
  101.     snd_bpmcount = 0;
  102.  
  103.     // (Re)allocate channels if necessary
  104.  
  105.     if (snd_previouschannels != channels)
  106.     {
  107.         CHANNEL *chptr;
  108.         if (snd_channel)
  109.         {
  110.             free(snd_channel);
  111.             snd_channel = NULL;
  112.             snd_channels = 0;
  113.         }
  114.  
  115.         snd_channel = malloc(channels * sizeof(CHANNEL));
  116.         if (!snd_channel)
  117.         {
  118.             bme_error = BME_OUT_OF_MEMORY;
  119.             snd_uninit();
  120.             return BME_ERROR;
  121.         }
  122.         chptr = &snd_channel[0];
  123.         snd_channels = channels;
  124.         snd_previouschannels = channels;
  125.  
  126.         // Init all channels (no sound played, no sample, mastervolume 64)
  127.         for (c = snd_channels; c > 0; c--)
  128.         {
  129.             chptr->voicemode = VM_OFF;
  130.             chptr->smp = NULL;
  131.             chptr->mastervol = 64;
  132.             chptr++;
  133.         }
  134.     }
  135.  
  136.     SDL_PauseAudio(1);
  137.  
  138.     if (SDL_OpenAudio(&desired, &obtained))
  139.     {
  140.         bme_error = BME_OPEN_ERROR;
  141.         snd_uninit();
  142.         return BME_ERROR;
  143.     }
  144.     snd_sndinitted = 1;
  145.  
  146.     snd_mixmode = 0;
  147.     snd_samplesize = 1;
  148.     if (obtained.channels == 2)
  149.     {
  150.         snd_mixmode |= STEREO;
  151.         snd_samplesize <<= 1;
  152.     }
  153.     if ((obtained.format == AUDIO_S16SYS) ||
  154.        (obtained.format == AUDIO_S16LSB) ||
  155.        (obtained.format == AUDIO_S16MSB))
  156.     {
  157.         snd_mixmode |= SIXTEENBIT;
  158.         snd_samplesize <<= 1;
  159.     }
  160.     snd_buffersize = obtained.size;
  161.     snd_mixrate = obtained.freq;
  162.  
  163.     // Allocate mixer tables
  164.  
  165.     if (!snd_initmixer())
  166.     {
  167.         bme_error = BME_OUT_OF_MEMORY;
  168.         snd_uninit();
  169.         return BME_ERROR;
  170.     }
  171.  
  172.     SDL_PauseAudio(0);
  173.  
  174.     bme_error = BME_OK;
  175.     return BME_OK;
  176. }
  177.  
  178. void snd_uninit(void)
  179. {
  180.     if (snd_sndinitted)
  181.     {
  182.         SDL_CloseAudio();
  183.         snd_sndinitted = 0;
  184.     }
  185.     snd_uninitmixer();
  186. }
  187.  
  188. void snd_setcustommixer(void (*custommixer)(Sint32 *dest, unsigned samples))
  189. {
  190.     snd_custommixer = custommixer;
  191. }
  192.  
  193. static int snd_initmixer(void)
  194. {
  195.     snd_uninitmixer();
  196.  
  197.     if (snd_mixmode & STEREO)
  198.     {
  199.         snd_clipbuffer = malloc((snd_buffersize / snd_samplesize) * sizeof(int) * 2);
  200.     }
  201.     else
  202.     {
  203.         snd_clipbuffer = malloc((snd_buffersize / snd_samplesize) * sizeof(int));
  204.     }
  205.     if (!snd_clipbuffer) return 0;
  206.  
  207.     return 1;
  208. }
  209.  
  210. static void snd_uninitmixer(void)
  211. {
  212.     if (snd_clipbuffer)
  213.     {
  214.         free(snd_clipbuffer);
  215.         snd_clipbuffer = NULL;
  216.     }
  217. }
  218.  
  219. static void snd_mixer(void *userdata, Uint8 *stream, int len)
  220. {
  221.     snd_mixdata(stream, len);
  222. }
  223.  
  224. static void snd_mixdata(Uint8 *dest, unsigned bytes)
  225. {
  226.     unsigned mixsamples = bytes;
  227.     unsigned clipsamples = bytes;
  228.     Sint32 *clipptr = (Sint32 *)snd_clipbuffer;
  229.     if (snd_mixmode & STEREO) mixsamples >>= 1;
  230.     if (snd_mixmode & SIXTEENBIT)
  231.     {
  232.         clipsamples >>= 1;
  233.         mixsamples >>= 1;
  234.     }
  235.     snd_clearclipbuffer(snd_clipbuffer, clipsamples);
  236.     if (snd_player) // Must the player be called?
  237.     {
  238.         int musicsamples;
  239.  
  240.         while(mixsamples)
  241.         {
  242.             if ((!snd_bpmcount) && (snd_player)) // Player still active?
  243.             {
  244.                 // Call player
  245.                 snd_player();
  246.                 // Reset tempocounter
  247.                 snd_bpmcount = ((snd_mixrate * 5) >> 1) / snd_bpmtempo;
  248.             }
  249.  
  250.             musicsamples = mixsamples;
  251.             if (musicsamples > snd_bpmcount) musicsamples = snd_bpmcount;
  252.             snd_bpmcount -= musicsamples;
  253.             if (!snd_custommixer)
  254.             {
  255.                 snd_mixchannels(clipptr, musicsamples);
  256.             }
  257.             else
  258.             {
  259.                 snd_custommixer(clipptr, musicsamples);
  260.             }
  261.             if (snd_mixmode & STEREO) clipptr += musicsamples * 2;
  262.             else clipptr += musicsamples;
  263.             mixsamples -= musicsamples;
  264.         }
  265.     }
  266.     else
  267.     {
  268.         if (!snd_custommixer)
  269.         {
  270.             snd_mixchannels(clipptr, mixsamples);
  271.         }
  272.         else
  273.         {
  274.             snd_custommixer(clipptr, mixsamples);
  275.         }
  276.     }
  277.  
  278.     clipptr = (Sint32 *)snd_clipbuffer;
  279.     if (snd_mixmode & SIXTEENBIT)
  280.     {
  281.         snd_16bit_postprocess(clipptr, (Sint16 *)dest, clipsamples);
  282.     }
  283.     else
  284.     {
  285.         snd_8bit_postprocess(clipptr, dest, clipsamples);
  286.     }
  287. }
  288.  
  289. static void snd_mixchannels(Sint32 *dest, unsigned samples)
  290. {
  291.     CHANNEL *chptr = &snd_channel[0];
  292.     int c;
  293.  
  294.     for (c = snd_channels; c; c--)
  295.     {
  296.         snd_mixchannel(chptr, dest, samples);
  297.         chptr++;
  298.     }
  299. }
  300.  
  301. static void snd_clearclipbuffer(Sint32 *clipbuffer, unsigned clipsamples)
  302. {
  303.     memset(clipbuffer, 0, clipsamples*sizeof(int));
  304. }
  305.  
  306. static void snd_16bit_postprocess(Sint32 *src, Sint16 *dest, unsigned samples)
  307. {
  308.     while (samples--)
  309.     {
  310.         int sample = *src++;
  311.         if (sample > 32767) sample = 32767;
  312.         if (sample < -32768) sample = -32768;
  313.         *dest++ = sample;
  314.     }
  315. }
  316.  
  317. static void snd_8bit_postprocess(Sint32 *src, Uint8 *dest, unsigned samples)
  318. {
  319.     while (samples--)
  320.     {
  321.           int sample = *src++;
  322.           if (sample > 32767) sample = 32767;
  323.           if (sample < -32768) sample = -32768;
  324.           *dest++ = (sample >> 8) + 128;
  325.     }
  326. }
  327.  
  328. static void snd_mixchannel(CHANNEL *chptr, Sint32 *dest, unsigned samples)
  329. {
  330.     if (chptr->voicemode & VM_ON)
  331.     {
  332.           unsigned freq, intadd, fractadd;
  333.  
  334.           freq = chptr->freq;
  335.           if (freq > 535232) freq = 535232;
  336.           intadd = freq / snd_mixrate;
  337.           fractadd = (((freq % snd_mixrate) << 16) / snd_mixrate) & 65535;
  338.  
  339.           if (snd_mixmode & STEREO)
  340.           {
  341.                 int leftvol = (((chptr->vol * chptr->mastervol) >> 6) * (255-chptr->panning)) >> 7;
  342.                 int rightvol = (((chptr->vol * chptr->mastervol) >> 6) * (chptr->panning)) >> 7;
  343.                 if (leftvol > 255) leftvol = 255;
  344.                 if (rightvol > 255) rightvol = 255;
  345.                 if (leftvol < 0) leftvol = 0;
  346.                 if (rightvol < 0) rightvol = 0;
  347.  
  348.                 if (chptr->voicemode & VM_16BIT)
  349.                 {
  350.                     Sint16 *pos = (Sint16 *)chptr->pos;
  351.                     Sint16 *end = (Sint16 *)chptr->end;
  352.                     Sint16 *repeat = (Sint16 *)chptr->repeat;
  353.  
  354.                     if (chptr->voicemode & VM_LOOP)
  355.                     {
  356.                           while (samples--)
  357.                           {
  358.                                 *dest = *dest + ((*pos * leftvol) >> 8);
  359.                                 dest++;
  360.                                 *dest = *dest + ((*pos * rightvol) >> 8);
  361.                                 dest++;
  362.                                 chptr->fractpos += fractadd;
  363.                                 if (chptr->fractpos > 65535)
  364.                                 {
  365.                                     chptr->fractpos &= 65535;
  366.                                     pos++;
  367.                                 }
  368.                                 pos += intadd;
  369.                                 while (pos >= end) pos -= (end - repeat);
  370.                           }
  371.                     }
  372.                     else
  373.                     {
  374.                           while (samples--)
  375.                           {
  376.                                 *dest = *dest + ((*pos * leftvol) >> 8);
  377.                                 dest++;
  378.                                 *dest = *dest + ((*pos * rightvol) >> 8);
  379.                                 dest++;
  380.                                 chptr->fractpos += fractadd;
  381.                                 if (chptr->fractpos > 65535)
  382.                                 {
  383.                                     chptr->fractpos &= 65535;
  384.                                     pos++;
  385.                                 }
  386.                                 pos += intadd;
  387.                                 if (pos >= end)
  388.                                 {
  389.                                     chptr->voicemode &= ~VM_ON;
  390.                                     break;
  391.                                 }
  392.                           }
  393.                     }
  394.                     chptr->pos = (Sint8 *)pos;
  395.                 }
  396.                 else
  397.                 {
  398.                     Sint8 *pos = (Sint8 *)chptr->pos;
  399.                     Sint8 *end = chptr->end;
  400.                     Sint8 *repeat = chptr->repeat;
  401.  
  402.                     if (chptr->voicemode & VM_LOOP)
  403.                     {
  404.                           while (samples--)
  405.                           {
  406.                                 *dest = *dest + (*pos * leftvol);
  407.                                 dest++;
  408.                                 *dest = *dest + (*pos * rightvol);
  409.                                 dest++;
  410.                                 chptr->fractpos += fractadd;
  411.                                 if (chptr->fractpos > 65535)
  412.                                 {
  413.                                     chptr->fractpos &= 65535;
  414.                                     pos++;
  415.                                 }
  416.                                 pos += intadd;
  417.                                 while (pos >= end) pos -= (end - repeat);
  418.                           }
  419.                     }
  420.                     else
  421.                     {
  422.                           while (samples--)
  423.                           {
  424.                                 *dest = *dest + (*pos * leftvol);
  425.                                 dest++;
  426.                                 *dest = *dest + (*pos * rightvol);
  427.                                 dest++;
  428.                                 chptr->fractpos += fractadd;
  429.                                 if (chptr->fractpos > 65535)
  430.                                 {
  431.                                     chptr->fractpos &= 65535;
  432.                                     pos++;
  433.                                 }
  434.                                 pos += intadd;
  435.                                 if (pos >= end)
  436.                                 {
  437.                                     chptr->voicemode &= ~VM_ON;
  438.                                     break;
  439.                                 }
  440.                           }
  441.                     }
  442.                     chptr->pos = (Sint8 *)pos;
  443.                 }
  444.           }
  445.           else
  446.           {
  447.                 int vol = ((chptr->vol * chptr->mastervol) >> 6);
  448.                 if (vol > 255) vol = 255;
  449.                 if (vol < 0) vol = 0;
  450.  
  451.                 if (chptr->voicemode & VM_16BIT)
  452.                 {
  453.                     Sint16 *pos = (Sint16 *)chptr->pos;
  454.                     Sint16 *end = (Sint16 *)chptr->end;
  455.                     Sint16 *repeat = (Sint16 *)chptr->repeat;
  456.  
  457.                     if (chptr->voicemode & VM_LOOP)
  458.                     {
  459.                           while (samples--)
  460.                           {
  461.                                 *dest = *dest + ((*pos * vol) >> 8);
  462.                                 dest++;
  463.                                 chptr->fractpos += fractadd;
  464.                                 if (chptr->fractpos > 65535)
  465.                                 {
  466.                                     chptr->fractpos &= 65535;
  467.                                     pos++;
  468.                                 }
  469.                                 pos += intadd;
  470.                                 while (pos >= end) pos -= (end - repeat);
  471.                           }
  472.                     }
  473.                     else
  474.                     {
  475.                           while (samples--)
  476.                           {
  477.                                 *dest = *dest + ((*pos * vol) >> 8);
  478.                                 dest++;
  479.                                 chptr->fractpos += fractadd;
  480.                                 if (chptr->fractpos > 65535)
  481.                                 {
  482.                                     chptr->fractpos &= 65535;
  483.                                     pos++;
  484.                                 }
  485.                                 pos += intadd;
  486.                                 if (pos >= end)
  487.                                 {
  488.                                     chptr->voicemode &= ~VM_ON;
  489.                                     break;
  490.                                 }
  491.                           }
  492.                     }
  493.                     chptr->pos = (Sint8 *)pos;
  494.                 }
  495.                 else
  496.                 {
  497.                     Sint8 *pos = (Sint8 *)chptr->pos;
  498.                     Sint8 *end = chptr->end;
  499.                     Sint8 *repeat = chptr->repeat;
  500.  
  501.                     if (chptr->voicemode & VM_LOOP)
  502.                     {
  503.                           while (samples--)
  504.                           {
  505.                                 *dest = *dest + (*pos * vol);
  506.                                 dest++;
  507.                                 chptr->fractpos += fractadd;
  508.                                 if (chptr->fractpos > 65535)
  509.                                 {
  510.                                     chptr->fractpos &= 65535;
  511.                                     pos++;
  512.                                 }
  513.                                 pos += intadd;
  514.                                 while (pos >= end) pos -= (end - repeat);
  515.                           }
  516.                     }
  517.                     else
  518.                     {
  519.                           while (samples--)
  520.                           {
  521.                                 *dest = *dest + (*pos * vol);
  522.                                 dest++;
  523.                                 chptr->fractpos += fractadd;
  524.                                 if (chptr->fractpos > 65535)
  525.                                 {
  526.                                     chptr->fractpos &= 65535;
  527.                                     pos++;
  528.                                 }
  529.                                 pos += intadd;
  530.                                 if (pos >= end)
  531.                                 {
  532.                                     chptr->voicemode &= ~VM_ON;
  533.                                     break;
  534.                                 }
  535.                           }
  536.                     }
  537.                     chptr->pos = (Sint8 *)pos;
  538.                 }
  539.           }
  540.     }
  541. }
  542.