Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /******************************************************************************/
- /******************************************************************************/
- //"2024-11-21\src\demo\callbacks.cpp":
- #include <include_all.hpp>
- using namespace kit;
- void watch_win_resize(Event& event, void* userdata){
- if(event.type != KEVENT_WIN_SIZE_CHANGED) return;
- if(canvas_lock && win){
- canvas_lock->lock();
- win->renewSurface();
- if(canvas){
- Surface* canvas_old = canvas;
- Surface* canvas_new = new Surface(*win, PIXELFMT_ABGR8888);
- canvas = canvas_new;
- delete canvas_old;
- }
- canvas_lock->unlock();
- }
- (void)userdata; //userdata isn't used here
- }
- s32 audio_callback(void* _buffer, const AudioDeviceInfo& info){
- Stereo_f32* dst = (Stereo_f32*)_buffer;
- u16 dst_len = info.sampleFrames;
- if(music) music->mixTracks(dst, dst_len, info.timeStartMS);
- if(sfx) sfx->mixTracks(dst, dst_len, info.timeStartMS);
- //clamp all samples to a unit range, before setting volume to VOLUME
- #define VOLUME 0.10f //10%
- for(u16 i=0; i<dst_len; ++i){
- dst[i].l = CLAMP(dst[i].l, -1.0f, 1.0f) * VOLUME;
- dst[i].r = CLAMP(dst[i].r, -1.0f, 1.0f) * VOLUME;
- }
- return 0;
- }
- /******************************************************************************/
- /******************************************************************************/
- //"2024-11-21\src\demo\main.cpp":
- #include <stdlib.h>
- #include <windows.h>
- #include <include_all.hpp>
- using namespace kit;
- DEF_GLOBAL_PTRS
- colors::ABGR* pixels;
- /*
- sim speed should slow music and sfx down
- 1 = 640, 480
- 2 = 320, 240
- 4 = 160, 120
- 5 = 128, 96
- 8 = 80, 60
- 10 = 64, 48
- 16 = 40, 30
- 20 = 32, 24
- 32 = 20, 15
- 40 = 16, 12
- 80 = 8, 6
- 160 = 4, 3
- */
- void watch_win_resize(Event& event, void* userdata);
- s32 audio_callback(void* _buffer, const AudioDeviceInfo& info);
- int user_main(int argc, char** argv);
- int main(int argc, char** argv){
- int returnStatus = -1; try {
- u64 ticksStart = time::getTicks();
- initSubsystems(KINIT_EVERYTHING);
- AudioDeviceInfo adev_info;
- adev_info.numChannels = 2;
- adev_info.zeroBuffer = true;
- adev_info.callback = audio_callback;
- audio = new AudioDevice(nullptr, adev_info);
- (void)adev_info;
- if(audio) audio->play();
- sfx = new SoundEngine(64, audio->info.sampleRate);
- music = new SoundEngine( 1, audio->info.sampleRate);
- //setting this to false allows me to play music starting at 0% volume
- music->stopIfVolumeIsZero = false;
- sfx_tick = new AudioData("audio/tick.wav", AudioDataLoadWAV);
- sfx_tick->convertFormat(SMPFMT_F32);
- sfx_alert = new AudioData("audio/alert.ogg", AudioDataLoadOGG);
- sfx_alert->convertFormat(SMPFMT_F32);
- AudioData music_data("audio/music.ogg", AudioDataLoadOGG);
- music_data.convertFormat(SMPFMT_F32);
- music_data.hdr->loopCount = 0xFFFF; //inf loop
- if(music->play(music_data, 0.0f, 0.0f, 1.0) == 0xFFFF)
- throw "failed to queue music track"; //should be impossible
- music->setVolumeDelta(5.0f, 5.0f); //fade-in over 5 seconds
- //EventWatch watch_resize_events(watch_win_resize);
- canvas_lock = new Mutex;
- win = new Window("kit_sdl2 + Box2D-Lite demo", WIN_X, WIN_Y,
- WINFLAG_HIDDEN, WINPOS_CENTERED, WINPOS_CENTERED);
- canvas = new Surface(CNV_X, CNV_Y, PIXELFMT_ABGR8888);
- pixels = (colors::ABGR*)canvas->getPixelData();
- #define GRAY(_hexvalue) 0xFF##_hexvalue##_hexvalue##_hexvalue
- font0 = new BFont_Surface(nullptr, nullptr, GRAY(10), 4096);
- font1 = new BFont_Surface(nullptr, nullptr, GRAY(FF), 4096);
- font1->txt_bg.v = font0->txt_bg.v = GRAY(40);
- srand((u32)time::getTicks());
- u64 ticksTaken = (time::getTicks()-ticksStart) * 1000; // *1000 to get milliseconds
- kit_LogInfo("INITIALIZED IN: %fms", (f64)ticksTaken/time::getTicksPerSecond());
- //win->setVisibility(true);
- returnStatus = user_main(argc, argv);
- music->stop();
- sfx ->stop();
- audio->pause();
- //watch_resize_events.setState(false); //stops the callback from being invoked
- NULLDELETE(win, Window);
- NULLDELETE(canvas, Surface);
- NULLDELETE(canvas_lock, Mutex);
- NULLDELETE(font0, BFont_Surface);
- NULLDELETE(font1, BFont_Surface);
- sfx->stop(0xFFFF, true);
- NULLDELETE(sfx_tick, AudioData);
- NULLDELETE(sfx_alert, AudioData);
- NULLDELETE(sfx, SoundEngine);
- audio->pauseAndWait();
- NULLDELETE(audio, AudioDevice);
- NULLDELETE(music, SoundEngine);
- } catch(const char* errorText){
- #ifdef _DEBUG
- kit_LogError("FATAL EXCEPTION OCCURRED: \"%s\"\n", errorText);
- #else
- MessageBeep(MB_ICONERROR);
- showMsgBox(errorText, "FATAL EXCEPTION OCCURRED!", MSGBOX_ERROR);
- #endif /* _DEBUG */
- //redundant, as quitSubsystems already does this when given KINIT_EVERYTHING
- //freeThreadErrors();
- }
- //can't error, and is also safe to call even if no subsystems are active!
- quitSubsystems(KINIT_EVERYTHING);
- //a nonzero value indicates a memory leak, or the number of allocations
- //was improperly inc/decremented internally!
- if(memory::getNumAllocations())
- kit_LogWarn("# OF ALLOCATIONS = %lli", (s64)memory::getNumAllocations());
- return returnStatus;
- }
- /******************************************************************************/
- /******************************************************************************/
- //"2024-11-21\src\demo\user_main.cpp":
- #include <cstddef>
- #include <unistd.h>
- #include <include_all.hpp>
- using namespace kit;
- #define CNV_POINT_EQ(_a, _b)
- bool dragging = false;
- shape::line drag;
- shape::fpoint velocity;
- #define VEL_MUL 10.0f
- static inline f32 getVelScalar(f32 x0, f32 y0, f32 x1, f32 y1){
- f32 dx = (x0-x1), dy = (y0-y1);
- return sqrtf(dx*dx + dy*dy)*VEL_MUL;
- }
- static inline shape::fpoint getVel(f32 x0, f32 y0, f32 x1, f32 y1){
- f32 dx = (x0-x1), dy = (y0-y1);
- //f32 len = sqrtf(dx*dx + dy*dy);
- return {(dx)*VEL_MUL, (dy)*VEL_MUL};
- }
- bool mouse_focus = false;
- shape::point mouse;
- f32 boxSize = 24.0f;
- Body bodies[200];
- int bodies_len = 0;
- //(gravity_x, gravity_y), iterations
- World world(Vec2(0.0f, 300.0f), 10);
- Body bodyFloor;
- void worldInit(){
- world.Clear();
- bodies_len = 0;
- bodyFloor.Set(Vec2(CNV_X-16-2, 10), FLT_MAX);
- bodyFloor.position.Set(CNV_X/2+8.0f, CNV_Y-6.0f);
- world.Add(&bodyFloor);
- }
- void launchBox(){
- if(bodies_len >= (sizeof(bodies)/sizeof(Body))) return; //can't add any more
- Body& newbody = bodies[bodies_len++];
- newbody.Set(Vec2(boxSize, boxSize), boxSize*50);
- newbody.position.Set(drag.x0, drag.y0);
- newbody.velocity = Vec2(velocity.x, velocity.y);
- world.Add(&newbody);
- }
- extern colors::ABGR* pixels;
- static inline void drawPoint(s32 x, s32 y, colors::ABGR pointColor){
- if(x >= 0 && x < CNV_X && y >= 0 && y < CNV_Y)
- pixels[x + y*CNV_X].v = pointColor.v;
- }
- void drawCursorTextCtx(){
- if(!mouse_focus) return;
- if(mouse.x > 16){
- if(!dragging){
- drawPoint(mouse.x, mouse.y, 0xFFFFFFFF);
- } else {
- f32 h = boxSize/2-1;
- Box(drag.x0-h, drag.y0-h, boxSize, boxSize).draw();
- drawCursorText(mouse.x, mouse.y, "vel: %.2f",
- getVelScalar(drag.x0, drag.y0, drag.x1, drag.y1));
- }
- } else {
- drawCursorText(mouse.x, mouse.y, "simulation speed: %.2fx", simSpeed);
- }
- }
- /******************************************************************************/
- bool handleEvents(){
- bool run = true;
- bool launch = false;
- Event evt;
- while(pollEvent(&evt))
- switch(evt.type){
- case KEVENT_QUIT: run = false; break;
- case KEVENT_MOUSE_DOWN: {
- sfx->play(*sfx_tick, 1.0f, 1.0f, 1.5);
- drag.x0 = evt.mouse.x/CNV_DIV;
- drag.y0 = evt.mouse.y/CNV_DIV;
- drag.x1 = drag.x0;
- drag.y1 = drag.y0;
- if(mouse.x <= 16) goto _set_sim_speed;
- else dragging = true;
- } break;
- case KEVENT_MOUSE_UP: {
- sfx->play(*sfx_tick, 1.0f, 1.0f, -1.0);
- dragging = false;
- if(mouse.x > 16){
- launch = true;
- _set_endpoint:
- drag.x1 = mouse.x;
- drag.y1 = mouse.y;
- velocity = getVel(drag.x0, drag.y0, drag.x1, drag.y1);
- if(launch) launchBox();
- }
- } break;
- case KEVENT_MOUSE_MOVED: {
- mouse.x = evt.mouse.x/CNV_DIV;
- mouse.y = evt.mouse.y/CNV_DIV;
- if(mouse.x > 16){
- if(evt.mouse.pressed && dragging) goto _set_endpoint;
- } else {
- if(evt.mouse.pressed) _set_sim_speed:
- setSimSpeed((f64)(CNV_Y-mouse.y)/CNV_Y);
- }
- } break;
- case KEVENT_MOUSE_WHEEL: { //negative = scrolling down
- boxSize += evt.mouse.pdy;
- boxSize = CLAMP(boxSize, 1.0f, 178.0f);
- } break;
- case KEVENT_WIN_MFOCUS_GAINED: mouse_focus = true; break;
- case KEVENT_WIN_MFOCUS_LOST : mouse_focus = false; break;
- case KEVENT_KEY_DOWN: {
- if(!evt.key.repeat){ //reset if a key is pressed
- sfx->play(*sfx_alert, 1.0f, 1.0f, 1.5);
- worldInit();
- }
- } break;
- default: kit_LogInfo("unhandled event = %s", getEventText(evt.type));
- }
- return run;
- }
- /******************************************************************************/
- int user_main(int argc, char** argv){
- win->setVisibility(true);
- worldInit();
- while(true){
- u64 timeStart = time::getTicks();
- if(!handleEvents()) break;
- clearCanvas();
- world.Step(timeStep);
- drawBody(bodyFloor);
- for(int i=0; i<bodies_len; ++i)
- drawBody(bodies[i]);
- Box(CNV_X-1-boxSize, 1.0f, boxSize, boxSize).draw();
- if(dragging && mouse.x > 16)
- drawLine(drag.x0, drag.y0, drag.x1, drag.y1, 0xFF00FF);
- drawSpeedBar();
- drawCursorText(CNV_X-2-boxSize, 1, "box size: %.0fpx", boxSize);
- drawCursorTextCtx();
- f64 timeDelta = (f64)(time::getTicks()-timeStart)/time::getTicksPerSecond();
- font1->draw(*canvas, 17, 1, "rendered in %.0f\nmicroseconds", 0, timeDelta*1000000);
- presentCanvas();
- time::sleep(16);
- }
- (void)argc, (void)argv; //begone, unused parameter warning
- return 0;
- }
- /******************************************************************************/
- /******************************************************************************/
- //"2024-11-21\src\demo\utils.cpp":
- #include <stdlib.h>
- #include <include_all.hpp>
- using namespace kit;
- //assumes RAND_MAX is 32767
- #define GET_FRAND_VALUE(cast) ( (cast)(rand()<<15|rand())/0x3fffffff )
- f64 frand(){ //0.0f -> 1.0f
- return GET_FRAND_VALUE(f64);
- }
- f64 frand2(){ //-1.0f -> 1.0f
- return GET_FRAND_VALUE(f64)*2.0f - 1.0f;
- }
- f32 frandf(){ //0.0f -> 1.0f
- return GET_FRAND_VALUE(f32);
- }
- f32 frandf2(){ //-1.0f -> 1.0f
- return GET_FRAND_VALUE(f32)*2.0f - 1.0f;
- }
- void presentCanvas(){
- if(canvas_lock && win){
- canvas_lock->lock();
- win->renewSurface();
- if(canvas) canvas->blitScaled(*win);
- win->updateSurface();
- canvas_lock->unlock();
- }
- }
- extern colors::ABGR* pixels;
- /*
- static inline void drawPoint(s32 x, s32 y, colors::ABGR pointColor){
- if(x >= 0 && x < CNV_X && y >= 0 && y < CNV_Y)
- pixels[x + y*CNV_X].v = pointColor.v;
- }
- void drawLine(s32 x_0, s32 y_0,
- s32 x_1, s32 y_1,
- colors::ABGR lineColor)
- {
- lineColor.v |= 0xFF000000; //make sure alpha is always 255
- s32 d_x = abs(x_1 - x_0);
- s32 d_y = -abs(y_1 - y_0);
- s32 s_x = (x_0<x_1) ? 1 : -1;
- s32 s_y = (y_0<y_1) ? 1 : -1;
- s32 err = d_x + d_y;
- while(true){
- drawPoint(x_0, y_0, lineColor);
- if(x_0 == x_1 && y_0 == y_1) break;
- s32 err2 = err<<1;
- if(err2 >= d_y){
- err += d_y;
- x_0 += s_x;
- }
- if(err2 <= d_x){
- err += d_x;
- y_0 += s_y;
- }
- }
- }
- */
- void drawLine(s32 x_0, s32 y_0,
- s32 x_1, s32 y_1,
- colors::ABGR lineColor)
- {
- lineColor.v |= 0xFF000000; //make sure alpha is always 255
- s32 d_x = abs(x_1 - x_0);
- s32 d_y = -abs(y_1 - y_0);
- s32 s_x = (x_0<x_1) ? 1 : -1;
- s32 s_y = (y_0<y_1) ? 1 : -1;
- s32 err = d_x + d_y;
- s32 _s_x = s_x * sizeof(colors::ABGR);
- s32 _s_y = s_y * sizeof(colors::ABGR) * CNV_X;
- u8* _pixels = (u8*)&pixels[x_0 + y_0*CNV_X];
- while(true){
- if((x_0 >= 0) && (x_0 < CNV_X) && (y_0 >= 0) && (y_0 < CNV_Y))
- ((colors::ABGR*)_pixels)->v = lineColor.v;
- if(x_0 == x_1 && y_0 == y_1) break;
- s32 err2 = err<<1;
- if(err2 >= d_y){
- err += d_y;
- x_0 += s_x;
- _pixels += _s_x;
- }
- if(err2 <= d_x){
- err += d_x;
- y_0 += s_y;
- _pixels += _s_y;
- }
- }
- }
- #define V2I(_p) (s32)((_p).x), (s32)((_p).y)
- #define DRAWLINE_VEC2(_a, _b, _color) \
- drawLine(V2I(_a), V2I(_b), _color)
- void drawBody(Body& body){
- Mat22 rot(body.rotation);
- Vec2 pos = body.position;
- Vec2 siz = 0.5f * body.width;
- Vec2 p0 = pos + rot * Vec2(-siz.x, -siz.y);
- Vec2 p1 = pos + rot * Vec2( siz.x, -siz.y);
- Vec2 p2 = pos + rot * Vec2( siz.x, siz.y);
- Vec2 p3 = pos + rot * Vec2(-siz.x, siz.y);
- colors::ABGR color = 0xFFFF00;
- color.a = 255;
- DRAWLINE_VEC2(p0, p1, color);
- DRAWLINE_VEC2(p1, p2, color);
- DRAWLINE_VEC2(p2, p3, color);
- DRAWLINE_VEC2(p3, p0, color);
- }
- #undef V2I
- #include <stdarg.h>
- #define BOXED_TEXT 1
- //draws whatever is currently in the font's format buffer
- void drawCursorText(s32 x, s32 y, const char* fmt, ...){
- bool npm0 = font0->neg_pos_margin;
- bool npm1 = font1->neg_pos_margin;
- font0->neg_pos_margin = false;
- font1->neg_pos_margin = false;
- u8* buffer0 = font0->getFmtBuffer();
- u32 buffer0_len = font0->getFmtBufferLen();
- //u8* buffer1 = font1->getFmtBuffer();
- //u32 buffer1_len = font1->getFmtBufferLen();
- va_list va;
- va_start(va, fmt);
- vsnPrintf((char*)buffer0, buffer0_len, fmt, va);
- va_end(va);
- font1->copy((char*)buffer0);
- #if BOXED_TEXT == 1
- shape::rect txtRect = font0->getRect(*canvas, x, y, true);
- if(!font0->box_padded) ++txtRect.w, ++txtRect.h;
- if(txtRect.x >= txtRect.w) txtRect.x -= txtRect.w;
- if(txtRect.y >= txtRect.h) txtRect.y -= txtRect.h;
- shape::point txtShift = font0->drawBoxNoText(*canvas, txtRect.x, txtRect.y,
- txtRect.w, txtRect.h);
- txtRect.x += txtShift.x + 1;
- txtRect.y += txtShift.y + 1;
- font0->draw(*canvas, txtRect.x, txtRect.y);
- font1->draw(*canvas, txtRect.x-1, txtRect.y-1);
- #else
- shape::rect txtRect = font0->getRect(*canvas, x, y, false);
- if(txtRect.x >= (CNV_X/2)) txtRect.x -= txtRect.w;
- if(txtRect.y >= txtRect.h) txtRect.y -= txtRect.h;
- font0->draw(*canvas, txtRect.x+1, txtRect.y+1);
- font1->draw(*canvas, txtRect.x, txtRect.y);
- #endif
- font0->neg_pos_margin = npm0;
- font1->neg_pos_margin = npm1;
- }
- f64 simSpeed = 1.0;
- f32 timeStep = 1.0f / (1000.0f/16);
- void drawSpeedBar(f32 speed){
- const static shape::rect bar(0,0, 16,CNV_Y);
- const shape::rect slider(0, (2.0-speed*2.0)*(CNV_Y-1), 17,1);
- canvas->fillRects(0xFF202020, &bar, 1);
- canvas->fillRects(0xFFFFFFFF, &slider, 1);
- }
- void setSimSpeed(f64 newSpeed){
- simSpeed = 0.5 + CLAMP(newSpeed,0.0,1.0)/2;
- music->setSpeed(simSpeed);
- timeStep = (simSpeed) / (1000.0f/16);
- }
- /******************************************************************************/
- /******************************************************************************/
- //"2024-11-21\src\kit_sdl2\kit_AudioCallbackWrapper.cpp":
- #include "_kit_common.hpp"
- namespace kit {
- //workaround for having _AudioCallbackWrapper pause the device,
- //without having to call SDL_PauseAudioDevice inside the callback itself
- //(this may potentially cut off playback before the current buffer plays, idk)
- static int _AudioPauseThread(void* data){
- _AudioDeviceOpaque* opq = (_AudioDeviceOpaque*)data;
- SDL_AudioDeviceID devID = opq->info_p->deviceID;
- //wait for the callback to exit before actually pausing
- SDL_LockAudioDevice(devID);
- SDL_PauseAudioDevice(devID, 1);
- opq->fadeOut = false;
- opq->playing = false;
- SDL_UnlockAudioDevice(devID);
- return 0;
- }
- static inline bool startPauseThread(_AudioDeviceOpaque* opq){
- SDL_Thread* pauseThread = SDL_CreateThread(_AudioPauseThread, "kADPause", opq);
- if(pauseThread){
- SDL_DetachThread(pauseThread);
- } else {
- opq->fadeDelay = KIT_U32_MAX;
- opq->fadeOut = false;
- opq->playing = false;
- }
- return pauseThread != nullptr;
- }
- //not inlined
- //(also, stream_len is in total samples, not sample frames)
- static void apply_fade(_AudioDeviceOpaque* opq,
- f32* stream, u32 stream_len)
- {
- f32 fadeDelta = opq->fadeDelta;
- f32 fadeVolume = opq->fadeVolume;
- u32 fadeDelay = opq->fadeDelay;
- u8 numChannels = opq->info_p->numChannels;
- u32 smp = 0; //this index is shared, as the loops can jump to others at will
- //FADING OUT
- if(opq->fadeOut){
- _FadeOut:;
- for(; smp<stream_len; ++smp){
- //if audio device starts fading in mid-fadeout, jump to the fade-in loop
- if(!opq->fadeOut) goto _FadeIn;
- stream[smp] *= fadeVolume;
- //only change fadeVolume every numChannels samples,
- //so that there's 1 fadeVolume state per sample frame
- if(!((smp+1)%numChannels)) fadeVolume -= fadeDelta;
- //to enforce a minimum volume
- if(fadeVolume < 0.0f) fadeVolume = 0.0f;
- }
- //trigger pause thread if fade out is complete
- if(fadeVolume == 0.0f)
- startPauseThread(opq);
- //FADING IN
- } else if(fadeVolume < 1.0f){
- //let stream warm up before fading in (if fadeDelay != 0)
- for(; (fadeDelay)&&(smp<stream_len); ++smp){
- stream[smp] = 0.0f;
- if(!((smp+1)%numChannels)) --fadeDelay;
- }
- _FadeIn:;
- for(; smp<stream_len; ++smp){
- if(opq->fadeOut) goto _FadeOut;
- stream[smp] *= fadeVolume;
- if(!((smp+1)%numChannels)) fadeVolume += fadeDelta;
- if(fadeVolume > 1.0f) fadeVolume = 1.0f;
- }
- }
- //update relevant data in opq
- opq->fadeVolume = fadeVolume;
- opq->fadeDelay = fadeDelay;
- }
- //for multiplying the by inverse of stuff
- #define INV_S8 0.0078125000000000000000000000000f // = 1.0f/0x80
- #define INV_S16 0.0000305175781250000000000000000f // = 1.0f/0x8000
- #define INV_S32 0.0000000004656612873077392578125f // = 1.0f/0x80000000
- #define fmtconvloop for(u32 i=0; i<length; ++i) to
- //used for output devices
- //(length should be in samples, not sample frames)
- static inline void fmt_to_f32(Mono_smp from, f32* to,
- u32 length, u16 from_fmt)
- {
- switch(from_fmt){
- case SMPFMT_U8 : fmtconvloop[i] = ((f32)from.u8_ [i]-0x80 )*INV_S8 ; break;
- case SMPFMT_S8 : fmtconvloop[i] = ((f32)from.s8_ [i] )*INV_S8 ; break;
- case SMPFMT_U16: fmtconvloop[i] = ((f32)from.u16_[i]-0x8000)*INV_S16; break;
- case SMPFMT_S16: fmtconvloop[i] = ((f32)from.s16_[i] )*INV_S16; break;
- case SMPFMT_S32: fmtconvloop[i] = ((f32)from.s32_[i] )*INV_S32; break;
- case SMPFMT_F32: memory::copy(to, from.f32_, length*sizeof(f32)); break;
- //(f32 samples aren't hard-clipped! make sure to keep them -1.0f -> 1.0f)
- }
- }
- //used for input devices
- //(again, length should be in samples, not sample frames)
- static inline void f32_to_fmt(f32* from, Mono_smp to,
- u32 length, u16 to_fmt)
- {
- //(input f32 samples aren't hard-clipped here either!)
- switch(to_fmt){
- case SMPFMT_U8 : fmtconvloop.u8_ [i] = (u8 )(from[i]*0x7F + 0x80 ); break;
- case SMPFMT_S8 : fmtconvloop.s8_ [i] = (s8 )(from[i]*0x7F ); break;
- case SMPFMT_U16: fmtconvloop.u16_[i] = (u16)(from[i]*0x7FFF + 0x8000); break;
- case SMPFMT_S16: fmtconvloop.s16_[i] = (s16)(from[i]*0x7FFF ); break;
- case SMPFMT_S32: fmtconvloop.s32_[i] = (s32)(from[i]*0x7FFFFFFF ); break;
- case SMPFMT_F32: memory::copy(to.f32_, from, length*sizeof(f32));
- }
- }
- void _AudioCallbackWrapper(void* userdata, u8* _stream, int len){
- u64 timeStartTicks = SDL_GetPerformanceCounter();
- u64 timeStartMS = SDL_GetTicks64();
- AudioDevice* device = (AudioDevice*)userdata;
- f32* stream = (f32*)_stream;
- u32 stream_size = len;
- u32 stream_len = len / sizeof(f32); //samples, not sample frames
- _AudioDeviceOpaque* opq = (_AudioDeviceOpaque*)KIT_GET_CLASS_OPAQUE(device);
- AudioDeviceInfo* info_p = opq->info_p;
- info_p->timeStartTicks = timeStartTicks;
- info_p->timeStartMS = timeStartMS;
- //if pause thread failed to start,
- //simply write zeros to stream (if !isInput) and exit
- if(opq->fadeDelay == KIT_U32_MAX){
- if(!info_p->isInput) memory::set(stream, 0, stream_size);
- return;
- }
- s32 callbackReturn = -1; //'abort playback' by default
- if(!info_p->isInput){ //buffer will be written to
- //(memset 0 the _user_ buffer, not the sdl stream)
- if(info_p->zeroBuffer) memory::set(opq->buffer, 0, opq->buffer_size);
- try { //attempt to call user callback
- if(info_p->callback)
- callbackReturn = info_p->callback(opq->buffer, *info_p);
- } catch(const char* errortext){
- kit_LogError("IN AUDIO CALLBACK: \"%s\"", errortext);
- freeThreadErrors();
- //set back to 0, since used callback failed
- memory::set(stream, 0, stream_size);
- }
- //copy buffer to stream (X to f32)
- fmt_to_f32(opq->buffer, stream, stream_len, info_p->sampleFormat);
- //apply fade to output stream
- apply_fade(opq, stream, stream_len);
- } else { //buffer will be read from
- //apply fade to input stream
- apply_fade(opq, stream, stream_len);
- //copy stream to buffer (f32 to X)
- f32_to_fmt(stream, opq->buffer, stream_len, info_p->sampleFormat);
- try { //attempt to call user callback
- if(info_p->callback)
- callbackReturn = info_p->callback(opq->buffer, *info_p);
- } catch(const char* errortext){
- kit_LogError("IN AUDIO CALLBACK: \"%s\"", errortext);
- freeThreadErrors();
- }
- }
- opq->fadeOut = callbackReturn != 0;
- if(callbackReturn < 0) startPauseThread(opq);
- }
- }; /* namespace kit */
- /******************************************************************************/
- /******************************************************************************/
- //"2024-11-21\src\kit_sdl2\kit_AudioData.cpp":
- #include "_kit_common.hpp"
- #define ADATA_IS_INVALID (!_valid)
- namespace kit {
- //#define DONT_USE_ALLOCSIMD //for debugging
- void AudioDataHeader::printHeader(const char* name){
- //(SDL_Log adds \n automatically, but ignores the last \n if added manually)
- if(name != nullptr) kit_LogInfo("%s = {\n", name);
- else kit_LogInfo("%p = {\n", this);
- #ifdef _DEBUG
- kit_LogInfo(" ->magic = \"%.4s\"; (0x%08X)\n", (char*)&magic, magic);
- const char* fmt_txt = "?";
- switch(format){
- case SMPFMT_U8 : fmt_txt = "U8"; break;
- case SMPFMT_S8 : fmt_txt = "S8"; break;
- case SMPFMT_U16LSB: fmt_txt = "U16LSB"; break;
- case SMPFMT_S16LSB: fmt_txt = "S16LSB"; break;
- case SMPFMT_S24LSB: fmt_txt = "S24LSB"; break;
- case SMPFMT_S32LSB: fmt_txt = "S32LSB"; break;
- case SMPFMT_F32LSB: fmt_txt = "F32LSB"; break;
- case SMPFMT_F64LSB: fmt_txt = "F64LSB"; break;
- case SMPFMT_U16MSB: fmt_txt = "U16MSB"; break;
- case SMPFMT_S16MSB: fmt_txt = "S16MSB"; break;
- case SMPFMT_S24MSB: fmt_txt = "S24MSB"; break;
- case SMPFMT_S32MSB: fmt_txt = "S32MSB"; break;
- case SMPFMT_F32MSB: fmt_txt = "F32MSB"; break;
- case SMPFMT_F64MSB: fmt_txt = "F64MSB"; break;
- default : fmt_txt = "UNKNOWN";
- }
- kit_LogInfo(" ->format = SMPFMT_%s; (0x%04X)\n", fmt_txt, format);
- kit_LogInfo(" ->headerSize = %u;\n", headerSize);
- kit_LogInfoS(" ->dataSize = %llu;\n", dataSize);
- kit_LogInfoS(" ->loopStart = %llu;\n", loopStart);
- kit_LogInfoS(" ->loopEnd = %llu;\n", loopEnd);
- kit_LogInfoS(" ->numSamples = %llu;\n", numSamples);
- kit_LogInfo(" ->sampleRate = %u;\n", sampleRate);
- kit_LogInfo(" ->bitRate = %u;\n", bitRate);
- kit_LogInfo(" ->loopCount = %u;\n", loopCount);
- kit_LogInfo(" ->channels = %u;\n", channels);
- kit_LogInfo(" ->_reserved = %u;\n", _reserved);
- kit_LogInfo(" ->fmt_version = %u;\n", fmt_version);
- kit_LogInfo(" ->mode = %u;\n", mode);
- kit_LogInfo(" ->metadata_type = %u;\n", metadata_type);
- kit_LogInfo(" ->samples = %p;\n", samples);
- kit_LogInfo(" ->userdata = %p;\n", userdata);
- kit_LogInfo("};");
- #else
- kit_LogInfo(" (AudioDataHeader::printHeader() is not available in release build!)\nINFO: }\n");
- #endif /* _DEBUG */
- }
- void AudioData::_allocate_hdr(u16 headerSize, u64 dataSize,
- const char* funcName)
- {
- if(_valid) return;
- _type = KIT_CLASSTYPE_AUDIODATA;
- if(funcName == nullptr)
- funcName = "AudioData::AudioData(raw allocation)";
- if(headerSize < sizeof(AudioDataHeader))
- THROW_ERRORF("%s: headerSize < sizeof(AudioDataHeader)", funcName);
- #ifndef DONT_USE_ALLOCSIMD
- hdr = (AudioDataHeader*)memory::allocSIMD(headerSize+dataSize);
- #else
- hdr = (AudioDataHeader*)memory::alloc(headerSize+dataSize);
- #endif /* DONT_USE_ALLOCSIMD */
- if(hdr == nullptr)
- THROW_ERRORF("%s: failed to allocate memory", funcName);
- memory::set(hdr, 0, headerSize+dataSize);
- hdr->headerSize = headerSize;
- hdr->dataSize = dataSize;
- hdr->samples = (u8*)hdr + hdr->headerSize;
- _valid = true;
- _constructing = false;
- }
- AudioData::AudioData(AudioSampleFormatEnum format,
- u64 numSamples, u16 channels, u32 sampleRate)
- {
- if(_valid) return;
- _type = KIT_CLASSTYPE_AUDIODATA;
- const u64 dataSize = KIT_AUDIO_BYTESIZE(format)*numSamples*channels;
- _allocate_hdr(sizeof(AudioDataHeader), dataSize,
- "AudioData::AudioData(formatted allocation)");
- hdr->magic = KIT_MAGIC_KPM;
- hdr->format = format;
- hdr->headerSize = sizeof(AudioDataHeader);
- hdr->dataSize = dataSize;
- hdr->loopStart = 0;
- hdr->loopEnd = numSamples;
- hdr->numSamples = numSamples;
- hdr->sampleRate = sampleRate;
- hdr->bitRate = KIT_AUDIO_BITSIZE(format)*sampleRate*channels;
- hdr->loopCount = 0;
- hdr->channels = channels;
- hdr->_reserved = 0;
- hdr->fmt_version = 1; //1 indicates the version kit_sdl2 uses
- hdr->mode = 0; //PCM or float data
- hdr->metadata_type = 0; //no metadata
- hdr->samples = (u8*)hdr + hdr->headerSize;
- hdr->userdata = nullptr;
- _valid = true;
- _constructing = false;
- }
- #define KIT_MAGIC_KPCM 0x4D43506B //.kpm's old file signature
- void AudioData::_construct_file(const char* filePath,
- AudioDataLoaderCallback callback,
- const char* funcName)
- {
- if(_valid) return;
- _type = KIT_CLASSTYPE_AUDIODATA;
- if(funcName == nullptr)
- funcName = "AudioData::AudioData(specific file format)";
- if(filePath == nullptr)
- THROW_ERRORF("%s: filePath = nullptr", funcName);
- if(!fileio::exists(filePath))
- THROW_ERRORF("%s: \"%s\" doesn't exist", funcName, filePath);
- AudioDataHeader* _hdr;
- if(callback == nullptr){ //load .kpm file
- size_t fileSize;
- _hdr = (AudioDataHeader*)fileio::readAll(filePath, &fileSize);
- //(assumes that _hdr != nullptr after this point)
- //check for the current and old version of .kpm's file signature
- //(but only if the fileSize is enough for a u32)
- if(fileSize >= sizeof(u32) &&
- (_hdr->magic != KIT_MAGIC_KPM && _hdr->magic != KIT_MAGIC_KPCM))
- {
- memory::free(&_hdr);
- THROW_ERRORF("%s: AudioDataLoadKPM used, but file is not a .kpm", funcName);
- }
- if(fileSize < sizeof(AudioDataHeader)){
- memory::free(&_hdr);
- THROW_ERRORF("%s: size of .kpm < sizeof(AudioDataHeader)", funcName);
- }
- /*
- if(_hdr->magic != KIT_MAGIC_KPM) throw "magic != KIT_MAGIC_KPM";
- if(!isFormatValid(_hdr->format)) throw "format is invalid";
- if(_hdr->headerSize < sizeof(AudioDataHeader)) throw "headerSize < sizeof(AudioDataHeader)";
- if(_hdr->dataSize != (fileSize-_hdr->headerSize)) throw "dataSize is invalid";
- //(channels are checked before numSamples to prevent divide-by-zero exceptions)
- if(_hdr->channels!=1 && _hdr->channels!=2) throw "audio is neither mono nor stereo";
- //(numSamples is checked before loopStart/loopEnd, as their checks rely upon numSamples)
- if(_hdr->numSamples != (_hdr->dataSize/KIT_ASTREAM_FMT_BYTESIZE(_hdr->format))/_hdr->channels) throw "numSamples is invalid";
- if(_hdr->loopStart >= _hdr->numSamples) throw "loopStart >= numSamples";
- if(_hdr->loopEnd > _hdr->numSamples) throw "loopEnd > numSamples";
- if(_hdr->sampleRate < 1000) throw "sampleRate < 1000";
- if(_hdr->bitRate != _hdr->sampleRate*_hdr->channels*KIT_ASTREAM_FMT_BITSIZE(_hdr->format)) throw "bitRate is invalid";
- if(_hdr->bitRemainder != 0) throw "bitRemainder != 0";
- if(_hdr->mode != 0) throw "only mode 0 kPCM files are currently supported";
- */
- //the only difference between 0 and 1 is that bitsPerSample is offset by -1
- if(_hdr->fmt_version == 0) ++_hdr->format;
- _hdr->magic = KIT_MAGIC_KPM; //if it was previously kPCM, now it is kPxM
- _hdr->fmt_version = 1; //
- } else {
- _hdr = callback(filePath);
- if(_hdr == nullptr)
- THROW_ERRORF("%s: callback returned as nullptr", funcName);
- }
- size_t totalSize = _hdr->headerSize + _hdr->dataSize;
- #ifndef DONT_USE_ALLOCSIMD
- hdr = (AudioDataHeader*)memory::allocSIMD(totalSize);
- #else
- hdr = (AudioDataHeader*)memory::alloc(totalSize);
- #endif /* DONT_USE_ALLOCSIMD */
- if(hdr == nullptr){
- memory::free(&_hdr);
- THROW_ERRORF("%s: failed to allocate memory", funcName);
- }
- memory::copy(hdr, _hdr, totalSize);
- memory::free(&_hdr);
- hdr->samples = (u8*)hdr + hdr->headerSize;
- _valid = true;
- _constructing = false;
- }
- //(the last constructor can be found in "kit_AudioData_LoadAllTypes.cpp")
- AudioData::~AudioData(){
- if(!_valid) return;
- _valid = false;
- #ifndef DONT_USE_ALLOCSIMD
- memory::freeSIMD(&hdr);
- #else
- memory::free(&hdr);
- #endif /* DONT_USE_ALLOCSIMD */
- }
- void AudioData::saveAudio(const char* filePath,
- AudioDataSaverCallback callback)
- {
- if(ADATA_IS_INVALID)
- THROW_ERROR("AudioData::saveAudio(): invalid AudioData");
- if(filePath == nullptr)
- THROW_ERROR("AudioData::saveAudio(): filePath = nullptr");
- if(callback == nullptr){ //save .kpm
- try {
- fileio::writeAll(filePath, hdr, hdr->headerSize+hdr->dataSize);
- } catch(const char* errorText){
- freeThreadErrors();
- THROW_ERRORF("AudioData::saveAudio(): \"%s\"", SDL_GetError());
- }
- } else {
- callback(filePath, *hdr);
- }
- }
- static bool _fmt_is_valid(u16 fmt){
- switch(fmt){
- case SMPFMT_U8 : SDL_FALLTHROUGH;
- case SMPFMT_S8 : SDL_FALLTHROUGH;
- case SMPFMT_U16: SDL_FALLTHROUGH;
- case SMPFMT_S16: SDL_FALLTHROUGH;
- case SMPFMT_S24: SDL_FALLTHROUGH;
- case SMPFMT_S32: SDL_FALLTHROUGH;
- case SMPFMT_F32: SDL_FALLTHROUGH;
- case SMPFMT_F64: return true; //lol
- default: return false;
- }
- }
- // = 2^(bits-1)
- #define ABS_S8_MIN (128) //ABS_Sx_MIN is a horrible name for this,
- #define ABS_S16_MIN (32768) //but it's the name i chose within 10 seconds
- #define ABS_S24_MIN (8388608) //(so i may or may not change it, idk)
- #define ABS_S32_MIN (2147483648)
- struct _s24 { u8 a, b, c; } //mostly for memory alignment purposes
- __attribute__((packed)); //(explicitly pack just in case; probably unnecessary)
- union _s24u {
- _s24 v;
- s32 n : 24;
- inline _s24u(_s24 _v) : v(_v) {}
- inline _s24u(s32 _n) : n(_n&KIT_S24_MAX) {}
- };
- static inline f64 frm_s24(_s24 x){ return (f64)_s24u(x).n/ABS_S24_MIN; }
- static inline _s24 to_s24(f64 x){ return _s24u((s32)(x*KIT_S24_MAX)).v; }
- void AudioData::convertFormat(AudioSampleFormatEnum format){
- if(ADATA_IS_INVALID)
- THROW_ERROR("AudioData::convertFormat(): invalid AudioData");
- if(hdr->format == format) return; //no need to convert anything; exit early
- if(!_fmt_is_valid(hdr->format))
- THROW_ERROR("AudioData::convertFormat(): unrecognized source format");
- if(!_fmt_is_valid(format))
- THROW_ERROR("AudioData::convertFormat(): unrecognized destination format");
- u64 totalSamples = hdr->numSamples*hdr->channels;
- u64 dataSize = KIT_AUDIO_BYTESIZE(format)*totalSamples;
- u32 bitRate = KIT_AUDIO_BITSIZE(format)*hdr->sampleRate*hdr->channels;
- try {
- memory::Wrapper temp_samples(totalSamples*sizeof(f64));
- f64* tmp = (f64*)temp_samples.ptr;
- void* smp = hdr->samples;
- #define FOR_TS_BRK(x) for(u64 i=0; i<totalSamples; ++i){ x; } break
- #define SMPCAST(_type) ( ((_type*)smp)[i] )
- #define FRM_CONV(_type, _scaling_factor, _modifier) \
- ( ((f64)SMPCAST(_type) _modifier) _scaling_factor )
- //convert all source samples to 64-bit floats
- switch(hdr->format){
- case SMPFMT_U8 : FOR_TS_BRK( tmp[i] = FRM_CONV(u8 , /ABS_S8_MIN , -128) );
- case SMPFMT_S8 : FOR_TS_BRK( tmp[i] = FRM_CONV(s8 , /ABS_S8_MIN , ) );
- case SMPFMT_U16: FOR_TS_BRK( tmp[i] = FRM_CONV(u16, /ABS_S16_MIN, -32768) );
- case SMPFMT_S16: FOR_TS_BRK( tmp[i] = FRM_CONV(s16, /ABS_S16_MIN, ) );
- case SMPFMT_S24: FOR_TS_BRK( tmp[i] = frm_s24(SMPCAST(_s24)) );
- case SMPFMT_S32: FOR_TS_BRK( tmp[i] = FRM_CONV(s32, /ABS_S32_MIN, ) );
- case SMPFMT_F32: FOR_TS_BRK( tmp[i] = FRM_CONV(f32, , ) );
- case SMPFMT_F64: memory::copy(tmp, smp, hdr->dataSize); break;
- }
- //resize header to match destination format's dataSize
- #ifndef DONT_USE_ALLOCSIMD
- if(!memory::reallocSIMD(&hdr, hdr->headerSize+dataSize))
- #else
- if(!memory::realloc(&hdr, hdr->headerSize+dataSize))
- #endif /* DONT_USE_ALLOCSIMD */
- THROW_ERROR("?"); //what is thrown doesn't matter as long as it's const char*
- //update relevant header values
- hdr->format = format;
- hdr->dataSize = dataSize;
- hdr->bitRate = bitRate;
- hdr->samples = (u8*)hdr + hdr->headerSize;
- smp = hdr->samples;
- #define TO_CONV(_type, _scl_fct, _mod) ( (_type)( tmp[i] _scl_fct _mod ) )
- //convert the f64 samples to the desired format
- switch(hdr->format){ //(hdr->format = format now)
- case SMPFMT_U8 : FOR_TS_BRK( SMPCAST( u8 ) = TO_CONV(u8 , *KIT_S8_MAX , +128) );
- case SMPFMT_S8 : FOR_TS_BRK( SMPCAST( s8 ) = TO_CONV(s8 , *KIT_S8_MAX , ) );
- case SMPFMT_U16: FOR_TS_BRK( SMPCAST( u16) = TO_CONV(u16, *KIT_S16_MAX, +32768) );
- case SMPFMT_S16: FOR_TS_BRK( SMPCAST( s16) = TO_CONV(s16, *KIT_S16_MAX, ) );
- case SMPFMT_S24: FOR_TS_BRK( SMPCAST(_s24) = to_s24(tmp[i]) );
- case SMPFMT_S32: FOR_TS_BRK( SMPCAST( s32) = TO_CONV(s32, *KIT_S32_MAX, ) );
- case SMPFMT_F32: FOR_TS_BRK( SMPCAST( f32) = TO_CONV(f32, , ) );
- case SMPFMT_F64: memory::copy(smp, tmp, hdr->dataSize); break;
- }
- } catch(const char* errorText){
- //the only 2 errors that should occur in that try block are failures
- //to allocate heap memory, so i'm just changing the function
- //name to indicate it occurred in this constructor specifically
- freeThreadErrors();
- THROW_ERROR("AudioData::convertFormat(): failed to allocate memory");
- }
- }
- }; /* namespace kit */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement