Advertisement
Kitomas

sfx_pcm.cpp 2023-12-08

Dec 8th, 2023
731
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.49 KB | None | 0 0
  1. #include "_sfx.hpp"
  2. #include <file.hpp>
  3.  
  4.  
  5.  
  6.  
  7. static inline bool _format_invalid(SDL_AudioFormat format){
  8.   if(format == AUDIO_U8 ) return false;
  9.   if(format == AUDIO_S16) return false;
  10.   if(format == AUDIO_F32) return false;
  11.   return true; //any other format is invalid
  12. }
  13.  
  14.  
  15.  
  16. union _every_sample_type {
  17.   void*     data;
  18.   Uint8*    u8;
  19.   Sint16*   i16;
  20.   float*    f32;
  21.   sfx_u8s*  u8s;
  22.   sfx_i16s* i16s;
  23.   sfx_f32s* f32s;
  24. };
  25.  
  26.  
  27.  
  28. #define _FORMAT_SWITCH(_channels, _format) ( ((_channels)<<16) | (_format) )
  29. enum _format_switch_enum {
  30.   fmt_u8   = _FORMAT_SWITCH(1,AUDIO_U8 ),
  31.   fmt_i16  = _FORMAT_SWITCH(1,AUDIO_S16),
  32.   fmt_f32  = _FORMAT_SWITCH(1,AUDIO_F32),
  33.   fmt_u8s  = _FORMAT_SWITCH(2,AUDIO_U8 ),
  34.   fmt_i16s = _FORMAT_SWITCH(2,AUDIO_S16),
  35.   fmt_f32s = _FORMAT_SWITCH(2,AUDIO_F32),
  36. };
  37.  
  38.  
  39.  
  40.  
  41.  
  42. sfx_pcm::sfx_pcm(const std::string& filePath,
  43.                  const sfx_class* sfx_ptr)
  44. {
  45.   sfx = (sfx_class*)sfx_ptr;
  46.   int deviceSampleRate = DEFAULT_SAMPLERATE;
  47.   if(sfx != nullptr) deviceSampleRate = sfx->getSampleRate();
  48.   if(deviceSampleRate < 1000) throw "sfx->_sampleRate < 1000";
  49.   if(deviceSampleRate > 384000) throw "sfx->_sampleRate > 384000";
  50.  
  51.   //load pcm data
  52.   std::vector<char> fileDataIn = file_readBin(filePath);
  53.   if(fileDataIn.size() < sizeof(sfx_pcm)) throw "fileSize < sizeof(sfx_pcm)";
  54.  
  55.   //header validation stuff
  56.   sfx_pcm* hdr = (sfx_pcm*)fileDataIn.data();
  57.  
  58.   if(hdr->magic != SFX_PCM_MAGIC) throw "magic != SFX_PCM_MAGIC";
  59.   if(_format_invalid(hdr->format)) throw "format is invalid";
  60.   if(hdr->headerSize != sizeof(sfx_pcm)) throw "headerSize != sizeof(sfx_pcm)";
  61.   if(hdr->dataSize != (fileDataIn.size()-sizeof(sfx_pcm))) throw "dataSize is invalid";
  62.   if(hdr->loopStart >= hdr->numSamples) throw "loopStart >= numSamples";
  63.   if(hdr->loopEnd > hdr->numSamples) throw "loopEnd >= numSamples";
  64.   if(hdr->numSamples != (hdr->dataSize/((hdr->format&255)/8))/hdr->channels) throw "numSamples is invalid";
  65.   if(hdr->sampleRate < 1000) throw "sampleRate < 1000";
  66.   if(hdr->bitRate != hdr->sampleRate*hdr->channels*(hdr->format&255)*hdr->channels) throw "bitRate is invalid";
  67.   if(hdr->channels!=1 && hdr->channels!=2) throw "channels are neither mono nor stereo";
  68.   void* smpData = fileDataIn.data() + hdr->headerSize;
  69.  
  70.  
  71.   //convert data type to float stereo
  72.   Uint64 numSamplesIn = hdr->numSamples;
  73.   std::vector<sfx_f32s> samplesF32S(numSamplesIn);
  74.   _every_sample_type smp = { .data = smpData };
  75.   switch(_FORMAT_SWITCH(hdr->channels,hdr->format)){
  76.   case fmt_u8  : for(Uint64 i=0; i<numSamplesIn; ++i) samplesF32S[i] = smp.u8  [i];  break;
  77.   case fmt_i16 : for(Uint64 i=0; i<numSamplesIn; ++i) samplesF32S[i] = smp.i16 [i];  break;
  78.   case fmt_f32 : for(Uint64 i=0; i<numSamplesIn; ++i) samplesF32S[i] = smp.f32 [i];  break;
  79.   case fmt_u8s : for(Uint64 i=0; i<numSamplesIn; ++i) samplesF32S[i] = smp.u8s [i];  break;
  80.   case fmt_i16s: for(Uint64 i=0; i<numSamplesIn; ++i) samplesF32S[i] = smp.i16s[i];  break;
  81.   case fmt_f32s: for(Uint64 i=0; i<numSamplesIn; ++i) samplesF32S[i] = smp.f32s[i];  break;
  82.   default: throw "channels/format is invalid (this exception should be impossible)";
  83.   }
  84.  
  85.  
  86.   //set relevant header values
  87.   double inRatio = (double)hdr->sampleRate/deviceSampleRate;
  88.   numSamples = ( ((double)hdr->numSamples)/inRatio ) + 0.5;
  89.   loopStart  = ( ((double)hdr->loopStart )/inRatio ) + 0.5;
  90.   loopEnd    = ( ((double)hdr->loopEnd   )/inRatio ) + 0.5;
  91.   dataSize   = numSamples * sizeof(sfx_f32s);
  92.   sampleRate = deviceSampleRate;
  93.   bitRate    = deviceSampleRate * sizeof(sfx_f32s) * 8;
  94.   loopCount  = hdr->loopCount;
  95.  
  96.   if(numSamples == 0) throw "output's numSamples was equal to 0";
  97.   samples = new std::vector<sfx_f32s>(numSamples);
  98.   std::vector<sfx_f32s>& samplesRef = *samples; //reference to output samples
  99.  
  100.  
  101.   //do linear sample rate conversion, with a target of deviceSampleRate
  102.   --numSamplesIn; // = highest element index of input samples
  103.   Uint64 numSamplesOut = numSamples - 1; // = highest element index of output samples
  104.   double inPosition = 0,  inSpeed = (double)numSamplesIn/numSamplesOut;
  105.   if(inSpeed <= 0) throw "sample rate conversion delta <= 0"; //just in case
  106.  
  107.   for(Uint64 i=0; i<numSamplesOut; ++i){
  108.     samplesRef[i] = sfx_linearSample(samplesF32S, inPosition);
  109.     inPosition += inSpeed;
  110.   }
  111.  
  112.   //handle last sample separately to (hopefully) account for any previous rounding errors
  113.   samplesRef[numSamplesOut] = samplesF32S.at(numSamplesIn);
  114.  
  115.  
  116.   magic = SFX_PCM_MAGIC; //signature is set properly to indicate success
  117. }
  118.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement