feat: refine exploration presentation and audio flow
This commit is contained in:
@@ -63,11 +63,22 @@ const server = await createServer({
|
||||
});
|
||||
|
||||
try {
|
||||
const { campMusicGroups, campAmbienceDefinitions, campSoundscapeMapping, getCampSoundscape } =
|
||||
const {
|
||||
campMusicGroups,
|
||||
campAmbienceDefinitions,
|
||||
campSoundscapeMapping,
|
||||
getCampSoundscape,
|
||||
campMusicVolumeForTrackKey,
|
||||
musicVolumeMatchedToCampTrack
|
||||
} =
|
||||
await server.ssrLoadModule('/src/game/data/campSoundscapes.ts');
|
||||
const { selectCampSkin } = await server.ssrLoadModule('/src/game/data/campSkins.ts');
|
||||
const { battleScenarios } = await server.ssrLoadModule('/src/game/data/battles.ts');
|
||||
const { musicTracks, ambienceTracks } = await server.ssrLoadModule('/src/game/audio/audioAssets.ts');
|
||||
const {
|
||||
musicTracks,
|
||||
ambienceTracks,
|
||||
musicTrackIntegratedLoudnessLufs
|
||||
} = await server.ssrLoadModule('/src/game/audio/audioAssets.ts');
|
||||
|
||||
const expectedSkinIds = Object.keys(expectedMapping);
|
||||
const musicEntries = Object.entries(campMusicGroups);
|
||||
@@ -83,6 +94,38 @@ try {
|
||||
|
||||
validateDefinitions(musicEntries, expectedMusicGroups, musicTracks, 'music group', 0.05, 0.4);
|
||||
validateDefinitions(ambienceEntries, expectedAmbiences, ambienceTracks, 'ambience', 0.03, 0.3);
|
||||
musicEntries.forEach(([, definition]) => {
|
||||
assertEqual(
|
||||
campMusicVolumeForTrackKey(definition.trackKey),
|
||||
definition.volume,
|
||||
`${definition.trackKey}: shared exploration music volume`
|
||||
);
|
||||
});
|
||||
assertEqual(
|
||||
campMusicVolumeForTrackKey('unknown-track', 0.19),
|
||||
0.19,
|
||||
'unknown exploration music fallback volume'
|
||||
);
|
||||
assertEqual(
|
||||
musicVolumeMatchedToCampTrack('militia-theme'),
|
||||
0.124,
|
||||
'militia theme volume matched to the camp-rally perceptual level'
|
||||
);
|
||||
const militiaEffectiveLoudness =
|
||||
musicTrackIntegratedLoudnessLufs['militia-theme'] +
|
||||
20 * Math.log10(musicVolumeMatchedToCampTrack('militia-theme'));
|
||||
const campRallyEffectiveLoudness =
|
||||
musicTrackIntegratedLoudnessLufs['camp-rally'] +
|
||||
20 * Math.log10(campMusicVolumeForTrackKey('camp-rally'));
|
||||
assert(
|
||||
Math.abs(
|
||||
militiaEffectiveLoudness - campRallyEffectiveLoudness
|
||||
) <= 0.1,
|
||||
`militia and camp-rally effective loudness must match within 0.1 LU; received ${(
|
||||
militiaEffectiveLoudness - campRallyEffectiveLoudness
|
||||
).toFixed(2)} LU`
|
||||
);
|
||||
validateExplorationSceneMixes();
|
||||
validateCampAudioAssets(
|
||||
musicEntries.map(([, definition]) => ({ key: definition.trackKey, url: musicTracks[definition.trackKey], kind: 'music' })),
|
||||
ambienceEntries.map(([, definition]) => ({ key: definition.trackKey, url: ambienceTracks[definition.trackKey], kind: 'ambience' }))
|
||||
@@ -143,6 +186,34 @@ try {
|
||||
await server.close();
|
||||
}
|
||||
|
||||
function validateExplorationSceneMixes() {
|
||||
const citySource = readFileSync('src/game/scenes/CityStayScene.ts', 'utf8');
|
||||
const villageSource = readFileSync('src/game/scenes/PrologueVillageScene.ts', 'utf8');
|
||||
const campVisitSource = readFileSync(
|
||||
'src/game/scenes/CampVisitExplorationScene.ts',
|
||||
'utf8'
|
||||
);
|
||||
assert(
|
||||
citySource.includes('musicVolume: campMusicVolumeForTrackKey(this.profile.musicKey)'),
|
||||
'city stays must reuse the calibrated camp music level for their selected track'
|
||||
);
|
||||
assert(
|
||||
villageSource.includes(
|
||||
"musicVolume: musicVolumeMatchedToCampTrack('militia-theme')"
|
||||
) &&
|
||||
!villageSource.includes('musicVolume: 0.72') &&
|
||||
!villageSource.includes('musicVolume: 0.22'),
|
||||
'the prologue village must loudness-match its hotter source track to the calibrated camp mix'
|
||||
);
|
||||
assertEqual(
|
||||
campVisitSource.match(
|
||||
/musicVolume:\s*campMusicVolumeForTrackKey\('camp-rally'\)/g
|
||||
)?.length ?? 0,
|
||||
2,
|
||||
'camp visits must reuse the calibrated camp-rally level in both exploration variants'
|
||||
);
|
||||
}
|
||||
|
||||
function validateDefinitions(entries, expectedDefinitions, registeredTracks, context, minimumVolume, maximumVolume) {
|
||||
const expectedIds = Object.keys(expectedDefinitions);
|
||||
const registeredKeys = new Set(Object.keys(registeredTracks));
|
||||
|
||||
Reference in New Issue
Block a user