Fixed audio stuff
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
#include "audiomanager.hh"
|
#include "audiomanager.hh"
|
||||||
|
|
||||||
|
#include "common/hardware/dma.h"
|
||||||
#include "common/hardware/spu.h"
|
#include "common/hardware/spu.h"
|
||||||
|
#include <psyqo/kernel.hh>
|
||||||
#include <psyqo/spu.hh>
|
#include <psyqo/spu.hh>
|
||||||
#include <psyqo/xprintf.h>
|
#include <psyqo/xprintf.h>
|
||||||
|
|
||||||
@@ -65,25 +67,34 @@ bool AudioManager::loadClip(int clipIndex, const uint8_t* adpcmData, uint32_t si
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// psyqo::SPU::dmaWrite takes dataSize as uint16_t so upload in chunks
|
// psyqo::SPU::dmaWrite takes dataSize as uint16_t and uses blockSize=4:
|
||||||
// for clips larger than 65532 bytes (largest multiple-of-4 that fits).
|
// BCR = blockSize | ((dataSize / blockSize) << 16)
|
||||||
|
// block_count = dataSize / blockSize (integer division - truncates!)
|
||||||
|
// actual bytes = block_count * blockSize * 4
|
||||||
//
|
//
|
||||||
// psyqo DMA math: BCR = blockSize | ((dataSize/blockSize) << 16)
|
// With blockSize=4: each block = 16 bytes. Max block_count that fits
|
||||||
// blockSize=4 → 4 words per block = 16 bytes per block
|
// in uint16_t's BCR field: 4095. Max clean transfer: 4095 * 16 = 65520.
|
||||||
// block count = dataSize/blockSize
|
// bytesThisRound MUST be a multiple of 16 to avoid the integer division
|
||||||
// total bytes = blockSize × (dataSize/blockSize) × 4 = dataSize × 4
|
// truncation causing fewer bytes to be DMA'd than the pointer advances.
|
||||||
// So dataSize = bytesThisRound / 4 gives the correct byte count.
|
|
||||||
const uint8_t* src = adpcmData;
|
const uint8_t* src = adpcmData;
|
||||||
uint32_t remaining = alignedSize;
|
uint32_t remaining = alignedSize;
|
||||||
uint32_t dstAddr = addr;
|
uint32_t dstAddr = addr;
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
// Max transfer per call: 65532 bytes (16383 blocks × 4 bytes each).
|
// Max transfer per call: 65520 bytes (4095 blocks * 16 bytes each).
|
||||||
uint32_t bytesThisRound = (remaining > 65532u) ? 65532u : remaining;
|
uint32_t bytesThisRound = (remaining > 65520u) ? 65520u : remaining;
|
||||||
bytesThisRound &= ~3u; // DMA alignment
|
bytesThisRound &= ~15u; // 16-byte block alignment
|
||||||
if (bytesThisRound == 0) break;
|
if (bytesThisRound == 0) break;
|
||||||
|
|
||||||
uint16_t dmaSizeParam = (uint16_t)(bytesThisRound / 4);
|
uint16_t dmaSizeParam = (uint16_t)(bytesThisRound / 4);
|
||||||
psyqo::SPU::dmaWrite(dstAddr, src, dmaSizeParam, 4);
|
psyqo::SPU::dmaWrite(dstAddr, src, dmaSizeParam, 4);
|
||||||
|
|
||||||
|
// PSYQo's internal waitForStatus only spins ~10000 iterations (~1.8ms).
|
||||||
|
// On real hardware, SPU DMA for 65KB takes tens of milliseconds.
|
||||||
|
// The timeout fires, the function returns, and the next chunk starts
|
||||||
|
// while the previous transfer is still in progress - corrupting data.
|
||||||
|
// Spin here until the DMA controller's busy bit actually clears.
|
||||||
|
while (DMA_CTRL[DMA_SPU].CHCR & (1 << 24)) {}
|
||||||
|
|
||||||
src += bytesThisRound;
|
src += bytesThisRound;
|
||||||
dstAddr += bytesThisRound;
|
dstAddr += bytesThisRound;
|
||||||
remaining -= bytesThisRound;
|
remaining -= bytesThisRound;
|
||||||
@@ -92,6 +103,12 @@ bool AudioManager::loadClip(int clipIndex, const uint8_t* adpcmData, uint32_t si
|
|||||||
// dmaWrite() now properly restores transfer mode to idle after each
|
// dmaWrite() now properly restores transfer mode to idle after each
|
||||||
// DMA transfer, so no manual SPU_CTRL fix-up is needed here.
|
// DMA transfer, so no manual SPU_CTRL fix-up is needed here.
|
||||||
|
|
||||||
|
// Restore SPU to manual (non-DMA) mode after upload.
|
||||||
|
// psyqo::SPU::dmaWrite sets SPU_CTRL bit 5 (DMA write mode) but never
|
||||||
|
// clears it. On real hardware, voice register writes (pitch, volume, etc.)
|
||||||
|
// may be ignored while the SPU bus is still in DMA mode.
|
||||||
|
SPU_CTRL &= ~(0b11 << 4);
|
||||||
|
|
||||||
m_clips[clipIndex].spuAddr = addr;
|
m_clips[clipIndex].spuAddr = addr;
|
||||||
m_clips[clipIndex].size = sizeBytes;
|
m_clips[clipIndex].size = sizeBytes;
|
||||||
m_clips[clipIndex].sampleRate = sampleRate;
|
m_clips[clipIndex].sampleRate = sampleRate;
|
||||||
@@ -125,21 +142,10 @@ int AudioManager::play(int clipIndex, int volume, int pan) {
|
|||||||
rightVol = (uint16_t)((uint32_t)vol * p / 127);
|
rightVol = (uint16_t)((uint32_t)vol * p / 127);
|
||||||
}
|
}
|
||||||
|
|
||||||
psyqo::SPU::ChannelPlaybackConfig config;
|
|
||||||
config.sampleRate.value = static_cast<uint16_t>(((uint32_t)clip.sampleRate << 12) / 44100);
|
|
||||||
config.volumeLeft = leftVol;
|
|
||||||
config.volumeRight = rightVol;
|
|
||||||
config.adsr = DEFAULT_ADSR;
|
|
||||||
|
|
||||||
// Set the repeat address depending on loop mode.
|
// Set the repeat address depending on loop mode.
|
||||||
// The new psyqo::SPU::getNextFreeChannel() uses the ENDX register:
|
// Looping clips: repeat -> clip start (loop back to beginning).
|
||||||
// a channel is "free" when its ENDX bit is set (voice reached loop-end).
|
// Non-looping clips: repeat -> dummy 0x1000 (go silent after clip ends,
|
||||||
// silenceChannels() points voices at psyqo's silent dummy sample at 0x1000
|
// dummy's loop-end flag re-sets ENDX -> channel freed).
|
||||||
// that immediately sets ENDX, so stopped channels are detected as free.
|
|
||||||
//
|
|
||||||
// Looping clips: repeat → clip start (loop back to beginning).
|
|
||||||
// Non-looping clips: repeat → dummy 0x1000 (go silent after clip ends,
|
|
||||||
// dummy's loop-end flag re-sets ENDX → channel freed).
|
|
||||||
constexpr uint16_t DUMMY_SPU_ADDR = 0x1000;
|
constexpr uint16_t DUMMY_SPU_ADDR = 0x1000;
|
||||||
if (clip.loop) {
|
if (clip.loop) {
|
||||||
SPU_VOICES[ch].sampleRepeatAddr = static_cast<uint16_t>(clip.spuAddr / 8);
|
SPU_VOICES[ch].sampleRepeatAddr = static_cast<uint16_t>(clip.spuAddr / 8);
|
||||||
@@ -147,9 +153,38 @@ int AudioManager::play(int clipIndex, int volume, int pan) {
|
|||||||
SPU_VOICES[ch].sampleRepeatAddr = DUMMY_SPU_ADDR / 8;
|
SPU_VOICES[ch].sampleRepeatAddr = DUMMY_SPU_ADDR / 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
psyqo::SPU::playADPCM(static_cast<uint8_t>(ch),
|
// Build playback config
|
||||||
static_cast<uint16_t>(clip.spuAddr),
|
psyqo::SPU::ChannelPlaybackConfig config;
|
||||||
config, true);
|
config.sampleRate.value = static_cast<uint16_t>(((uint32_t)clip.sampleRate << 12) / 44100);
|
||||||
|
config.volumeLeft = leftVol;
|
||||||
|
config.volumeRight = rightVol;
|
||||||
|
config.adsr = DEFAULT_ADSR;
|
||||||
|
|
||||||
|
// Write SPU voice registers directly instead of PSYQo's playADPCM(),
|
||||||
|
// which truncates addresses above 64KB (uint16_t parameter).
|
||||||
|
// The sampleStartAddr register stores addr/8, so uint16_t covers
|
||||||
|
// the full 512KB SPU RAM range.
|
||||||
|
|
||||||
|
// KEY_OFF (hard cut)
|
||||||
|
if (ch > 15) {
|
||||||
|
SPU_KEY_OFF_HIGH = 1 << (ch - 16);
|
||||||
|
} else {
|
||||||
|
SPU_KEY_OFF_LOW = 1 << ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
SPU_VOICES[ch].volumeLeft = config.volumeLeft;
|
||||||
|
SPU_VOICES[ch].volumeRight = config.volumeRight;
|
||||||
|
SPU_VOICES[ch].sampleRate = config.sampleRate.value;
|
||||||
|
SPU_VOICES[ch].sampleStartAddr = static_cast<uint16_t>(clip.spuAddr / 8);
|
||||||
|
SPU_VOICES[ch].ad = config.adsr & 0xFFFF;
|
||||||
|
SPU_VOICES[ch].sr = (config.adsr >> 16) & 0xFFFF;
|
||||||
|
|
||||||
|
// KEY_ON
|
||||||
|
if (ch > 15) {
|
||||||
|
SPU_KEY_ON_HIGH = 1 << (ch - 16);
|
||||||
|
} else {
|
||||||
|
SPU_KEY_ON_LOW = 1 << ch;
|
||||||
|
}
|
||||||
|
|
||||||
return static_cast<int>(ch);
|
return static_cast<int>(ch);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,12 @@ static constexpr int MAX_VOICES = 24;
|
|||||||
/// psyqo places a 16-byte silent dummy sample at 0x1000.
|
/// psyqo places a 16-byte silent dummy sample at 0x1000.
|
||||||
/// User clips start at 0x1010.
|
/// User clips start at 0x1010.
|
||||||
///
|
///
|
||||||
/// Upper bound is 0x10000 (64KB) because psyqo::SPU::playADPCM()
|
/// Note: psyqo::SPU::playADPCM() takes a uint16_t for the address,
|
||||||
/// takes a uint16_t for the SPU RAM address.
|
/// which would limit to 64KB. We bypass it and write SPU registers
|
||||||
|
/// directly to address the full 512KB range (register stores addr/8,
|
||||||
|
/// so uint16_t covers 0-0x7FFF8).
|
||||||
static constexpr uint32_t SPU_RAM_START = 0x1010;
|
static constexpr uint32_t SPU_RAM_START = 0x1010;
|
||||||
static constexpr uint32_t SPU_RAM_END = 0x10000;
|
static constexpr uint32_t SPU_RAM_END = 0x80000;
|
||||||
|
|
||||||
/// Default ADSR: instant attack, sustain at max, ~46ms linear release.
|
/// Default ADSR: instant attack, sustain at max, ~46ms linear release.
|
||||||
/// Lower 16-bit (AD): attack linear shift=0 step=0("+7"), decay shift=0,
|
/// Lower 16-bit (AD): attack linear shift=0 step=0("+7"), decay shift=0,
|
||||||
|
|||||||
2
third_party/nugget
vendored
2
third_party/nugget
vendored
Submodule third_party/nugget updated: 338ec49a57...668163091e
Reference in New Issue
Block a user