Add cutscene controls for the audio mixer, fix PSP pause latency

- Fixed PSP pause taking up to ~1.1s to actually go silent: its output
  thread ran independently of stream->state, draining its whole software
  ring regardless. audiostream_t.state is now volatile and the output
  thread checks AUDIO_STREAM_STATE_PLAYING before each hardware chunk,
  skipping output (without consuming the ring) while paused - pause now
  goes silent within about one chunk (~23ms) and resume has no gap.
- Added audioMixerPause/Resume/SetPan/SetLoop/FadeTo/IsFading to the
  mixer - immediate, channel-indexed primitives for cutscenes to drive.
  Fade transitions (fadeFrom/To/Duration/Time/Easing) live on
  audiomixerchannelstate_t and advance every frame in
  audioMixerChannelApplyVolume(), reusing the same easingApply()
  interpolation uifullbox_t already uses for screen fades.
- New src/dusk/rpg/cutscene/item/audio/ with 9 cutscene item types:
  AUDIO_PLAY (+ AUDIO_PLAY_SIMPLE/AUDIO_PLAY_LOOPED shorthands),
  AUDIO_STOP, AUDIO_PAUSE, AUDIO_RESUME, AUDIO_FADE (+ FADE_OUT/FADE_IN
  shorthands), AUDIO_FADE_WAIT, AUDIO_SET_PAN, AUDIO_SET_LOOP, and the
  combined AUDIO_SET - registered through the same enum/union/callback
  table/macro mechanism every other item type uses.
- Wired the same 9 types into the JSON-based (offline JSONC -> binary
  .cts) cutscene asset pipeline: tools/asset/cutscene/__main__.py's
  encoder and assetcutsceneloader.c's decoder. Verified round-trip by
  hand-encoding/decoding a test file covering all 9 types, and confirmed
  the two existing real cutscene files re-encode byte-identical.

Built and verified on Linux, PSP (Docker), GameCube (Docker) and Wii
(Docker).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-09-02 17:44:06 -05:00
co-authored by Claude Sonnet 5
parent 9c28d5a3b7
commit 9364768397
31 changed files with 1183 additions and 3 deletions
@@ -0,0 +1,35 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "audio/mixer/audiomixerchannel.h"
typedef struct cutsceneitem_s cutsceneitem_t;
typedef union cutsceneitemdata_u cutsceneitemdata_t;
/**
* Starts an audio resume step (resumes the channel immediately).
*
* @param item The cutscene item.
* @param data Runtime data storage.
*/
void cutsceneAudioResumeStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates an audio resume step (always completes immediately).
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true always.
*/
bool_t cutsceneAudioResumeUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);