Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\_kit_common_shared.hpp":
- #ifndef _KIT_SRC__KIT_COMMON_SHARED_HPP
- #define _KIT_SRC__KIT_COMMON_SHARED_HPP
- #include <kit/all.hpp>
- #include "_kit_globals.hpp"
- #include "_kit_opaques.hpp"
- namespace kit {
- //nothing to put here (yet)
- };
- #endif /* _KIT_SRC__KIT_COMMON_SHARED_HPP */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\_kit_globals.hpp":
- #ifndef _KIT_SRC__KIT_GLOBALS_HPP
- #define _KIT_SRC__KIT_GLOBALS_HPP
- //(this file should not be included on its own,
- //rather it should be included as part of _kit_common_shared.hpp)
- /*tbd:
- set window icon(s)
- warp mouse in window and hide mouse when in window
- draw rectangles
- add timers
- WINPOS_UNDEFINED is broken for some reason
- currently working on:
- */
- /* low priority tbd:
- right side of window glitches out when going off-screen?
- Window::setMinimized() breaks things, and it shouldn't be doing that
- add WIN_MINIMIZE, WIN_MAXIMIZE, and WIN_RESTORE events
- check to see if sdl sends a window resize event when minimizing/maximizing
- before or after the minimize/maximize event itself (if at all)
- set process priority
- make "ran out of memory creating _opq" error text global
- BitmapFont:
- set step direction
- set anchor point
- set transparent color
- set offsets
- printCentered
- (look at Bitmap to look for any more get and set functions)
- mention getLastSystemError in win32-related exceptions
- make a thing for getsysteminfo in general
- move relevant _misc_func stuff to _video_func
- */
- #include <windowsx.h>
- #include <Windows.h>
- #include <string.h> //using strcpy_s and strnlen_s
- #include <stdarg.h> //for fstr's stuff
- # include <stdio.h> //
- #include <portaudio.h> //portaudio my beloved
- #ifdef _DEBUG
- #define _printf(_fmt,...) printf(_fmt,__VA_ARGS__)
- #else
- #define _printf(_fmt,...)
- #endif
- #if defined(_DEBUG)
- #include <stdio.h>
- #define loghere printf("line %4i: (%s)\n",__LINE__,__FILE__);
- #else
- #define loghere /* do {} while(0); */
- #endif /* _DEBUG */
- #define KIT_LOCK_SPINCOUNT (2048)
- //used for Window and Bitmap
- #define KIT_INITIAL_STRETCH_MODE COLORONCOLOR //basically nearest-neighbor
- //class type ID macros
- #define KIT_OPAQUE_PRESENT (0x80000000)
- #define KIT_IS_OPAQUE_PRESENT(_type) ( ((_type)&KIT_OPAQUE_PRESENT) != 0 )
- #define KIT_CLASSTYPE_NULL (0x0000 )
- #define KIT_CLASSTYPE_MUTEXSIMPLE (0x0001 | KIT_OPAQUE_PRESENT)
- #define KIT_CLASSTYPE_WINDOW (0x0002 | KIT_OPAQUE_PRESENT)
- #define KIT_CLASSTYPE_BITMAP (0x0003 | KIT_OPAQUE_PRESENT)
- #define KIT_CLASSTYPE_FILEIO_BINARYDATA (0x0004 )
- #define KIT_CLASSTYPE_BITMAPFONT (0x0005 )
- #define KIT_CLASSTYPE_FSTR (0x0006 )
- #define KIT_CLASSTYPE_AUDIOSTREAM (0x0007 | KIT_OPAQUE_PRESENT)
- #define KIT_CLASSTYPE_THREAD (0x0008 | KIT_OPAQUE_PRESENT)
- #define KIT_CLASSTYPE_TIMER (0x0009 | KIT_OPAQUE_PRESENT)
- namespace kit {
- #define KIT_GET_CLASS_TYPE(_ptr) ( ((_commonClassValues*)(_ptr))->type )
- #define KIT_GET_CLASS_VALID(_ptr) ( ((_commonClassValues*)(_ptr))->valid )
- #define KIT_GET_CLASS_CONSTRUCTING(_ptr) ( ((_commonClassValues*)(_ptr))->constructing )
- #define KIT_GET_CLASS_DATA(_ptr) ( ((_commonClassValues*)(_ptr))->data )
- #define KIT_GET_CLASS_OPAQUE(_ptr) ( ((_commonClassValues*)(_ptr))->opq )
- #define KIT_IS_CLASS_TYPE(_ptr,_type) ( KIT_GET_CLASS_TYPE(_ptr) == (_type) )
- #define KIT_IS_CLASS_VALID(_ptr) ( KIT_GET_CLASS_VALID(_ptr) != 0 )
- #define KIT_IS_CLASS_CONSTRUCTING(_ptr) ( KIT_GET_CLASS_CONSTRUCTING(_ptr) != 0 )
- struct _commonClassValues {
- u32 type;
- bool valid; //'is object fully and successfully constructed?'
- bool constructing; //'is object currently inside constructor?'
- //^^this is useful for if public class functions are called inside the
- //constructor itself, but the valid flag is not set to true yet
- u16 data; //purpose varies by class type; unused by some (or it's split into 2 u8)
- _GenericOpaquePtr opq; //nonexistent if type lacks the KIT_OPAQUE_PRESENT flag
- };
- /*++++++++++*/
- /*+kit_main+*/
- /*++++++++++*/
- namespace w32 {
- extern HINSTANCE hThisInst;
- extern HINSTANCE hPrevInst;
- extern LPSTR lpszArg;
- extern int nCmdShow;
- extern LARGE_INTEGER ticksPerSecond; //used in time::getTicksPerSecond()
- };
- namespace eventVars {
- extern CRITICAL_SECTION lock;
- //eventVars::end indicates what index should be queued to next,
- //while eventVars::next indicates what index should be dequeued next
- //(if they are the same, that means the queue is empty!)
- extern WindowEvent* queue; //length of 2^16 (which is why u16 indexes are used)
- extern u16 next;
- extern u16 end;
- };
- //returns false if queue is full
- static inline bool AddToEventQueue(WindowEvent& event){
- bool success = false;
- EnterCriticalSection(&eventVars::lock);
- if((eventVars::end+1) != eventVars::next){
- eventVars::queue[eventVars::end++] = event;
- success = true;
- }
- LeaveCriticalSection(&eventVars::lock);
- return success;
- }
- //returns a WINEVENT_NULL event if queue is empty
- static inline WindowEvent RemoveFromEventQueue(){
- WindowEvent event; //should auto-initialize to type WINEVENT_NULL
- EnterCriticalSection(&eventVars::lock);
- if(eventVars::next != eventVars::end){
- event = eventVars::queue[eventVars::next++];
- }
- LeaveCriticalSection(&eventVars::lock);
- return event;
- }
- /*++++++++++*/
- /*+kit_main+*/
- /*++++++++++*/
- /*++++++++++++*/
- /*+kit_Window+*/
- /*++++++++++++*/
- namespace w32 {
- //tbd: maybe put a critical section on winCount specifically
- extern u32 winCount; //number of existing kit::Window instances
- extern const char winClassName[];
- extern WNDCLASSEXA winClass;
- extern ATOM winClassAtom;
- };
- /*------------*/
- /*-kit_Window-*/
- /*------------*/
- }; /* namespace kit */
- #endif /* _KIT_SRC__KIT_GLOBALS_HPP */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_w32\src\kit_win32\_kit_opaques.hpp":
- #ifndef _KIT_SRC__KIT_OPAQUES_HPP
- #define _KIT_SRC__KIT_OPAQUES_HPP
- //(this file should not be included on its own,
- //rather it should be included as part of _kit_common_shared.hpp)
- /*
- Opaques are included as follows: (classes without opaques are omitted)
- [ ] MutexSimple
- [X] Bitmap
- [X] Window
- [X] AudioStream
- [X] Thread
- */
- namespace kit {
- struct _WindowOpaque;
- struct _BitmapOpaque {
- CRITICAL_SECTION lock;
- BITMAPINFO info;
- HBITMAP handle;
- color::ARGB* pixels;
- shape::point size;
- HDC devCtx;
- _WindowOpaque* window; //window associated with the bitmap
- s32 stretchMode; //stretch mode when used as blit destination (canvas only basically)
- u8 _unused[3];
- //false for CreateDIBitmap() bitmap, true for CreateDIBSection() bitmap
- bool directAccess;
- };
- union WindowEvent;
- struct _WindowOpaque {
- CRITICAL_SECTION lock;
- WindowEvent_Key_Mod kmod; //key modifier flags for key events (shift, ctrl, ...)
- //set to true after first WINEVENT_MOUSE_MOVE since entering client area
- bool mouseWasMovedBefore;
- bool canvasStretch; //if false, canvas is resized alongside window
- _BitmapOpaque canvas;
- shape::point mousePosition;
- //true if a virtual key code's key is currently pressed
- //(don't set any key states during KEY_CHAR events, only KEY_UP & KEY_DOWN!)
- bool keyStates[256];
- HWND winHandle;
- shape::rect winRect; //contains both window position, and window size
- u32 winStretchMode;
- DWORD winFlags;
- DWORD winFlagsEx;
- u32 winIndex;
- bool winFullscreen;
- bool winShown;
- bool winFocus;
- bool winClosed; //true if window has been destroyed, false otherwise
- bool winMinimized;
- bool winMaximized;
- };
- struct _AudioStreamOpaque {
- CRITICAL_SECTION lock;
- PaStreamParameters streamInputParams;
- PaStreamParameters streamOutputParams;
- PaStream* streamPtr;
- AudioStreamInfo astreamInfo;
- AudioStreamCallback callback;
- void* userdata;
- AudioStreamEndCallback endCallback;
- };
- //i really don't feel like making a whole 'kit_audio_shared.hpp'
- //just for this, so i'll keep this here for now
- static inline PaSampleFormat ConvertToPaSampleFormat(u16 kitSmpFmt){
- PaSampleFormat paSmpFmt;
- switch(kitSmpFmt){
- case ASTREAM_FMT_U8 : paSmpFmt = paUInt8; break;
- case ASTREAM_FMT_S8 : paSmpFmt = paInt8; break;
- case ASTREAM_FMT_S16: paSmpFmt = paInt16; break;
- case ASTREAM_FMT_S24: paSmpFmt = paInt24; break;
- case ASTREAM_FMT_S32: paSmpFmt = paInt32; break;
- case ASTREAM_FMT_F32: paSmpFmt = paFloat32; break;
- default: paSmpFmt = paCustomFormat; //indicates an error
- }
- return paSmpFmt;
- }
- struct _ThreadOpaque {
- ThreadFunction threadFunc;
- void* threadUserdata;
- HANDLE threadHandle;
- DWORD threadID;
- s32 threadReturn;
- bool threadDetached;
- bool threadDone;
- u16 _padding16;
- };
- }; /* namespace kit */
- #endif /* _KIT_SRC_KIT_OPAQUES_HPP */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_xmp_sfx\include\kit\xmp_sfx.hpp":
- #ifndef _KIT_INC_XMP_SFX_HPP
- #define _KIT_INC_XMP_SFX_HPP
- #include "_xmp_sfx_AudioData.hpp"
- #include "_xmp_sfx_SoundEngine.hpp"
- #endif /* _KIT_INC_XMP_SFX_HPP */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_xmp_sfx\include\kit\_xmp_sfx_AudioData.hpp":
- #ifndef _KIT_INC__XMP_SFX_AUDIODATA_HPP
- #define _KIT_INC__XMP_SFX_AUDIODATA_HPP
- #include <kit/commondef.hpp>
- namespace kit {
- #define KIT_MAGIC_KPM (0x4D43506B) // = 'kPCM'
- #define KIT_MAGIC_QOA (0x66616F71) // = 'qoaf'
- class AudioData;
- struct AudioDataHeader { //72B (0x48B)
- u32 magic; // (0x00) = KIT_MAGIC_KPM
- u16 format; // (0x04) = one of AudioStreamFormats enum values
- u16 headerSize; // (0x06) = sizeof(AudioDataHeader)
- u64 dataSize; // (0x08) = size of audio data, in bytes
- u64 loopStart; // (0x10) = which sample to loop back to
- u64 loopEnd; // (0x18) = which sample to jump back to loopStart on
- u64 numSamples; // (0x20) = # of sample frames in audio data
- u32 sampleRate; // (0x28) = the audio data's sample rate, in Hz
- u32 bitRate; // (0x2C) = the audio's bit rate (per second)
- u16 loopCount; // (0x30) = # of times to loop audio (0 = no loop, 0xFFFF = inf loop)
- u16 channels; // (0x32) = # of interlaced channels in the audio data
- u8 bitRemainder; // (0x34) = <bits per sample> % 8
- u8 userflags; // (0x35) = user-defined (is just padding otherwise)
- u16 mode; // (0x36) = 0 for normal PCM data
- void* samples; // (0x38) = the audio's sample data (appears as nullptr in file)
- AudioData* AD_p; // (0x40) = the associated AudioData class (also nullptr in file)
- };
- class SoundEngine;
- class AudioData {
- u32 _type;
- bool _valid = false;
- bool _constructing = true;
- u16 _padding16;
- AudioDataHeader* _data = nullptr;
- //(_parse<format> functions must free what is returned to prevent leaks)
- AudioDataHeader* _parseKPM(BinaryData& fileData);
- AudioDataHeader* _parseQOA(BinaryData& fileData);
- void _construct(const char* filePath, u32 convertToSampleRate,
- bool convertToStereo); //will convert to mono otherwise
- public:
- //master volume for this AudioData clip specifically
- f32 volumeL = 1.0f;
- f32 volumeR = 1.0f;
- AudioData(const char* filePath, u32 convertToSampleRate,
- bool convertToStereo)
- { _construct(filePath, convertToSampleRate, convertToStereo); }
- AudioData(const char* filePath, const SoundEngine* se);
- ~AudioData();
- const AudioDataHeader* getData(){ return _data; }
- void print(size_t samplesToPrint = 0);
- };
- };
- #endif /* _KIT_INC__XMP_SFX_AUDIODATA_HPP */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_xmp_sfx\include\kit\_xmp_sfx_SoundEngine.hpp":
- #ifndef _KIT_INC__XMP_SFX_SOUNDENGINE_HPP
- #define _KIT_INC__XMP_SFX_SOUNDENGINE_HPP
- #include <kit/commondef.hpp>
- namespace kit {
- struct _SoundEngineOpaque;
- class SoundEngine {
- u32 _type;
- bool _valid = false;
- bool _constructing = true;
- u16 _padding16;
- _SoundEngineOpaque* _opq = nullptr;
- public:
- SoundEngine(s32 sfxNumTracks = 64,
- bool musicUseNearestNeighbor = false,
- bool musicCheckLoop = true,
- bool musicNoFilter = false);
- ~SoundEngine();
- bool streamIsMono();
- f64 streamGetCPULoad();
- bool sfxIsTrackPlaying(s32 track);
- u32 sfxGetActiveTracks();
- bool musicIsPlaying();
- bool musicIsModuleLoaded();
- //if stream is mono internally, only the left channel parameter is used
- void streamSetVolume(f32 volumeL, f32 volumeR);
- void streamSetPlayback(bool playing);
- void streamSetPlaybackAndWait(bool playing);
- void streamSetVolumeForced(f32 volumeL, f32 volumeR);
- //if stream is mono internally, pan values are completely ignored
- void sfxSetPanAll(f32 pan); //-1.0f -> 1.0f (0.0f for neutral panning)
- void sfxSetPan(s32 track, f32 pan);
- void sfxSetVolumeAll(f32 volumeL, f32 volumeR);
- void sfxSetVolume(s32 track, f32 volumeL, f32 volumeR);
- void sfxSetVolumeDelta(s32 track, f32 deltaSecondsL, f32 deltaSecondsR);
- void sfxSetSpeedDelta(s32 track, f64 deltaSeconds);
- void sfxSetVolumeAllForced(f32 volumeL, f32 volumeR);
- void sfxSetVolumeForced(s32 track, f32 volumeL, f32 volumeR);
- void musicSetPan(f32 pan);
- void musicSetVolume(f32 volumeL, f32 volumeR);
- void musicSetPlayback(bool playing);
- //this one shouldn't *break* if the stream isn't playing as well per se,
- //but it won't work as intended, as all this does (in addition to stopping)
- //is sleep for as long as the fade in/out's set duration
- void musicSetPlaybackAndWait(bool playing);
- void musicSetCheckLoop(bool enable);
- void musicSetUseNearest(bool enable);
- void musicSetVolumeForced(f32 volumeL, f32 volumeR);
- void lock(bool locked = true);
- void unlock(){ lock(false); }
- void streamStart(){ streamSetPlayback(true); }
- void streamStop(){ streamSetPlayback(false); }
- void streamStopForced();
- void streamStartAndWait(){ streamSetPlaybackAndWait(true); }
- void streamStopAndWait(){ streamSetPlaybackAndWait(false); }
- //returns false if timeout is reached, returning true otherwise
- bool sfxWaitForTracks(size_t timeoutMS = 0); //0 to wait indefinitely
- bool sfxWaitForTrack(s32 track, size_t timeoutMS = 0);
- //returns the track the audio was queued into, or -1 if no empty track was found
- s32 sfxPlay(const AudioData* audio,
- f32 volumeL = 1.0f, f32 volumeR = 1.0f,
- f64 speed = 1.0, f32 pan = 0.0f);
- //make sure to stop all tracks before freeing any instances of AudioData,
- //as to avoid any issues relating to dangling pointers
- void sfxStop(s32 track);
- void sfxStopForced(s32 track); //marks tracks as finished, rather than fading out over 10ms
- void sfxStopAll();
- void sfxStopAllForced();
- void musicLoadModule(const char* filePath);
- void musicReleaseModule();
- void musicStart(){ musicSetPlayback(true); }
- void musicStop(){ musicSetPlayback(false); }
- void musicStopForced();
- void musicStartAndWait(){ musicSetPlaybackAndWait(true); }
- void musicStopAndWait(){ musicSetPlaybackAndWait(false); }
- };
- };
- #endif /* _KIT_INC__XMP_SFX_SOUNDENGINE_HPP */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_xmp_sfx\src\kit_xmp_sfx\kit_SoundEngine_callbackSfx.hpp":
- //this is a header rather than a source file, since the sound effect mixer
- //is in the form of an inline function, to avoid the overhead of a normal one
- #ifndef _KIT_SRC_KIT_SOUNDENGINE_CALLBACKSFX_HPP
- #define _KIT_SRC_KIT_SOUNDENGINE_CALLBACKSFX_HPP
- #include "_kit_shared.hpp"
- namespace kit {
- static inline void mixTracksMono(_SoundEngineTrack& track, f64 streamTimeStamp,
- f32* dst, s32 dst_len, f64 sampleRate)
- {
- //the value volumeDelta is set to if the track hits 0x speed
- const smp_f32s speed0VDelta = -( (1000.0f/_speed0VolDeltaMS) / sampleRate );
- //create stack copy of track data
- //(deltas that can be modified at will (without mutex locking) should not be
- //referenced or set, as they might change by the time the delta values are set back)
- _SoundEngineTrack tr = track;
- //make copies of relevant data from t.audio
- u64 loopStart = tr.audio->loopStart;
- u64 loopEnd = tr.audio->loopEnd; //doubles as src_len
- f32* src = (f32*)tr.audio->samples;
- //calculate position based on difference between dac and audio timestamps
- if(tr.timestamp > 0){
- f64 difference = (streamTimeStamp-tr.timestamp) * sampleRate; //in samples
- tr.position = -(difference*tr.speed_old); //starts playing when position reaches 0
- track.timestamp = 0; //to ensure that this only occurs once per clip queued
- }
- //used for interpolating speed and volume settings from old to new
- f32 t = 0.0f;
- f32 t_increment = 1.0f/dst_len;
- //mix src audio into dst
- for(s32 i=0; i<dst_len; ++i){
- //loop handling (or end-of-clip handling i guess)
- if(tr.position >= loopEnd){ //audio clip finished loop
- if(!tr.loops){ tr.stopping = true; break; } //mark as inactive and break
- if(tr.loops != KIT_U16_MAX) --tr.loops; //decrement loops (unless infinite)
- tr.position -= (u64)tr.position; //basically position %= 1
- tr.position += loopStart; //now new_position = loopStart + old_position%1
- } else if(tr.position < 0){ //if clip has yet to start playing
- if(tr.position < -tr.speed_old){
- tr.position += tr.speed_old; //step forward by current speed
- continue;
- } else { //if position >= -speed, the clip should start next sample
- tr.position = 0; //make sure clip starts at 0
- }
- }
- //get sample
- f32 sample = linearSampleMono(src, tr.position, loopEnd);
- //apply volume while interpolating between its old and new state
- sample *= LERP2(tr.volume_old.l, tr.volume_new.l, t);
- //apply master volume provided by the AudioData's .volumeL member
- sample *= tr.volumeMaster.l;
- //(panning is not applied for mono)
- //update position by speed, while interpolating between speed's old and new state
- tr.position += LERP2(tr.speed_old, tr.speed_new, t);
- //change old and new volume by volumeDelta
- //(deltas are referenced directly with track instead of tr)
- f32 currentVolumeDelta = track.volumeDelta.l;
- tr.volume_old.l += currentVolumeDelta;
- tr.volume_new.l += currentVolumeDelta;
- //make sure the volume is always between 0.0f and 1.0f
- tr.volume_old.l = CLAMP(tr.volume_old.l, 0.0f, 1.0f);
- tr.volume_new.l = CLAMP(tr.volume_new.l, 0.0f, 1.0f);
- //change old and new speed by speedDelta
- f64 currentSpeedDelta = track.speedDelta;
- tr.speed_old += currentSpeedDelta;
- tr.speed_new += currentSpeedDelta;
- //raise interpolation t value
- t += t_increment;
- //start rapid fade out if clip's new speed <= 0
- if(LERP2(tr.speed_old, tr.speed_new, t) <= 0.0){
- tr.speed_old = tr.speed_new = 0.0;
- //volumeDelta is sorta volatile, so that might need to be accounted for...
- track.volumeDelta = speed0VDelta;
- }
- }
- //set relevant old values to the new ones
- track.position = tr.position;
- track.speed_old = tr.speed_new; //both old *and* new speeds
- track.speed_new = tr.speed_new; //must be set to their new values
- track.volume_old = tr.volume_new; //both old *and* new volumes
- track.volume_new = tr.volume_new; //must be set to their new values
- track.loops = tr.loops;
- track.stopping = tr.stopping;
- //check if track needs to be marked as complete
- if(tr.volume_new.l <= 0) track.stopping = true;
- if(track.stopping) track.audio = nullptr;
- }
- static inline void mixTracksStereo(_SoundEngineTrack& track, f64 streamTimeStamp,
- smp_f32s* dst, s32 dst_len, f64 sampleRate)
- {
- //the value volumeDelta is set to if the track hits 0x speed
- const smp_f32s speed0VDelta = -( (1000.0f/_speed0VolDeltaMS) / sampleRate );
- //create stack copy of track data
- //(deltas that can be modified at will (without mutex locking) should not be
- //referenced or set, as they might change by the time the delta values are set back)
- _SoundEngineTrack tr = track;
- //make copies of relevant data from t.audio
- u64 loopStart = tr.audio->loopStart;
- u64 loopEnd = tr.audio->loopEnd; //doubles as src_len
- smp_f32s* src = (smp_f32s*)tr.audio->samples;
- //calculate position based on difference between dac and audio timestamps
- if(tr.timestamp > 0){
- f64 difference = (streamTimeStamp-tr.timestamp) * sampleRate; //in samples
- tr.position = -(difference*tr.speed_old); //starts playing when position reaches 0
- track.timestamp = 0; //to ensure that this only occurs once per clip queued
- }
- //used for interpolating speed and volume settings from old to new
- f32 t = 0.0f;
- f32 t_increment = 1.0f/dst_len;
- //mix src audio into dst
- for(s32 i=0; i<dst_len; ++i){
- //loop handling (or end-of-clip handling i guess)
- if(tr.position >= loopEnd){ //audio clip finished loop
- if(!tr.loops){ tr.stopping = true; break; } //mark as inactive and break
- if(tr.loops != KIT_U16_MAX) --tr.loops; //decrement loops (unless infinite)
- tr.position -= (u64)tr.position; //basically position %= 1
- tr.position += loopStart; //now new_position = loopStart + old_position%1
- } else if(tr.position < 0){ //if clip has yet to start playing
- if(tr.position < -tr.speed_old){
- tr.position += tr.speed_old; //step forward by current speed
- continue;
- } else { //if position >= -speed, the clip should start next sample
- tr.position = 0; //make sure clip starts at 0
- }
- }
- //get sample
- smp_f32s sample = linearSampleStereo(src, tr.position, loopEnd);
- //apply volume while interpolating between its old and new state
- sample *= interpolateF32S(tr.volume_old, tr.volume_new, t);
- //apply master volume provided by the AudioData's .volumeL&R members
- sample *= tr.volumeMaster;
- //mix sample to dst while applying pan WHILE interpolating between old and new
- dst[i] += applyPan(sample, LERP2(tr.pan_old, tr.pan_new, t) );
- //update position by speed, while interpolating between speed's old and new state
- tr.position += LERP2(tr.speed_old, tr.speed_new, t);
- //change old and new volume by volumeDelta
- //(deltas are referenced directly with track instead of tr)
- smp_f32s currentVolumeDelta = track.volumeDelta;
- tr.volume_old += currentVolumeDelta;
- tr.volume_new += currentVolumeDelta;
- //change old and new speed by speedDelta
- f64 currentSpeedDelta = track.speedDelta;
- tr.speed_old += currentSpeedDelta;
- tr.speed_new += currentSpeedDelta;
- //make sure the volume is always between 0.0f and 1.0f
- tr.volume_old.l = CLAMP(tr.volume_old.l, 0.0f, 1.0f);
- tr.volume_old.r = CLAMP(tr.volume_old.r, 0.0f, 1.0f);
- tr.volume_new.l = CLAMP(tr.volume_new.l, 0.0f, 1.0f);
- tr.volume_new.r = CLAMP(tr.volume_new.r, 0.0f, 1.0f);
- //raise interpolation t value
- t += t_increment;
- //start rapid fade out if clip's new speed <= 0
- if(LERP2(tr.speed_old, tr.speed_new, t) <= 0.0){
- tr.speed_old = tr.speed_new = 0.0;
- //volumeDelta is sorta volatile, so that might need to be accounted for...
- track.volumeDelta = speed0VDelta;
- }
- }
- //set relevant old values to the new ones
- track.position = tr.position;
- track.speed_old = tr.speed_new; //both old *and* new speeds
- track.speed_new = tr.speed_new; //must be set to their new values
- track.pan_old = tr.pan_new;
- //track.pan_new = tr.pan_new; //no need to set this, as no delta is applied to pan
- track.volume_old = tr.volume_new; //both old *and* new volumes
- track.volume_new = tr.volume_new; //must be set to their new values
- track.loops = tr.loops;
- track.stopping = tr.stopping;
- //check if track needs to be marked as complete
- if(tr.volume_new.l <= 0 && tr.volume_new.r <= 0) track.stopping = true;
- if(track.stopping) track.audio = nullptr;
- }
- }; /* namespace kit */
- #endif /* _KIT_SRC_KIT_SOUNDENGINE_CALLBACKSFX_HPP */
- /******************************************************************************/
- /******************************************************************************/
- //"kit_xmp_sfx\src\kit_xmp_sfx\_kit_shared.hpp":
- #ifndef _KIT_SRC__KIT_SHARED_HPP
- #define _KIT_SRC__KIT_SHARED_HPP
- #include <math.h>
- #define LIBXMP_STATIC
- #include <libxmp-lite/xmp.h>
- #include <Windows.h>
- #include <kit/audio.hpp>
- #include <kit/xmp_sfx.hpp>
- #ifdef _DEBUG
- #include <stdio.h>
- #define _printf(_fmt,...) printf(_fmt,__VA_ARGS__)
- #else
- #define _printf(_fmt,...)
- #endif
- #define loghere _printf("line %4i: (%s)\n",__LINE__,__FILE__);
- #define KIT_LOCK_SPINCOUNT (2048)
- //class type ID macros
- #define KIT_OPAQUE_PRESENT (0x80000000)
- #define KIT_IS_OPAQUE_PRESENT(_type) ( ((_type)&KIT_OPAQUE_PRESENT) != 0 )
- //classes from kit_w32
- #define KIT_CLASSTYPE_NULL (0x0000 )
- #define KIT_CLASSTYPE_MUTEXSIMPLE (0x0001 | KIT_OPAQUE_PRESENT)
- #define KIT_CLASSTYPE_WINDOW (0x0002 | KIT_OPAQUE_PRESENT)
- #define KIT_CLASSTYPE_BITMAP (0x0003 | KIT_OPAQUE_PRESENT)
- #define KIT_CLASSTYPE_FILEIO_BINARYDATA (0x0004 )
- #define KIT_CLASSTYPE_BITMAPFONT (0x0005 )
- #define KIT_CLASSTYPE_FSTR (0x0006 )
- #define KIT_CLASSTYPE_AUDIOSTREAM (0x0007 | KIT_OPAQUE_PRESENT)
- #define KIT_CLASSTYPE_THREAD (0x0008 | KIT_OPAQUE_PRESENT)
- //classes from kit_xmp_sfx
- #define KIT_CLASSTYPE_AUDIODATA (0x1001 )
- #define KIT_CLASSTYPE_SOUNDENGINE (0x1002 | KIT_OPAQUE_PRESENT)
- namespace kit {
- #define KIT_GET_CLASS_TYPE(_ptr) ( ((_commonClassValues*)(_ptr))->type )
- #define KIT_GET_CLASS_VALID(_ptr) ( ((_commonClassValues*)(_ptr))->valid )
- #define KIT_GET_CLASS_CONSTRUCTING(_ptr) ( ((_commonClassValues*)(_ptr))->constructing )
- #define KIT_GET_CLASS_DATA(_ptr) ( ((_commonClassValues*)(_ptr))->data )
- #define KIT_GET_CLASS_OPAQUE(_ptr) ( ((_commonClassValues*)(_ptr))->opq )
- #define KIT_IS_CLASS_TYPE(_ptr,_type) ( KIT_GET_CLASS_TYPE(_ptr) == (_type) )
- #define KIT_IS_CLASS_VALID(_ptr) ( KIT_GET_CLASS_VALID(_ptr) != 0 )
- #define KIT_IS_CLASS_CONSTRUCTING(_ptr) ( KIT_GET_CLASS_CONSTRUCTING(_ptr) != 0 )
- struct _commonClassValues {
- u32 type;
- bool valid; //'is object fully and successfully constructed?'
- bool constructing; //'is object currently inside constructor?'
- //^^this is useful for if public class functions are called inside the
- //constructor itself, but the valid flag is not set to true yet
- u16 data; //purpose varies by class type; unused by some (or it's split into 2 u8)
- _GenericOpaquePtr opq; //nonexistent if type lacks the KIT_OPAQUE_PRESENT flag
- };
- //in seconds
- #define _totalFadeDelay (0.100f)
- //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 _speed0VolDeltaMS (10.0f)
- //SoundEngine's buffer size, in seconds
- #define _soundEngineBufferSize (0.025)
- #define FORMAT_SWITCH(_channels, _format) \
- ( ((_channels)<<16) | (_format) )
- enum format_switch_enum {
- fmtsw_u8 = FORMAT_SWITCH(1, ASTREAM_FMT_U8 ),
- fmtsw_s8 = FORMAT_SWITCH(1, ASTREAM_FMT_S8 ),
- fmtsw_s16 = FORMAT_SWITCH(1, ASTREAM_FMT_S16),
- fmtsw_s24 = FORMAT_SWITCH(1, ASTREAM_FMT_S24),
- fmtsw_s32 = FORMAT_SWITCH(1, ASTREAM_FMT_S32),
- fmtsw_f32 = FORMAT_SWITCH(1, ASTREAM_FMT_F32),
- fmtsw_u8s = FORMAT_SWITCH(2, ASTREAM_FMT_U8 ),
- fmtsw_s8s = FORMAT_SWITCH(2, ASTREAM_FMT_S8 ),
- fmtsw_s16s = FORMAT_SWITCH(2, ASTREAM_FMT_S16),
- fmtsw_s24s = FORMAT_SWITCH(2, ASTREAM_FMT_S24),
- fmtsw_s32s = FORMAT_SWITCH(2, ASTREAM_FMT_S32),
- fmtsw_f32s = FORMAT_SWITCH(2, ASTREAM_FMT_F32),
- };
- #define s8_inv (0.0078125) // = 1.0/2^7
- #define s16_inv (0.000030517578125) // = 1.0/2^15
- #define s24_inv (0.00000011920928955078125) // = 1.0/2^23
- #define s32_inv (0.0000000004656612873077392578125) // = 1.0/2^31
- //converts formats to f32
- #define u8_conv( _v) ( (f32)( (f64)( (s8)((_v)-128) ) * s8_inv ) )
- #define s8_conv( _v) ( (f32)( (f64)( _v ) * s8_inv ) )
- #define s16_conv(_v) ( (f32)( (f64)( _v ) * s16_inv ) )
- #define s24_conv(_v) ( (f32)( (f64)( _v ) * s24_inv ) )
- #define s32_conv(_v) ( (f32)( (f64)( _v ) * s32_inv ) )
- //the following 5 sample types are only used when loading audio,
- //as they will all be converted to f32 or smp_f32s for use in sfx
- struct smp_u8s { u8 l,r; };
- struct smp_s8s { s8 l,r; };
- struct smp_s32s { s32 l,r; };
- struct smp_s24 { //bruh
- s32 v : 24;
- s32 _ : 8;
- };
- struct smp_s24s { //bruh
- s64 l : 24;
- s64 r : 24;
- s64 _ : 16;
- };
- //in addition to sfx loading, smp_s16s is also used for interactions with libxmp
- struct smp_s16s {
- s16 l,r;
- smp_s16s& operator*=(const f32& smp){ l = (s16)(l*smp); r = (s16)(r*smp); return *this; }
- };
- struct smp_f32s {
- f32 l,r;
- smp_f32s( ) : l( 0.0f), r( 0.0f) {}
- smp_f32s(const f64& _v) : l((f32)_v), r((f32)_v) {}
- smp_f32s(const f32& _l, const f32& _r) : l( _l), r( _r) {}
- smp_f32s(const f64& _l, const f64& _r) : l((f32)_l), r((f32)_r) {}
- smp_f32s(const u8 & smp){ l = r = u8_conv( smp ); }
- smp_f32s(const s8 & smp){ l = r = s8_conv( smp ); }
- smp_f32s(const s16 & smp){ l = r = s16_conv(smp ); }
- smp_f32s(const smp_s24 & smp){ l = r = s24_conv(smp.v); }
- smp_f32s(const s32 & smp){ l = r = s32_conv(smp ); }
- smp_f32s(const f32 & smp){ l = r = smp ; }
- smp_f32s(const smp_u8s & smp){ l = u8_conv( smp.l); r = u8_conv( smp.r); }
- smp_f32s(const smp_s8s & smp){ l = s8_conv( smp.l); r = s8_conv( smp.r); }
- smp_f32s(const smp_s16s& smp){ l = s16_conv(smp.l); r = s16_conv(smp.r); }
- smp_f32s(const smp_s24s& smp){ l = s24_conv(smp.l); r = s24_conv(smp.r); }
- smp_f32s(const smp_s32s& smp){ l = s32_conv(smp.l); r = s32_conv(smp.r); }
- smp_f32s(const smp_f32s& smp){ l = smp.l ; r = smp.r ; }
- smp_f32s& operator+=(const u8 & smp){ l += u8_conv( smp ); r += u8_conv( smp ); return *this; }
- smp_f32s& operator+=(const s8 & smp){ l += s8_conv( smp ); r += s8_conv( smp ); return *this; }
- smp_f32s& operator+=(const s16& smp){ l += s16_conv(smp ); r += s16_conv(smp ); return *this; }
- smp_f32s& operator+=(const smp_s24& smp){ l += s24_conv(smp.v); r += s24_conv(smp.v); return *this; }
- smp_f32s& operator+=(const s32& smp){ l += s32_conv(smp ); r += s32_conv(smp ); return *this; }
- smp_f32s& operator+=(const f32& smp){ l += smp; r += smp; return *this; }
- smp_f32s& operator-=(const f32& smp){ l -= smp; r -= smp; return *this; }
- smp_f32s& operator*=(const f32& smp){ l *= smp; r *= smp; return *this; }
- smp_f32s& operator+=(const smp_u8s & smp){ l += u8_conv( smp.l); r += u8_conv( smp.r); return *this; }
- smp_f32s& operator+=(const smp_s8s & smp){ l += s8_conv( smp.l); r += s8_conv( smp.r); return *this; }
- smp_f32s& operator+=(const smp_s16s& smp){ l += s16_conv(smp.l); r += s16_conv(smp.r); return *this; }
- smp_f32s& operator+=(const smp_s24s& smp){ l += s24_conv(smp.l); r += s24_conv(smp.r); return *this; }
- smp_f32s& operator+=(const smp_s32s& smp){ l += s32_conv(smp.l); r += s32_conv(smp.r); return *this; }
- smp_f32s& operator+=(const smp_f32s& smp){ l += smp.l; r += smp.r; return *this; }
- smp_f32s& operator-=(const smp_f32s& smp){ l -= smp.l; r -= smp.r; return *this; }
- smp_f32s& operator*=(const smp_f32s& smp){ l *= smp.l; r *= smp.r; return *this; }
- bool operator!=(f32 v) const { return (l != v) || (r != v); }
- };
- union smp_ptr {
- void* _data;
- u8* _u8;
- s8* _s8;
- s16* _s16;
- smp_s24* _s24;
- s32* _s32;
- f32* _f32;
- smp_u8s* _u8s;
- smp_s8s* _s8s;
- smp_s16s* _s16s;
- smp_s24s* _s24s;
- smp_s32s* _s32s;
- smp_f32s* _f32s;
- smp_ptr() : _data(nullptr) {}
- smp_ptr(void* data) : _data(data) {}
- };
- //these two are used inside the xmp thread function
- #define to_s16(_smpIn) ( (s16)(_smpIn*KIT_S16_MAX) )
- static inline smp_s16s to_s16s(const smp_f32s& smpIn){
- smp_s16s smpOut;
- smpOut.l = to_s16(smpIn.l);
- smpOut.r = to_s16(smpIn.r);
- return smpOut;
- }
- struct _SoundEngineTrack {
- f64 timestamp; //stream time at time of AudioData being queued
- f64 position;
- f64 speed_old, speed_new;
- f64 speedDelta;
- //speedDelta ^^ (and volumeDelta VV) should affect X_new and not X_old,
- //as to not negatively affect old-to-new interpolation
- //(also, make sure to lock mutex when editing X_new stuff)
- f32 pan_old, pan_new;
- smp_f32s volume_old, volume_new;
- smp_f32s volumeDelta;
- smp_f32s volumeMaster;
- u16 loops;
- bool stopping;
- char _padding[5];
- const AudioDataHeader* audio;
- };
- struct _SoundEngineOpaque {
- CRITICAL_SECTION lock; //the type of mutex object used for synchronization
- AudioStream* stream; //pointer to the internal AudioStream class
- _SoundEngineTrack* tracks; //pointer to array of sound effect tracks
- xmp_context xmpCtx; //used in calls to libxmp functions
- smp_ptr xmpBuffer; //for s16 and smp_s16s
- //the new and old values are interpolated between eachother
- //every invocation of the callback (lock mutex before modifying these!)
- smp_f32s volumeStream_old, volumeStream_new;
- f32 panSfx_old, panSfx_new;
- smp_f32s volumeSfx_old, volumeSfx_new;
- f32 panXmp_old, panXmp_new;
- smp_f32s volumeXmp_old, volumeXmp_new;
- //fadeDelta = 1.0f / (streamSampleRate*_fadeDeltaSeconds)
- f32 fadeDelta; //(used for both music and the actual stream)
- u32 fadeInDelayStream;
- f32 fadeVolumeStream;
- f32 fadeVolumeXmp;
- bool fadeOutStream;
- bool fadeOutXmp;
- bool xmpUseNearest; //use nearest-neighbor interpolation
- bool xmpCheckLoop; //stop looping when loop counter reaches specified value
- bool xmpNoFilter; //disable low-pass filter (this has yet to be implemented)
- bool xmpModuleLoaded;
- bool xmpPlaying;
- bool streamIsMono;
- bool streamPlaying;
- char _padding8[3];
- f64 streamSampleRate;
- u32 streamSampleFrames;
- s32 tracks_len;
- };
- static inline bool isFormatValid(u16 format){
- switch(format){
- case ASTREAM_FMT_U8 :
- case ASTREAM_FMT_S8 :
- case ASTREAM_FMT_S16:
- case ASTREAM_FMT_S24:
- case ASTREAM_FMT_S32:
- case ASTREAM_FMT_F32: return true;
- default : return false;
- }
- }
- #ifndef LERP2
- #define LERP2(_v0,_v1, _t) ( (_v0) + (_t)*((_v1)-(_v0)) )
- #endif
- static inline smp_f32s interpolateF32S(const smp_f32s& smpA,
- const smp_f32s& smpB,
- f32 t_value)
- {
- return smp_f32s(
- LERP2(smpA.l, smpB.l, t_value),
- LERP2(smpA.r, smpB.r, t_value)
- );
- }
- static inline f32 linearSampleMono(const f32* src, f64 position,
- u64 loopEnd = KIT_U64_MAX)
- {
- u64 intPosition = (u64)position;
- f32 modPosition = (f32)(position-intPosition); //the position's fraction
- f32 smpA = src[ intPosition];
- f32 smpB = src[(++intPosition)%loopEnd];
- return LERP2(smpA, smpB, modPosition);
- }
- static inline smp_f32s linearSampleStereo(const smp_f32s* src, f64 position,
- u64 loopEnd = KIT_U64_MAX)
- {
- u64 intPosition = (u64)position;
- f32 modPosition = (f32)(position-intPosition); //the position's fraction
- smp_f32s smpA = src[ intPosition];
- smp_f32s smpB = src[(++intPosition)%loopEnd];
- return interpolateF32S(smpA, smpB, modPosition);
- }
- #define convertPan(_pan) CLAMP(_pan, -1.0f, 1.0f)
- //#define convertPan(_pan) CLAMP( (_pan+1.0f)*0.5f, 0.0f, 1.0f )
- #define sqrt2_inv ( 0.70710678f )
- //sort of a work-in-progress
- static inline smp_f32s& applyPan(smp_f32s& sample, f32 pan){
- 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;
- }
- }; /* namespace kit */
- #endif /* _KIT_SRC__KIT_SHARED_HPP */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement