Fix the SFX extractor. Should use less memory now too as the end of sound detection had regressed as well.

This commit is contained in:
caturria 2025-07-03 20:27:22 -04:00
parent 24e617b765
commit 0fb52ab567
4 changed files with 25 additions and 22 deletions

View file

@ -13,26 +13,29 @@ void AudioMgr_CreateNextAudioBuffer(s16* samples, u32 num_samples);
extern bool freezeGame; extern bool freezeGame;
} }
bool SfxExtractor::isAllZero(int16_t* buffer, size_t count) { bool SfxExtractor::isAllSilence(int16_t* buffer, size_t count) {
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
if (buffer[i] != 0) if (!isSilentSample(buffer[i]))//Tolerance for low-amplitude dither noise.
return false; return false;
} }
return true; return true;
} }
bool SfxExtractor::isSilentSample(int16_t sample) {
return abs(sample) <= SFX_EXTRACTION_SILENCE_THRESHOLD;
}
// Find the beginning of a captured signal. // Find the beginning of a captured signal.
size_t SfxExtractor::adjustedStartOfInput() { size_t SfxExtractor::adjustedStartOfInput() {
size_t startOfInput = 0; size_t startOfInput = 0;
while (startOfInput + 2 < SFX_EXTRACTION_BUFFER_SIZE * 2 && while (startOfInput + 2 < SFX_EXTRACTION_BUFFER_SIZE * 2 && isSilentSample(tempBuffer[startOfInput]) && isSilentSample(tempBuffer[startOfInput + 1])) {
(tempBuffer[startOfInput] == 0 || tempBuffer[startOfInput + 1] == 0)) {
startOfInput += 2; startOfInput += 2;
} }
return startOfInput; return startOfInput;
} }
size_t SfxExtractor::adjustedEndOfInput(size_t endOfInput) { size_t SfxExtractor::adjustedEndOfInput(size_t endOfInput) {
while (endOfInput > 0 && (tempBuffer[endOfInput] == 0 || tempBuffer[endOfInput - 1] == 0)) { while (endOfInput > 0 && (!isSilentSample(tempBuffer[endOfInput]) || isSilentSample(tempBuffer[endOfInput - 1]))) {
endOfInput -= 2; endOfInput -= 2;
} }
return endOfInput; return endOfInput;
@ -82,6 +85,7 @@ void SfxExtractor::setup() {
} }
sfxToRip = 0; sfxToRip = 0;
currentSfx = -1;
currentStep = STEP_MAIN; currentStep = STEP_MAIN;
archive = std::make_shared<Ship::O2rArchive>(sohAccessibilityPath); archive = std::make_shared<Ship::O2rArchive>(sohAccessibilityPath);
archive->Open(); archive->Open();
@ -89,11 +93,11 @@ void SfxExtractor::setup() {
} }
void SfxExtractor::ripNextSfx() { void SfxExtractor::ripNextSfx() {
{ //This entire method is expected to be atomic; Don't try to narrow the scope of this lock please!
auto lock = OTRAudio_Lock(); //Todo: remove the thread altogether as we don't actually need or want parallelism here.
auto lock = OTRAudio_Lock();
if (captureThreadState == CT_READY || captureThreadState == CT_PRIMING) if (captureThreadState == CT_READY || captureThreadState == CT_PRIMING)
return; // Keep going. return; // Keep going.
}
// Was the last sfx a loop? If so then we need to stop it, and then we need to run audio out to nowhere for as long // Was the last sfx a loop? If so then we need to stop it, and then we need to run audio out to nowhere for as long
// as it takes to get back to a blank slate. // as it takes to get back to a blank slate.
if (currentSfx != -1) { if (currentSfx != -1) {
@ -111,11 +115,7 @@ void SfxExtractor::ripNextSfx() {
currentSfx = sfxTable[sfxToRip++]; currentSfx = sfxTable[sfxToRip++];
Audio_PlaySoundGeneral(currentSfx, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, Audio_PlaySoundGeneral(currentSfx, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultReverb); &gSfxDefaultReverb);
{
auto lock = OTRAudio_Lock();
captureThreadState = CT_READY; captureThreadState = CT_READY;
}
maybeGiveProgressReport(); maybeGiveProgressReport();
} }
void SfxExtractor::finished() { void SfxExtractor::finished() {
@ -168,9 +168,10 @@ void SfxExtractor::frameCallback() {
} }
void SfxExtractor::prime() { void SfxExtractor::prime() {
int frameLimit = 0;//A couple of sounds don't come to a full stop until another sound is loaded, but should be effectively silent after a couple of seconds.
do { do {
AudioMgr_CreateNextAudioBuffer(tempBuffer + 0, SFX_EXTRACTION_ONE_FRAME); AudioMgr_CreateNextAudioBuffer(tempBuffer + 0, SFX_EXTRACTION_ONE_FRAME);
} while (isAllZero(tempBuffer + 0, SFX_EXTRACTION_ONE_FRAME * 2)); } while (frameLimit ++ < 200 && !isAllSilence(tempBuffer + 0, SFX_EXTRACTION_ONE_FRAME * 2));
captureThreadState = CT_FINISHED; captureThreadState = CT_FINISHED;
} }
@ -187,7 +188,7 @@ void SfxExtractor::captureCallback() {
while (samplesLeft > 0) { while (samplesLeft > 0) {
AudioMgr_CreateNextAudioBuffer(mark, SFX_EXTRACTION_ONE_FRAME); AudioMgr_CreateNextAudioBuffer(mark, SFX_EXTRACTION_ONE_FRAME);
if (isAllZero(mark, SFX_EXTRACTION_ONE_FRAME * 2)) { if (isAllSilence(mark, SFX_EXTRACTION_ONE_FRAME * 2)) {
if (outputStarted) { if (outputStarted) {
break; break;
} else if (waitTime++ < 300) { } else if (waitTime++ < 300) {

View file

@ -1,8 +1,10 @@
#pragma once #pragma once
#include "libultraship/libultraship.h" #include "libultraship/libultraship.h"
#define SFX_EXTRACTION_BUFFER_SIZE 44100 * 15 #define SFX_EXTRACTION_BUFFER_SIZE 32000 * 15
#define SFX_EXTRACTION_ONE_FRAME 736 #define SFX_EXTRACTION_ONE_FRAME 560
#define SFX_EXTRACTION_SILENCE_THRESHOLD 6//Corresponds to an amplitude of -75dB.
enum CaptureThreadStates { enum CaptureThreadStates {
CT_WAITING, // for a sound to start ripping. CT_WAITING, // for a sound to start ripping.
@ -29,7 +31,8 @@ class SfxExtractor {
// Stores raw audio data for the sfx currently being ripped. // Stores raw audio data for the sfx currently being ripped.
int16_t tempBuffer[(SFX_EXTRACTION_BUFFER_SIZE + SFX_EXTRACTION_ONE_FRAME * 3) * 2]; int16_t tempBuffer[(SFX_EXTRACTION_BUFFER_SIZE + SFX_EXTRACTION_ONE_FRAME * 3) * 2];
// Check if a buffer contains meaningful audio output. // Check if a buffer contains meaningful audio output.
bool isAllZero(int16_t* buffer, size_t count); bool isAllSilence(int16_t* buffer, size_t count);
bool isSilentSample(int16_t sample);
size_t adjustedStartOfInput(); size_t adjustedStartOfInput();
size_t adjustedEndOfInput(size_t endOfInput); size_t adjustedEndOfInput(size_t endOfInput);
bool renderOutput(size_t endOfInput); bool renderOutput(size_t endOfInput);

View file

@ -1092,7 +1092,7 @@ const s16 sfxTable[] = {
NA_SE_OC_SECRET_WARP_OUT, NA_SE_OC_SECRET_WARP_OUT,
NA_SE_OC_SECRET_HOLE_OUT, NA_SE_OC_SECRET_HOLE_OUT,
NA_SE_OC_REVENGE, NA_SE_OC_REVENGE,
NA_SE_OC_HINT_MOVIE, NA_SE_OC_HINT_MOVIE,
NA_SE_OC_HINT_MOVIE2_WHITE, NA_SE_OC_HINT_MOVIE2_WHITE,
NA_SE_OC_HINT_MOVIE_ZOOMIN, NA_SE_OC_HINT_MOVIE_ZOOMIN,
NA_SE_OC_HIBIKI_ISHI, NA_SE_OC_HIBIKI_ISHI,

View file

@ -2628,8 +2628,9 @@ extern "C" void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* repla
void OTRAudio_SfxCaptureThread() { void OTRAudio_SfxCaptureThread() {
while (audio.running) { while (audio.running) {
{ // This entire body is expected to be atomic; Don't try to narrow the scope of this lock please!
std::unique_lock<std::mutex> Lock(audio.mutex); // Todo: remove the thread altogether as we don't actually need or want parallelism here.
std::unique_lock<std::mutex> Lock(audio.mutex);
while (!audio.processing && audio.running) { while (!audio.processing && audio.running) {
audio.cv_to_thread.wait(Lock); audio.cv_to_thread.wait(Lock);
} }
@ -2637,8 +2638,6 @@ void OTRAudio_SfxCaptureThread() {
if (!audio.running) { if (!audio.running) {
break; break;
} }
}
std::unique_lock<std::mutex> Lock(audio.mutex);
#if !defined(__SWITCH__) && !defined(__WIIU__) #if !defined(__SWITCH__) && !defined(__WIIU__)
ActorAccessibility_DoSoundExtractionStep(); ActorAccessibility_DoSoundExtractionStep();
#endif #endif