hush
This commit is contained in:
97
src/audiomanager.hh
Normal file
97
src/audiomanager.hh
Normal file
@@ -0,0 +1,97 @@
|
||||
#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
|
||||
Reference in New Issue
Block a user