98 lines
3.4 KiB
C++
98 lines
3.4 KiB
C++
#pragma once
|
|
|
|
#include <stdint.h>
|
|
|
|
namespace psxsplash {
|
|
|
|
/// Maximum number of audio clips that can be loaded in a scene
|
|
static constexpr int MAX_AUDIO_CLIPS = 32;
|
|
|
|
/// Maximum SPU voices (hardware limit)
|
|
static constexpr int MAX_VOICES = 24;
|
|
|
|
/// SPU RAM is 512KB total (0x00000-0x7FFFF).
|
|
/// First 0x1000 bytes reserved for capture buffers.
|
|
/// psyqo places a 16-byte silent dummy sample at 0x1000.
|
|
/// User clips start at 0x1010.
|
|
///
|
|
/// Upper bound is 0x10000 (64KB) because psyqo::SPU::playADPCM()
|
|
/// takes a uint16_t for the SPU RAM address.
|
|
static constexpr uint32_t SPU_RAM_START = 0x1010;
|
|
static constexpr uint32_t SPU_RAM_END = 0x10000;
|
|
|
|
/// Default ADSR: instant attack, sustain at max, ~46ms linear release.
|
|
/// Lower 16-bit (AD): attack linear shift=0 step=0("+7"), decay shift=0,
|
|
/// sustain level=0xF (max -> decay skipped)
|
|
/// Upper 16-bit (SR): sustain linear increase shift=0 step=0("+7"),
|
|
/// release linear shift=10 (~46ms to zero)
|
|
static constexpr uint32_t DEFAULT_ADSR = 0x000A000F;
|
|
|
|
/// Descriptor for a loaded audio clip in SPU RAM
|
|
struct AudioClip {
|
|
uint32_t spuAddr; // Byte address in SPU RAM
|
|
uint32_t size; // Size of ADPCM data in bytes
|
|
uint16_t sampleRate; // Original sample rate in Hz
|
|
bool loop; // Whether this clip should loop
|
|
bool loaded; // Whether this slot is valid
|
|
};
|
|
|
|
/// Manages SPU voices and audio clip playback.
|
|
///
|
|
/// Uses psyqo::SPU for all hardware interaction: initialization,
|
|
/// DMA uploads, voice allocation (via currentVolume check), playback
|
|
/// (playADPCM), and silencing (silenceChannels).
|
|
///
|
|
/// init()
|
|
/// loadClip(index, data, size, rate, loop) -> bool
|
|
/// play(clipIndex) -> channel
|
|
/// play(clipIndex, volume, pan) -> channel
|
|
/// stopVoice(channel)
|
|
/// stopAll()
|
|
/// setVoiceVolume(channel, vol, pan)
|
|
///
|
|
/// Volume is 0-128 (0=silent, 128=max). Pan is 0-127 (64=center).
|
|
class AudioManager {
|
|
public:
|
|
/// Initialize SPU hardware and reset state
|
|
void init();
|
|
|
|
/// Upload ADPCM data to SPU RAM and register as clip index.
|
|
/// Data must be 16-byte aligned (SPU ADPCM block size). Returns true on success.
|
|
bool loadClip(int clipIndex, const uint8_t* adpcmData, uint32_t sizeBytes,
|
|
uint16_t sampleRate, bool loop);
|
|
|
|
/// Play a clip by index. Returns channel (0-23), or -1 if full.
|
|
/// Volume: 0-128 (128=max). Pan: 0 (left) to 127 (right), 64 = center.
|
|
int play(int clipIndex, int volume = 128, int pan = 64);
|
|
|
|
/// Stop a specific channel (returned from play())
|
|
void stopVoice(int channel);
|
|
|
|
/// Stop all playing channels
|
|
void stopAll();
|
|
|
|
/// Set volume/pan on a playing channel
|
|
void setVoiceVolume(int channel, int volume, int pan = 64);
|
|
|
|
/// Get total SPU RAM used by loaded clips (for visualization)
|
|
uint32_t getUsedSPURam() const { return m_nextAddr - SPU_RAM_START; }
|
|
|
|
/// Get total SPU RAM available
|
|
uint32_t getTotalSPURam() const { return SPU_RAM_END - SPU_RAM_START; }
|
|
|
|
/// Get number of loaded clips
|
|
int getLoadedClipCount() const;
|
|
|
|
/// Reset all clips and free SPU RAM (call on scene unload)
|
|
void reset();
|
|
|
|
private:
|
|
/// Convert 0-128 volume to hardware 0-0x3FFF (fixed-volume mode)
|
|
static uint16_t volToHw(int v);
|
|
|
|
AudioClip m_clips[MAX_AUDIO_CLIPS];
|
|
uint32_t m_nextAddr = SPU_RAM_START; // Bump allocator for SPU RAM
|
|
};
|
|
|
|
} // namespace psxsplash
|