Advertisement
Kitomas

2024-07-19 (4/13)

Jul 19th, 2024
152
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 35.61 KB | None | 0 0
  1. /******************************************************************************/
  2. /******************************************************************************/
  3. //"kit_xmp_sfx\main.cpp":
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <math.h>
  7.  
  8. #include <kit/all.hpp>
  9. #include <kit/xmp_sfx.hpp>
  10.  
  11. using namespace kit;
  12.  
  13.  
  14. f32 randf(){
  15.   u32 value = ((u32)rand())<<15 | rand();
  16.   return (f32)value/(KIT_U32_MAX>>2);
  17. }
  18.  
  19.  
  20. #define winSize 600
  21. #define canvasSize 300
  22. #define in_bounds(_e_mouse) (\
  23.   (_e_mouse.x >=      0) &&\
  24.   (_e_mouse.y >=      0) &&\
  25.   (_e_mouse.x < winSize) &&\
  26.   (_e_mouse.y < winSize)   \
  27. )
  28.  
  29. //crashes sometimes
  30. int main(int argc, char** argv){ try {
  31.   srand((u32)time::getTicks());
  32.  
  33.  
  34.   Window win("left click to change the music's volume/pan settings, right click to play a sound effect",
  35.              winSize, winSize, WINFLAG_REM_MAXIMIZE | WINFLAG_REM_MINIMIZE,
  36.              WINPOS_CENTERED, WINPOS_CENTERED, canvasSize, canvasSize);
  37.  
  38.   BitmapFont _text("_font8x8.qoi", &win);
  39.   FStr _fstr(512);
  40.   #define textf(_x, _y, _fmt, ...) \
  41.     _text.print(_x,_y, _fstr.fmt(_fmt, __VA_ARGS__), 0);
  42.  
  43.  
  44.   SoundEngine* snd = new SoundEngine(64, false);
  45.   snd->streamStartAndWait();
  46.   //snd->musicLoadModule("2ND_PM.S3M");
  47.   snd->musicLoadModule("tao tao.xm");
  48.   snd->musicSetVolume(0.2f,0.2f);
  49.   snd->musicStart();
  50.  
  51.   AudioData kameria("kameria-se.qoa", snd);
  52.   snd->sfxSetVolumeAll(0.67f, 0.67f);
  53.   kameria.volumeL = 0.1f; //test of AudioData master volume
  54.   kameria.volumeR = 0.1f;
  55.  
  56.  
  57.   bool run = true;
  58.   _before_loop:
  59.   while(run){
  60.  
  61.     WindowEvent e;
  62.     while(pollWindowEvent(&e)){
  63.       switch(e.type){
  64.         case WINEVENT_WIN_CLOSE: run = false; goto _before_loop;
  65.  
  66.         case WINEVENT_MOUSE_MOVE: {
  67.           if(e.mouse.button&MBUTTON_LEFT && in_bounds(e.mouse)){
  68.             f32 pan = ((f32)e.mouse.x/winSize)*2.0f - 1.0f;
  69.             f32 vol = 0.5f-((f32)e.mouse.y/winSize)*0.5f;
  70.             snd->musicSetPan(pan);
  71.             snd->musicSetVolume(vol,vol);
  72.             //snd->musicSetVolumeForced(vol,vol);
  73.           }
  74.         } break;
  75.  
  76.         case WINEVENT_MOUSE_DOWN: {
  77.           if(e.mouse.button&MBUTTON_RIGHT && in_bounds(e.mouse)){
  78.             f64 audioSpeed = 2.0 - ((f64)e.mouse.y/winSize)*2.0;
  79.             snd->sfxPlay(&kameria, 1,1, audioSpeed, 0);
  80.           }
  81.         } break;
  82.  
  83.       }
  84.     }
  85.  
  86.     f64 cpu_load = snd->streamGetCPULoad();
  87.     u32 active_tracks = snd->sfxGetActiveTracks();
  88.  
  89.     win.clear();
  90.     textf(1,1, "audio's CPU load = %4.2f%%\nactive sfx tracks = %u/64", cpu_load*100, active_tracks);
  91.     win.present();
  92.  
  93.     time::sleep(10);
  94.   }
  95.  
  96.  
  97.   snd->sfxStopAll();
  98.   snd->musicStopAndWait();
  99.   time::sleep(75);
  100.  
  101.  
  102.   printf("%llu,",memory::getNumAllocations());
  103.   MutexSimple* mutex = new MutexSimple;
  104.   printf("%llu,",memory::getNumAllocations());
  105.   delete mutex;
  106.   printf("%llu\n",memory::getNumAllocations());
  107.  
  108.   AudioData* sndfx = new AudioData("kameria-se.qoa", snd);
  109.   printf("%llu,",memory::getNumAllocations());
  110.   delete sndfx;
  111.   printf("%llu\n",memory::getNumAllocations());
  112.  
  113.  
  114.   return 0;
  115.  
  116. } catch(const char* errorText){
  117. #ifdef _DEBUG
  118.   printf("FATAL EXCEPTION OCCERRED!: \"%s\"\n", errorText);
  119. #else
  120.   showMessageBox(errorText, "FATAL EXCEPTION OCCURRED! COMPLAIN TO THE DEV! (lol)", MSGBOX_ICN_ERROR);
  121. #endif
  122.   return -1;
  123. }}
  124.  
  125. /******************************************************************************/
  126. /******************************************************************************/
  127. //"kit_xmp_sfx\src\main.cpp":
  128. #include <stdio.h>
  129. #include <stdlib.h>
  130. #include <math.h>
  131.  
  132. #include <kit/all.hpp>
  133. #include <kit/xmp_sfx.hpp>
  134.  
  135. using namespace kit;
  136.  
  137.  
  138. f32 randf(){
  139.   u32 value = ((u32)rand())<<15 | rand();
  140.   return (f32)value/(KIT_U32_MAX>>2);
  141. }
  142.  
  143.  
  144. #define winSize 600
  145. #define canvasSize 300
  146. #define in_bounds(_e_mouse) (\
  147.   (_e_mouse.x >=      0) &&\
  148.   (_e_mouse.y >=      0) &&\
  149.   (_e_mouse.x < winSize) &&\
  150.   (_e_mouse.y < winSize)   \
  151. )
  152.  
  153. //crashes sometimes
  154. int main(int argc, char** argv){ try {
  155.   srand((u32)time::getTicks());
  156.  
  157.  
  158.   Window win("left click to change the music's volume/pan settings, right click to play a sound effect",
  159.              winSize, winSize, WINFLAG_REM_MAXIMIZE | WINFLAG_REM_MINIMIZE,
  160.              WINPOS_CENTERED, WINPOS_CENTERED, canvasSize, canvasSize);
  161.  
  162.   BitmapFont _text("_font8x8.qoi", &win);
  163.   FStr _fstr(512);
  164.   #define textf(_x, _y, _fmt, ...) \
  165.     _text.print(_x,_y, _fstr.fmt(_fmt, __VA_ARGS__), 0);
  166.  
  167.  
  168.   SoundEngine* snd = new SoundEngine(64, false);
  169.   snd->streamStartAndWait();
  170.   //snd->musicLoadModule("2ND_PM.S3M");
  171.   snd->musicLoadModule("tao tao.xm");
  172.   snd->musicSetVolume(0.2f,0.2f);
  173.   snd->musicStart();
  174.  
  175.   AudioData kameria("kameria-se.qoa", snd);
  176.   snd->sfxSetVolumeAll(0.67f, 0.67f);
  177.   kameria.volumeL = 0.1f; //test of AudioData master volume
  178.   kameria.volumeR = 0.1f;
  179.  
  180.  
  181.   bool run = true;
  182.   _before_loop:
  183.   while(run){
  184.  
  185.     WindowEvent e;
  186.     while(pollWindowEvent(&e)){
  187.       switch(e.type){
  188.         case WINEVENT_WIN_CLOSE: run = false; goto _before_loop;
  189.  
  190.         case WINEVENT_MOUSE_MOVE: {
  191.           if(e.mouse.button&MBUTTON_LEFT && in_bounds(e.mouse)){
  192.             f32 pan = ((f32)e.mouse.x/winSize)*2.0f - 1.0f;
  193.             f32 vol = 0.5f-((f32)e.mouse.y/winSize)*0.5f;
  194.             snd->musicSetPan(pan);
  195.             snd->musicSetVolume(vol,vol);
  196.             //snd->musicSetVolumeForced(vol,vol);
  197.           }
  198.         } break;
  199.  
  200.         case WINEVENT_MOUSE_DOWN: {
  201.           if(e.mouse.button&MBUTTON_RIGHT && in_bounds(e.mouse)){
  202.             f64 audioSpeed = 2.0 - ((f64)e.mouse.y/winSize)*2.0;
  203.             snd->sfxPlay(&kameria, 1,1, audioSpeed, 0);
  204.           }
  205.         } break;
  206.  
  207.       }
  208.     }
  209.  
  210.     f64 cpu_load = snd->streamGetCPULoad();
  211.     u32 active_tracks = snd->sfxGetActiveTracks();
  212.  
  213.     win.clear();
  214.     textf(1,1, "audio's CPU load = %4.2f%%\nactive sfx tracks = %u/64", cpu_load*100, active_tracks);
  215.     win.present();
  216.  
  217.     time::sleep(10);
  218.   }
  219.  
  220.  
  221.   snd->sfxStopAll();
  222.   snd->musicStopAndWait();
  223.   time::sleep(75);
  224.  
  225.  
  226.   printf("%llu,",memory::getNumAllocations());
  227.   MutexSimple* mutex = new MutexSimple;
  228.   printf("%llu,",memory::getNumAllocations());
  229.   delete mutex;
  230.   printf("%llu\n",memory::getNumAllocations());
  231.  
  232.   AudioData* sndfx = new AudioData("kameria-se.qoa", snd);
  233.   printf("%llu,",memory::getNumAllocations());
  234.   delete sndfx;
  235.   printf("%llu\n",memory::getNumAllocations());
  236.  
  237.  
  238.   return 0;
  239.  
  240. } catch(const char* errorText){
  241. #ifdef _DEBUG
  242.   printf("FATAL EXCEPTION OCCERRED!: \"%s\"\n", errorText);
  243. #else
  244.   showMessageBox(errorText, "FATAL EXCEPTION OCCURRED! COMPLAIN TO THE DEV! (lol)", MSGBOX_ICN_ERROR);
  245. #endif
  246.   return -1;
  247. }}
  248.  
  249. /******************************************************************************/
  250. /******************************************************************************/
  251. //"kit_xmp_sfx\src\kit_xmp_sfx\kit_AudioData.cpp":
  252. #include "_kit_shared.hpp"
  253.  
  254.  
  255. namespace kit {
  256.  
  257.  
  258.  
  259.  
  260. static inline void printAudioData(AudioDataHeader* data, size_t samplesToPrint){
  261.   _printf("AudioDataHeader* = %p:\n", data);
  262.   _printf("  magic        = \"%.4s\" (0x%08X)\n", (char*)&data->magic, data->magic);
  263.   char* format_name = nullptr;
  264.   switch(data->format){
  265.     case ASTREAM_FMT_U8 : format_name = "ASTREAM_FMT_U8";  break;
  266.     case ASTREAM_FMT_S8 : format_name = "ASTREAM_FMT_S8";  break;
  267.     case ASTREAM_FMT_S16: format_name = "ASTREAM_FMT_S16"; break;
  268.     case ASTREAM_FMT_S24: format_name = "ASTREAM_FMT_S24"; break;
  269.     case ASTREAM_FMT_S32: format_name = "ASTREAM_FMT_S32"; break;
  270.     case ASTREAM_FMT_F32: format_name = "ASTREAM_FMT_F32"; break;
  271.     default:              format_name = "(unknown)";
  272.   }
  273.   _printf("  format       = %s (0x%04X)\n", format_name, data->format);
  274.   _printf("  headerSize   = %u\n",     data->headerSize);
  275.   _printf("  dataSize     = %llu\n",   data->dataSize);
  276.  
  277.   _printf("  loopStart    = %llu\n",   data->loopStart);
  278.   _printf("  loopEnd      = %llu\n",   data->loopEnd);
  279.  
  280.   _printf("  numSamples   = %llu\n",   data->numSamples);
  281.   _printf("  sampleRate   = %u\n",     data->sampleRate);
  282.   _printf("  bitRate      = %u\n",     data->bitRate);
  283.  
  284.   _printf("  loopCount    = %u\n",     data->loopCount);
  285.   _printf("  channels     = %u\n",     data->channels);
  286.   _printf("  bitRemainder = %u\n",     data->bitRemainder);
  287.   _printf("  userflags    = 0x%02X\n", data->userflags);
  288.   _printf("  mode         = %u\n",     data->mode);
  289.   _printf("  samples      = %p\n",     data->samples);
  290.   _printf("  AD_p         = %p\n",     data->AD_p);
  291.  
  292.  
  293.   if(samplesToPrint > 0){
  294.     if(data->format != ASTREAM_FMT_F32){
  295.       _printf("  FORMAT != ASTREAM_FMT_F32\n");
  296.       return;
  297.     }
  298.     u64 sampleRange = MIN(samplesToPrint, data->numSamples);
  299.  
  300.  
  301.     if(data->channels == 1){
  302.       f32* smpMono = (f32*)data->samples;
  303.       for(u64 i=0; i<sampleRange; ++i)
  304.         _printf("%4llu: %7.4f\n", i, smpMono[i]);
  305.  
  306.     } else if(data->channels == 2){
  307.       smp_f32s* smpStereo = (smp_f32s*)data->samples;
  308.       for(u64 i=0; i<sampleRange; ++i)
  309.         _printf("%4llu: %7.4f, %7.4f\n", i, smpStereo[i].l, smpStereo[i].r);
  310.  
  311.     } else {
  312.       _printf("CHANNELS IS NEITHER MONO NOR STEREO\n");
  313.  
  314.     }
  315.   }
  316. }
  317.  
  318.  
  319.  
  320.  
  321. AudioDataHeader* AudioData::_parseKPM(BinaryData& fileData){
  322.   //verify header data
  323.   AudioDataHeader* hdr = (AudioDataHeader*)fileData.getData();
  324.   size_t totalSize = fileData.getSize();
  325.  
  326.   if(hdr->magic != KIT_MAGIC_KPM) throw "magic != KIT_MAGIC_KPM";
  327.  
  328.   if(!isFormatValid(hdr->format)) throw "format is invalid";
  329.  
  330.   if(hdr->headerSize < sizeof(AudioDataHeader)) throw "headerSize < sizeof(AudioDataHeader)";
  331.  
  332.   if(hdr->dataSize != (totalSize-hdr->headerSize)) throw "dataSize is invalid";
  333.  
  334.   //(channels are checked before numSamples to prevent divide-by-zero exceptions)
  335.   if(hdr->channels!=1 && hdr->channels!=2) throw "audio is neither mono nor stereo";
  336.  
  337.   //(numSamples is checked before loopStart/loopEnd, as their checks rely upon numSamples)
  338.   if(hdr->numSamples != (hdr->dataSize/KIT_ASTREAM_FMT_BYTESIZE(hdr->format))/hdr->channels) throw "numSamples is invalid";
  339.  
  340.   if(hdr->loopStart >= hdr->numSamples) throw "loopStart >= numSamples";
  341.  
  342.   if(hdr->loopEnd > hdr->numSamples) throw "loopEnd > numSamples";
  343.  
  344.   if(hdr->sampleRate < 1000) throw "sampleRate < 1000";
  345.  
  346.   if(hdr->bitRate != hdr->sampleRate*hdr->channels*KIT_ASTREAM_FMT_BITSIZE(hdr->format)) throw "bitRate is invalid";
  347.  
  348.   if(hdr->bitRemainder != 0) throw "bitRemainder != 0";
  349.  
  350.   if(hdr->mode != 0) throw "only mode 0 kPCM files are currently supported";
  351.  
  352.  
  353.   //allocate and copy buffers
  354.   AudioDataHeader* data = (AudioDataHeader*)memory::alloc(totalSize);
  355.   if(data == nullptr) throw "failed to allocate memory for intermediate buffer";
  356.  
  357.   //(header data is contiguous with sample data, so it's fine to do a straight copy here)
  358.   memory::copy(data, hdr, totalSize);
  359.  
  360.  
  361.   return data;
  362. }
  363.  
  364.  
  365.  
  366.  
  367. void AudioData::_construct(const char* filePath, u32 convertToSampleRate,
  368.                            bool convertToStereo)
  369. {
  370.   _type = KIT_CLASSTYPE_AUDIODATA;
  371.  
  372.   BinaryData fileData(filePath);
  373.   AudioDataHeader* audioIn = nullptr;
  374.  
  375.   switch(fileData.getMagic32()){
  376.     case KIT_MAGIC_KPM: audioIn = _parseKPM(fileData); break;
  377.     case KIT_MAGIC_QOA: audioIn = _parseQOA(fileData); break;
  378.     default: throw "uknown audio format";
  379.   }
  380.  
  381.   AudioDataHeader headerIn = *audioIn;
  382.   //printAudioData(audioIn,0); //for debug
  383.  
  384.  
  385.   //convert to stereo f32
  386.   u64 numSamplesIn = headerIn.numSamples;
  387.  
  388.    //(the size of these does not include the header. this is just sample data)
  389.   smp_ptr   smpIn      = ((u8*)audioIn) + audioIn->headerSize;
  390.   smp_f32s* smpIn_f32s = (smp_f32s*)memory::alloc(numSamplesIn*sizeof(smp_f32s));
  391.   if(smpIn_f32s == nullptr) throw "failed to allocate memory for 2nd intermediate buffer";
  392.  
  393.   u64 smpSize_s24  = numSamplesIn*3;
  394.   u64 smpSize_s24s = numSamplesIn*6;
  395.  
  396.   switch(FORMAT_SWITCH(audioIn->channels, audioIn->format)){
  397.     case fmtsw_u8  : for(u64 i=0; i<numSamplesIn; ++i) smpIn_f32s[i] = smpIn._u8  [i]; break;
  398.     case fmtsw_s8  : for(u64 i=0; i<numSamplesIn; ++i) smpIn_f32s[i] = smpIn._s8  [i]; break;
  399.     case fmtsw_s16 : for(u64 i=0; i<numSamplesIn; ++i) smpIn_f32s[i] = smpIn._s16 [i]; break;
  400.     case fmtsw_s32 : for(u64 i=0; i<numSamplesIn; ++i) smpIn_f32s[i] = smpIn._s32 [i]; break;
  401.     case fmtsw_f32 : for(u64 i=0; i<numSamplesIn; ++i) smpIn_f32s[i] = smpIn._f32 [i]; break;
  402.  
  403.     case fmtsw_u8s : for(u64 i=0; i<numSamplesIn; ++i) smpIn_f32s[i] = smpIn._u8s [i]; break;
  404.     case fmtsw_s8s : for(u64 i=0; i<numSamplesIn; ++i) smpIn_f32s[i] = smpIn._s8s [i]; break;
  405.     case fmtsw_s16s: for(u64 i=0; i<numSamplesIn; ++i) smpIn_f32s[i] = smpIn._s16s[i]; break;
  406.     case fmtsw_s32s: for(u64 i=0; i<numSamplesIn; ++i) smpIn_f32s[i] = smpIn._s32s[i]; break;
  407.     case fmtsw_f32s: for(u64 i=0; i<numSamplesIn; ++i) smpIn_f32s[i] = smpIn._f32s[i]; break;
  408.  
  409.     //24-bit is considered a special case(s)
  410.     case fmtsw_s24 :
  411.       for(u64 i=KIT_U64_MAX, ii=0;  ii<smpSize_s24;  ii+=3){
  412.         smpIn_f32s[++i] = *( (smp_s24*)(&smpIn._u8[ii]) );
  413.       } break;
  414.  
  415.     case fmtsw_s24s:
  416.       for(u64 i=KIT_U64_MAX, ii=0;  ii<smpSize_s24s;  ii+=6){
  417.         smpIn_f32s[++i] = *( (smp_s24s*)(&smpIn._u8[ii]) );
  418.       } break;
  419.  
  420.     default:
  421.       memory::free(&audioIn);
  422.       throw "channels/format is invalid (this exception should be impossible)";
  423.   }
  424.  
  425.   memory::free(&audioIn); //free input buffer
  426.  
  427.  
  428.  
  429.   //sample rate conversion
  430.    //first, calculate output header values
  431.   f64 smpRateRatio  = (f64)headerIn.sampleRate/convertToSampleRate;
  432.   AudioDataHeader headerOut;
  433.   headerOut.numSamples   = (u64)( ((f64)headerIn.numSamples/smpRateRatio) + 0.5);
  434.  
  435.   headerOut.magic        = headerIn.magic;
  436.   headerOut.format       = ASTREAM_FMT_F32;
  437.   headerOut.headerSize   = sizeof(AudioDataHeader);
  438.   headerOut.dataSize     = headerOut.numSamples * sizeof(smp_f32s);
  439.  
  440.   headerOut.loopStart    = (u64)( ((f64)headerIn.loopStart /smpRateRatio) + 0.5);
  441.   headerOut.loopEnd      = (u64)( ((f64)headerIn.loopEnd   /smpRateRatio) + 0.5);
  442.  
  443.   //(numSamples is already set)
  444.   headerOut.sampleRate   = convertToSampleRate;
  445.   headerOut.bitRate      = headerOut.sampleRate * sizeof(smp_f32s) * 8;
  446.  
  447.   headerOut.loopCount    = headerIn.loopCount;
  448.   headerOut.channels     = 2;
  449.   headerOut.bitRemainder = 0;
  450.   headerOut.userflags    = headerIn.userflags;
  451.   headerOut.mode         = 0;
  452.   //headerOut.samples    = <whatever the output audio data + headerSize is>
  453.   headerOut.AD_p         = this;
  454.  
  455.   if(headerOut.numSamples == 0){
  456.     memory::free(&smpIn_f32s);
  457.     throw "output's numSamples was equal to 0";
  458.   }
  459.  
  460.   u64 totalSizeOut = headerOut.headerSize + headerOut.dataSize;
  461.   AudioDataHeader* audioOut = (AudioDataHeader*)memory::alloc(totalSizeOut);
  462.   if(audioOut == nullptr){
  463.     memory::free(&smpIn_f32s);
  464.     throw "failed to allocate memory for 3rd intermediate buffer";
  465.   }
  466.   headerOut.samples = ((u8*)audioOut) + headerOut.headerSize;
  467.  
  468.  
  469.   *audioOut = headerOut;
  470.   smp_f32s* smpOut = (smp_f32s*)audioOut->samples;
  471.    //highest index of both the input and output sample buffers
  472.   u64 hiIndexIn  = headerIn.numSamples  - 1;
  473.   u64 hiIndexOut = headerOut.numSamples - 1;
  474.   f64 inPosition = 0;
  475.   f64 inSpeed    = (f64)hiIndexIn/hiIndexOut;
  476.  
  477.   for(u64 i=0; i<hiIndexOut; ++i){
  478.     smpOut[i] = linearSampleStereo(smpIn_f32s, inPosition);
  479.     inPosition += inSpeed;
  480.   }
  481.  
  482.    //do last sample separately to (hopefully) account for any prev. rounding errors
  483.   smpOut[hiIndexOut] = smpIn_f32s[hiIndexIn];
  484.  
  485.   memory::free(&smpIn_f32s);
  486.  
  487.  
  488.  
  489.   //convert to mono if necessary
  490.   if(!convertToStereo){
  491.     //since we're *reducing* the number of channels here,
  492.      //the mono sample assignments should always be outpaced
  493.      //by the stereo sample accesses, thereby avoiding overlap
  494.     f32*      smpOutMono   = (f32*     )audioOut->samples;
  495.     smp_f32s* smpOutStereo = (smp_f32s*)audioOut->samples;
  496.     for(u64 i=0; i<headerOut.numSamples; ++i){
  497.       smp_f32s smp = smpOutStereo[i];
  498.       smpOutMono[i] = (smp.l + smp.r) / 2;
  499.     }
  500.  
  501.     //update header to reflect the change from stereo to mono
  502.     audioOut->dataSize /= 2;
  503.     audioOut->bitRate  /= 2;
  504.     audioOut->channels  = 1;
  505.  
  506.     //reallocate buffer *down* to reflect the change to dataSize
  507.     if(!memory::realloc(&audioOut, audioOut->headerSize + audioOut->dataSize)){
  508.       memory::free(&audioOut);
  509.       throw "failed to reallocate memory for mono buffer";
  510.     }
  511.  
  512.     audioOut->samples = ((u8*)audioOut) + headerOut.headerSize;
  513.   }
  514.  
  515.   _data = audioOut;
  516.  
  517.  
  518.  
  519.   _valid = true;
  520.   _constructing = false;
  521. }
  522.  
  523.  
  524.  
  525. AudioData::AudioData(const char* filePath, const SoundEngine* se){
  526.   if(se == nullptr)
  527.     throw "se = nullptr";
  528.   if(!KIT_IS_CLASS_TYPE(se,KIT_CLASSTYPE_SOUNDENGINE))
  529.     throw "se is not a sound engine";
  530.   if(!KIT_IS_CLASS_VALID(se))
  531.     throw "se is invalid";
  532.  
  533.   _SoundEngineOpaque* se_opq = (_SoundEngineOpaque*)KIT_GET_CLASS_OPAQUE(se);
  534.   AudioStreamInfo info = se_opq->stream->getInfo();
  535.  
  536.   u32  convertToSampleRate = (u32)info.sampleRate;
  537.   bool convertToStereo     = info.outputChannels == 2;
  538.   _construct(filePath, convertToSampleRate, convertToStereo);
  539.   //(^^_construct already throws if filePath is nullptr,
  540.    //so a check here would be redundant)
  541. }
  542.  
  543.  
  544.  
  545. AudioData::~AudioData(){
  546.   if(!_valid) return;
  547.   _valid = false;
  548.  
  549.   memory::free(&_data);
  550. }
  551.  
  552.  
  553.  
  554.  
  555. void AudioData::print(size_t samplesToPrint){
  556. #if defined(_DEBUG)
  557.   printAudioData(_data, samplesToPrint);
  558. #endif
  559. }
  560.  
  561.  
  562.  
  563.  
  564. }; /* namespace kit */
  565. /******************************************************************************/
  566. /******************************************************************************/
  567. //"kit_xmp_sfx\src\kit_xmp_sfx\kit_AudioData_QOA.cpp":
  568. #include "_kit_shared.hpp"
  569.  
  570.  
  571. namespace kit {
  572.  
  573. #include "kit_qoa.h"
  574.  
  575.  
  576.  
  577.  
  578. AudioDataHeader* AudioData::_parseQOA(BinaryData& fileData){
  579.   s32 fileDataSize = (s32)fileData.getSize();
  580.   u8* fileDataRaw  = (u8*)fileData.getData();
  581.  
  582.   if(fileData.getSize() > KIT_S32_MAX) throw "qoa file data size >= 2GiB";
  583.  
  584.  
  585.   //decode file data
  586.   qoa_desc samples_info;
  587.   s16*     samples = qoa_decode(fileDataRaw, fileDataSize, &samples_info);
  588.   if(samples == nullptr) "failed to decode qoa file data";
  589.  
  590.   u32 numSamples = samples_info.samples;
  591.   u32 sampleRate = samples_info.samplerate;
  592.   u32 channels   = samples_info.channels;
  593.   if(channels != 1  &&  channels != 2){
  594.     memory::free(&samples);
  595.     throw "qoa is neither mono nor stereo";
  596.   }
  597.  
  598.  
  599.   //copy sample data to intermediate buffer
  600.   size_t dataSize = numSamples * sizeof(s16) * channels;
  601.   AudioDataHeader* header = (AudioDataHeader*)memory::alloc(sizeof(AudioDataHeader) + dataSize);
  602.   if(header == nullptr){
  603.     memory::free(&samples);
  604.     throw "failed to allocate space for intermediate buffer";
  605.   }
  606.   memory::set(header, 0, sizeof(AudioDataHeader) + dataSize);
  607.   memory::copy((u8*)header + sizeof(AudioDataHeader), samples, dataSize);
  608.   memory::free(&samples);
  609.  
  610.  
  611.   //fill in header data
  612.   header->magic        = KIT_MAGIC_KPM;
  613.   header->format       = ASTREAM_FMT_S16;
  614.   header->headerSize   = sizeof(AudioDataHeader);
  615.   header->dataSize     = dataSize;
  616.  
  617.   header->loopStart    = 0;
  618.   header->loopEnd      = numSamples;
  619.  
  620.   header->numSamples   = numSamples;
  621.   header->sampleRate   = sampleRate;
  622.   header->bitRate      = sampleRate * sizeof(s16) * channels * 8;
  623.  
  624.   header->loopCount    = 0;
  625.   header->channels     = channels;
  626.   header->bitRemainder = 0;
  627.   header->userflags    = 0;
  628.   header->mode         = 0;
  629.   //the AudioData ignores this section for input, so there's no need to set these
  630.   //header->samples    = (u8*)header + sizeof(AudioDataHeader);
  631.   //header->AD_p       = this;
  632.  
  633.  
  634.   return header;
  635. }
  636.  
  637.  
  638.  
  639.  
  640. #define QOA_IMPLEMENTATION
  641. #include "kit_qoa.h"
  642.  
  643. }; /* namespace kit */
  644. /******************************************************************************/
  645. /******************************************************************************/
  646. //"kit_xmp_sfx\src\kit_xmp_sfx\kit_SoundEngine.cpp":
  647. #include "_kit_shared.hpp"
  648.  
  649. #define KIT_INVALID_SOUNDENGINE _kit_invalid_soundengine
  650.  
  651. #define KIT_IS_INVALID_SOUNDENGINE (!_valid && !_constructing)
  652.  
  653.  
  654. namespace kit {
  655.  
  656.  
  657. const char _kit_invalid_soundengine[] = "invalid sound engine";
  658.  
  659.  
  660.  
  661.  
  662. extern s32 _SoundEngine_callback(const void* _input, void* _output,
  663.                                  const AudioStreamInfo* info, void* userdata);
  664.  
  665.  
  666. SoundEngine::SoundEngine(s32 sfxNumTracks,
  667.                          bool musicUseNearestNeighbor,
  668.                          bool musicCheckLoop,
  669.                          bool musicNoFilter)
  670. {
  671.   _type = KIT_CLASSTYPE_SOUNDENGINE;
  672.  
  673.   if(sfxNumTracks < 1) throw "sfxNumTracks < 1";
  674.  
  675.   _opq = (_SoundEngineOpaque*)memory::alloc(sizeof(_SoundEngineOpaque));
  676.   if(_opq == nullptr) throw "ran out of memory creating _opq";
  677.   memory::set(_opq, 0, sizeof(_SoundEngineOpaque));
  678.  
  679.   const char* errorText = nullptr;
  680.   if(0){ //entered in the event of an exception
  681.     //no need to delete critical section, since it's the last thing to be done,
  682.      //and there is no failure condition for creating one anyway
  683.     //_DeleteCritSect: DeleteCriticalSection(&_opq->lock);
  684.  
  685.     //(and by extension, this isn't necessary either!)
  686.     //_FreeXMPBuffer : memory::free(&_opq->xmpBuffer);
  687.  
  688.     _FreeXMPContext: xmp_free_context(_opq->xmpCtx);
  689.     _FreeTracks    : memory::free(&_opq->tracks);
  690.     _DelAudioStream: delete _opq->stream;
  691.     _FreeOpaque    : memory::free(&_opq);
  692.     throw errorText;
  693.   }
  694.  
  695.  
  696.  
  697.   //open audio stream
  698.   s32 deviceID = audio::getDefOutputDevice();
  699.   AudioDeviceInfo deviceInfo = audio::getDeviceInfo(deviceID);
  700.  
  701.    //libxmp only accepts sample rates between 8000 and 48000, so hopefully
  702.     //no output device has a default that's lower or higher than that
  703.   if(deviceInfo.defSampleRate <  8000.0) throw "default sample rate < 8000";
  704.   if(deviceInfo.defSampleRate > 48000.0) throw "default sample rate > 48000";
  705.  
  706.   AudioStreamParams params;
  707.   params.callback               = _SoundEngine_callback;
  708.   params.userdata               = this;
  709.   params.outputDeviceID         = deviceID;
  710.   params.outputChannels         = MIN(2, deviceInfo.maxChannels.output);
  711.   params.outputFormat           = ASTREAM_FMT_F32;
  712.   params.sampleFrames           = (u32)( deviceInfo.defSampleRate*_soundEngineBufferSize );
  713.   params.sampleRate             = deviceInfo.defSampleRate;
  714.   params.outputSuggestedLatency = deviceInfo.defHiLatency.output;
  715.  
  716.   if(params.outputChannels == 0) //idk how this could happen lol, but just in case
  717.     throw "default output device's maximum channel count is 0";
  718.  
  719.   try {
  720.     _opq->stream = new AudioStream(&params);
  721.   } catch(const char* _errorText){
  722.     errorText = _errorText;
  723.     goto _FreeOpaque;
  724.   }
  725.  
  726.   _opq->streamIsMono       = params.outputChannels == 1;
  727.   _opq->streamSampleRate   = params.sampleRate;
  728.   _opq->streamSampleFrames = params.sampleFrames;
  729.  
  730.  
  731.  
  732.   //create tracks
  733.   _opq->tracks = (_SoundEngineTrack*)memory::alloc(sizeof(_SoundEngineTrack)*sfxNumTracks);
  734.   if(_opq == nullptr){
  735.     errorText = "failed to allocate memory for tracks";
  736.     goto _DelAudioStream;
  737.   }
  738.  
  739.   memory::set(_opq->tracks, 0, sizeof(_SoundEngineTrack)*sfxNumTracks);
  740.   _opq->tracks_len = sfxNumTracks;
  741.  
  742.  
  743.  
  744.   //create xmp context, and set
  745.   _opq->xmpCtx = xmp_create_context();
  746.   if(_opq->xmpCtx == nullptr){
  747.     errorText = "failed to create xmp context";
  748.     goto _FreeTracks;
  749.   }
  750.  
  751.  
  752.  
  753.   //create special buffer for libxmp, since it uses s16, not f32
  754.    //(no need to cast from void*, since _data is already void*)
  755.   _opq->xmpBuffer._data = memory::alloc(sizeof(s16)*params.sampleFrames*params.outputChannels);
  756.   if(_opq->xmpBuffer._data == nullptr){
  757.     errorText = "failed to allocate memory for intermediate libxmp buffer";
  758.     goto _FreeXMPContext;
  759.   }
  760.  
  761.   memory::set(_opq->xmpBuffer._data, 0, sizeof(s16)*params.sampleFrames*params.outputChannels);
  762.  
  763.  
  764.  
  765.   //create critical section
  766.   InitializeCriticalSectionAndSpinCount(&_opq->lock, KIT_LOCK_SPINCOUNT);
  767.  
  768.  
  769.  
  770.   //initialize the rest of _opq's members
  771.   _opq->volumeStream_old  = 1.0f;
  772.   _opq->volumeStream_new  = 1.0f;
  773.   _opq->panSfx_old        = 0.0f;
  774.   _opq->panSfx_new        = 0.0f;
  775.   _opq->volumeSfx_old     = 1.0f;
  776.   _opq->volumeSfx_new     = 1.0f;
  777.   _opq->panXmp_old        = 0.0f;
  778.   _opq->panXmp_new        = 0.0f;
  779.   _opq->volumeXmp_old     = 1.0f;
  780.   _opq->volumeXmp_new     = 1.0f;
  781.  
  782.   _opq->fadeDelta         = 1.0f / (f32)(_opq->streamSampleRate*_fadeDeltaSeconds);
  783.   _opq->fadeInDelayStream = (u32)(_opq->streamSampleRate*_fadeInDelaySeconds);
  784.   _opq->fadeVolumeStream  = 0.0f;
  785.   _opq->fadeVolumeXmp     = 0.0f;
  786.   _opq->fadeOutStream     = false;
  787.   _opq->fadeOutXmp        = false;
  788.  
  789.   _opq->xmpUseNearest     = musicUseNearestNeighbor;
  790.   _opq->xmpCheckLoop      = musicCheckLoop;
  791.   _opq->xmpNoFilter       = musicNoFilter;
  792.   _opq->xmpModuleLoaded   = false;
  793.   _opq->xmpPlaying        = false;
  794.   _opq->streamPlaying     = false;
  795.  
  796.  
  797.  
  798.   _valid = true;
  799.   _constructing = false;
  800. }
  801.  
  802.  
  803.  
  804.  
  805. SoundEngine::~SoundEngine(){
  806.   if(!_valid) return;
  807.   _valid = false;
  808.  
  809.   if(_opq != nullptr){
  810.     _opq->stream->stop();
  811.     while(_opq->stream->isActive()) time::sleep(0);
  812.  
  813.     EnterCriticalSection(&_opq->lock);
  814.  
  815.     delete _opq->stream;
  816.  
  817.     //force module playback to stop before freeing any stuff relevant to libxmp
  818.     if(_opq->xmpPlaying     ){ xmp_end_player(_opq->xmpCtx); _opq->xmpPlaying=false; }
  819.     if(_opq->xmpModuleLoaded){ xmp_release_module(_opq->xmpCtx); _opq->xmpModuleLoaded=false; }
  820.     xmp_free_context(_opq->xmpCtx);
  821.     memory::free(&_opq->xmpBuffer);
  822.  
  823.  
  824.     //force all sound effects to stop playing, before freeing tracks
  825.     _SoundEngineTrack* tracks     = _opq->tracks;
  826.     s32                tracks_len = _opq->tracks_len;
  827.     for(s32 t=0; t<tracks_len; ++t) tracks[t].audio = nullptr;
  828.     memory::free(&_opq->tracks);
  829.  
  830.     LeaveCriticalSection(&_opq->lock);
  831.  
  832.     DeleteCriticalSection(&_opq->lock);
  833.  
  834.     memory::free(&_opq);
  835.  
  836.   }
  837. }
  838.  
  839.  
  840.  
  841.  
  842. bool SoundEngine::streamIsMono(){
  843.   if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
  844.  
  845.   return _opq->streamIsMono;
  846. }
  847.  
  848.  
  849.  
  850. f64 SoundEngine::streamGetCPULoad(){
  851.   if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
  852.  
  853.   return _opq->stream->getCPULoad();
  854. }
  855.  
  856.  
  857.  
  858.  
  859. void SoundEngine::streamSetVolume(f32 volumeL, f32 volumeR){
  860.   if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
  861.  
  862.   smp_f32s volumeNew(volumeL, volumeR);
  863.  
  864.   lock(true);
  865.   _opq->volumeStream_new = volumeNew;
  866.   lock(false);
  867. }
  868.  
  869.  
  870.  
  871. void SoundEngine::streamSetPlayback(bool playing){
  872.   if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
  873.  
  874.   if(playing != _opq->streamPlaying){
  875.     lock(true);
  876.  
  877.     _opq->fadeOutStream = !playing;
  878.  
  879.     if(playing){
  880.       _opq->fadeInDelayStream = (u32)(_opq->streamSampleRate*_fadeInDelaySeconds);
  881.       _opq->streamPlaying = true;
  882.       _opq->stream->start();
  883.     }
  884.  
  885.     //(fade out and actual pausing is done inside the callback)
  886.  
  887.     lock(false);
  888.   }
  889. }
  890.  
  891.  
  892.  
  893. void SoundEngine::streamSetPlaybackAndWait(bool playing){
  894.   //(streamSetPlayback already does a validity check)
  895.   //if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
  896.  
  897.   u64 timeStamp = time::getTicks();
  898.   bool wasPlaying = _opq->streamPlaying;
  899.   //mutex is locked inside streamSetPlayback,
  900.    //and there's no need to lock in this function otherwise
  901.   streamSetPlayback(playing);
  902.  
  903.  
  904.   if(playing && !wasPlaying){
  905.     time::sleep( (u32)(_totalFadeDelay*1000) );
  906.  
  907.   } else if(!playing && wasPlaying){
  908.     u64 timeoutTicks = (u64)(_totalFadeDelay*3 * time::getTicksPerSecond());
  909.     while(_opq->streamPlaying){
  910.       time::sleep(10);
  911.       if((time::getTicks()-timeStamp) > timeoutTicks) throw "stream pause timed out";
  912.     }
  913.  
  914.   }
  915. }
  916.  
  917.  
  918.  
  919. void SoundEngine::streamSetVolumeForced(f32 volumeL, f32 volumeR){
  920.   if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
  921.  
  922.   smp_f32s volumeNew(volumeL, volumeR);
  923.  
  924.   lock(true);
  925.   _opq->volumeStream_old = volumeNew;
  926.   _opq->volumeStream_new = volumeNew;
  927.   lock(false);
  928. }
  929.  
  930.  
  931.  
  932.  
  933. void SoundEngine::lock(bool locked){
  934.   if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
  935.  
  936.   if(locked) EnterCriticalSection(&_opq->lock);
  937.   else       LeaveCriticalSection(&_opq->lock);
  938. }
  939.  
  940.  
  941.  
  942.  
  943. void SoundEngine::streamStopForced(){
  944.   if(KIT_IS_INVALID_SOUNDENGINE) throw KIT_INVALID_SOUNDENGINE;
  945.  
  946.   if(_opq->streamPlaying){
  947.     lock(true);
  948.  
  949.     _opq->stream->abort();
  950.     _opq->streamPlaying = false;
  951.  
  952.     lock(false);
  953.  
  954.   }
  955. }
  956.  
  957.  
  958.  
  959.  
  960. }; /* namespace kit */
  961. /******************************************************************************/
  962. /******************************************************************************/
  963. //"kit_xmp_sfx\src\kit_xmp_sfx\kit_SoundEngine_callback.cpp":
  964. //#include "_kit_shared.hpp" //included by kit_SoundEngine_callbackSfx.hpp
  965. #include "kit_SoundEngine_callbackSfx.hpp"
  966.  
  967.  
  968. namespace kit {
  969.  
  970.  
  971.  
  972.  
  973. static inline void applyFadeStream(_SoundEngineOpaque* opq,
  974.                                    smp_ptr buffer, u32 buffer_len)
  975. {
  976.   f32 fDelta   = opq->fadeDelta;
  977.   f32 fVolume  = opq->fadeVolumeStream;
  978.   u32 fInDelay = opq->fadeInDelayStream;
  979.  
  980.   u32 i = 0; //this index is shared, as the loops can jump to others at will
  981.  
  982.  
  983.   //FADING OUT
  984.   if(opq->fadeOutStream){
  985.     _FadeOut:;
  986.     if(opq->streamIsMono){ //mono fade out
  987.       for(; i<buffer_len; ++i){
  988.         if(!opq->fadeOutStream) goto _FadeIn;
  989.         buffer._f32[i] *= fVolume;
  990.         fVolume -= fDelta;
  991.         if(fVolume < 0.0f) fVolume = 0.0f;
  992.       }
  993.  
  994.     } else { //stereo fade out
  995.       for(; i<buffer_len; ++i){
  996.         if(!opq->fadeOutStream) goto _FadeIn;
  997.         buffer._f32s[i] *= fVolume;
  998.         fVolume -= fDelta;
  999.         if(fVolume < 0.0f) fVolume = 0.0f;
  1000.       }
  1001.  
  1002.     }
  1003.  
  1004.     //pause stream if fade-out finishes
  1005.     if(fVolume <= 0.0f){
  1006.       opq->stream->stop();
  1007.       opq->streamPlaying = false;
  1008.     }
  1009.  
  1010.  
  1011.   //FADING IN
  1012.   } else if(fVolume < 1.0f){
  1013.     //let stream warm up before fading in
  1014.     //(this *was* a solution to an issue specific to SDL's audio subsystem,
  1015.      //but i'll include it here too, just in case)
  1016.     if(opq->streamIsMono){ //mono fade delay
  1017.       for(; (fInDelay)&&(i<buffer_len); ++i,--fInDelay) buffer._f32 [i] = 0.0f;
  1018.     } else { //stereo fade delay
  1019.       for(; (fInDelay)&&(i<buffer_len); ++i,--fInDelay) buffer._f32s[i] = 0.0f;
  1020.     }
  1021.  
  1022.     _FadeIn:;
  1023.     if(opq->streamIsMono){ //mono fade in
  1024.       for(; i<buffer_len; ++i){
  1025.         if(opq->fadeOutStream) goto _FadeOut;
  1026.         else if(fVolume >= 1.0f){ fVolume = 1.0f; break; }
  1027.         buffer._f32[i] *= fVolume;
  1028.         fVolume += fDelta;
  1029.       }
  1030.  
  1031.     } else { //stereo fade in
  1032.       for(; i<buffer_len; ++i){
  1033.         if(opq->fadeOutStream) goto _FadeOut;
  1034.         else if(fVolume >= 1.0f){ fVolume = 1.0f; break; }
  1035.         buffer._f32s[i] *= fVolume;
  1036.         fVolume += fDelta;
  1037.       }
  1038.  
  1039.     }
  1040.  
  1041.   }
  1042.  
  1043.  
  1044.   opq->fadeVolumeStream  = fVolume;  //update fade volume to new value
  1045.   opq->fadeInDelayStream = fInDelay; //update fade delay to new value
  1046. }
  1047.  
  1048.  
  1049.  
  1050.  
  1051. extern s32 _SoundEngine_callbackXmp(void* userdata);
  1052.  
  1053.  
  1054. s32 _SoundEngine_callback(const void* _input, void* _output,
  1055.                           const AudioStreamInfo* info, void* userdata)
  1056. {
  1057.   s32 returnStatus = ASTREAM_RTN_CONTINUE;
  1058.  
  1059.   //userdata points to a SoundEngine, so to get its opaque we need to do this
  1060.   _SoundEngineOpaque* opq = (_SoundEngineOpaque*)KIT_GET_CLASS_OPAQUE(userdata);
  1061.  
  1062.   (void)_input; //input is left unused
  1063.   smp_ptr output      = _output;
  1064.   u32     output_len  = info->sampleFrames;
  1065.   bool    output_mono = info->outputChannels == 1;
  1066.  
  1067.   if(!KIT_IS_CLASS_VALID(userdata)) return ASTREAM_RTN_ABORT;
  1068.   EnterCriticalSection(&opq->lock); //lock mutex
  1069.   if(!KIT_IS_CLASS_VALID(userdata)){ //just in case
  1070.     LeaveCriticalSection(&opq->lock);
  1071.     return ASTREAM_RTN_ABORT;
  1072.   }
  1073.  
  1074.  
  1075.  
  1076.   //start music thread
  1077.   Thread* musicThread = nullptr;
  1078.   try {
  1079.     musicThread = new Thread(_SoundEngine_callbackXmp, opq);
  1080.  
  1081.   } catch(const char* errorText){
  1082.     _printf("musicThread constructor error = \"%s\"\n", errorText);
  1083.     (void)errorText; //otherwise compiler warns of unreferenced variable #ifndef _DEBUG
  1084.  
  1085.   }
  1086.  
  1087.  
  1088.  
  1089.   //initialize output buffer to 0, as the stream buffer
  1090.    //has to be filled with *something* no matter what
  1091.   memory::set(_output, 0, info->outputBufferSize);
  1092.  
  1093.  
  1094.  
  1095.   //mix sfx
  1096.   _SoundEngineTrack* tracks     = opq->tracks;
  1097.   s32                tracks_len = opq->tracks_len;
  1098.   f64                timestamp  = info->timeOutput;
  1099.   f64                sampleRate = info->sampleRate;
  1100.  
  1101.   if(output_mono){
  1102.     for(s32 t=0; t<tracks_len; ++t){
  1103.       if(tracks[t].audio != nullptr)
  1104.         mixTracksMono(tracks[t], timestamp, output._f32, output_len, sampleRate);
  1105.     }
  1106.  
  1107.   } else { //stereo
  1108.     for(s32 t=0; t<tracks_len; ++t){
  1109.       if(tracks[t].audio != nullptr)
  1110.         mixTracksStereo(tracks[t], timestamp, output._f32s, output_len, sampleRate);
  1111.     }
  1112.  
  1113.   }
  1114.  
  1115.  
  1116.  
  1117.   //(if volume or pan is not normal, basically)
  1118.   if(opq->volumeSfx_old != 1.0f  ||  opq->volumeSfx_new != 1.0f  ||
  1119.      opq->panSfx_old    != 0.0f  ||  opq->panSfx_new    != 0.0f  )
  1120.   {
  1121.     //apply sfx's volume and pan, while interpolating their values
  1122.      //from their old state to its new one
  1123.     f32 t           = 0.0f;
  1124.     f32 t_increment = 1.0f/output_len;
  1125.  
  1126.     smp_f32s volume_old = opq->volumeSfx_old;
  1127.     smp_f32s volume_new = opq->volumeSfx_new;
  1128.  
  1129.     opq->volumeSfx_old = volume_new; //update old volume to the new one
  1130.  
  1131.  
  1132.     if(output_mono){
  1133.       for(u32 i=0; i<output_len; ++i){
  1134.         output._f32[i] *= LERP2(volume_old.l, volume_new.l, t);
  1135.         t += t_increment; //add to interpolation t value
  1136.       }
  1137.  
  1138.     } else { //stereo
  1139.       //panning is only applied if samples are stereo,
  1140.        //so there's no need to declare it outside of this scope
  1141.       f32 pan_old = opq->panSfx_old;
  1142.       f32 pan_new = opq->panSfx_new;
  1143.  
  1144.       opq->panSfx_old = pan_new; //update old pan to the new one
  1145.  
  1146.       for(u32 i=0; i<output_len; ++i){
  1147.         smp_f32s sample = output._f32s[i];
  1148.         sample *= interpolateF32S(volume_old, volume_new, t);
  1149.         output._f32s[i] = applyPan(sample, LERP2(pan_old, pan_new, t) );
  1150.         t += t_increment; //add to interpolation t value
  1151.       }
  1152.  
  1153.     }
  1154.  
  1155.   }
  1156.  
  1157.  
  1158.  
  1159.   //wait for music thread
  1160.   if(musicThread != nullptr){
  1161.     try {
  1162.       musicThread->waitUntilDone(2000); //2 seconds of timeout should be fine
  1163.  
  1164.     } catch(const char* errorText){
  1165.       _printf("musicThread->waitUntilDone() error = \"%s\"\n", errorText);
  1166.       (void)errorText;
  1167.  
  1168.     }
  1169.  
  1170.     delete musicThread;
  1171.  
  1172.   }
  1173.  
  1174.  
  1175.  
  1176.   //mix intermediate music buffer into output
  1177.   smp_ptr buffer = opq->xmpBuffer;
  1178.   if(output_mono){
  1179.     for(u32 i=0; i<output_len; ++i) output._f32 [i] += s16_conv(buffer._s16[i]);
  1180.   } else {
  1181.     for(u32 i=0; i<output_len; ++i) output._f32s[i] += buffer._s16s[i];
  1182.   }
  1183.  
  1184.  
  1185.  
  1186.   //apply stream's volume, while interpolating their values
  1187.    //from their old state to its new one
  1188.   f32 t           = 0.0f;
  1189.   f32 t_increment = 1.0f/output_len;
  1190.  
  1191.   smp_f32s volume_old = opq->volumeStream_old;
  1192.   smp_f32s volume_new = opq->volumeStream_new;
  1193.  
  1194.   opq->volumeStream_old = volume_new; //update old volume to the new one
  1195.  
  1196.   if(output_mono){
  1197.     for(u32 i=0; i<output_len; ++i){
  1198.       output._f32[i] *= LERP2(volume_old.l, volume_new.l, t);
  1199.       t += t_increment; //add to interpolation t value
  1200.     }
  1201.  
  1202.   } else { //stereo
  1203.     for(u32 i=0; i<output_len; ++i){
  1204.       output._f32s[i] *= interpolateF32S(volume_old, volume_new, t);
  1205.       t += t_increment; //add to interpolation t value
  1206.     }
  1207.  
  1208.   }
  1209.  
  1210.  
  1211.  
  1212.   //apply stream's fade in/out
  1213.   applyFadeStream(opq, output, output_len);
  1214.  
  1215.  
  1216.  
  1217.   LeaveCriticalSection(&opq->lock); //unlock mutex
  1218.  
  1219.   return returnStatus;
  1220. }
  1221.  
  1222.  
  1223.  
  1224.  
  1225. }; /* namespace kit */
  1226.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement