Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //todo: make device fade within 10ms
- //note: lock sfx when playing sound effect
- #pragma once
- #include <SDL2/SDL.h>
- #include <algorithm>
- #include <string>
- #include <vector>
- #define DEFAULT_SAMPLERATE (44100)
- #define DEFAULT_BITRATE (DEFAULT_SAMPLERATE*sizeof(sfx_f32s)*8)
- #define DEFAULT_BUFFERLEN (4096)
- /*******/
- /* sfx */
- /*******/
- extern const float _sfx_i8inv; // = 1/2^7
- extern const float _sfx_i16inv; // = 1/2^15
- //for converting i8/i16 to f32
- #define _sfx_i8conv(_v) ( (float)((Sint8)((_v)-128)) * _sfx_i8inv )
- #define _sfx_i16conv(_v) ( (float)( (_v) ) * _sfx_i16inv )
- struct sfx_u8s {
- Uint8 l,r;
- sfx_u8s() : l(0), r(0) {}
- sfx_u8s(const Uint8 _l, const Uint8 _r) : l(_l), r(_r) {}
- };
- struct sfx_i16s {
- Sint16 l,r;
- sfx_i16s() : l(0), r(0) {}
- sfx_i16s(const Sint16 _l, const Sint16 _r) : l(_l), r(_r) {}
- };
- struct sfx_f32s {
- float l,r;
- sfx_f32s() : l(0), r(0) {}
- sfx_f32s(const float& _l, const float& _r) : l(_l), r(_r) {}
- sfx_f32s(const Uint8& smp){ l = _sfx_i8conv( smp); r = _sfx_i8conv( smp); }
- sfx_f32s(const Sint16& smp){ l = _sfx_i16conv(smp); r = _sfx_i16conv(smp); }
- sfx_f32s(const float& smp){ l = smp; r = smp; }
- sfx_f32s(const sfx_u8s& smp){ l = _sfx_i8conv( smp.l); r = _sfx_i8conv( smp.r); }
- sfx_f32s(const sfx_i16s& smp){ l = _sfx_i16conv(smp.l); r = _sfx_i16conv(smp.r); }
- sfx_f32s(const sfx_f32s& smp){ l = smp.l; r = smp.r; }
- sfx_f32s& operator+=(const sfx_f32s& smp){ l += smp.l; r += smp.r; return *this; }
- sfx_f32s& operator-=(const sfx_f32s& smp){ l -= smp.l; r -= smp.r; return *this; }
- sfx_f32s& operator*=(const sfx_f32s& smp){ l *= smp.l; r *= smp.r; return *this; }
- sfx_f32s& clip(){ l = std::clamp(l, -1.0f,1.0f); r = std::clamp(r, -1.0f,1.0f); return *this; }
- sfx_f32s& unit(){ l = std::clamp(l, 0.0f,1.0f); r = std::clamp(r, 0.0f,1.0f); return *this; }
- };
- /*************/
- /* sfx_class */
- /*************/
- struct sfx_pcm; //forward declaration
- struct sfx_track { //64B
- sfx_pcm* pcm = nullptr; //audio data; track considered available/inactive if nullptr
- Uint64 timeStamp; //result of SDL_GetTicks64() called at time of queueing an audio clip
- double position; //sample position, including fraction
- double speed; //what amount to increase position by every sample
- double speedDelta; //what number to apply to speed every sample
- sfx_f32s volume; //left and right channel volumes; 0.0f -> 1.0f
- sfx_f32s volumeDelta; //determines the rate at which volume changes each sample
- float pan; //the current pan of the track; -1.0f -> 1.0f (should be applied AFTER volume)
- Uint16 loops; //number of times to loop before deactivating clip (-1 for endless loop)
- bool stopOnMute = true; //'deactivate track when volume or speed reaches 0?'
- bool stopping = false; //used inside _sfx_mixTrack
- };
- class sfx_class { //104B
- bool _valid = false;
- bool _closing = false;
- bool _fadeOut = false;
- bool _playing = false;
- SDL_AudioDeviceID _deviceID = 0;
- Uint64 _timeStampStart = 0;
- Uint64 _timeStampEnd = 0;
- std::vector<sfx_track>* _tracks = nullptr;
- SDL_mutex* _lock = nullptr;
- sfx_f32s _volume = 1.0f;
- float _pan = 1.0f;
- Uint32 _fadeInDelay = 0;
- float _fadeDelta = 0;
- float _fadeVolume = 0;
- Uint32 _sampleRate = DEFAULT_SAMPLERATE;
- Uint32 _bufferLength = DEFAULT_BUFFERLEN;
- std::string _deviceName;
- public:
- bool isValid() const { return _valid; }
- bool isClosing() const { return _closing; }
- bool isFadingOut() const { return _fadeOut; }
- bool isPlaying() const { return _playing; }
- SDL_AudioDeviceID getDeviceID() const { return _deviceID; }
- Uint64 getTimeStampStart() const { return _timeStampStart; }
- Uint64 getTimeStampEnd() const { return _timeStampEnd; }
- size_t getNumTracks() const { return _tracks->size(); }
- sfx_f32s getVolume() const { return _volume; }
- sfx_f32s getPan() const { return _pan; }
- Uint32 getSampleRate() const { return _sampleRate; }
- Uint32 getBufferLength() const { return _bufferLength; }
- std::string& getDeviceName(){ return _deviceName; }
- Uint32 getActiveTracks(){
- if(!_valid) throw "invalid sfx_class instance";
- lock(true);
- if(_closing) return 0;
- Uint32 amount = 0;
- std::vector<sfx_track>& tracksRef = *_tracks;
- size_t numTracks = tracksRef.size();
- for(size_t i=0; i<numTracks; ++i)
- if(tracksRef.at(i).pcm != nullptr) ++amount;
- lock(false);
- return amount;
- }
- void setVolume(sfx_f32s& volume){
- if(!_valid) throw "invalid sfx_class instance";
- _volume = volume;
- }
- void setPan(float pan){
- if(!_valid) throw "invalid sfx_class instance";
- _pan = pan;
- }
- //should be used solely by _sfx_callback related stuff
- //(these are hardly public functions; do not touch these, seriously)
- Uint32& _getFadeInDelay(){ return _fadeInDelay; }
- float& _getFadeDelta(){ return _fadeDelta; }
- float& _getFadeVolume(){ return _fadeVolume; }
- std::vector<sfx_track>& _getTracks(){ return *_tracks; }
- void _setPlaying(bool playState){ _playing = playState; }
- void _setTimeStampStart(){ _timeStampStart = SDL_GetTicks64(); }
- void _setTimeStampEnd(){ _timeStampEnd = SDL_GetTicks64(); }
- sfx_class(const Uint32 numTracks,
- const int sampleRate = DEFAULT_SAMPLERATE,
- const std::string& deviceName = "",
- const Uint32 bufferLength = DEFAULT_BUFFERLEN);
- ~sfx_class(){
- lock(true);
- _closing = true;
- _fadeOut = true; //probably redundant
- if(_deviceID > 0){
- SDL_CloseAudioDevice(_deviceID);
- _playing = false;
- _deviceID = 0;
- }
- delete _tracks;
- _tracks = nullptr;
- lock(false);
- _valid = false;
- if(_lock != nullptr){
- SDL_DestroyMutex(_lock);
- _lock = nullptr;
- }
- }
- void lock(bool lockState){
- if(!_valid) throw "invalid sfx_class instance";
- int failure;
- if(lockState) failure = (SDL_LockMutex(_lock)<0);
- else failure = (SDL_UnlockMutex(_lock)<0);
- if(failure) throw SDL_GetError();
- }
- void lockDevice(bool lockState){
- if(!_valid) throw "invalid sfx_class instance";
- if(lockState) SDL_LockAudioDevice(_deviceID);
- else SDL_UnlockAudioDevice(_deviceID);
- }
- void pauseDevice(bool pauseState);
- void pauseDeviceAndWait(bool pauseState);
- int play(const sfx_pcm* pcm);
- };
- /***********/
- /* sfx_pcm */
- /***********/
- #define SFX_PCM_MAGIC (0x4D43506B)
- struct sfx_pcm { //an altered (but backwards compatible) version of kit_acodecPCM; 72B
- Uint32 magic = 0; // (0x00) = 0x4D43506B = "kPCM" (no terminator)
- SDL_AudioFormat format = AUDIO_F32; // (0x04) The data format of the stream
- Uint16 headerSize = sizeof(sfx_pcm); // (0x06) = sizeof(sfx_pcm)
- Uint64 dataSize = 0; // (0x08) The size of the PCM buffer, in bytes
- Uint64 loopStart = 0; // (0x10) Which sample to loop back to
- Uint64 loopEnd = 0; // (0x18) Which sample to restart the loop on
- Uint64 numSamples = 0; // (0x20) # of sample frames in stream
- Uint32 sampleRate = DEFAULT_SAMPLERATE; // (0x28) The stream's sample rate, in Hz
- Uint32 bitRate = DEFAULT_BITRATE; // (0x2C) The audio's bit rate (per second)
- Uint16 loopCount = 0; // (0x30) # of times to loop audio (-1 = inf loop)
- Uint16 channels = 2; // (0x32) # of interlaced channels in the stream
- Uint8 bitRemainder = 0; // (0x34) = bitsPerSample%8
- Uint8 userflags = 0; // (0x35) User-defined (is just padding otherwise)
- Uint16 uservalue = 0; // (0x36) User-defined (is just padding otherwise)
- std::vector<sfx_f32s>* samples = nullptr; // (0x38) Sample data (appears as nullptr in file)
- sfx_class* sfx = nullptr; // (0x40) Bound sfx class (appears as nullptr in file)
- // Samples will be converted to f32s at deviceSampleRate Hz
- sfx_pcm(const std::string& filePath, const sfx_class* sfx_ptr = nullptr);
- ~sfx_pcm(){
- magic = 0; //a magic of 0 indicates an invalid pcm struct
- delete samples;
- samples = nullptr; //just in case
- }
- void print(const size_t samplesToPrint = 0){
- SDL_Log("magic = \"%.4s\" (0x%08X)", (char*)&magic, magic);
- switch(format){
- case AUDIO_U8 : SDL_Log("format = AUDIO_U8 (0x%04X)", format); break;
- case AUDIO_S16: SDL_Log("format = AUDIO_S16 (0x%04X)", format); break;
- case AUDIO_F32: SDL_Log("format = AUDIO_F32 (0x%04X)", format); break;
- default: SDL_Log("format = UNKNOWN (0x%04X)", format); }
- SDL_Log("headerSize = %u", headerSize);
- SDL_Log("dataSize = %u", (unsigned)dataSize); //overflows if dataSize > 4GB
- SDL_Log("loopStart = %u", (unsigned)loopStart);
- SDL_Log("loopEnd = %u", (unsigned)loopEnd);
- SDL_Log("numSamples = %u", (unsigned)numSamples);
- SDL_Log("sampleRate = %u", sampleRate);
- SDL_Log("bitrate = %u", bitRate);
- SDL_Log("loopCount = %u", loopCount);
- SDL_Log("channels = %u", channels);
- SDL_Log("bitRemainder = %u", bitRemainder);
- SDL_Log("userflags = 0x%02X", userflags);
- SDL_Log("uservalue = %u", uservalue);
- if(samplesToPrint > 0){
- if(format!=AUDIO_F32 || channels!=2) throw "data type is not f32s";
- Uint64 sampleRange = std::min(samplesToPrint, numSamples);
- std::vector<sfx_f32s>& samplesRef = *samples;
- for(Uint32 i=0; i<sampleRange; ++i)
- SDL_Log("%4u: %7.4f, %7.4f", i, samplesRef.at(i).l,samplesRef.at(i).r);
- }
- }
- void setSfx(sfx_class* sfx_ptr){ sfx = sfx_ptr; }
- int play() {
- if(sfx != nullptr) return sfx->play(this);
- else throw "no sfx_class instance currently bound";
- }
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement