mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-04-28 13:17:58 +03:00
remove AudioDecoder
This commit is contained in:
parent
3ec02994fb
commit
61889eb9da
6 changed files with 1 additions and 232 deletions
|
@ -8,6 +8,7 @@
|
|||
#define AAE_LPF_ORDER 4
|
||||
|
||||
#define NOMINMAX // because Windows is a joke.
|
||||
#define MINIAUDIO_IMPLEMENTATION
|
||||
#include "AccessibleAudioEngine.h"
|
||||
|
||||
extern "C" {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue