/* SdlAudio.cpp * * An SDL2 audio implementation. */ #include #include "SdlAudio.h" namespace PlipSdl { SdlAudio::SdlAudio() { SDL_InitSubSystem(SDL_INIT_AUDIO); // Open audio device. SDL_AudioSpec want {}; want.freq = Plip::PlipAudio::SampleRate; want.format = AUDIO_F32; want.channels = Plip::PlipAudio::Channels; want.samples = SampleLength; want.callback = nullptr; m_device = SDL_OpenAudioDevice(nullptr, 0, &want, &m_spec, SDL_AUDIO_ALLOW_ANY_CHANGE); if(m_device < 0) { std::cerr << "Unable to open audio: " << SDL_GetError() << std::endl; return; } // Set up conversion structure. SDL_BuildAudioCVT(&m_cvt, AUDIO_F32, 2, 48000, m_spec.format, m_spec.channels, m_spec.freq); if(m_cvt.needed > 0) { // Conversion required. m_playFunc = &SdlAudio::ConvertQueue; } else if(m_cvt.needed < 0) { // An error has occurred. std::cerr << "Unable to set up audio converter: " << SDL_GetError() << std::endl; SDL_CloseAudio(); return; } else { // No conversion required. m_playFunc = &SdlAudio::DirectQueue; } m_active = true; SDL_PauseAudioDevice(m_device, 0); } SdlAudio::~SdlAudio() { if(m_active) SDL_CloseAudioDevice(m_device); SDL_QuitSubSystem(SDL_INIT_AUDIO); } void SdlAudio::ConvertQueue(void *data, int size) { m_cvt.len = size * 4; // 32-bit float == 4 bytes m_cvt.buf = (Uint8*)SDL_malloc(m_cvt.len * m_cvt.len_mult); SDL_memcpy(m_cvt.buf, data, m_cvt.len); SDL_ConvertAudio(&m_cvt); // TODO: This currently leaves gaps in the audio if m_cvt.buf is not a // multiple of SampleRate. Should probably be fixed at some point. :) SDL_QueueAudio(m_device, m_cvt.buf, m_cvt.len_cvt); SDL_free(m_cvt.buf); } void SdlAudio::DequeueAll() { SDL_ClearQueuedAudio(m_device); } #pragma clang diagnostic push #pragma ide diagnostic ignored "readability-make-member-function-const" void SdlAudio::DirectQueue(void *data, int size) { SDL_QueueAudio(m_device, data, size * 4); } #pragma clang diagnostic pop void SdlAudio::Enqueue(std::vector buffer) { if(!IsActive()) return; (this->*m_playFunc)(buffer.data(), buffer.size()); } int SdlAudio::GetBufferSize() { return m_spec.samples; } uintmax_t SdlAudio::GetQueueSize() { return SDL_GetQueuedAudioSize(m_device); } }