int osd_update_audio_stream(INT16 *buffer) { // Soundcard switch off? if (Machine->sample_rate == 0) return samples_per_frame; Uint32 unBytesQueued = SDL_GetQueuedAudioSize(audio_device); if (unBytesQueued == 0) { ++fifo_underrun; // Queue some silence to start buffering uint8_t silence[bytes_per_frame]; memset(silence, 0, sizeof(silence)); SDL_QueueAudio(audio_device, silence, sizeof(silence)); } if (unBytesQueued > 10*bytes_per_frame) { ++fifo_overrun; SDL_ClearQueuedAudio(audio_device); } profiler_mark(PROFILER_USER1); if (attenuation < 0) { /* FIXME: Need to attenuate the audio stream? */ } SDL_QueueAudio(audio_device, buffer, bytes_per_frame); profiler_mark(PROFILER_END); return samples_per_frame; }
void SoundSystemImpl::queueAudio() { #ifdef IMGUI_ENABLE const int max_samples = mAudioSpecObtained.samples * mAudioSpecObtained.channels; const uint32_t bytePerSample = sizeof(float); SDL_AudioDeviceID audioDeviceID = mAudioDeviceId; uint32_t alreadyQueuedByte = SDL_GetQueuedAudioSize(audioDeviceID); int16_t alreadyQueued = numeric_cast<int16_t>(alreadyQueuedByte / bytePerSample); int16_t toQueue = max_samples - alreadyQueued; while (g_debug_sample_buffer.max_size() <= g_debug_sample_buffer.size()) { g_debug_sample_buffer.read(); } g_debug_sample_buffer.write(mFrameMixer.size()); while (g_debug_required_buffer.max_size() <= g_debug_required_buffer.size()) { g_debug_required_buffer.read(); } g_debug_required_buffer.write(toQueue); #endif int audioError = SDL_QueueAudio(audioDeviceID, (const void*)mFrameMixer.data(), mFrameMixer.size() * bytePerSample); if (0 != audioError) { printf("Audio queue error %s\n", SDL_GetError()); } mFrameMixer.clear(); }
static void sdl_renderer_decode_and_play_sample(char* data, int length) { int decodeLen = opus_decode(decoder, data, length, pcmBuffer, FRAME_SIZE, 0); if (decodeLen > 0) { SDL_QueueAudio(dev, pcmBuffer, decodeLen * CHANNEL_COUNT * sizeof(short)); } else { printf("Opus error from decode: %d\n", decodeLen); } }
void audio_play() { if (paused) { updateok = true; return; } bufsize = 2 * channels * (conf.audio_sample_rate / framerate); if (conf.audio_api == 0) { // SDL #if SDL_VERSION_ATLEAST(2,0,4) SDL_QueueAudio(dev, (const void*)audiobuf, bufsize); // Clear the audio queue arbitrarily to avoid it backing up too far if (SDL_GetQueuedAudioSize(dev) > (Uint32)(bufsize * 3)) { SDL_ClearQueuedAudio(dev); } #endif } #ifndef _MINGW else if (conf.audio_api == 1) { // libao ao_play(aodevice, (char*)audiobuf, bufsize); } #endif updateok = true; }
void loop() { #ifdef __EMSCRIPTEN__ if (done || (SDL_GetAudioStatus() != SDL_AUDIO_PLAYING)) { emscripten_cancel_main_loop(); } else #endif { /* The device from SDL_OpenAudio() is always device #1. */ const Uint32 queued = SDL_GetQueuedAudioSize(1); SDL_Log("Device has %u bytes queued.\n", (unsigned int) queued); if (queued <= 8192) { /* time to requeue the whole thing? */ if (SDL_QueueAudio(1, wave.sound, wave.soundlen) == 0) { SDL_Log("Device queued %u more bytes.\n", (unsigned int) wave.soundlen); } else { SDL_Log("Device FAILED to queue %u more bytes: %s\n", (unsigned int) wave.soundlen, SDL_GetError()); } } } }
int main(int argc, char *argv[]) { sdl_state SDLState = {}; platform_work_queue HighPriorityQueue = {}; SDLMakeQueue(&HighPriorityQueue, 6); platform_work_queue LowPriorityQueue = {}; SDLMakeQueue(&LowPriorityQueue, 2); GlobalPerfCountFrequency = SDL_GetPerformanceFrequency(); SDLGetEXEFileName(&SDLState); char SourceGameCodeDLLFullpath[SDL_STATE_FILE_NAME_COUNT]; SDLBuildEXEPathFileName(&SDLState, "handmade.dylib", sizeof(SourceGameCodeDLLFullpath), SourceGameCodeDLLFullpath); char TempGameCodeDLLFullpath[SDL_STATE_FILE_NAME_COUNT]; SDLBuildEXEPathFileName(&SDLState, "handmade_temp.dylib", sizeof(TempGameCodeDLLFullpath), TempGameCodeDLLFullpath); char GameCodeLockFullpath[SDL_STATE_FILE_NAME_COUNT]; SDLBuildEXEPathFileName(&SDLState, "lock.tmp", sizeof(GameCodeLockFullpath), GameCodeLockFullpath); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) != 0) { printf("Failed to initialize SDL: %s\n", SDL_GetError()); return -1; } SDL_Window *Window = SDL_CreateWindow("Handmade Hero", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 960, 540, SDL_WINDOW_OPENGL); if (!Window) { printf("Failed to create window: %s\n", SDL_GetError()); return -1; } SDLResizeDIBSection(Window, &GlobalBackBuffer, 960, 540); // TODO: Set GameUpdateHz by monitor refresh HZ real32 GameUpdateHz = 60.0f; real32 TargetSecondsPerFrame = 1.0f / GameUpdateHz; sdl_sound_output SoundOutput = {}; SoundOutput.SamplesPerSecond = 48000; SoundOutput.BytesPerSample = sizeof(int16) * 2; SoundOutput.BufferSize = SoundOutput.SamplesPerSecond * SoundOutput.BytesPerSample; SDL_AudioDeviceID Audio = SDLInitSound(SoundOutput.SamplesPerSecond); u32 MaxPossibleOverrun = 2 * 4 * sizeof(u16); int16 *Samples = (int16 *)mmap(0, (size_t)(SoundOutput.BufferSize + MaxPossibleOverrun), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); GlobalRunning = true; #if HANDMADE_INTERNAL void *BaseAddress = (void *)Terabytes(2); #else void *BaseAddress = 0; #endif game_memory GameMemory = {}; GameMemory.PermanentStorageSize = Megabytes(64); GameMemory.TransientStorageSize = Gigabytes(256); GameMemory.HighPriorityQueue = &HighPriorityQueue; GameMemory.LowPriorityQueue = &LowPriorityQueue; GameMemory.PlatformAPI.AddEntry = SDLAddEntry; GameMemory.PlatformAPI.CompleteAllWork = SDLCompleteAllWork; GameMemory.PlatformAPI.GetAllFilesOfTypeBegin = SDLGetAllFilesOfTypeBegin; GameMemory.PlatformAPI.GetAllFilesOfTypeEnd = SDLGetAllFilesOfTypeEnd; GameMemory.PlatformAPI.OpenNextFile = SDLOpenNextFile; GameMemory.PlatformAPI.ReadDataFromFile = SDLReadDataFromFile; GameMemory.PlatformAPI.FileError = SDLFileError; GameMemory.PlatformAPI.AllocateMemory = SDLAllocateMemory; GameMemory.PlatformAPI.DeallocateMemory = SDLDeallocateMemory; GameMemory.PlatformAPI.DEBUGFreeFileMemory = DEBUGPlatformFreeFileMemory; GameMemory.PlatformAPI.DEBUGReadEntireFile = DEBUGPlatformReadEntireFile; GameMemory.PlatformAPI.DEBUGWriteEntireFile = DEBUGPlatformWriteEntireFile; SDLState.TotalSize = GameMemory.PermanentStorageSize + GameMemory.TransientStorageSize; SDLState.GameMemoryBlock = mmap(BaseAddress, (size_t) SDLState.TotalSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); GameMemory.PermanentStorage = SDLState.GameMemoryBlock; GameMemory.TransientStorage = ((uint8 *) GameMemory.PermanentStorage + GameMemory.PermanentStorageSize); if (!(GameMemory.PermanentStorage && GameMemory.TransientStorage)) { printf("Failed to allocate game memory\n"); return -1; } // TODO: Add game replay support here game_input Input[2] = {}; game_input *NewInput = &Input[0]; game_input *OldInput = &Input[1]; uint64 LastCounter = SDL_GetPerformanceCounter(); uint64 FlipWallClock = SDL_GetPerformanceCounter(); sdl_game_code Game = SDLLoadGameCode(SourceGameCodeDLLFullpath, TempGameCodeDLLFullpath, GameCodeLockFullpath); uint64 LastCycleCount = _rdtsc(); while (GlobalRunning) { NewInput->dtForFrame = TargetSecondsPerFrame; NewInput->ExecutableReloaded = false; time_t NewDLLWriteTime = SDLGetLastWriteTime(SourceGameCodeDLLFullpath); if (difftime(NewDLLWriteTime, Game.DLLLastWriteTime) > 0) { SDLCompleteAllWork(&HighPriorityQueue); SDLCompleteAllWork(&LowPriorityQueue); SDLUnloadGameCode(&Game); Game = SDLLoadGameCode(SourceGameCodeDLLFullpath, TempGameCodeDLLFullpath, GameCodeLockFullpath); NewInput->ExecutableReloaded = true; } game_controller_input *OldKeyboardController = GetController(OldInput, 0); game_controller_input *NewKeyboardController = GetController(NewInput, 0); *NewKeyboardController = {}; NewKeyboardController->IsConnected = true; for (size_t ButtonIndex = 0; ButtonIndex < ArrayCount(NewKeyboardController->Buttons); ++ButtonIndex) { NewKeyboardController->Buttons[ButtonIndex].EndedDown = OldKeyboardController->Buttons[ButtonIndex].EndedDown; } SDLProcessPendingMessage(&SDLState, NewKeyboardController); if (!GlobalPause) { Uint32 MouseButtons = SDL_GetMouseState(&NewInput->MouseX, &NewInput->MouseY); NewInput->MouseZ = 0; SDLProcessKeyboardMessage(&NewInput->MouseButtons[0], SDL_BUTTON(SDL_BUTTON_LEFT)); SDLProcessKeyboardMessage(&NewInput->MouseButtons[1], SDL_BUTTON(SDL_BUTTON_MIDDLE)); SDLProcessKeyboardMessage(&NewInput->MouseButtons[2], SDL_BUTTON(SDL_BUTTON_RIGHT)); SDLProcessKeyboardMessage(&NewInput->MouseButtons[3], SDL_BUTTON(SDL_BUTTON_X1)); SDLProcessKeyboardMessage(&NewInput->MouseButtons[4], SDL_BUTTON(SDL_BUTTON_X2)); // TODO: Handle Mouse button here // TODO: Game controller support here game_offscreen_buffer Buffer = {}; Buffer.Memory = GlobalBackBuffer.Memory; Buffer.Width = GlobalBackBuffer.Width; Buffer.Height = GlobalBackBuffer.Height; Buffer.Pitch = GlobalBackBuffer.Pitch; if (Game.UpdateAndRender) { Game.UpdateAndRender(&GameMemory, NewInput, &Buffer); HandleDebugCycleCounters(&GameMemory); } // TODO: Game audio support here game_sound_output_buffer SoundBuffer = {}; SoundBuffer.SamplesPerSecond = SoundOutput.SamplesPerSecond; SoundBuffer.SampleCount = Align8((u32)(SoundOutput.SamplesPerSecond * TargetSecondsPerFrame)); SoundBuffer.Samples = Samples; if (Game.GetSoundSamples) { Game.GetSoundSamples(&GameMemory, &SoundBuffer); SDL_QueueAudio(Audio, SoundBuffer.Samples, SoundBuffer.SampleCount * SoundOutput.BytesPerSample); } SDLDisplayBufferInWindow(&GlobalBackBuffer); game_input *Temp = NewInput; NewInput = OldInput; OldInput = Temp; } } return 0; }
static void loop() { SDL_bool please_quit = SDL_FALSE; SDL_Event e; while (SDL_PollEvent(&e)) { if (e.type == SDL_QUIT) { please_quit = SDL_TRUE; } else if (e.type == SDL_KEYDOWN) { if (e.key.keysym.sym == SDLK_ESCAPE) { please_quit = SDL_TRUE; } } else if (e.type == SDL_MOUSEBUTTONDOWN) { if (e.button.button == 1) { SDL_PauseAudioDevice(devid_out, SDL_TRUE); SDL_PauseAudioDevice(devid_in, SDL_FALSE); } } else if (e.type == SDL_MOUSEBUTTONUP) { if (e.button.button == 1) { SDL_PauseAudioDevice(devid_in, SDL_TRUE); SDL_PauseAudioDevice(devid_out, SDL_FALSE); } } } if (SDL_GetAudioDeviceStatus(devid_in) == SDL_AUDIO_PLAYING) { SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); } else { SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); } SDL_RenderClear(renderer); SDL_RenderPresent(renderer); if (please_quit) { /* stop playing back, quit. */ SDL_Log("Shutting down.\n"); SDL_PauseAudioDevice(devid_in, 1); SDL_CloseAudioDevice(devid_in); SDL_PauseAudioDevice(devid_out, 1); SDL_CloseAudioDevice(devid_out); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); #ifdef __EMSCRIPTEN__ emscripten_cancel_main_loop(); #endif exit(0); } /* Note that it would be easier to just have a one-line function that calls SDL_QueueAudio() as a capture device callback, but we're trying to test the API, so we use SDL_DequeueAudio() here. */ while (SDL_TRUE) { Uint8 buf[1024]; const Uint32 br = SDL_DequeueAudio(devid_in, buf, sizeof (buf)); SDL_QueueAudio(devid_out, buf, br); if (br < sizeof (buf)) { break; } } }
int main(int argc, char *argv[]) { int i; char filename[4096]; /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); /* Load the SDL library */ if (SDL_Init(SDL_INIT_AUDIO) < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL: %s\n", SDL_GetError()); return (1); } if (argc > 1) { SDL_strlcpy(filename, argv[1], sizeof(filename)); } else { SDL_strlcpy(filename, "sample.wav", sizeof(filename)); } /* Load the wave file into memory */ if (SDL_LoadWAV(filename, &wave.spec, &wave.sound, &wave.soundlen) == NULL) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", filename, SDL_GetError()); quit(1); } wave.spec.callback = NULL; /* we'll push audio. */ #if HAVE_SIGNAL_H /* Set the signals */ #ifdef SIGHUP signal(SIGHUP, poked); #endif signal(SIGINT, poked); #ifdef SIGQUIT signal(SIGQUIT, poked); #endif signal(SIGTERM, poked); #endif /* HAVE_SIGNAL_H */ /* Initialize fillerup() variables */ if (SDL_OpenAudio(&wave.spec, NULL) < 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open audio: %s\n", SDL_GetError()); SDL_FreeWAV(wave.sound); quit(2); } /*static x[99999]; SDL_QueueAudio(1, x, sizeof (x));*/ /* Let the audio run */ SDL_PauseAudio(0); /* Note that we stuff the entire audio buffer into the queue in one shot. Most apps would want to feed it a little at a time, as it plays, but we're going for simplicity here. */ while (!done && (SDL_GetAudioStatus() == SDL_AUDIO_PLAYING)) { /* The device from SDL_OpenAudio() is always device #1. */ const Uint32 queued = SDL_GetQueuedAudioSize(1); SDL_Log("Device has %u bytes queued.\n", (unsigned int) queued); if (queued <= 8192) { /* time to requeue the whole thing? */ if (SDL_QueueAudio(1, wave.sound, wave.soundlen) == 0) { SDL_Log("Device queued %u more bytes.\n", (unsigned int) wave.soundlen); } else { SDL_Log("Device FAILED to queue %u more bytes: %s\n", (unsigned int) wave.soundlen, SDL_GetError()); } } SDL_Delay(100); /* let it play for awhile. */ } /* Clean up on signal */ SDL_CloseAudio(); SDL_FreeWAV(wave.sound); SDL_Quit(); return 0; }
//******************************************************* MAIN ******************************* int main(int argc, char* argv[]){ //set up sdl SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO); SDL_Window *Window = SDL_CreateWindow("Handmade Hero", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_RESIZABLE); if(Window){ SDL_Renderer *Renderer = SDL_CreateRenderer(Window, -1, 0); if(Renderer){ // VIDEO sdl_offscreen_buffer Buffer = {}; // if non-initialized, declaring variables in a loop fails on SDLResizeTexture with a pointer error - im blaming the compiler sdl_window_dimension Dimension = SDLGetWindowDimension(Window); SDLResizeTexture(&Buffer, Renderer, Dimension.Width, Dimension.Height); keystates Keys = {}; //AUDIO sdl_sound_output sound_output = sdl_sound_outputH(48000); //open audio SDLInitAudio(sound_output.SamplesPerSecond, sound_output.SamplesPerSecond * sound_output.BytesPerSample / 60); SDL_PauseAudio(0); //BW: state area allocation void *new_state_area = malloc(128*1024*1024);//need ~2 MB at least; give it 128 MiB -- 2MB for video; dont know audio void *prev_state_area = malloc(1024);// should be sizeof(state0), or sizeof(biggest statetype) later //apparently we didnt have enough memory, but only crashed sometimes? this fixed it void *state; { uint8 *next_ptr = (uint8*)prev_state_area; anim_comp *animation = (anim_comp*)next_ptr; next_ptr += sizeof(anim_comp); init_anim_comp(animation, 0,0); state0 *stateptr = (state0*)next_ptr; printf("state0 size %ld\n", sizeof(state0)); uint64 stateptrn = (uint64)stateptr; uint64 sizeptr = (uint64)&(stateptr->size); uint64 deepc_ptr = (uint64)&(stateptr->deep_count); uint64 anim_ptr = (uint64)&(stateptr->animation); uint64 tsine_ptr = (uint64)&(stateptr->tSine); uint64 tvol_ptr = (uint64)&(stateptr->ToneVolume); uint64 thz_ptr = (uint64)&(stateptr->ToneHz); uint64 pu_ptr = (uint64)&(stateptr->pitch_up_was_pressed); printf("offset begin %lu\n", sizeptr - stateptrn); printf("width of size %lu\n", deepc_ptr - sizeptr); printf("width of deepc %lu\n", anim_ptr - deepc_ptr); printf("width of animpt %lu\n", tsine_ptr - anim_ptr); printf("width of tsine %lu\n", tvol_ptr - tsine_ptr); printf("width of tvol %lu\n", thz_ptr - tvol_ptr); printf("width of thz %lu\n", pu_ptr - thz_ptr); next_ptr += sizeof(state0); init_state0(stateptr, animation, 3000, 256, 0); state = stateptr; //return 0; } uint64 LastCounter = SDL_GetPerformanceCounter(); uint64 LastCycleCount = _rdtsc(); uint64 PerfCountFrequency = SDL_GetPerformanceFrequency(); bool running = true; //main loop printf("enter main event loop\n"); while(running){ ///////NP_UPDATE///////////// //event capturing event_return events = eventHandler(&Keys); if(events.shouldQuit) running = false; //setup for p state_window_info Wi = {}; Wi.Height = Buffer.Height; Wi.Width = Buffer.Width; Wi.Pitch = Buffer.Pitch; int TargetQueueBytes = sound_output.LatencySampleCount * sound_output.BytesPerSample; state_sound_info Si = {}; Si.BytesToGet = TargetQueueBytes - SDL_GetQueuedAudioSize(1); Si.BytesPerSample = sound_output.BytesPerSample; Si.SamplesPerSecond = sound_output.SamplesPerSecond; uint64 state_size = 0; uint64 vbuffer_size = Buffer.Height * Buffer.Pitch; uint64 abuffer_size = Si.BytesToGet; state_return next; { //in case(statetype) or similar next = P_update_state0(*(state0*)state, new_state_area, Keys, Wi, Si); //p should return state_size? and also, what statetype we are in -> later state_size = sizeof(state0); } //GARBAGE COLLECTOR //move this state to previous state //fmemcpy(prev_state_area, new_state_area, state_size); //shallow copy, as supposed //printf("hi\n"); deepcopy(prev_state_area, next.state, new_state_area, (uint8*)new_state_area + 128*1024*1024); //TODO(md): DEEPCPY //queue audio if (Si.BytesToGet > 0) SDL_QueueAudio(1, next.abuffer, abuffer_size); //render SDLUpdateWindow(Window, Renderer, Buffer, next.vbuffer); uint64 EndCycleCount = _rdtsc(); uint64 EndCounter = SDL_GetPerformanceCounter(); uint64 CounterElapsed = EndCounter - LastCounter; uint64 CyclesElapsed = EndCycleCount - LastCycleCount; real64 MSPerFrame = (((1000.0f * (real64)CounterElapsed) / (real64)PerfCountFrequency)); real64 FPS = (real64)PerfCountFrequency / (real64)CounterElapsed; real64 MCPF = ((real64)CyclesElapsed / (1000.0f * 1000.0f)); printf("%.02fms/f, %.02f/s, %.02fmc/f\n", MSPerFrame, FPS, MCPF); LastCycleCount = EndCycleCount; LastCounter = EndCounter; } } } //if(Renderer, Window) SDL_Quit(); return 0; }
void loop(NES nesSystem, const char * fileLoc) { if (!init_sdl(fileLoc)) { std::cerr << "SDL did not initialize, quitting" << std::endl; return; } Debugger debugger(&nesSystem); //game loop variables double frequency = SDL_GetPerformanceFrequency(); uintmax_t startTime = SDL_GetPerformanceCounter(); bool paused = true; SDL_Event event; for (int x = 0; x < 256 * 240; x++) localPixels[x] = 0; draw(nesSystem.m_nesCPU.m_nesPPU.m_pixels); //draw screen black SDL_PauseAudioDevice(sdlAudioDevice, 0); //unpause audio for (;;) { //1 process events if (!process_events(&event, &nesSystem.m_nesCPU.m_controllerByte, &paused)) { break; } //2 logic if (!paused) { do { enum DebuggerEventStatus debugEventStatus = debugger.pre_instr_events(); if (debugEventStatus == BREAK_HIT || debugEventStatus == CRASH_IMMINENT) { paused = true; break; } else if (debugEventStatus == DONE_LOGGED_EXECUTION) { paused = true; } //execute one cpu opcode nesSystem.m_nesCPU.execute_next_opcode(); debugger.post_instr_events(); //ppu catches up nesSystem.m_nesCPU.m_nesPPU.tick(&nesSystem.m_nesCPU.m_NMI, &nesSystem.m_nesCPU.m_cpuClock); } while (!nesSystem.m_nesCPU.m_nesPPU.m_draw && !paused); //3.1 audio nesSystem.m_nesCPU.m_nesAPU.fill_buffer(&nesSystem, &nesSystem.m_nesCPU.m_IRQ); if (SDL_GetQueuedAudioSize(sdlAudioDevice) > (unsigned int) nesSystem.m_nesCPU.m_nesAPU.m_audioBufferSize * 10) { //prevents audio from becoming too out of sync SDL_ClearQueuedAudio(sdlAudioDevice); } SDL_QueueAudio(sdlAudioDevice, (void *) nesSystem.m_nesCPU.m_nesAPU.m_audioBuffer, nesSystem.m_nesCPU.m_nesAPU.m_audioBufferSize); } else { enum DebuggerCommandStatus commandStatus; do { commandStatus = debugger.cmd(); } while (commandStatus == CONTINUE_DEBUG); //SDL_FlushEvents(SDL_USEREVENT, SDL_LASTEVENT); if (commandStatus == RUN_NO_FOCUS) { paused = false; } else if (commandStatus == QUIT) { break; } else if (commandStatus == RUN_RETURN_FOCUS) { paused = false; SDL_RaiseWindow(window); } else { break; } } //3.2 video draw(nesSystem.m_nesCPU.m_nesPPU.m_pixels); //4 sync framerate double delay = MILLISECONDS_PER_FRAME - (((SDL_GetPerformanceCounter() - startTime) / frequency) * 1000) - 0.5; if (delay > 0) { std::this_thread::sleep_for(std::chrono::microseconds((int) (delay * 1000))); } while ((((SDL_GetPerformanceCounter() - startTime) / frequency) * 1000) < MILLISECONDS_PER_FRAME) { } startTime = SDL_GetPerformanceCounter(); } SDL_PauseAudioDevice(sdlAudioDevice, 1); //pause SDL_ClearQueuedAudio(sdlAudioDevice); //clear audio queue close_sdl(); return; }