Not a member of Pastebin yet?
                        Sign Up,
                        it unlocks many cool features!                    
                - #pragma once
 - #include <sfx.hpp>
 - //500ms
 - #define _totalFadeDelay (0.500f)
 - //linearly fade over the course of 10ms
 - #define _fadeDeltaSeconds (0.010f)
 - //the most common audio clipping ends at 10-11ms after unpausing,
 - //but i've seen clipping as far as ~450ms after unpausing
 - #define _fadeInDelaySeconds (_totalFadeDelay - _fadeDeltaSeconds)
 - //lower clip's volume to 0 within 10ms if speed reaches 0
 - #define _speed0DeltaVolMS (10.0f)
 - union _every_sample_type {
 - void* data;
 - Uint8* u8;
 - Sint16* i16;
 - float* f32;
 - sfx_u8s* u8s;
 - sfx_i16s* i16s;
 - sfx_f32s* f32s;
 - };
 - #define _FORMAT_SWITCH(_channels, _format) ( ((_channels)<<16) | (_format) )
 - enum _format_switch_enum {
 - fmt_u8 = _FORMAT_SWITCH(1,AUDIO_U8 ),
 - fmt_i16 = _FORMAT_SWITCH(1,AUDIO_S16),
 - fmt_f32 = _FORMAT_SWITCH(1,AUDIO_F32),
 - fmt_u8s = _FORMAT_SWITCH(2,AUDIO_U8 ),
 - fmt_i16s = _FORMAT_SWITCH(2,AUDIO_S16),
 - fmt_f32s = _FORMAT_SWITCH(2,AUDIO_F32),
 - };
 - static inline bool _format_invalid(SDL_AudioFormat format){
 - if(format == AUDIO_U8 ) return false;
 - if(format == AUDIO_S16) return false;
 - if(format == AUDIO_F32) return false;
 - return true; //any other format is invalid
 - }
 - #ifndef LERP2
 - #define LERP2(_v0,_v1, _t) ( (_v0) + (_t)*((_v1)-(_v0)) )
 - #endif
 - static inline sfx_f32s sfx_linearSample(std::vector<sfx_f32s>& src,
 - double& position,
 - Uint64 loopEnd = 0xffffffffffffffff)
 - {
 - Uint64 intPosition = (Uint64)position;
 - double modPosition = position-intPosition;
 - sfx_f32s smpA = src.at( intPosition);
 - sfx_f32s smpB = src.at((++intPosition)%loopEnd);
 - sfx_f32s smpOut(
 - LERP2(smpA.l, smpB.l, modPosition),
 - LERP2(smpA.r, smpB.r, modPosition)
 - );
 - return smpOut;
 - }
 - /****************/
 - /* sfx_callback */
 - /****************/
 - static inline sfx_f32s& _sfx_applyPan(sfx_f32s& sample, float pan){
 - //(i think this is how audacity does it...)
 - if(pan < 0){
 - sample.l += sample.r*(-pan);
 - sample.r *= 1.0f+pan;
 - } else if(pan > 0){
 - sample.r += sample.l*pan;
 - sample.l *= 1.0f-pan;
 - }
 - return sample;
 - }
 - static inline void _sfx_mixTrack(sfx_track& track, Uint64 sfxTimeStampEnd,
 - sfx_f32s* dst, int dst_len)
 - {
 - sfx_pcm* pcm = track.pcm;
 - const sfx_f32s speed0VolumeDelta = -( (1000.0f/_speed0DeltaVolMS) / pcm->sampleRate );
 - if(track.timeStamp > 0){
 - //calculate position based on difference between device and clip timestamps
 - //(timeStampEnd is used instead of Start, so the clip's time stamp
 - // can be compared to the last time the device callback exited)
 - double difference = (double)(track.timeStamp-sfxTimeStampEnd)/1000;
 - difference *= pcm->sampleRate; //convert seconds to samples
 - track.position = -(difference*track.speed); //starts playing when position reaches 0
 - track.timeStamp = 0; //to ensure that this only occurs once per clip queued
 - }
 - //make copies of relevant track values
 - float pan = std::clamp(track.pan, -1.0f,1.0f);
 - Uint64 loopStart = pcm->loopStart;
 - Uint64 loopEnd = pcm->loopEnd;
 - std::vector<sfx_f32s>& src = *pcm->samples;
 - //
 - double position = track.position;
 - double speed = track.speed;
 - Uint16 loops = track.loops;
 - bool stopping = track.stopping;
 - //make sure volume is clamped before applying it to the first sample,
 - //since volume is only clamped after volumeDelta is applied otherwise
 - track.volume.unit(); //clamp to 0.0 -> 1.0
 - for(int i=0; i<dst_len; ++i){
 - //loop handling (or end-of-clip handling i guess)
 - if(position >= loopEnd){ //clip finished loop
 - if(!loops){ stopping = true; break; } //mark as inactive and break
 - if(loops != 0xffff) --loops; //decrement loops (unless infinite)
 - position -= (Uint64)position; //basically position %= 1
 - position += loopStart; //now new_position = loopStart + old_position%1
 - } else if(position < 0){ //clip has yet to start playing
 - if(position < -speed){
 - position += speed; //step forward by current speed
 - continue;
 - } else { //if position >= -speed, the clip should start next sample
 - position = 0; //make sure clip starts at 0
 - }
 - }
 - //get sample, apply volume, hard clip to -1.0f -> 1.0f
 - sfx_f32s sample = sfx_linearSample(src, position, loopEnd);
 - sample *= track.volume;
 - sample.clip();
 - //apply pan and mix, apply volumeDelta, clamp volume to 0.0f -> 1.0f
 - dst[i] += _sfx_applyPan(sample,pan);
 - track.volume += track.volumeDelta;
 - track.volume.unit();
 - //update position, apply speedDelta, start fade out if clip's speed <= 0
 - position += speed;
 - speed += track.speedDelta;
 - if(speed <= 0){
 - speed = 0;
 - track.volumeDelta = speed0VolumeDelta;
 - }
 - }
 - //update relevant values in track
 - track.position = position;
 - track.speed = speed;
 - track.loops = loops;
 - track.stopping = stopping;
 - if(track.volume.l<=0 && track.volume.r<=0 && track.stopOnMute)
 - track.stopping = true;
 - if(track.stopping) track.pcm = nullptr;
 - }
 - extern int _sfx_pauseThread(void* data);
 - static inline void _sfx_globalFade(sfx_class* sfx, sfx_f32s* stream, int len){
 - sfx_f32s fadeDelta = sfx->_getFadeDelta();
 - sfx_f32s fadeVolume = sfx->_getFadeVolume();
 - sfx_f32s& volume = sfx->_getVolume();
 - float& pan = sfx->_getPan();
 - Uint32& fadeInDelayRef = sfx->_getFadeInDelay();
 - Uint32 fadeInDelay = fadeInDelayRef;
 - int i = 0; //this index is shared, as the loops can jump to others at will
 - //FADING OUT
 - if(sfx->isFadingOut()){ _fade_out_:;
 - for(; i<len; ++i){
 - if(!sfx->isFadingOut()) goto _fade_in_;
 - stream[i] *= fadeVolume;
 - fadeVolume -= fadeDelta;
 - if(fadeVolume.l < 0) fadeVolume = 0.0f;
 - }
 - //trigger pause thread if fade out is complete
 - if(fadeVolume.l <= 0.0f){
 - SDL_Thread* pauseThread = SDL_CreateThread(_sfx_pauseThread,"_PauseTh", sfx);
 - //setting _fadeInDelay to -1 will cause further calls to the device callback
 - //to simply memset 0 until sfx_class::pause() is called again
 - if(pauseThread == NULL) fadeInDelayRef = 0xffffffff;
 - else SDL_DetachThread(pauseThread); //make sure thread cleans up when finished
 - }
 - //FADING IN
 - } else if(fadeVolume.l < 1.0f){
 - for(; (fadeInDelay)&&(i<len); ++i){ //let device warm up before fading in
 - stream[i] = 0.0f; --fadeInDelay;
 - }
 - _fade_in_:;
 - for(; i<len; ++i){
 - if(sfx->isFadingOut()) goto _fade_out_;
 - else if(fadeVolume.l >= 1.0f){ fadeVolume = 1.0f; break; }
 - stream[i] *= fadeVolume;
 - fadeVolume += fadeDelta;
 - }
 - }
 - //even if no fade is being done, output should be hard clipped no matter what
 - //(while we're at it, apply global volume and pan too i guess)
 - for(i=0; i<len; ++i){
 - stream[i] *= volume;
 - stream[i].clip();
 - stream[i] = _sfx_applyPan(stream[i], std::clamp(pan, -1.0f,1.0f));
 - }
 - //update any relevant new values for sfx
 - sfx->_getFadeVolume() = fadeVolume.l; //.l should equal .r anyway
 - if(fadeInDelayRef != 0xffffffff) fadeInDelayRef = fadeInDelay;
 - }
 
Advertisement
 
                    Add Comment                
                
                        Please, Sign In to add comment