Advertisement
Kitomas

sfx_pcm.cpp as of 2023-12-15

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