joeylib2/include/joey/audio.h

73 lines
3.1 KiB
C

// Audio: 4-channel Protracker .MOD music with digital one-shot SFX.
//
// Authors compose music as .MOD modules. The host-side asset pipeline
// (tools/joeymod) converts each module into the runtime form the
// target platform expects:
//
// Apple IIgs -- NinjaTrackerPlus .NTP, played by Ninjaforce's
// 65816 replayer linked into the binary.
// Amiga -- raw .MOD, played by Frank Wille's PTPlayer.
// DOS -- raw .MOD, played by libxmp-lite over SB DMA.
// Atari ST -- raw .MOD, played by libxmp-lite (parser only) plus
// a hand-rolled 68k 4-channel mixer that outputs via
// YM2149 4-bit PWM at ~12.5 kHz.
//
// Game code always calls the same five entry points; the per-port
// HAL hides the engine choice. A failed audio init is non-fatal --
// joeyInit still succeeds and audio calls become no-ops.
#ifndef JOEYLIB_AUDIO_H
#define JOEYLIB_AUDIO_H
#include "platform.h"
#include "types.h"
#define JOEY_AUDIO_SFX_SLOTS 4
// Initialize audio. Returns true if the platform has a working audio
// engine and was able to start it. Returns false silently otherwise;
// the rest of the API stays callable but produces no sound.
bool joeyAudioInit(void);
// Tear down the engine. Safe to call when audio is not initialized.
void joeyAudioShutdown(void);
// Begin module playback. data points at the platform-native module
// blob (.MOD on most platforms, .NTP on IIgs); the asset pipeline
// produces the right form for each target. If a module is already
// playing, it is replaced.
//
// loop=true plays forever. loop=false stops at song end, but Amiga
// requires the module to contain an E8FF effect at song end for the
// stop to fire (PTPlayer has no native song-end signal). The
// `joeymod` tool's .amod output extension injects that marker
// automatically; ship .amod for Amiga and .mod for the other ports.
// loop=false on a .mod (no E8FF) loops anyway on Amiga.
void joeyAudioPlayMod(const uint8_t *data, uint32_t length, bool loop);
// Stop the current module (if any). The playhead is reset so the next
// joeyAudioPlayMod starts from the top.
void joeyAudioStopMod(void);
// True if a module is currently producing output (false during silence
// after StopMod or before the first PlayMod, and on platforms where
// audio init failed).
bool joeyAudioIsPlayingMod(void);
// Trigger a one-shot digital SFX on the given slot (0..JOEY_AUDIO_SFX_SLOTS-1).
// sample points at raw signed 8-bit PCM. rateHz is the playback rate
// the sample was recorded at; the engine pitches as needed for its
// own output rate. If the slot is currently playing, the new sample
// replaces it.
void joeyAudioPlaySfx(uint8_t slot, const uint8_t *sample, uint32_t length, uint16_t rateHz);
// Stop a SFX slot early. No-op if the slot is already idle.
void joeyAudioStopSfx(uint8_t slot);
// Hook the engine into the game loop. Most platforms drive their
// engines off a hardware IRQ and ignore this call, but it's safe to
// invoke once per frame regardless and required for any port that
// runs its mixer in user-thread context.
void joeyAudioFrameTick(void);
#endif