mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-08-26 16:15:19 -07:00
Finish re-integration. Also support playback of raw samples as external sounds.
This commit is contained in:
parent
d8ec5ff94e
commit
56c6cc3848
5 changed files with 89 additions and 18 deletions
|
@ -296,7 +296,10 @@ void accessible_goma(AccessibleActor* actor) {
|
|||
}
|
||||
|
||||
void accessible_door_of_time(AccessibleActor* actor) {
|
||||
ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);
|
||||
ActorAccessibility_PlaySampleForActor(actor, 0, "Chanting", false);
|
||||
ActorAccessibility_SetSoundPitch(actor, 0, 1.0);
|
||||
|
||||
//ActorAccessibility_PlaySoundForActor(actor, 0, NA_SE_EV_DIAMOND_SWITCH, false);
|
||||
}
|
||||
|
||||
void accessible_sticks(AccessibleActor* actor) {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#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;
|
||||
extern bool freezeGame;
|
||||
|
@ -48,13 +49,15 @@ typedef std::map<s32, VAList_t> VAZones_t;//Maps room/ scene indices to their co
|
|||
typedef std::unordered_set<s16> SceneList_t;//A list of scenes which have already been visited (since the game was launched). Used to prevent re-creation of terrain VAs every time the player reloads a scene.
|
||||
|
||||
typedef struct {
|
||||
std::string hexName;
|
||||
std::string path;
|
||||
std::shared_ptr<LUS::File> resource;
|
||||
std::shared_ptr<s16*> decodedSample;//Set if the record is for a raw sample as opposed to a SFX.
|
||||
|
||||
}SfxRecord;
|
||||
|
||||
class ActorAccessibility {
|
||||
public:
|
||||
bool isOn = false;
|
||||
int isOn = 0;
|
||||
uint64_t nextActorID = 0;
|
||||
SupportedActors_t supportedActors;
|
||||
TrackedActors_t trackedActors;
|
||||
|
@ -64,6 +67,7 @@ class ActorAccessibility {
|
|||
AccessibleAudioEngine* audioEngine;
|
||||
SfxExtractor sfxExtractor;
|
||||
std::unordered_map<s16, SfxRecord> sfxMap;//Maps internal sfx to external (prerendered) resources.
|
||||
std::unordered_map<std::string, SfxRecord> sampleMap;//Similar to above, but this one maps raw audio samples as opposed to SFX.
|
||||
int extractSfx = 0;
|
||||
};
|
||||
static ActorAccessibility* aa;
|
||||
|
@ -100,6 +104,9 @@ void ActorAccessibility_OnGameStillFrozen()
|
|||
void ActorAccessibility_Init() {
|
||||
|
||||
aa = new ActorAccessibility();
|
||||
aa->isOn = CVarGetInteger("gA11yAudioInteraction", 0);
|
||||
if (!aa->isOn)
|
||||
return;
|
||||
aa->extractSfx = CVarGetInteger("gExtractSfx", 0);
|
||||
if (aa->extractSfx)
|
||||
freezeGame = true;
|
||||
|
@ -126,7 +133,7 @@ void ActorAccessibility_Shutdown() {
|
|||
policy->pitch = 1.5;
|
||||
policy->runsAlways = false;
|
||||
policy->sound = sfx;
|
||||
policy->volume = 1.0;
|
||||
policy->volume = 0.5;
|
||||
policy->initUserData = NULL;
|
||||
policy->cleanupUserData = NULL;
|
||||
policy->pitchModifier = 0.1;
|
||||
|
@ -216,12 +223,23 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
|
|||
Audio_PlaySoundGeneral(sfxId, &actor->projectedPos, 4, &actor->currentPitch, &actor->currentVolume, &actor->currentReverb);
|
||||
}
|
||||
const char* ActorAccessibility_MapSfxToExternalAudio(s16 sfxId);
|
||||
|
||||
void ActorAccessibility_PlaySound(void* handle, int slot, s16 sfxId, bool looping)
|
||||
{
|
||||
const char* path = ActorAccessibility_MapSfxToExternalAudio(sfxId);
|
||||
if (path == NULL)
|
||||
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);
|
||||
|
@ -269,17 +287,29 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
|
|||
aa->audioEngine->seekSound((uintptr_t)handle, slot, offset);
|
||||
|
||||
}
|
||||
void ActorAccessibility_ConfigureSoundForActor(AccessibleActor* actor, int slot)
|
||||
{
|
||||
ActorAccessibility_SetSoundPitch(actor, slot, actor->policy.pitch);
|
||||
ActorAccessibility_SetPitchBehindModifier(actor, slot, actor->policy.pitchModifier);
|
||||
ActorAccessibility_SetSoundPos(actor, slot, &actor->projectedPos, actor->xyzDistToPlayer,
|
||||
actor->policy.distance);
|
||||
ActorAccessibility_SetSoundVolume(actor, slot, actor->policy.volume);
|
||||
actor->managedSoundSlots[slot] = true;
|
||||
}
|
||||
void ActorAccessibility_PlaySoundForActor(AccessibleActor* actor, int slot, s16 sfxId, bool looping)
|
||||
{
|
||||
if (slot < 0 || slot > NUM_MANAGED_SOUND_SLOTS)
|
||||
return;
|
||||
ActorAccessibility_PlaySound(actor, slot, sfxId, looping);
|
||||
ActorAccessibility_SetSoundPitch(actor, slot, actor->policy.pitch);
|
||||
ActorAccessibility_SetPitchBehindModifier(actor, slot, actor->policy.pitchModifier);
|
||||
ActorAccessibility_SetSoundPos(actor, slot, &actor->projectedPos, actor->xzDistToPlayer,
|
||||
actor->policy.distance);
|
||||
ActorAccessibility_SetSoundVolume(actor, slot, actor->policy.volume);
|
||||
actor->managedSoundSlots[slot] = true;
|
||||
ActorAccessibility_ConfigureSoundForActor(actor, slot);
|
||||
|
||||
}
|
||||
void ActorAccessibility_PlaySampleForActor(AccessibleActor* actor, int slot, const char* name, bool looping)
|
||||
{
|
||||
if (slot < 0 || slot > NUM_MANAGED_SOUND_SLOTS)
|
||||
return;
|
||||
ActorAccessibility_PlayRawSample(actor, slot, name, looping);
|
||||
ActorAccessibility_ConfigureSoundForActor(actor, slot);
|
||||
|
||||
}
|
||||
void ActorAccessibility_StopSoundForActor(AccessibleActor* actor, int slot)
|
||||
|
@ -509,9 +539,14 @@ int ActorAccessibility_GetRandomStartingFrameCount(int min, int max) {
|
|||
return true;
|
||||
}
|
||||
void ActorAccessibility_ShutdownAudio() {
|
||||
if (aa->isOn == 0)
|
||||
return;
|
||||
delete aa->audioEngine;
|
||||
}
|
||||
void ActorAccessibility_MixAccessibleAudioWithGameAudio(int16_t* ogBuffer, uint32_t nFrames) {
|
||||
if (aa->isOn == 0)
|
||||
return;
|
||||
|
||||
aa->audioEngine->mix(ogBuffer, nFrames);
|
||||
|
||||
}
|
||||
|
@ -532,18 +567,48 @@ return NULL;//Resource doesn't exist, user's gotta run the extractor.
|
|||
tempRecord.resource = res;
|
||||
std::stringstream ss;
|
||||
ss << std::setw(4) << std::setfill('0') << std::hex << sfxId;
|
||||
tempRecord.hexName = ss.str();
|
||||
tempRecord.path = ss.str();
|
||||
aa->sfxMap[sfxId] = tempRecord;
|
||||
record = &aa->sfxMap[sfxId];
|
||||
aa->audioEngine->cacheDecodedSample(record->hexName, record->resource->Buffer.data(),
|
||||
aa->audioEngine->cacheDecodedSample(record->path, record->resource->Buffer.data(),
|
||||
record->resource->Buffer.size());
|
||||
} else
|
||||
record = &it->second;
|
||||
|
||||
return record->hexName.c_str();
|
||||
return record->path.c_str();
|
||||
|
||||
|
||||
}
|
||||
//Map the path to a raw sample to the external audio engine.
|
||||
const char* ActorAccessibility_MapRawSampleToExternalAudio(const char* name)
|
||||
{
|
||||
SfxRecord* record;
|
||||
std::string key(name);
|
||||
auto it = aa->sampleMap.find(key);
|
||||
if (it == aa->sampleMap.end()) {
|
||||
SfxRecord tempRecord;
|
||||
std::stringstream ss;
|
||||
ss << "audio/samples/" << key;
|
||||
std::string fullPath = ss.str();
|
||||
auto res = LUS::Context::GetInstance()->GetResourceManager()->LoadResource(fullPath);
|
||||
if (res == nullptr)
|
||||
return NULL; // Resource doesn't exist, user's gotta run the extractor.
|
||||
AudioDecoder decoder;
|
||||
decoder.setSample((LUS::AudioSample*)res.get());
|
||||
s16* wav;
|
||||
size_t wavSize = decoder.decodeToWav(&wav);
|
||||
|
||||
tempRecord.path = key;
|
||||
tempRecord.decodedSample = std::make_shared<s16*>(wav);
|
||||
aa->sampleMap[key] = tempRecord;
|
||||
record = &aa->sampleMap[key];
|
||||
aa->audioEngine->cacheDecodedSample(record->path, wav,
|
||||
wavSize);
|
||||
} else
|
||||
record = &it->second;
|
||||
|
||||
return record->path.c_str();
|
||||
}
|
||||
// Call once per frame to tell the audio engine to start working on the latest batch of queued instructions.
|
||||
|
||||
void ActorAccessibility_PrepareNextAudioFrame() {
|
||||
|
|
|
@ -99,6 +99,9 @@ void ActorAccessibility_PlaySpecialSound(AccessibleActor* actor, s16 sfxId);
|
|||
*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);
|
||||
|
@ -121,6 +124,8 @@ 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);
|
||||
f32 ActorAccessibility_ComputeCurrentVolume(f32 maxDistance, f32 xzDistToPlayer);
|
||||
|
|
|
@ -93,8 +93,6 @@ void SfxExtractor::renderOutput() {
|
|||
}
|
||||
void SfxExtractor::setup() {
|
||||
try {
|
||||
ogMusicVolume = CVarGetFloat("gMainMusicVolume", 1.0);
|
||||
CVarSetFloat("gMainMusicVolume", 0.0);
|
||||
|
||||
SpeechSynthesizer::Instance->Speak("Sfx extraction speedrun initiated. Please wait. This will take a few minutes.", GetLanguageCode());
|
||||
// Kill the audio thread so we can take control.
|
||||
|
@ -158,6 +156,8 @@ void SfxExtractor::finished() {
|
|||
CVarClear("gExtractSfx");
|
||||
CVarSave();
|
||||
archive = nullptr;
|
||||
freezeGame = false;
|
||||
|
||||
Audio_QueueSeqCmd(NA_BGM_TITLE);
|
||||
|
||||
if (currentStep == STEP_ERROR || currentStep == STEP_ERROR_OTR) {
|
||||
|
@ -171,7 +171,6 @@ void SfxExtractor::finished() {
|
|||
SpeechSynthesizer::Instance->Speak(ss.str().c_str(), GetLanguageCode());
|
||||
} else
|
||||
Audio_PlayFanfare(NA_BGM_ITEM_GET);
|
||||
freezeGame = false;
|
||||
|
||||
}
|
||||
void SfxExtractor::maybeGiveProgressReport() {
|
||||
|
|
|
@ -10,7 +10,6 @@ class SfxExtractor {
|
|||
s16 currentSfx;
|
||||
std::vector<int16_t> tempStorage; // Stores raw audio data for the sfx currently being ripped.
|
||||
int16_t* tempBuffer; // Raw pointer to the above vector.
|
||||
f32 ogMusicVolume;
|
||||
int progressMilestones[9]; // Implements progress reports after every 10 percent.
|
||||
// Check if a buffer contains meaningful audio output.
|
||||
bool isAllZero(int16_t* buffer, size_t count);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue