Files
Portfolio/src/audio/journey-music-state.ts

58 lines
1.8 KiB
TypeScript

import type { SectionId } from '@/content/types';
import type {
AudioJourneyState,
ChapterIntent,
DriveEnergySample,
MusicMood,
} from '@/audio/types';
const JOURNEY_MUSIC = Object.freeze({
start: { mood: 'open', entryPhrase: 0 },
profile: { mood: 'open', entryPhrase: 1 },
experience: { mood: 'shadow', entryPhrase: 2 },
infrastructure: { mood: 'shadow', entryPhrase: 3 },
'selected-builds': { mood: 'lift', entryPhrase: 4 },
'additional-work': { mood: 'lift', entryPhrase: 5 },
toolkit: { mood: 'resolve', entryPhrase: 6 },
contact: { mood: 'resolve', entryPhrase: 7 },
} as const satisfies Readonly<Record<
SectionId,
{ readonly mood: MusicMood; readonly entryPhrase: number }
>>);
export function resolveChapterIntent(
sectionId: SectionId,
generation = 0,
): ChapterIntent {
const chapter = JOURNEY_MUSIC[sectionId];
return Object.freeze({
sectionId,
mood: chapter.mood,
atStart: sectionId === 'start',
entryPhrase: chapter.entryPhrase,
generation: Math.max(0, Math.trunc(generation)),
});
}
export const DEFAULT_CHAPTER_INTENT = resolveChapterIntent('start');
export const DEFAULT_DRIVE_ENERGY = Object.freeze({
energy: 0,
source: 'idle',
} as const satisfies DriveEnergySample);
export function resolveJourneyMusicState(sectionId: string, intensity = 0): AudioJourneyState {
const canonicalId = Object.hasOwn(JOURNEY_MUSIC, sectionId)
? sectionId as SectionId
: 'start';
const chapter = resolveChapterIntent(canonicalId);
const finiteIntensity = Number.isFinite(intensity) ? intensity : 0;
return Object.freeze({
atStart: sectionId === 'start',
intensity: Math.min(1, Math.max(0, finiteIntensity)),
bias: chapter.mood,
entryPhrase: chapter.entryPhrase,
});
}
export const DEFAULT_AUDIO_JOURNEY_STATE = resolveJourneyMusicState('start');