remove AudioDecoder

This commit is contained in:
Demur Rumed 2025-04-26 03:55:21 +00:00
parent 3ec02994fb
commit 61889eb9da
6 changed files with 1 additions and 232 deletions

View file

@ -8,6 +8,7 @@
#define AAE_LPF_ORDER 4
#define NOMINMAX // because Windows is a joke.
#define MINIAUDIO_IMPLEMENTATION
#include "AccessibleAudioEngine.h"
extern "C" {

View file

@ -18,7 +18,6 @@
#include "soh/Enhancements/speechsynthesizer/SpeechSynthesizer.h"
#include "soh/Enhancements/tts/tts.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/Enhancements/audio/AudioDecoder.h"
extern "C" {
extern PlayState* gPlayState;
@ -89,8 +88,6 @@ class ActorAccessibility {
SfxExtractor sfxExtractor;
// Maps internal sfx to external (prerendered) resources.
std::unordered_map<s16, SfxRecord> sfxMap;
// Similar to above, but this one maps raw audio samples as opposed to SFX.
std::unordered_map<const char*, std::vector<uint8_t>> sampleMap;
int extractSfx = 0;
s16 currentScene = -1;
s8 currentRoom = -1;
@ -266,14 +263,7 @@ void ActorAccessibility_PlaySound(void* handle, int slot, s16 sfxId, bool loopin
return;
aa->audioEngine->playSound((uintptr_t)handle, slot, path, looping);
}
const char* ActorAccessibility_MapRawSampleToExternalAudio(const char* name);
void ActorAccessibility_PlayRawSample(void* handle, int slot, const char* name, bool looping) {
const char* path = ActorAccessibility_MapRawSampleToExternalAudio(name);
if (path == NULL)
return;
aa->audioEngine->playSound((uintptr_t)handle, slot, path, looping);
}
void ActorAccessibility_StopSound(void* handle, int slot) {
aa->audioEngine->stopSound((uintptr_t)handle, slot);
}
@ -319,12 +309,6 @@ void ActorAccessibility_PlaySoundForActor(AccessibleActor* actor, int slot, s16
ActorAccessibility_PlaySound(actor, slot, sfxId, looping);
ActorAccessibility_ConfigureSoundForActor(actor, slot);
}
void ActorAccessibility_PlaySampleForActor(AccessibleActor* actor, int slot, const char* name, bool looping) {
if (slot < 0 || slot > AAE_SLOTS_PER_HANDLE)
return;
ActorAccessibility_PlayRawSample(actor, slot, name, looping);
ActorAccessibility_ConfigureSoundForActor(actor, slot);
}
void ActorAccessibility_StopSoundForActor(AccessibleActor* actor, int slot) {
if (slot < 0 || slot >= AAE_SLOTS_PER_HANDLE)
return;
@ -717,26 +701,6 @@ const char* ActorAccessibility_MapSfxToExternalAudio(s16 sfxId) {
return record->path.c_str();
}
// Map the path to a raw sample to the external audio engine.
const char* ActorAccessibility_MapRawSampleToExternalAudio(const char* name) {
auto it = aa->sampleMap.find(name);
if (it == aa->sampleMap.end()) {
std::stringstream ss;
ss << "audio/samples/" << name;
std::string fullPath = ss.str();
auto res = Ship::Context::GetInstance()->GetResourceManager()->LoadResource(fullPath);
if (res == nullptr)
return NULL; // Resource doesn't exist, user's gotta run the extractor.
AudioDecoder decoder;
decoder.setSample((SOH::AudioSample*)res.get());
auto pair = aa->sampleMap.insert({ name, decoder.decodeToWav() });
ma_resource_manager_register_encoded_data(&aa->audioEngine->resourceManager, name,
pair.first->second.data(), pair.first->second.size());
}
return name;
}
// Call once per frame to tell the audio engine to start working on the latest batch of queued instructions.
void ActorAccessibility_PrepareNextAudioFrame() {
aa->audioEngine->prepare();

View file

@ -103,9 +103,6 @@ void ActorAccessibility_RunAccessibilityForAllActors(PlayState* play);
*must have previously prepared. looping: whether to play the sound just once or on a continuous loop.
*/
void ActorAccessibility_PlaySound(void* actor, int slot, s16 sfxId, bool looping);
// Play one of the game's internal samples.
void ActorAccessibility_PlayRawSample(void* handle, int slot, const char* name, bool looping);
//
// Stop a sound. Todo: consider making this a short fade instead of just cutting it off.
void ActorAccessibility_StopSound(void* handle, int slot);
void ActorAccessibility_StopAllSounds(void* handle);
@ -130,7 +127,6 @@ void ActorAccessibility_SeekSound(void* handle, int slot, size_t offset);
*
*/
void ActorAccessibility_PlaySoundForActor(AccessibleActor* actor, int slot, s16 sfxId, bool looping);
void ActorAccessibility_PlaySampleForActor(AccessibleActor* actor, int slot, const char* name, bool looping);
void ActorAccessibility_StopSoundForActor(AccessibleActor* actor, int slot);
void ActorAccessibility_StopAllSoundsForActor(AccessibleActor* actor);

View file

@ -1,5 +1,4 @@
#include "SfxExtractor.h"
#include "soh/Enhancements/audio/AudioDecoder.h"
#include "soh/Enhancements/audio/miniaudio.h"
#include "soh/Enhancements/speechsynthesizer/SpeechSynthesizer.h"
#include "soh/Enhancements/tts/tts.h"

View file

@ -1,158 +0,0 @@
#define MINIAUDIO_IMPLEMENTATION
#include "AudioDecoder.h"
#include "z64audio.h"
#include <stdexcept>
#define WAV_DECODE_CHUNK_SIZE 64
// A handful of definitions need to be copied from mixer.c.
#define ROUND_UP_32(v) (((v) + 31) & ~31)
// The below is copied verbatim from mixer.c.
static inline int16_t clamp16(int32_t v) {
if (v < -0x8000) {
return -0x8000;
} else if (v > 0x7fff) {
return 0x7fff;
} else {
return v;
}
}
AudioDecoder::AudioDecoder() {
prev1 = 0;
prev2 = 0;
}
AudioDecoder::~AudioDecoder() {
}
void AudioDecoder::setSample(SOH::AudioSample* sample) {
this->sample.codec = sample->sample.codec;
this->sample.loop.start = sample->sample.loop->start;
this->sample.loop.end = sample->sample.loop->end;
this->sample.loop.count = sample->sample.loop->count;
if (sample->book.book == nullptr)
memset(adpcm_table, 0, 8 * 2 * 8 * 2);
else
memcpy(adpcm_table, sample->sample.book->book,
16 * sample->sample.book->order * sample->sample.book->npredictors);
prev1 = 0;
prev2 = 0;
in = sample->sample.sampleAddr;
inStart = in;
inEnd = in + sample->sample.size;
}
void AudioDecoder::setSample(SoundFontSample* sample) {
this->sample.codec = sample->codec;
this->sample.loop.start = sample->loop->start;
this->sample.loop.end = sample->loop->end;
this->sample.loop.count = sample->loop->count;
if (sample->book->book == nullptr)
memset(adpcm_table, 0, 8 * 2 * 8 * 2);
else
memcpy(adpcm_table, sample->book->book, 16 * sample->book->order * sample->book->npredictors);
prev1 = 0;
prev2 = 0;
in = sample->sampleAddr;
inStart = in;
inEnd = in + sample->size;
}
size_t AudioDecoder::decode(int16_t* out, size_t nSamples) {
size_t samplesOut = 0;
size_t nbytes = nSamples * 2;
// Prevent the decoder from using more output bytes than declared to be available by the callee.
nbytes -= 31;
nbytes = ROUND_UP_32(nbytes);
while (nbytes > 0 && in < inEnd) {
int shift = *in >> 4; // should be in 0..12 or 0..14
int table_index = *in++ & 0xf; // should be in 0..7
int16_t(*tbl)[8] = adpcm_table[table_index];
int i;
for (i = 0; i < 2; i++) {
int16_t ins[8];
int j, k;
if (sample.codec == CODEC_SMALL_ADPCM) {
for (j = 0; j < 2; j++) {
ins[j * 4] = (((*in >> 6) << 30) >> 30) << shift;
ins[j * 4 + 1] = ((((*in >> 4) & 0x3) << 30) >> 30) << shift;
ins[j * 4 + 2] = ((((*in >> 2) & 0x3) << 30) >> 30) << shift;
ins[j * 4 + 3] = (((*in++ & 0x3) << 30) >> 30) << shift;
}
} else {
for (j = 0; j < 4; j++) {
ins[j * 2] = (((*in >> 4) << 28) >> 28) << shift;
ins[j * 2 + 1] = (((*in++ & 0xf) << 28) >> 28) << shift;
}
}
for (j = 0; j < 8; j++) {
int32_t acc = tbl[0][j] * prev2 + tbl[1][j] * prev1 + (ins[j] << 11);
for (k = 0; k < j; k++) {
acc += tbl[1][((j - k) - 1)] * ins[k];
}
acc >>= 11;
*out++ = clamp16(acc);
samplesOut++;
}
prev1 = out[-1];
prev2 = out[-2];
}
nbytes -= 16 * sizeof(int16_t);
}
return samplesOut;
}
ma_result wavWrite(ma_encoder* pEncoder, const void* pBufferIn, size_t bytesToWrite, size_t* pBytesWritten) {
auto fileData = (std::vector<uint8_t>*)pEncoder->pUserData;
fileData->insert(fileData->end(), (uint8_t*)pBufferIn, (uint8_t*)pBufferIn + bytesToWrite);
if (pBytesWritten != NULL) {
*pBytesWritten = bytesToWrite;
}
return MA_SUCCESS;
}
ma_result wavSeek(ma_encoder* pEncoder, ma_int64 offset, ma_seek_origin origin) {
return MA_ERROR;
}
std::vector<uint8_t> AudioDecoder::decodeToWav() {
std::vector<uint8_t> fileData;
ma_uint32 sampleRate;
// Todo: figure out how to really determine the sample rate. CODEC_ADPCM tends to stream at higher rates (usually
// 20KHZ) while CODEC_SMALL_ADPCM is usually around 14000. They're still not consistent though.
if (sample.codec == CODEC_ADPCM)
sampleRate = 20000;
else if (sample.codec = CODEC_SMALL_ADPCM)
sampleRate = 14000;
else
throw std::runtime_error("AudioDecoder: Unsupported codec.");
ma_encoder_config maconfig = ma_encoder_config_init(ma_encoding_format_wav, ma_format_s16, 1, sampleRate);
ma_encoder wavEncoder;
ma_result init_result = ma_encoder_init(wavWrite, wavSeek, &fileData, &maconfig, &wavEncoder);
if (init_result != MA_SUCCESS) {
return fileData;
}
int16_t chunk[WAV_DECODE_CHUNK_SIZE];
// Don't decode past the end of the loop.
size_t samplesLeft = sample.loop.end;
// Unless the loop is 0?
if (samplesLeft == 0)
samplesLeft = sample.loop.count;
while (samplesLeft > 0) {
size_t samplesRead = decode(chunk, WAV_DECODE_CHUNK_SIZE);
if (samplesRead > samplesLeft)
samplesRead = samplesLeft;
if (samplesRead == 0)
break;
ma_encoder_write_pcm_frames(&wavEncoder, chunk, samplesRead, NULL);
samplesLeft -= samplesRead;
}
ma_encoder_uninit(&wavEncoder);
return fileData;
}

View file

@ -1,33 +0,0 @@
#pragma once
// A standalone, incremental audio sample decoder.
// Based on the ADPCM decoding routines in mixer.c.
#include "miniaudio.h"
#include "libultraship/libultraship.h"
#include "soh/resource/type/AudioSample.h"
#include "z64audio.h"
class AudioDecoder {
struct {
int codec;
struct {
int start;
int end;
int count;
} loop;
} sample;
uint8_t *in, *inStart, *inEnd;
int16_t adpcm_table[8][2][8];
int16_t prev1, prev2; // The internal decoder takes an array of 16 shorts which it calls ADPCM_STATE. Strictly
// speaking only the last two decoded samples are needed for continuation.
public:
AudioDecoder();
~AudioDecoder();
// Support both SOH samples and Z64 samples.
void setSample(SOH::AudioSample* sample);
void setSample(SoundFontSample* sample);
size_t decode(int16_t* out, size_t nSamples);
std::vector<uint8_t> decodeToWav();
};