22 unsigned wantedFreq,
unsigned wantedSamples)
25 SDL_AudioSpec desired;
26 desired.freq = narrow<int>(wantedFreq);
27 desired.samples = narrow<Uint16>(std::bit_ceil(wantedSamples));
29 desired.format = AUDIO_F32SYS;
30 desired.callback = audioCallbackHelper;
31 desired.userdata =
this;
33 SDL_AudioSpec obtained;
34 deviceID = SDL_OpenAudioDevice(
nullptr, SDL_FALSE, &desired, &obtained,
35 SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
37 throw MSXException(
"Unable to open SDL audio: ", SDL_GetError());
40 frequency = obtained.freq;
41 fragmentSize = obtained.samples;
43 mixBuffer.resize(3 * (obtained.size /
sizeof(
StereoFloat)) + 1);
49 SDL_CloseAudioDevice(deviceID);
52void SDLSoundDriver::reInit()
54 SDL_LockAudioDevice(deviceID);
57 SDL_UnlockAudioDevice(deviceID);
64 SDL_PauseAudioDevice(deviceID, 1);
73 SDL_PauseAudioDevice(deviceID, 0);
87void SDLSoundDriver::audioCallbackHelper(
void* userdata, uint8_t* strm,
int len)
89 assert((len & 7) == 0);
91 audioCallback(std::span{std::bit_cast<StereoFloat*>(strm),
92 len / (2 *
sizeof(float))});
95unsigned SDLSoundDriver::getBufferFilled()
const
97 int result = narrow_cast<int>(writeIdx - readIdx);
98 if (result < 0) result += narrow<int>(mixBuffer.size());
99 assert((0 <= result) && (narrow<unsigned>(result) < mixBuffer.size()));
103unsigned SDLSoundDriver::getBufferFree()
const
108 auto result = narrow<unsigned>(mixBuffer.size() - 1 - getBufferFilled());
109 assert(narrow_cast<int>(result) >= 0);
110 assert(result < mixBuffer.size());
114void SDLSoundDriver::audioCallback(std::span<StereoFloat> stream)
116 auto len = stream.size();
118 size_t available = getBufferFilled();
119 auto num = std::min(len, available);
120 if ((readIdx + num) < mixBuffer.size()) {
124 auto len1 = mixBuffer.size() - readIdx;
126 auto len2 = num - len1;
127 ranges::copy(mixBuffer.first(len2), stream.subspan(len1));
128 readIdx = narrow<unsigned>(len2);
130 auto missing = narrow_cast<ptrdiff_t>(len - available);
139 SDL_LockAudioDevice(deviceID);
140 unsigned free = getBufferFree();
141 if (buffer.size() > free) {
143 if (board && !board->getMSXMixer().isSynchronousMode() &&
146 SDL_UnlockAudioDevice(deviceID);
148 SDL_LockAudioDevice(deviceID);
149 board->getRealTime().resync();
150 free = getBufferFree();
151 }
while (buffer.size() > free);
154 buffer = buffer.subspan(0, free);
157 assert(buffer.size() <= free);
158 if ((writeIdx + buffer.size()) < mixBuffer.size()) {
160 writeIdx += narrow<unsigned>(buffer.size());
162 auto len1 = mixBuffer.size() - writeIdx;
163 ranges::copy(buffer.subspan(0, len1), mixBuffer.subspan(writeIdx));
164 auto len2 = buffer.size() - len1;
165 ranges::copy(buffer.subspan(len1, len2), std::span{mixBuffer});
166 writeIdx = narrow<unsigned>(len2);
169 SDL_UnlockAudioDevice(deviceID);
ThrottleManager & getThrottleManager()
Contains the main loop of openMSX.
GlobalSettings & getGlobalSettings()
MSXMotherBoard * getMotherBoard() const
void uploadBuffer(std::span< const StereoFloat > buffer) override
void unmute() override
Unmute the sound system.
void mute() override
Mute the sound system.
~SDLSoundDriver() override
unsigned getFrequency() const override
Returns the actual sample frequency.
SDLSoundDriver(Reactor &reactor, unsigned wantedFreq, unsigned samples)
unsigned getSamples() const override
Get the number of samples that should be created 'per fragment'.
bool isThrottled() const
Ask if throttling is enabled.
void sleep(uint64_t us)
Sleep for the specified amount of time (in us).
This file implemented 3 utility functions:
constexpr void fill(ForwardRange &&range, const T &value)
constexpr auto copy(InputRange &&range, OutputIter out)
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)