Kitomas

sfx_class.cpp 2023-12-08

Dec 8th, 2023
120
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.25 KB | None | 0 0
  1. #include "_sfx.hpp"
  2.  
  3.  
  4.  
  5.  
  6. static inline int numBitsU32(Uint32 n){
  7.     int active = 0;
  8.     while(n != 0){
  9.         if(n&1) ++active;
  10.         n >>= 1;
  11.     }
  12.     return active;
  13. }
  14.  
  15.  
  16. extern void _sfx_callback(void* userdata, Uint8* _stream, int size);
  17.  
  18.  
  19. sfx_class::sfx_class(const Uint32 numTracks,
  20.                      const int sampleRate,
  21.                      const std::string& deviceName,
  22.                      const Uint32 bufferLength)
  23. {
  24.   if(numTracks == 0) throw "numTracks = 0";
  25.   if(numTracks > 1024) throw "numTracks > 1024";
  26.   if(sampleRate < 1000) throw "sampleRate < 1000";
  27.   if(sampleRate > 384000) throw "sampleRate > 384000";
  28.   if(bufferLength < 32) throw "bufferLength < 32";
  29.   if(bufferLength > 65535) throw "bufferLength > 65535";
  30.   if(numBitsU32(bufferLength) != 1) throw "bufferLength is not a power of 2";
  31.   const char* deviceNameRaw = nullptr;
  32.   if(deviceName != "") deviceNameRaw = deviceName.c_str();
  33.  
  34.   SDL_AudioSpec specWant, specHave;
  35.   specWant.freq     = sampleRate;
  36.   specWant.format   = AUDIO_F32;
  37.   specWant.channels = 2;
  38.   specWant.samples  = bufferLength;
  39.   specWant.callback = _sfx_callback;
  40.   specWant.userdata = this;
  41.  
  42.  
  43.   _deviceID = SDL_OpenAudioDevice(deviceNameRaw,0,&specWant,&specHave,0);
  44.   if(_deviceID == 0) throw SDL_GetError();
  45.  
  46.   _tracks = new std::vector<sfx_track>(numTracks);
  47.   if(_tracks == nullptr){
  48.     SDL_CloseAudioDevice(_deviceID);
  49.     throw "failed to make tracks vector";
  50.   }
  51.  
  52.   _lock = SDL_CreateMutex();
  53.   if(_lock == nullptr){
  54.     SDL_CloseAudioDevice(_deviceID);
  55.     delete _tracks;
  56.     throw SDL_GetError();
  57.   }
  58.  
  59.   _volume       = 1.0f;
  60.   _pan          = 0.0f;
  61.  
  62.   _fadeDelta    = 1.0f / ( ((float)sampleRate)*_fadeDeltaSeconds );
  63.   _fadeVolume   = 0.0f;
  64.  
  65.   _sampleRate   = sampleRate;
  66.   _bufferLength = bufferLength;
  67.   _deviceName   = SDL_GetAudioDeviceName(_deviceID,0);
  68.  
  69.  
  70.   _valid = true; //set valid to true to indicate success
  71. }
  72.  
  73.  
  74.  
  75.  
  76. void sfx_class::pauseDevice(bool pauseState){
  77.   if(!_valid) throw "invalid sfx_class instance";
  78.   if(_closing) return; //return early if closing
  79.   lock(true);
  80.  
  81.   //this should occur when _sfx_callback's pause thread fails,
  82.    //or if the callback itself does
  83.   if(_fadeInDelay == 0xffffffff){ //if equal to -1
  84.     SDL_PauseAudioDevice(_deviceID,1);
  85.     _playing = false;
  86.     _fadeInDelay = 0;
  87.   }
  88.  
  89.   _fadeOut = pauseState;
  90.   if(!pauseState && !_playing){
  91.     //the purpose of fadeInDelay is to mute for some samples
  92.      //to give the sdl audio device some time to warm up,
  93.      //otherwise artifacts start to occur (for me, anyway)
  94.     _fadeInDelay = _sampleRate*_fadeInDelaySeconds;
  95.     if(!_timeStampStart) _timeStampStart = SDL_GetTicks64();
  96.     if(!_timeStampEnd  ) _timeStampEnd   = SDL_GetTicks64();
  97.     SDL_PauseAudioDevice(_deviceID,0);
  98.     _playing = true;
  99.   }
  100.  
  101.   lock(false);
  102. }
  103.  
  104.  
  105.  
  106. void sfx_class::pauseDeviceAndWait(bool pauseState){
  107.   Uint64 startTimeMS = SDL_GetTicks64();
  108.   bool wasPaused = !_playing;
  109.   pauseDevice(pauseState); //should throw if invalid
  110.   if(_closing) return;
  111.  
  112.   if(pauseState){
  113.     // *4 seems to completely stop clipping (but not *1 for some reason)
  114.     Uint32 fadeOutMS = _fadeDeltaSeconds*1000 * 4;
  115.     do { SDL_Delay(fadeOutMS); } while(_playing);
  116.  
  117.   } else if(wasPaused){ //delay only if previously paused
  118.     Uint32 totalDelayMS = _totalFadeDelay*1000;
  119.     Uint32 timeDifferenceMS = SDL_GetTicks64()-startTimeMS;
  120.     SDL_Delay( std::max(totalDelayMS-timeDifferenceMS,0u) );
  121.  
  122.   }
  123.  
  124. }
  125.  
  126.  
  127.  
  128.  
  129. int sfx_class::play(const sfx_pcm* pcm){
  130.   if(!_valid) throw "invalid sfx_class instance";
  131.   Uint64     timeStamp = SDL_GetTicks64();
  132.  
  133.   int queuedTrackID = -1;
  134.   std::vector<sfx_track>& tracksRef = *_tracks;
  135.   size_t numTracks = tracksRef.size();
  136.  
  137.  
  138.   for(size_t i=0; i<numTracks; ++i){
  139.     sfx_track& track = tracksRef.at(i);
  140.  
  141.     if(track.pcm == nullptr){
  142.       track.timeStamp   = timeStamp;
  143.       track.speed       = 1.0;
  144.       track.speedDelta  = 0.0;
  145.       track.volume      = 1.0f;
  146.       track.volumeDelta = 0.0f;
  147.       track.pan         = 0.0f;
  148.       track.loops       = pcm->loopCount;
  149.       track.stopOnMute  = true;
  150.       track.stopping    = false;
  151.  
  152.       track.pcm         = (sfx_pcm*)pcm;
  153.  
  154.       queuedTrackID = i; break;
  155.     }
  156.   }
  157.  
  158.  
  159.   return queuedTrackID;
  160. }
  161.  
Add Comment
Please, Sign In to add comment