Emu?
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

91 lines
2.6 KiB

/* SdlAudio.cpp
*
* An SDL2 audio implementation.
*/
#include <iostream>
#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<float> 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);
}
}