mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-05-24 15:00:55 -04:00
We have audio!!
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
void DuskAudioInitialize();
|
||||
namespace dusk::audio {
|
||||
void Initialize();
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ void JAU_JASInitializer::initJASystem(JKRSolidHeap* heap) {
|
||||
|
||||
JASDvd::createThread(dvdThreadPriority_, 0x80, 0x1000);
|
||||
#if TARGET_PC
|
||||
DuskAudioInitialize();
|
||||
dusk::audio::Initialize();
|
||||
#else
|
||||
JASAudioThread::create(audioThreadPriority_);
|
||||
#endif
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <SDL3/SDL_init.h>
|
||||
#include <array>
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
|
||||
#include "JSystem/JAudio2/JASAiCtrl.h"
|
||||
#include "JSystem/JAudio2/JASChannel.h"
|
||||
@@ -10,6 +12,9 @@
|
||||
#include "JSystem/JAudio2/JASHeapCtrl.h"
|
||||
|
||||
#include "DuskDsp.hpp"
|
||||
#include "JSystem/JAudio2/JASAudioThread.h"
|
||||
|
||||
using namespace dusk::audio;
|
||||
|
||||
static DspSubframe AllSubframeBuffers[DSP_OUTPUT_CHANNELS];
|
||||
|
||||
@@ -39,7 +44,7 @@ static void InitSDL3Output() {
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void DuskAudioInitialize() {
|
||||
void dusk::audio::Initialize() {
|
||||
InitSDL3Output();
|
||||
|
||||
JASDsp::initBuffer();
|
||||
@@ -53,22 +58,30 @@ void DuskAudioInitialize() {
|
||||
void SDLCALL GetNewAudio(
|
||||
void*,
|
||||
SDL_AudioStream*,
|
||||
int,
|
||||
int total_amount) {
|
||||
while (total_amount > 0) {
|
||||
int needed,
|
||||
int) {
|
||||
while (needed > 0) {
|
||||
const int rendered = RenderNewAudioFrame();
|
||||
total_amount -= rendered;
|
||||
needed -= rendered;
|
||||
}
|
||||
}
|
||||
|
||||
static std::ofstream outRaw("guh.raw", std::ios_base::out | std::ios_base::binary);
|
||||
|
||||
int RenderNewAudioFrame() {
|
||||
JASCriticalSection section;
|
||||
const u32 countSubframes = JASDriver::getSubFrames();
|
||||
|
||||
JASAudioThread::setDSPSyncCount(countSubframes);
|
||||
|
||||
for (u32 i = 0; i < countSubframes; i++) {
|
||||
RenderAudioSubframe();
|
||||
|
||||
JASAudioThread::snIntCount -= 1;
|
||||
}
|
||||
|
||||
outRaw.flush();
|
||||
|
||||
return static_cast<u16>(countSubframes) * DSP_SUBFRAME_SIZE;
|
||||
}
|
||||
|
||||
@@ -76,7 +89,9 @@ void RenderAudioSubframe() {
|
||||
DspSubframe& subFrame = AllSubframeBuffers[0];
|
||||
|
||||
JASDriver::updateDSP();
|
||||
DuskDspRender(subFrame);
|
||||
DspRender(subFrame);
|
||||
|
||||
outRaw.write((const char*)subFrame.data(), subFrame.size() * sizeof(s16));
|
||||
|
||||
SDL_PutAudioStreamData(PlaybackStream, &subFrame, sizeof(subFrame));
|
||||
}
|
||||
|
||||
+142
-8
@@ -1,16 +1,150 @@
|
||||
#include <ar.h>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#include "DuskDsp.hpp"
|
||||
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <iosfwd>
|
||||
|
||||
static float SinePos;
|
||||
#include "Adpcm.hpp"
|
||||
#include "global.h"
|
||||
|
||||
void DuskDspRender(DspSubframe& subframe) {
|
||||
subframe.fill(0);
|
||||
using namespace dusk::audio;
|
||||
|
||||
for (auto& elem : subframe) {
|
||||
elem = static_cast<s16>(sinf(SinePos) * std::numeric_limits<s16>::max() * 0.2);
|
||||
SinePos += 0.05f;
|
||||
ChannelAuxData dusk::audio::ChannelAux[DSP_CHANNELS] = {};
|
||||
|
||||
static bool ValidateChannelWaveFormat(const JASDsp::TChannel& channel) {
|
||||
if (channel.mSamplesPerBlock == AdpcmSampleCount && channel.mBytesPerBlock == Adpcm4FrameSize)
|
||||
return true;
|
||||
/*
|
||||
if (channel.mSamplesPerBlock == AdpcmSampleCount && channel.mBytesPerBlock == Adpcm2FrameSize)
|
||||
return true;
|
||||
if (channel.mSamplesPerBlock == 1 && channel.mBytesPerBlock == 8)
|
||||
return true;
|
||||
if (channel.mSamplesPerBlock == 1 && channel.mBytesPerBlock == 16)
|
||||
return true;
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ValidateChannel(const JASDsp::TChannel& channel) {
|
||||
if (!ValidateChannelWaveFormat(channel)) {
|
||||
CRASH(
|
||||
"Unable to handle channel format: %02x, %02x\n",
|
||||
channel.mSamplesPerBlock,
|
||||
channel.mBytesPerBlock);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 ConvertDataLengthToSamples(const JASDsp::TChannel& channel, u32 dataLen) {
|
||||
if (dataLen % channel.mBytesPerBlock != 0) {
|
||||
CRASH("Indivisible data length: %d\n", dataLen);
|
||||
}
|
||||
|
||||
auto& channels = *reinterpret_cast<std::array<JASDsp::TChannel, DSP_CHANNELS>*>(JASDsp::CH_BUF);
|
||||
return (dataLen / channel.mBytesPerBlock) * channel.mSamplesPerBlock;
|
||||
}
|
||||
|
||||
static u32 ConvertSamplesToDataLength(const JASDsp::TChannel& channel, u32 samples) {
|
||||
if (samples % channel.mSamplesPerBlock != 0) {
|
||||
CRASH("Indivisible sample count: %d\n", samples);
|
||||
}
|
||||
|
||||
return (samples / channel.mSamplesPerBlock) * channel.mBytesPerBlock;
|
||||
}
|
||||
|
||||
static void RenderChannel(
|
||||
JASDsp::TChannel& channel,
|
||||
ChannelAuxData& channelAux,
|
||||
DspSubframe& subframe);
|
||||
|
||||
static void ResetChannel(JASDsp::TChannel& channel) {
|
||||
channel.mSamplesLeft = channel.mEndSample - channel.mSamplePosition;
|
||||
|
||||
channel.mResetFlag = false;
|
||||
}
|
||||
|
||||
static void MixSubframe(DspSubframe& dst, const DspSubframe& src) {
|
||||
for (int i = 0; i < dst.size(); i++) {
|
||||
dst[i] = static_cast<s16>(dst[i] + src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void dusk::audio::DspRender(DspSubframe& subframe) {
|
||||
subframe.fill(0);
|
||||
|
||||
// This cast half exists because my debugger sucks and this is an easy way to look at the data.
|
||||
auto& channels = *reinterpret_cast<std::array<JASDsp::TChannel, DSP_CHANNELS>*>(JASDsp::CH_BUF);
|
||||
|
||||
for (int i = 0; i < channels.size(); i++) {
|
||||
auto& channel = channels[i];
|
||||
auto& channelAux = ChannelAux[i];
|
||||
|
||||
if (!channel.mIsActive) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ValidateChannel(channel);
|
||||
|
||||
DspSubframe channelSubframe = {};
|
||||
RenderChannel(channel, channelAux, channelSubframe);
|
||||
MixSubframe(subframe, channelSubframe);
|
||||
}
|
||||
}
|
||||
|
||||
static void RenderChannel(
|
||||
JASDsp::TChannel& channel,
|
||||
ChannelAuxData& channelAux,
|
||||
DspSubframe& subframe) {
|
||||
if (channel.mResetFlag) {
|
||||
ResetChannel(channel);
|
||||
}
|
||||
|
||||
auto aramBase = static_cast<u8*>(ARGetStorageAddress()) + channel.mWaveAramAddress;
|
||||
|
||||
// Streaming logic directly modifies mSamplesLeft.
|
||||
// So we use that as our tracking of where we are.
|
||||
auto curSamplePosition = channel.mEndSample - channel.mSamplesLeft;
|
||||
auto dataPosition = ConvertSamplesToDataLength(channel, curSamplePosition);
|
||||
|
||||
u32 renderSamples = std::min(channel.mSamplesLeft, static_cast<u32>(DSP_SUBFRAME_SIZE));
|
||||
|
||||
Adpcm4ToPcm16(
|
||||
aramBase + dataPosition,
|
||||
ConvertSamplesToDataLength(channel, renderSamples),
|
||||
subframe.data(),
|
||||
renderSamples,
|
||||
channelAux.hist1,
|
||||
channelAux.hist0);
|
||||
|
||||
channel.mSamplesLeft -= renderSamples;
|
||||
channel.mSamplePosition += renderSamples;
|
||||
|
||||
if (channel.mSamplesLeft == 0) {
|
||||
// Reached end of buffer.
|
||||
if (!channel.mLoopFlag) {
|
||||
// Finish.
|
||||
channel.mIsFinished = true;
|
||||
return;
|
||||
}
|
||||
|
||||
channel.mSamplesLeft = channel.mEndSample - channel.mLoopStartSample;
|
||||
channel.mSamplePosition = channel.mLoopStartSample;
|
||||
curSamplePosition = channel.mEndSample - channel.mSamplesLeft;
|
||||
dataPosition = ConvertSamplesToDataLength(channel, curSamplePosition);
|
||||
|
||||
Adpcm4ToPcm16(
|
||||
aramBase + dataPosition,
|
||||
ConvertSamplesToDataLength(channel, DSP_SUBFRAME_SIZE - renderSamples),
|
||||
subframe.data() + renderSamples,
|
||||
subframe.size() - renderSamples,
|
||||
channelAux.hist1,
|
||||
channelAux.hist0);
|
||||
|
||||
channel.mSamplesLeft -= (DSP_SUBFRAME_SIZE - renderSamples);
|
||||
channel.mSamplePosition += (DSP_SUBFRAME_SIZE - renderSamples);
|
||||
}
|
||||
|
||||
channel.mAramStreamPosition = channel.mWaveAramAddress
|
||||
+ ConvertSamplesToDataLength(channel, channel.mSamplePosition);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,15 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
using DspSubframe = std::array<s16, DSP_SUBFRAME_SIZE>;
|
||||
namespace dusk::audio {
|
||||
struct ChannelAuxData {
|
||||
s16 hist1;
|
||||
s16 hist0;
|
||||
};
|
||||
|
||||
void DuskDspRender(DspSubframe& subframe);
|
||||
extern ChannelAuxData ChannelAux[DSP_CHANNELS];
|
||||
|
||||
using DspSubframe = std::array<s16, DSP_SUBFRAME_SIZE>;
|
||||
|
||||
void DspRender(DspSubframe& subframe);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user