diff --git a/platform/cafe/include/driver/AudioBuffer.hpp b/platform/cafe/include/driver/AudioBuffer.hpp new file mode 100644 index 00000000..3c1b2af2 --- /dev/null +++ b/platform/cafe/include/driver/AudioBuffer.hpp @@ -0,0 +1,224 @@ +#pragma once + +#include + +#include +#include +#include + +#include +#include + +namespace love +{ + class AudioBuffer + { + public: + AudioBuffer() : voices {}, channels(0), volume(1.0f), ready(false) + {} + + ~AudioBuffer() + { + if (!this->ready) + return; + + for (int index = 0; index < this->channels; index++) + AXFreeVoice(this->voices[index]); + } + + void initialize(int channels, AXVoiceFormat format) + { + this->channels = channels; + + for (int index = 0; index < channels; index++) + { + this->voices[index] = AXAcquireVoice(0x1F, nullptr, nullptr); + + if (!this->voices[index]) + continue; + + AXVoiceBegin(this->voices[index]); + AXSetVoiceType(this->voices[index], AX_VOICE_TYPE_UNKNOWN); + AXVoiceEnd(this->voices[index]); + } + + this->ready = true; + this->setFormat(format); + } + + bool isInitialized() const + { + return this->ready; + } + + void prepare(size_t nsamples, void* data, size_t size, bool looping) + { + if (!this->ready) + return; + + DCFlushRange(data, size); + + for (int index = 0; index < this->channels; index++) + { + AXVoiceBegin(this->voices[index]); + + AXSetVoiceState(this->voices[index], AX_VOICE_STATE_STOPPED); + AXSetVoiceLoop(this->voices[index], AudioBuffer::getLooping(looping)); + + AXVoiceOffsets offsets {}; + AXGetVoiceOffsets(this->voices[index], &offsets); + + offsets.currentOffset = 0; + offsets.endOffset = nsamples; + offsets.loopOffset = 0; + offsets.data = data; + + AXSetVoiceOffsets(this->voices[index], &offsets); + AXSetVoiceCurrentOffset(this->voices[index], 0); + + AXVoiceEnd(this->voices[index]); + } + } + + void setDeviceMix(AXVoiceDeviceMixData (&mix)[6]) + { + if (!this->ready) + return; + + for (int index = 0; index < this->channels; index++) + { + AXVoiceBegin(this->voices[index]); + AXSetVoiceDeviceMix(this->voices[index], AX_DEVICE_TYPE_TV, 0, mix); + AXSetVoiceDeviceMix(this->voices[index], AX_DEVICE_TYPE_DRC, 0, mix); + AXVoiceEnd(this->voices[index]); + } + } + + void setState(AXVoiceState state) + { + if (!this->ready) + return; + + for (int index = 0; index < this->channels; index++) + { + AXVoiceBegin(this->voices[index]); + AXSetVoiceState(this->voices[index], state); + AXVoiceEnd(this->voices[index]); + } + } + + void setFormat(AXVoiceFormat format) + { + std::printf("Trying format: %d\n", format); + if (!this->ready) + return; + std::printf("Setting format: %d\n", format); + for (int index = 0; index < this->channels; index++) + { + AXVoiceBegin(this->voices[index]); + + AXVoiceOffsets offsets {}; + AXGetVoiceOffsets(this->voices[index], &offsets); + offsets.dataType = format; + + AXSetVoiceOffsets(this->voices[index], &offsets); + + AXVoiceEnd(this->voices[index]); + } + } + + bool isFinished() const + { + if (!this->ready) + return false; + + AXVoiceBegin(this->voices[0]); + bool done = this->voices[0]->state == AX_VOICE_STATE_STOPPED; + AXVoiceEnd(this->voices[0]); + + return done == true; + } + + void setVolume(float volume) + { + volume = std::clamp(volume, 0.0f, 1.0f); + + AXVoiceVeData ve {}; + ve.volume = volume * 0x8000; + + for (int index = 0; index < this->channels; index++) + { + AXVoiceBegin(this->voices[index]); + AXSetVoiceVe(this->voices[index], &ve); + AXVoiceEnd(this->voices[index]); + } + + this->volume = volume; + } + + float getVolume() const + { + return this->volume; + } + + bool setSampleRate(int sampleRate) + { + float ratio = (float)sampleRate / (float)AXGetInputSamplesPerSec(); + + for (int index = 0; index < this->channels; index++) + { + AXVoiceBegin(this->voices[index]); + + // clang-format off + if (AXSetVoiceSrcRatio(this->voices[index], ratio) != AX_VOICE_RATIO_RESULT_SUCCESS) + return false; + // clang-format on + + AXSetVoiceSrcType(this->voices[index], AX_VOICE_SRC_TYPE_LINEAR); + + AXVoiceEnd(this->voices[index]); + } + + return true; + } + + size_t getSampleOffset() const + { + AXVoiceOffsets offsets {}; + + AXVoiceBegin(this->voices[0]); + AXGetVoiceOffsets(this->voices[0], &offsets); + AXVoiceEnd(this->voices[0]); + + return offsets.currentOffset; + } + + void setLooping(bool looping) + { + for (int index = 0; index < this->channels; index++) + { + AXVoiceBegin(this->voices[index]); + + AXVoiceOffsets offsets {}; + AXGetVoiceOffsets(this->voices[index], &offsets); + + offsets.loopingEnabled = looping ? AX_VOICE_LOOP_ENABLED : AX_VOICE_LOOP_DISABLED; + + AXSetVoiceOffsets(this->voices[index], &offsets); + + AXVoiceEnd(this->voices[index]); + } + } + + private: + static AXVoiceLoop getLooping(bool looping) + { + return looping ? AX_VOICE_LOOP_ENABLED : AX_VOICE_LOOP_DISABLED; + } + + std::array voices; + int channels; + float volume; + bool ready; + }; +} // namespace love diff --git a/platform/cafe/include/driver/DigitalSound.hpp b/platform/cafe/include/driver/DigitalSound.hpp index c5a052ac..3a842e98 100644 --- a/platform/cafe/include/driver/DigitalSound.hpp +++ b/platform/cafe/include/driver/DigitalSound.hpp @@ -1,15 +1,12 @@ #pragma once +#include "driver/AudioBuffer.hpp" #include "driver/DigitalSound.tcc" #include "driver/DigitalSoundMix.hpp" #include "driver/SoundChannel.hpp" #include -#include -#include -#include - extern "C" { void AXSetMasterVolume(uint32_t volume); @@ -18,11 +15,8 @@ extern "C" namespace love { - using AudioBuffer = AXVoice; - class DigitalSound : public DigitalSoundBase { - public: ~DigitalSound(); @@ -71,15 +65,7 @@ namespace love ); // clang-format on - OSEvent& getEvent() - { - return event; - } - private: - OSEvent event; - std::array channels; - bool shutdown = false; }; } // namespace love diff --git a/platform/cafe/include/driver/SoundChannel.hpp b/platform/cafe/include/driver/SoundChannel.hpp index bb0d4cac..683b5de5 100644 --- a/platform/cafe/include/driver/SoundChannel.hpp +++ b/platform/cafe/include/driver/SoundChannel.hpp @@ -9,7 +9,7 @@ #include "driver/DigitalSoundMix.hpp" #include -#include +#include namespace love { @@ -24,79 +24,34 @@ namespace love STATE_DONE }; - SoundChannel() : buffers {}, state(STATE_DONE), channels(0), volume(1.0f) + SoundChannel() : buffers {}, state(STATE_DONE), volume(1.0f) {} - void begin(AXVoice* voice, int channels) + bool reset(AudioBuffer* buffer, int channels, float volume) { - for (int index = 0; index < channels; index++) - this->buffers[index] = voice; - - this->channels = channels; - } + if (!buffer->isInitialized()) + return false; - void setFormat(AXVoiceFormat format) - { - for (int index = 0; index < this->channels; index++) - { - AXVoiceBegin(this->buffers[index]); - - AXVoiceOffsets offsets {}; - AXGetVoiceOffsets(this->buffers[index], &offsets); - offsets.dataType = format; - - AXSetVoiceOffsets(this->buffers[index], &offsets); - - AXVoiceEnd(this->buffers[index]); - } - } + this->current = buffer; - bool reset(int channels, int sampleRate, float volume) - { volume = std::clamp(volume, 0.0f, 1.0f); - AXVoiceVeData ve {}; - ve.volume = volume * 0x8000; - - float ratio = (float)sampleRate / (float)AXGetInputSamplesPerSec(); - - for (int index = 0; index < channels; index++) + switch (channels) { - if (this->buffers[index] == nullptr) - continue; - - AXVoiceBegin(this->buffers[index]); - - AXSetVoiceType(this->buffers[index], AX_VOICE_TYPE_UNKNOWN); - AXSetVoiceVe(this->buffers[index], &ve); - - switch (channels) - { - case AX_VOICE_MONO: - DEVICE_MIX[0].bus[0].volume = 0x8000; - break; - case AX_VOICE_STEREO: - DEVICE_MIX[0].bus[0].volume = 0x8000; - DEVICE_MIX[1].bus[0].volume = 0x8000; - break; - default: - return false; - } - - AXSetVoiceDeviceMix(this->buffers[index], AX_DEVICE_TYPE_TV, 0, DEVICE_MIX); - AXSetVoiceDeviceMix(this->buffers[index], AX_DEVICE_TYPE_DRC, 0, DEVICE_MIX); - - // clang-format off - if (AXSetVoiceSrcRatio(this->buffers[index], ratio) != AX_VOICE_RATIO_RESULT_SUCCESS) + case AX_VOICE_MONO: + DEVICE_MIX[0].bus[0].volume = 0x8000; + break; + case AX_VOICE_STEREO: + DEVICE_MIX[0].bus[0].volume = 0x8000; + DEVICE_MIX[1].bus[0].volume = 0x8000; + break; + default: return false; - // clang-format on - - AXSetVoiceSrcType(this->buffers[index], AX_VOICE_SRC_TYPE_LINEAR); - AXSetVoiceCurrentOffset(this->buffers[index], 0); - - AXVoiceEnd(this->buffers[index]); } + this->current->setDeviceMix(DEVICE_MIX); + this->current->setVolume(volume); + return true; } @@ -104,16 +59,7 @@ namespace love { volume = std::clamp(volume, 0.0f, 1.0f); - AXVoiceVeData ve {}; - ve.volume = volume * 0x8000; - - for (int index = 0; index < this->channels; index++) - { - AXVoiceBegin(this->buffers[index]); - AXSetVoiceVe(this->buffers[index], &ve); - AXVoiceEnd(this->buffers[index]); - } - + this->current->setVolume(volume); this->volume = volume; } @@ -124,26 +70,14 @@ namespace love void setLooping(bool looping) { - auto voiceLooping = looping ? AX_VOICE_LOOP_ENABLED : AX_VOICE_LOOP_DISABLED; - - for (int index = 0; index < this->channels; index++) - { - AXVoiceBegin(this->buffers[index]); - AXSetVoiceLoop(this->buffers[index], voiceLooping); - AXVoiceEnd(this->buffers[index]); - } + this->current->setLooping(looping); } bool play() { - for (int index = 0; index < this->channels; index++) - { - AXVoiceBegin(this->buffers[index]); - AXSetVoiceState(this->buffers[index], AX_VOICE_STATE_PLAYING); - AXVoiceEnd(this->buffers[index]); - } - + this->current->setState(AX_VOICE_STATE_PLAYING); this->state = STATE_PLAYING; + return true; } @@ -154,26 +88,14 @@ namespace love void stop() { - for (int index = 0; index < this->channels; index++) - { - AXVoiceBegin(this->buffers[index]); - AXSetVoiceState(this->buffers[index], AX_VOICE_STATE_STOPPED); - AXVoiceEnd(this->buffers[index]); - } - + this->current->setState(AX_VOICE_STATE_STOPPED); this->state = STATE_STOPPED; } void setPaused(bool paused) { auto voiceState = paused ? AX_VOICE_STATE_STOPPED : AX_VOICE_STATE_PLAYING; - - for (int index = 0; index < this->channels; index++) - { - AXVoiceBegin(this->buffers[index]); - AXSetVoiceState(this->buffers[index], voiceState); - AXVoiceEnd(this->buffers[index]); - } + this->current->setState(voiceState); this->state = paused ? STATE_PAUSED : STATE_PLAYING; } @@ -185,20 +107,15 @@ namespace love size_t getSampleOffset() const { - AXVoiceOffsets offsets {}; - - AXVoiceBegin(this->buffers[0]); - AXGetVoiceOffsets(this->buffers[0], &offsets); - AXVoiceEnd(this->buffers[0]); - - return offsets.currentOffset; + return this->current->getSampleOffset(); } private: - std::array buffers; + std::queue buffers; + AudioBuffer* current; + ChannelState state; - int channels; float volume; }; } // namespace love diff --git a/platform/cafe/source/driver/DigitalSound.cpp b/platform/cafe/source/driver/DigitalSound.cpp index 056d0ae6..5793b186 100644 --- a/platform/cafe/source/driver/DigitalSound.cpp +++ b/platform/cafe/source/driver/DigitalSound.cpp @@ -49,15 +49,9 @@ namespace love return volume / (float)0x8000; } - AudioBuffer* DigitalSound::createBuffer(int size) + AudioBuffer* DigitalSound::createBuffer(int) { - auto* voice = AXAcquireVoice(0x1F, nullptr, nullptr); - - AXVoiceBegin(voice); - AXSetVoiceState(voice, AX_VOICE_STATE_STOPPED); - AXVoiceEnd(voice); - - return voice; + return new AudioBuffer(); } bool DigitalSound::isBufferDone(AudioBuffer* buffer) const @@ -65,13 +59,7 @@ namespace love if (buffer == nullptr) return false; - bool done = false; - - AXVoiceBegin(buffer); - done = buffer->state == AX_VOICE_STATE_STOPPED; - AXVoiceEnd(buffer); - - return done; + return buffer->isFinished(); } void DigitalSound::prepareBuffer(AudioBuffer* buffer, size_t nsamples, void* data, size_t size, @@ -80,24 +68,7 @@ namespace love if (buffer == nullptr || data == nullptr) return; - AXVoiceBegin(buffer); - - AXSetVoiceState(buffer, AX_VOICE_STATE_STOPPED); - AXSetVoiceLoop(buffer, looping ? AX_VOICE_LOOP_ENABLED : AX_VOICE_LOOP_DISABLED); - - AXVoiceOffsets offsets {}; - AXGetVoiceOffsets(buffer, &offsets); - - DCFlushRange(data, size); - - offsets.currentOffset = 0; - offsets.endOffset = nsamples; - offsets.loopOffset = 0; - offsets.data = data; - - AXSetVoiceOffsets(buffer, &offsets); - - AXVoiceEnd(buffer); + buffer->prepare(nsamples, data, size, looping); } void DigitalSound::setLooping(AudioBuffer* buffer, bool looping) @@ -105,11 +76,7 @@ namespace love if (buffer == nullptr) return; - AXVoiceBegin(buffer); - - AXSetVoiceLoop(buffer, looping ? AX_VOICE_LOOP_ENABLED : AX_VOICE_LOOP_DISABLED); - - AXVoiceEnd(buffer); + buffer->setLooping(looping); } bool DigitalSound::channelReset(size_t id, AudioBuffer* buffer, int channels, int bitDepth, @@ -118,14 +85,14 @@ namespace love if (id >= this->channels.size()) return false; - this->channels[id].begin(buffer, channels); - int32_t format = 0; - if (format = DigitalSound::getFormat(channels, bitDepth); format < 0) + if ((format = DigitalSound::getFormat(channels, bitDepth)) < 0) return false; - this->channels[id].setFormat(format); - return this->channels[id].reset(channels, sampleRate, 1.0f); + buffer->initialize(channels, format); + buffer->setSampleRate(sampleRate); + + return this->channels[id].reset(buffer, channels, 1.0f); } void DigitalSound::channelSetVolume(size_t id, float volume) diff --git a/source/modules/audio/Source.cpp b/source/modules/audio/Source.cpp index 6bc3fcec..af18fc22 100644 --- a/source/modules/audio/Source.cpp +++ b/source/modules/audio/Source.cpp @@ -144,11 +144,7 @@ namespace love while (!this->unusedBuffers.empty()) { -#if !defined(__WIIU__) delete this->unusedBuffers.top(); -#else - AXFreeVoice(this->unusedBuffers.top()); -#endif this->unusedBuffers.pop(); } }