int main(void) { PlatformState state; SDL_Event e; SDL_Window *window; SDL_Renderer *renderer; SDLInputContext sdlIC; SDLSoundRingBuffer srb; GameSoundOutput sb; GameMemory gameMemory; //controller input state InputContext inputStates[2]; //contains old and new state InputContext* newInputState = &inputStates[0]; InputContext* oldInputState = &inputStates[1]; real32_t secsSinceLastFrame = 0; sb.volume = 2500; gameMemory.permanentStorageSize = MB(64); gameMemory.transientStorageSize = MB(64); state.gameMemorySize = gameMemory.transientStorageSize + gameMemory.permanentStorageSize; state.memoryBlock = mmap(nullptr, state.gameMemorySize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE , -1, 0); gameMemory.permanentStorage = state.memoryBlock; gameMemory.transientStorage = (uint8_t*)(gameMemory.transientStorage) + gameMemory.transientStorageSize; initSDL(&window, &renderer, &gOsb, &sdlIC, &srb); GameCode gameCode = loadGameCode(); assert(gameCode.guarf); uint64_t startCount = SDL_GetPerformanceCounter(); real32_t targetFrameSeconds = 1./getRefreshRate(window); SDL_PauseAudio(0); while(state.running) { if(getCreateTimeOfFile(GAME_LIB_PATH) != gameCode.dateLastModified) { reloadGameCode(&gameCode); } //keyboard input ControllerInput* newKeyInput = getContoller(newInputState, 0); //TODO: figure out why this is special ControllerInput* oldKeyInput = getContoller(oldInputState, 0); *newKeyInput = {}; for(size_t i = 0; i < ARRAY_SIZE(oldKeyInput->buttons); i++) { newKeyInput->buttons[i] = oldKeyInput->buttons[i]; } while(SDL_PollEvent(&e)) { processEvent(&e, newInputState, &state); } //controller input for(int i = 0; i < MAX_SDL_CONTROLLERS; i++) { if(sdlIC.controllers[i] != nullptr && SDL_GameControllerGetAttached(sdlIC.controllers[i])) { ControllerInput* newCIState = getContoller(newInputState, i+1); ControllerInput* oldCIState = getContoller(oldInputState, i+1); int16_t xVal = SDL_GameControllerGetAxis(sdlIC.controllers[i], SDL_CONTROLLER_AXIS_LEFTX); int16_t yVal = SDL_GameControllerGetAxis(sdlIC.controllers[i], SDL_CONTROLLER_AXIS_LEFTY); newCIState->avgX = normalizeStickInput(xVal, LEFT_THUMB_DEADZONE); newCIState->avgY = normalizeStickInput(yVal, LEFT_THUMB_DEADZONE); if(newCIState->avgX != 0 || newCIState->avgY != 0) { newCIState->isAnalog = true; } processControllerButtonInput(&newCIState->actionDown, &oldCIState->actionDown, &newCIState->isAnalog, sdlIC.controllers[i], SDL_CONTROLLER_BUTTON_A); processControllerButtonInput(&newCIState->actionUp, &oldCIState->actionUp, &newCIState->isAnalog, sdlIC.controllers[i], SDL_CONTROLLER_BUTTON_Y); processControllerButtonInput(&newCIState->actionLeft, &oldCIState->actionLeft, &newCIState->isAnalog, sdlIC.controllers[i], SDL_CONTROLLER_BUTTON_X); processControllerButtonInput(&newCIState->actionRight, &oldCIState->actionRight, &newCIState->isAnalog, sdlIC.controllers[i], SDL_CONTROLLER_BUTTON_B); processControllerButtonInput(&newCIState->directionDown, &oldCIState->directionDown, &newCIState->isAnalog, sdlIC.controllers[i], SDL_CONTROLLER_BUTTON_DPAD_DOWN); processControllerButtonInput(&newCIState->directionUp, &oldCIState->directionUp, &newCIState->isAnalog, sdlIC.controllers[i], SDL_CONTROLLER_BUTTON_DPAD_UP); processControllerButtonInput(&newCIState->directionLeft, &oldCIState->directionLeft, &newCIState->isAnalog, sdlIC.controllers[i], SDL_CONTROLLER_BUTTON_DPAD_LEFT); processControllerButtonInput(&newCIState->directionRight, &oldCIState->directionRight, &newCIState->isAnalog, sdlIC.controllers[i], SDL_CONTROLLER_BUTTON_DPAD_RIGHT); oldCIState->isAnalog = newCIState->isAnalog; } else { //TODO: Logging } } //TODO: Do this instead of processing input, not after //process recording/playback assert(!(state.isRecording && state.isPlayingBack)); if(state.isRecording) { recordInput(newInputState, state.inputRecordFile); } if(state.isPlayingBack) { playInput(newInputState, state.inputRecordFile); } //calculate audio buffers' indicies and sizes SDL_LockAudioDevice(1); uint32_t startIndex = srb.runningIndex % ARRAY_SIZE(srb.samples); uint32_t endIndex = (srb.sampleToPlay + SOUND_LATENCY) % ARRAY_SIZE(srb.samples); uint32_t samplesToGetFromGame = (startIndex <= endIndex) ? endIndex - startIndex : (ARRAY_SIZE(srb.samples) - startIndex) + endIndex; sb.numSamples = samplesToGetFromGame; SDL_UnlockAudioDevice(1); gameCode.guarf(&gameMemory, &gOsb, &sb, newInputState, secsSinceLastFrame); updateSDLSoundBuffer(&srb, &sb, startIndex, endIndex); updateWindow(window, gTexture); InputContext* temp = newInputState; newInputState = oldInputState; oldInputState = temp; //benchmark stuff real32_t secsElapsed = secondsForCountRange(startCount, SDL_GetPerformanceCounter()); //sleep to lock frame rate if(secsElapsed < targetFrameSeconds) { //NOTE: .5 denotes the amount we will spin manually since // SDL_Delay is not 100% accurate real32_t timeToSleep = (targetFrameSeconds - secsElapsed)*1000 - .5; SDL_Delay(timeToSleep); secsElapsed = secondsForCountRange(startCount, SDL_GetPerformanceCounter()); //This assert will fire if the window is moved //assert(secondsForCountRange(startCount, SDL_GetPerformanceCounter()) < targetFrameSeconds); while(secondsForCountRange(startCount, SDL_GetPerformanceCounter()) < targetFrameSeconds) { //wait } secsElapsed = secondsForCountRange(startCount, SDL_GetPerformanceCounter()); } uint64_t endCount = SDL_GetPerformanceCounter(); real32_t fpsCount = ((1./secsElapsed)); real32_t mcPerFrame = (real32_t)(endCount-startCount) / (1000 * 1000 ); printf("TPF: %.2fms FPS: %.2f MCPF: %.2f\n", secsElapsed*1000, fpsCount, mcPerFrame); startCount = endCount; secsSinceLastFrame = secsElapsed; } cleanUp(&state, &gameCode); return 0; }
void snd_PlayStreaming( int streamID, float volume, float pan ) // todo: fade in? { assert( ( streamID >= 0 ) && ( streamID < MAX_STREAMING_SOUNDS ) ); SDL_LockAudioDevice( devID ); { if( ( streamingSounds[streamID].access != NULL ) && !streamingSounds[streamID].playing ) { streamingSounds[streamID].sdlStream = SDL_NewAudioStream( AUDIO_S16, (Uint8)( streamingSounds[streamID].access->channels ), streamingSounds[streamID].access->sample_rate, WORKING_FORMAT, streamingSounds[streamID].channels, WORKING_RATE ); if( streamingSounds[streamID].sdlStream == NULL ) { llog( LOG_ERROR, "Unable to create SDL_AudioStream for streaming sound." ); return; } streamingSounds[streamID].playing = true; streamingSounds[streamID].volume = volume; streamingSounds[streamID].pan = pan; stb_vorbis_seek_start( streamingSounds[streamID].access ); streamingSounds[streamID].readDone = false; } } SDL_UnlockAudioDevice( devID ); }
void snd_ChangeStreamVolume( int streamID, float volume ) { assert( ( streamID >= 0 ) && ( streamID < MAX_STREAMING_SOUNDS ) ); SDL_LockAudioDevice( devID ); { streamingSounds[streamID].volume = volume; } SDL_UnlockAudioDevice( devID ); }
void snd_ChangeStreamPan( int streamID, float pan ) { assert( ( streamID >= 0 ) && ( streamID < MAX_STREAMING_SOUNDS ) ); SDL_LockAudioDevice( devID ); { streamingSounds[streamID].pan = pan; } SDL_UnlockAudioDevice( devID ); }
void SDL2Sink::EnqueueSamples(const s16* samples, size_t sample_count) { if (impl->audio_device_id <= 0) return; SDL_LockAudioDevice(impl->audio_device_id); impl->queue.emplace_back(samples, samples + sample_count * 2); SDL_UnlockAudioDevice(impl->audio_device_id); }
void SDLAudioContext::PauseAudio(AudioObject& ao) { SDL_LockAudioDevice(m_device); RemoveAudio(ao); SDL_UnlockAudioDevice(m_device); }
static void SSDL_UnlockBuffer(soundcardinfo_t *sc, void *buffer) { #if SDL_MAJOR_VERSION >= 2 SDL_UnlockAudioDevice(sc->audio_fd); #else SDL_UnlockAudio(); #endif }
// Pan is assumed to be [-1,1] void snd_ChangeSoundPan( EntityID soundID, float pan ) { SDL_LockAudioDevice( devID ); { if( idSet_IsIDValid( &playingIDSet, soundID ) ) { int idx = idSet_GetIndex( soundID ); playingSounds[idx].pan = pan; } } SDL_UnlockAudioDevice( devID ); }
void snd_SetVolume( float volume, unsigned int group ) { assert( group < sb_Count( sbSoundGroups ) ); assert( ( volume >= 0.0f ) && ( volume <= 1.0f ) ); SDL_LockAudioDevice( devID ); { sbSoundGroups[group].volume = volume; } SDL_UnlockAudioDevice( devID ); }
// Volume is assumed to be [0,1] void snd_ChangeSoundVolume( EntityID soundID, float volume ) { SDL_LockAudioDevice( devID ); { if( idSet_IsIDValid( &playingIDSet, soundID ) ) { int idx = idSet_GetIndex( soundID ); playingSounds[idx].volume = volume; } } SDL_UnlockAudioDevice( devID ); }
void snd_StopStreaming( int streamID ) { assert( ( streamID >= 0 ) && ( streamID < MAX_STREAMING_SOUNDS ) ); SDL_LockAudioDevice( devID ); { streamingSounds[streamID].playing = false; SDL_FreeAudioStream( streamingSounds[streamID].sdlStream ); streamingSounds[streamID].sdlStream = NULL; } SDL_UnlockAudioDevice( devID ); }
void SDLAudioContext::PlayAudio(AudioObject& ao) { SDL_LockAudioDevice(m_device); // This prevents duplicates RemoveAudio(ao); m_playingAudio.push_back(&ao); SDL_UnlockAudioDevice(m_device); }
void AudioManager::add_sound(std::shared_ptr<SoundImpl> sound) { SDL_LockAudioDevice(device_id); auto category = sound->get_category(); auto &playing_list = playing_sounds.find(category)->second; // TODO probably check if sound already exists in playing list playing_list.push_back(sound); SDL_UnlockAudioDevice(device_id); }
/** * \brief Locks and unlocks open audio device. * * \sa https://wiki.libsdl.org/SDL_LockAudioDevice * \sa https://wiki.libsdl.org/SDL_UnlockAudioDevice */ int audio_lockUnlockOpenAudioDevice() { int i; int count; char *device; SDL_AudioDeviceID id; SDL_AudioSpec desired, obtained; /* Get number of devices. */ count = SDL_GetNumAudioDevices(0); SDLTest_AssertPass("Call to SDL_GetNumAudioDevices(0)"); if (count > 0) { for (i = 0; i < count; i++) { /* Get device name */ device = (char *)SDL_GetAudioDeviceName(i, 0); SDLTest_AssertPass("SDL_GetAudioDeviceName(%i,0)", i); SDLTest_AssertCheck(device != NULL, "Validate device name is not NULL; got: %s", (device != NULL) ? device : "NULL"); if (device == NULL) return TEST_ABORTED; /* Set standard desired spec */ desired.freq=22050; desired.format=AUDIO_S16SYS; desired.channels=2; desired.samples=4096; desired.callback=_audio_testCallback; desired.userdata=NULL; /* Open device */ id = SDL_OpenAudioDevice((const char *)device, 0, &desired, &obtained, SDL_AUDIO_ALLOW_ANY_CHANGE); SDLTest_AssertPass("SDL_OpenAudioDevice('%s',...)", device); SDLTest_AssertCheck(id > 1, "Validate device ID; expected: >=2, got: %i", id); if (id > 1) { /* Lock to protect callback */ SDL_LockAudioDevice(id); SDLTest_AssertPass("SDL_LockAudioDevice(%i)", id); /* Simulate callback processing */ SDL_Delay(10); SDLTest_Log("Simulate callback processing - delay"); /* Unlock again */ SDL_UnlockAudioDevice(id); SDLTest_AssertPass("SDL_UnlockAudioDevice(%i)", id); /* Close device again */ SDL_CloseAudioDevice(id); SDLTest_AssertPass("Call to SDL_CloseAudioDevice()"); } } } else { SDLTest_Log("No devices to test with"); } return TEST_COMPLETED; }
void snd_UnloadStream( int streamID ) { assert( ( streamID >= 0 ) && ( streamID < MAX_STREAMING_SOUNDS ) ); SDL_LockAudioDevice( devID ); { streamingSounds[streamID].playing = false; stb_vorbis_close( streamingSounds[streamID].access ); streamingSounds[streamID].access = NULL; SDL_FreeAudioStream( streamingSounds[streamID].sdlStream ); streamingSounds[streamID].sdlStream = NULL; } SDL_UnlockAudioDevice( devID ); }
void SDLAudioContext::StopAudio(AudioObject& ao) { SDL_LockAudioDevice(m_device); if(RemoveAudio(ao)) { ao.SetPos(0.0); } SDL_UnlockAudioDevice(m_device); }
void snd_SetMasterVolume( float volume ) { SDL_LockAudioDevice( devID ); { masterVolume = volume; } SDL_UnlockAudioDevice( devID ); // just save this out every single time if( soundCfgFile != NULL ) { cfg_SetInt( soundCfgFile, "vol", (int)volume ); cfg_SaveFile( soundCfgFile ); } }
void snd_StopStreamingAllBut( int streamID ) { SDL_LockAudioDevice( devID ); { for( int i = 0; i < MAX_STREAMING_SOUNDS; ++i ) { if( i == streamID ) continue; if( ( streamingSounds[i].access != NULL ) && streamingSounds[i].playing ) { streamingSounds[i].playing = false; SDL_FreeAudioStream( streamingSounds[streamID].sdlStream ); streamingSounds[streamID].sdlStream = NULL; } } } SDL_UnlockAudioDevice( devID ); }
void snd_CleanUp( ) { snd_StopStreamingAllBut( -1 ); if( workingBuffer != NULL ) { SDL_LockAudioDevice( devID ); { sb_Release( sbStreamWorkingBuffer ); mem_Release( workingBuffer ); workingBuffer = NULL; } SDL_UnlockAudioDevice( devID ); } if( devID == 0 ) return; SDL_CloseAudioDevice( devID ); }
void AudioManager::remove_sound(std::shared_ptr<SoundImpl> sound) { SDL_LockAudioDevice(device_id); auto category = sound->get_category(); auto &playing_list = playing_sounds.find(category)->second; for (size_t i = 0; i < playing_list.size(); i++) { if (playing_list[i] == sound) { remove_from_vector(playing_list, i); break; } } SDL_UnlockAudioDevice(device_id); }
size_t SDL2Sink::SamplesInQueue() const { if (impl->audio_device_id <= 0) return 0; SDL_LockAudioDevice(impl->audio_device_id); size_t total_size = std::accumulate(impl->queue.begin(), impl->queue.end(), static_cast<size_t>(0), [](size_t sum, const auto& buffer) { // Division by two because each stereo sample is made of two s16. return sum + buffer.size() / 2; }); SDL_UnlockAudioDevice(impl->audio_device_id); return total_size; }
static void sdl_fill_audio_ring_buffer(sdl_audio_ring_buffer_t* ring_buffer, memory_block_t* sound_samples, int32_t bytes_to_write) { int32_t region1_size, region2_size; int16_t* region1; int16_t* region2; SDL_LockAudioDevice(1); region1_size = bytes_to_write; region2_size = 0; if ((ring_buffer->write_index + region1_size) > ring_buffer->size) { region1_size = ring_buffer->size - ring_buffer->write_index; region2_size = bytes_to_write - region1_size; } memcpy(ring_buffer->data + ring_buffer->write_index, sound_samples->base, region1_size); memcpy(ring_buffer->data, (uint8_t*)sound_samples->base + region1_size, region2_size); ring_buffer->write_index = (ring_buffer->write_index + bytes_to_write) % ring_buffer->size; SDL_UnlockAudioDevice(1); }
// Returns an id that can be used to change the volume and pitch // loops - if the sound will loop back to the start once it's over // volume - how loud the sound will be, in the range [0,1], 0 being off, 1 being loudest // pitch - pitch change for the sound, multiplies the sample rate, 1 for normal, lesser for slower, higher for faster // pan - how far left or right the sound is, 0 is center, -1 is left, +1 is right // TODO: Some sort of event system so we can get when a sound has finished playing? EntityID snd_Play( int sampleID, float volume, float pitch, float pan, unsigned int group ) { assert( group >= 0 ); assert( group < sb_Count( sbSoundGroups ) ); EntityID playingID = INVALID_ENTITY_ID; SDL_LockAudioDevice( devID ); { playingID = idSet_ClaimID( &playingIDSet ); if( playingID != INVALID_ENTITY_ID ) { int idx = idSet_GetIndex( playingID ); playingSounds[idx].sample = sampleID; playingSounds[idx].volume = volume; playingSounds[idx].pitch = pitch; playingSounds[idx].pan = pan; playingSounds[idx].pos = 0.0f; playingSounds[idx].group = group; } } SDL_UnlockAudioDevice( devID ); return playingID; }
void snd_UnloadSample( int sampleID ) { assert( sampleID >= 0 ); assert( sampleID < MAX_SAMPLES ); if( samples[sampleID].data == NULL ) { return; } SDL_LockAudioDevice( devID ); { // find all playing sounds using this sample and stop them for( EntityID id = idSet_GetFirstValidID( &playingIDSet ); id != INVALID_ENTITY_ID; id = idSet_GetNextValidID( &playingIDSet, id ) ) { int idx = idSet_GetIndex( id ); if( playingSounds[idx].sample == sampleID ) { idSet_ReleaseID( &playingIDSet, id ); } } mem_Release( samples[sampleID].data ); samples[sampleID].data = NULL; } SDL_UnlockAudioDevice( devID ); }
/* Sets up the SDL mixer. Returns 0 on success. */ int snd_Init( unsigned int numGroups ) { assert( numGroups > 0 ); // clear out the samples storage SDL_memset( samples, 0, ARRAY_SIZE( samples ) * sizeof( samples[0] ) ); for( int i = 0; i < MAX_STREAMING_SOUNDS; ++i ) { streamingSounds[i].access = NULL; streamingSounds[i].sdlStream = NULL; streamingSounds[i].playing = false; } SDL_AudioSpec desired; SDL_memset( &desired, 0, sizeof( desired ) ); desired.freq = WORKING_RATE; desired.format = WORKING_FORMAT; desired.channels = WORKING_CHANNELS; desired.samples = AUDIO_SAMPLES; desired.callback = mixerCallback; desired.userdata = NULL; if( idSet_Init( &playingIDSet, MAX_PLAYING_SOUNDS ) != 0 ) { llog( LOG_CRITICAL, "Failed to create playing sounds id set." ); return -1; } // sending 0 will cause SDL to convert everything automatically devID = SDL_OpenAudioDevice( NULL, 0, &desired, NULL, 0 ); if( devID == 0 ) { llog( LOG_CRITICAL, "Failed to open audio device: %s", SDL_GetError( ) ); return -1; } SDL_PauseAudioDevice( devID, 0 ); workingSilence = desired.silence; workingBufferSize = desired.samples * desired.channels * ( ( SDL_AUDIO_MASK_BITSIZE & WORKING_FORMAT ) / 8 ); SDL_LockAudioDevice( devID ); workingBuffer = mem_Allocate( workingBufferSize ); SDL_UnlockAudioDevice( devID ); if( workingBuffer == NULL ) { llog( LOG_CRITICAL, "Failed to create audio working buffer." ); return -1; } sb_Add( sbSoundGroups, numGroups ); for( size_t i = 0; i < sb_Count( sbSoundGroups ); ++i ) { sbSoundGroups[i].volume = 1.0f; } // load the master volume soundCfgFile = cfg_OpenFile( "snd.cfg" ); if( soundCfgFile != NULL ) { int vol; cfg_GetInt( soundCfgFile, "vol", 1, &vol ); masterVolume = (float)vol; } else { masterVolume = 1.0f; } return 0; }
void unlock_audio() { SDL_UnlockAudioDevice(audio_device_id); }
void snd_SetFocus( bool hasFocus ) { SDL_LockAudioDevice( devID ); { SDL_PauseAudioDevice( devID, hasFocus ? 0 : 1 ); } SDL_UnlockAudioDevice( devID ); }
void Mixer::Unlock() { SDL_UnlockAudioDevice(deviceid); }
void Mix_UnlockAudio() { SDL_UnlockAudioDevice(audio_device); }
void snd_Stop( EntityID soundID ) { SDL_LockAudioDevice( devID ); { idSet_ReleaseID( &playingIDSet, soundID ); } SDL_UnlockAudioDevice( devID ); }