Call the sound effect mixer directly from Mix instead of pushing the samples from background audio.

This commit is contained in:
Henrik Rydgård committed 2023-07-12 17:55:46 +02:00
1 parent 830679503d
commit 19f4eadeb1
4 files changed
+130 -93

No files matched your search

+84 -65
View File
@@ -257,49 +257,6 @@ BackgroundAudio::~BackgroundAudio() {
delete[] buffer;
}
BackgroundAudio::Sample *BackgroundAudio::LoadSample(const std::string &path) {
size_t bytes;
uint8_t *data = g_VFS.ReadFile(path.c_str(), &bytes);
if (!data) {
return nullptr;
}
RIFFReader reader(data, (int)bytes);
WavData wave;
wave.Read(reader);
delete [] data;
if (wave.num_channels != 2 || wave.sample_rate != 44100 || wave.raw_bytes_per_frame != 4) {
ERROR_LOG(AUDIO, "Wave format not supported for mixer playback. Must be 16-bit raw stereo. '%s'", path.c_str());
return nullptr;
}
int16_t *samples = new int16_t[2 * wave.numFrames];
memcpy(samples, wave.raw_data, wave.numFrames * wave.raw_bytes_per_frame);
return new BackgroundAudio::Sample(samples, wave.numFrames);
}
void BackgroundAudio::LoadSamples() {
samples_.resize((size_t)UI::UISound::COUNT);
samples_[(size_t)UI::UISound::BACK] = std::unique_ptr<Sample>(LoadSample("sfx_back.wav"));
samples_[(size_t)UI::UISound::SELECT] = std::unique_ptr<Sample>(LoadSample("sfx_select.wav"));
samples_[(size_t)UI::UISound::CONFIRM] = std::unique_ptr<Sample>(LoadSample("sfx_confirm.wav"));
samples_[(size_t)UI::UISound::TOGGLE_ON] = std::unique_ptr<Sample>(LoadSample("sfx_toggle_on.wav"));
samples_[(size_t)UI::UISound::TOGGLE_OFF] = std::unique_ptr<Sample>(LoadSample("sfx_toggle_off.wav"));
UI::SetSoundCallback([](UI::UISound sound) {
g_BackgroundAudio.PlaySFX(sound);
});
}
void BackgroundAudio::PlaySFX(UI::UISound sfx) {
std::lock_guard<std::mutex> lock(mutex_);
plays_.push_back(PlayInstance{ sfx, 0, 64, false });
}
void BackgroundAudio::Clear(bool hard) {
if (!hard) {
fadingOut_ = true;
@@ -372,28 +329,6 @@ bool BackgroundAudio::Play() {
}
}
// Mix in menu sound effects. Terribly slow mixer but meh.
if (!plays_.empty()) {
for (int i = 0; i < sz * 2; i += 2) {
std::vector<PlayInstance>::iterator iter = plays_.begin();
while (iter != plays_.end()) {
PlayInstance inst = *iter;
auto sample = samples_[(int)inst.sound].get();
if (!sample || iter->offset >= sample->length_) {
iter->done = true;
iter = plays_.erase(iter);
} else {
if (!iter->done) {
buffer[i] += sample->data_[inst.offset * 2] * inst.volume >> 8;
buffer[i + 1] += sample->data_[inst.offset * 2 + 1] * inst.volume >> 8;
}
iter->offset++;
iter++;
}
}
}
}
System_AudioPushSamples(buffer, sz);
if (at3Reader_ && fadingOut_ && volume_ <= 0.0f) {
@@ -431,3 +366,87 @@ void BackgroundAudio::Update() {
sndLoadPending_ = false;
}
}
static inline int16_t Clamp16(int32_t sample) {
if (sample < -32767) return -32767;
if (sample > 32767) return 32767;
return sample;
}
void SoundEffectMixer::Mix(int16_t *buffer, int sz, int sampleRateHz) {
// Mix in menu sound effects. Terribly slow mixer but meh.
if (plays_.empty()) {
return;
}
for (std::vector<PlayInstance>::iterator iter = plays_.begin(); iter != plays_.end(); ) {
auto sample = samples_[(int)iter->sound].get();
for (int i = 0; i < sz * 2; i += 2) {
if (!sample || iter->offset >= sample->length_) {
iter->done = true;
break;
}
// Clamping add on top. Not great, we should be mixing at higher bitrate instead. Oh well.
int left = buffer[i];
int right = buffer[i + 1];
left = Clamp16(left + (sample->data_[iter->offset * 2] * iter->volume >> 8));
right = Clamp16(right + (sample->data_[iter->offset * 2 + 1] * iter->volume >> 8));
buffer[i] = left;
buffer[i + 1] = right;
iter->offset++;
}
if (iter->done) {
iter = plays_.erase(iter);
} else {
iter++;
}
}
}
void SoundEffectMixer::Play(UI::UISound sfx) {
std::lock_guard<std::mutex> guard(mutex_);
plays_.push_back(PlayInstance{ sfx, 0, 64, false });
}
Sample *SoundEffectMixer::LoadSample(const std::string &path) {
size_t bytes;
uint8_t *data = g_VFS.ReadFile(path.c_str(), &bytes);
if (!data) {
return nullptr;
}
RIFFReader reader(data, (int)bytes);
WavData wave;
wave.Read(reader);
delete[] data;
if (wave.num_channels != 2 || wave.sample_rate != 44100 || wave.raw_bytes_per_frame != 4) {
ERROR_LOG(AUDIO, "Wave format not supported for mixer playback. Must be 16-bit raw stereo. '%s'", path.c_str());
return nullptr;
}
int16_t *samples = new int16_t[2 * wave.numFrames];
memcpy(samples, wave.raw_data, wave.numFrames * wave.raw_bytes_per_frame);
return new Sample(samples, wave.numFrames);
}
void SoundEffectMixer::LoadSamples() {
samples_.resize((size_t)UI::UISound::COUNT);
samples_[(size_t)UI::UISound::BACK] = std::unique_ptr<Sample>(LoadSample("sfx_back.wav"));
samples_[(size_t)UI::UISound::SELECT] = std::unique_ptr<Sample>(LoadSample("sfx_select.wav"));
samples_[(size_t)UI::UISound::CONFIRM] = std::unique_ptr<Sample>(LoadSample("sfx_confirm.wav"));
samples_[(size_t)UI::UISound::TOGGLE_ON] = std::unique_ptr<Sample>(LoadSample("sfx_toggle_on.wav"));
samples_[(size_t)UI::UISound::TOGGLE_OFF] = std::unique_ptr<Sample>(LoadSample("sfx_toggle_off.wav"));
UI::SetSoundCallback([](UI::UISound sound) {
g_BackgroundAudio.SFX().Play(sound);
});
}