Add a work-in-progress API for using Nintendo's default DSP component
This commit is contained in:
parent
9e43411a0e
commit
f1ce480ed9
@ -27,6 +27,7 @@ BUILD := build
|
|||||||
SOURCES := source \
|
SOURCES := source \
|
||||||
source/allocator \
|
source/allocator \
|
||||||
source/gpu \
|
source/gpu \
|
||||||
|
source/ndsp \
|
||||||
source/services \
|
source/services \
|
||||||
source/services/soc \
|
source/services/soc \
|
||||||
source/util/rbtree \
|
source/util/rbtree \
|
||||||
|
@ -49,6 +49,9 @@ extern "C" {
|
|||||||
#include <3ds/gpu/shbin.h>
|
#include <3ds/gpu/shbin.h>
|
||||||
#include <3ds/gpu/shaderProgram.h>
|
#include <3ds/gpu/shaderProgram.h>
|
||||||
|
|
||||||
|
#include <3ds/ndsp/ndsp.h>
|
||||||
|
#include <3ds/ndsp/channel.h>
|
||||||
|
|
||||||
#include <3ds/sdmc.h>
|
#include <3ds/sdmc.h>
|
||||||
#include <3ds/romfs.h>
|
#include <3ds/romfs.h>
|
||||||
|
|
||||||
|
52
libctru/include/3ds/ndsp/channel.h
Normal file
52
libctru/include/3ds/ndsp/channel.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NDSP_ENCODING_PCM8 = 0,
|
||||||
|
NDSP_ENCODING_PCM16,
|
||||||
|
NDSP_ENCODING_ADPCM, // DSPADPCM (GameCube format)
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NDSP_CHANNELS(n) ((u32)(n) & 3)
|
||||||
|
#define NDSP_ENCODING(n) (((u32)(n) & 3) << 2)
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NDSP_FORMAT_MONO_PCM8 = NDSP_CHANNELS(1) | NDSP_ENCODING(NDSP_ENCODING_PCM8),
|
||||||
|
NDSP_FORMAT_MONO_PCM16 = NDSP_CHANNELS(1) | NDSP_ENCODING(NDSP_ENCODING_PCM16),
|
||||||
|
NDSP_FORMAT_MONO_ADPCM = NDSP_CHANNELS(1) | NDSP_ENCODING(NDSP_ENCODING_ADPCM),
|
||||||
|
NDSP_FORMAT_STEREO_PCM8 = NDSP_CHANNELS(2) | NDSP_ENCODING(NDSP_ENCODING_PCM8),
|
||||||
|
NDSP_FORMAT_STEREO_PCM16 = NDSP_CHANNELS(2) | NDSP_ENCODING(NDSP_ENCODING_PCM16),
|
||||||
|
|
||||||
|
NDSP_FORMAT_PCM8 = NDSP_FORMAT_MONO_PCM8,
|
||||||
|
NDSP_FORMAT_PCM16 = NDSP_FORMAT_MONO_PCM16,
|
||||||
|
NDSP_FORMAT_ADPCM = NDSP_FORMAT_MONO_ADPCM,
|
||||||
|
|
||||||
|
// Flags
|
||||||
|
NDSP_FRONT_BYPASS = BIT(4),
|
||||||
|
NDSP_3D_SURROUND_PREPROCESSED = BIT(6), //?
|
||||||
|
};
|
||||||
|
|
||||||
|
// Basic channel operation
|
||||||
|
void ndspChnReset(int id);
|
||||||
|
void ndspChnInitParams(int id);
|
||||||
|
bool ndspChnIsPlaying(int id);
|
||||||
|
u32 ndspChnGetSamplePos(int id);
|
||||||
|
u16 ndspChnGetWaveBufSeq(int id);
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
void ndspChnSetFormat(int id, u16 format);
|
||||||
|
void ndspChnSetInterp(int id, int type);
|
||||||
|
void ndspChnSetRate(int id, float rate);
|
||||||
|
void ndspChnSetMix(int id, float mix[12]);
|
||||||
|
void ndspChnSetAdpcmCoefs(int id, u16 coefs[16]);
|
||||||
|
|
||||||
|
// Wave buffers
|
||||||
|
void ndspChnWaveBufClear(int id);
|
||||||
|
void ndspChnWaveBufAdd(int id, ndspWaveBuf* buf);
|
||||||
|
|
||||||
|
// IIR filters
|
||||||
|
void ndspChnIirMonoSetEnable(int id, bool enable);
|
||||||
|
// ndspChnIirMonoSetParams
|
||||||
|
void ndspChnIirBiquadSetEnable(int id, bool enable);
|
||||||
|
// ndspChnIirBiquadSetParams
|
59
libctru/include/3ds/ndsp/ndsp.h
Normal file
59
libctru/include/3ds/ndsp/ndsp.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u16 index;
|
||||||
|
s16 history0, history1;
|
||||||
|
} ndspAdpcmData;
|
||||||
|
|
||||||
|
typedef struct tag_ndspWaveBuf ndspWaveBuf;
|
||||||
|
|
||||||
|
struct tag_ndspWaveBuf
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
s8* data_pcm8;
|
||||||
|
s16* data_pcm16;
|
||||||
|
u8* data_adpcm;
|
||||||
|
u32 data_vaddr;
|
||||||
|
};
|
||||||
|
u32 nsamples;
|
||||||
|
ndspAdpcmData* adpcm_data;
|
||||||
|
|
||||||
|
u32 offset; // only used for capture
|
||||||
|
bool looping;
|
||||||
|
u8 padding;
|
||||||
|
|
||||||
|
// The following fields are used internally
|
||||||
|
u16 sequence_id;
|
||||||
|
ndspWaveBuf* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*ndspCallback)(void* data);
|
||||||
|
typedef void (*ndspAuxCallback)(void* data, int nsamples, void* samples[4]);
|
||||||
|
|
||||||
|
// Initialization and basic operations
|
||||||
|
void ndspUseComponent(const void* binary, u32 size, u16 progMask, u16 dataMask);
|
||||||
|
Result ndspInit(void);
|
||||||
|
void ndspExit(void);
|
||||||
|
u32 ndspGetDroppedFrames(void);
|
||||||
|
u32 ndspGetFrameCount(void);
|
||||||
|
|
||||||
|
// General parameters
|
||||||
|
void ndspSetMasterVol(float volume);
|
||||||
|
void ndspSetOutputMode(int mode);
|
||||||
|
void ndspSetClippingMode(int mode);
|
||||||
|
void ndspSetOutputCount(int count);
|
||||||
|
void ndspSetCapture(ndspWaveBuf* capture);
|
||||||
|
void ndspSetCallback(ndspCallback callback, void* data);
|
||||||
|
|
||||||
|
// Surround
|
||||||
|
void ndspSurroundSetDepth(u16 depth);
|
||||||
|
void ndspSurroundSetPos(u16 pos);
|
||||||
|
void ndspSurroundSetRearRatio(u16 ratio);
|
||||||
|
|
||||||
|
// Auxiliary output
|
||||||
|
void ndspAuxSetEnable(int id, bool enable);
|
||||||
|
void ndspAuxSetFrontBypass(int id, bool bypass);
|
||||||
|
void ndspAuxSetVolume(int id, float volume);
|
||||||
|
void ndspAuxSetCallback(int id, ndspAuxCallback callback, void* data);
|
385
libctru/source/ndsp/ndsp-channel.c
Normal file
385
libctru/source/ndsp/ndsp-channel.c
Normal file
@ -0,0 +1,385 @@
|
|||||||
|
#include "ndsp-internal.h"
|
||||||
|
#include <3ds/ndsp/channel.h>
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CFLAG_INITPARAMS = BIT(0),
|
||||||
|
CFLAG_SYNCCOUNT = BIT(1),
|
||||||
|
CFLAG_PLAYSTATUS = BIT(2),
|
||||||
|
CFLAG_INTERPTYPE = BIT(3),
|
||||||
|
CFLAG_IIRFILTERTYPE = BIT(4),
|
||||||
|
CFLAG_RATE = BIT(5),
|
||||||
|
CFLAG_MIX = BIT(6),
|
||||||
|
CFLAG_ADPCMCOEFS = BIT(7),
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 flags;
|
||||||
|
|
||||||
|
LightLock lock;
|
||||||
|
u16 syncCount, waveBufSeqPos;
|
||||||
|
u32 samplePos;
|
||||||
|
|
||||||
|
ndspWaveBuf* waveBuf;
|
||||||
|
u16 wavBufCount, wavBufIdNext;
|
||||||
|
|
||||||
|
bool playing;
|
||||||
|
u8 interpType, iirFilterType;
|
||||||
|
|
||||||
|
u16 format;
|
||||||
|
u16 wavBufSeq;
|
||||||
|
|
||||||
|
float rate;
|
||||||
|
float mix[12];
|
||||||
|
|
||||||
|
u16 adpcmCoefs[16];
|
||||||
|
|
||||||
|
} ndspChnSt;
|
||||||
|
|
||||||
|
static ndspChnSt ndspChn[24];
|
||||||
|
|
||||||
|
void ndspChnReset(int id)
|
||||||
|
{
|
||||||
|
ndspChnSt* chn = &ndspChn[id];
|
||||||
|
LightLock_Lock(&chn->lock);
|
||||||
|
chn->flags = ~0;
|
||||||
|
chn->syncCount = 1;
|
||||||
|
chn->waveBufSeqPos = 0;
|
||||||
|
chn->samplePos = 0;
|
||||||
|
chn->waveBuf = NULL;
|
||||||
|
chn->wavBufCount = 0;
|
||||||
|
chn->wavBufIdNext = 0;
|
||||||
|
chn->wavBufSeq = 0;
|
||||||
|
chn->playing = false;
|
||||||
|
chn->interpType = 0;
|
||||||
|
chn->iirFilterType = 0;
|
||||||
|
chn->format = NDSP_FORMAT_PCM16;
|
||||||
|
chn->rate = 1.0f;
|
||||||
|
chn->mix[0] = chn->mix[1] = 1.0f;
|
||||||
|
memset(&chn->mix[2], 0, 14*sizeof(float));
|
||||||
|
LightLock_Unlock(&chn->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspChnInitParams(int id)
|
||||||
|
{
|
||||||
|
ndspChnSt* chn = &ndspChn[id];
|
||||||
|
LightLock_Lock(&chn->lock);
|
||||||
|
chn->flags |= CFLAG_INITPARAMS;
|
||||||
|
LightLock_Unlock(&chn->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ndspChnIsPlaying(int id)
|
||||||
|
{
|
||||||
|
return ndspChn[id].playing;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 ndspChnGetSamplePos(int id)
|
||||||
|
{
|
||||||
|
return ndspChn[id].samplePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 ndspChnGetWaveBufSeq(int id)
|
||||||
|
{
|
||||||
|
return ndspChn[id].waveBufSeqPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspChnSetFormat(int id, u16 format)
|
||||||
|
{
|
||||||
|
ndspChn[id].format = format;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspChnSetInterp(int id, int type)
|
||||||
|
{
|
||||||
|
ndspChnSt* chn = &ndspChn[id];
|
||||||
|
LightLock_Lock(&chn->lock);
|
||||||
|
chn->interpType = type;
|
||||||
|
chn->flags |= CFLAG_INTERPTYPE;
|
||||||
|
LightLock_Unlock(&chn->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspChnSetRate(int id, float rate)
|
||||||
|
{
|
||||||
|
ndspChnSt* chn = &ndspChn[id];
|
||||||
|
LightLock_Lock(&chn->lock);
|
||||||
|
chn->rate = rate/32728.0f;
|
||||||
|
chn->flags |= CFLAG_RATE;
|
||||||
|
LightLock_Unlock(&chn->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspChnSetMix(int id, float mix[12])
|
||||||
|
{
|
||||||
|
ndspChnSt* chn = &ndspChn[id];
|
||||||
|
LightLock_Lock(&chn->lock);
|
||||||
|
memcpy(&chn->mix, mix, sizeof(ndspChn[id].mix));
|
||||||
|
chn->flags |= CFLAG_MIX;
|
||||||
|
LightLock_Unlock(&chn->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspChnSetAdpcmCoefs(int id, u16 coefs[16])
|
||||||
|
{
|
||||||
|
ndspChnSt* chn = &ndspChn[id];
|
||||||
|
LightLock_Lock(&chn->lock);
|
||||||
|
memcpy(&chn->adpcmCoefs, coefs, sizeof(ndspChn[id].adpcmCoefs));
|
||||||
|
chn->flags |= CFLAG_ADPCMCOEFS;
|
||||||
|
LightLock_Unlock(&chn->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspChnWaveBufClear(int id)
|
||||||
|
{
|
||||||
|
ndspChnSt* chn = &ndspChn[id];
|
||||||
|
LightLock_Lock(&chn->lock);
|
||||||
|
chn->waveBuf = NULL;
|
||||||
|
chn->waveBufSeqPos = 0;
|
||||||
|
chn->wavBufCount = 0;
|
||||||
|
chn->wavBufIdNext = 0;
|
||||||
|
chn->wavBufSeq = 0;
|
||||||
|
chn->playing = false;
|
||||||
|
chn->syncCount ++;
|
||||||
|
chn->flags |= CFLAG_SYNCCOUNT | CFLAG_PLAYSTATUS;
|
||||||
|
LightLock_Unlock(&chn->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspChnWaveBufAdd(int id, ndspWaveBuf* buf)
|
||||||
|
{
|
||||||
|
ndspChnSt* chn = &ndspChn[id];
|
||||||
|
ndspWaveBuf* cb = chn->waveBuf;
|
||||||
|
if (!buf->nsamples) return;
|
||||||
|
|
||||||
|
buf->next = NULL;
|
||||||
|
LightLock_Lock(&chn->lock);
|
||||||
|
|
||||||
|
if (cb)
|
||||||
|
{
|
||||||
|
while (cb->next) cb = cb->next;
|
||||||
|
cb->next = buf;
|
||||||
|
} else
|
||||||
|
chn->waveBuf = buf;
|
||||||
|
|
||||||
|
u16 seq = chn->wavBufSeq;
|
||||||
|
if (!seq) seq = 1;
|
||||||
|
buf->sequence_id = seq;
|
||||||
|
chn->wavBufSeq = seq + 1;
|
||||||
|
|
||||||
|
LightLock_Unlock(&chn->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspChnIirMonoSetEnable(int id, bool enable)
|
||||||
|
{
|
||||||
|
ndspChnSt* chn = &ndspChn[id];
|
||||||
|
LightLock_Lock(&chn->lock);
|
||||||
|
u16 f = chn->iirFilterType &~ BIT(0);
|
||||||
|
if (enable) f |= BIT(0);
|
||||||
|
chn->iirFilterType = f;
|
||||||
|
chn->flags |= CFLAG_IIRFILTERTYPE;
|
||||||
|
LightLock_Unlock(&chn->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspChnIirBiquadSetEnable(int id, bool enable)
|
||||||
|
{
|
||||||
|
ndspChnSt* chn = &ndspChn[id];
|
||||||
|
LightLock_Lock(&chn->lock);
|
||||||
|
u16 f = chn->iirFilterType &~ BIT(1);
|
||||||
|
if (enable) f |= BIT(1);
|
||||||
|
chn->iirFilterType = f;
|
||||||
|
chn->flags |= CFLAG_IIRFILTERTYPE;
|
||||||
|
LightLock_Unlock(&chn->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspiInitChn(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 24; i ++)
|
||||||
|
{
|
||||||
|
LightLock_Init(&ndspChn[i].lock);
|
||||||
|
ndspChnReset(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspiDirtyChn(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 24; i ++)
|
||||||
|
ndspChn[i].flags |= ~CFLAG_INITPARAMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspiUpdateChn(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 24; i ++)
|
||||||
|
{
|
||||||
|
ndspChnSt* chn = &ndspChn[i];
|
||||||
|
DspChnStruct* st = ndspiGetChnStruct(i);
|
||||||
|
LightLock_Lock(&chn->lock);
|
||||||
|
|
||||||
|
u32 flags = chn->flags;
|
||||||
|
u32 stflags = st->flags;
|
||||||
|
|
||||||
|
if (flags & CFLAG_INITPARAMS)
|
||||||
|
stflags |= 0x20000000;
|
||||||
|
|
||||||
|
if (flags & CFLAG_MIX)
|
||||||
|
{
|
||||||
|
memcpy(st->mix, chn->mix, sizeof(st->mix));
|
||||||
|
stflags |= 0xE000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & CFLAG_RATE)
|
||||||
|
{
|
||||||
|
st->rate = chn->rate;
|
||||||
|
stflags |= 0x40000;
|
||||||
|
if (chn->interpType == 0)
|
||||||
|
flags |= CFLAG_INTERPTYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & CFLAG_IIRFILTERTYPE)
|
||||||
|
{
|
||||||
|
st->iirFilterType = chn->iirFilterType;
|
||||||
|
stflags |= 0x400000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: IIR filter coefficent update
|
||||||
|
|
||||||
|
if (flags & CFLAG_INTERPTYPE)
|
||||||
|
{
|
||||||
|
st->rim[0] = chn->interpType;
|
||||||
|
if (chn->interpType == 0)
|
||||||
|
{
|
||||||
|
if (chn->rate <= 1.0f)
|
||||||
|
st->rim[1] = 2;
|
||||||
|
else if (chn->rate <= (4.0f/3))
|
||||||
|
st->rim[1] = 1;
|
||||||
|
else
|
||||||
|
st->rim[1] = 0;
|
||||||
|
} else
|
||||||
|
st->rim[1] = 1;
|
||||||
|
stflags |= 0x20000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & CFLAG_ADPCMCOEFS)
|
||||||
|
{
|
||||||
|
memcpy(ndspiGetChnAdpcmCoefs(i), chn->adpcmCoefs, sizeof(chn->adpcmCoefs));
|
||||||
|
stflags |= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do wavebuf stuff
|
||||||
|
int wvcount = chn->wavBufCount;
|
||||||
|
ndspWaveBuf* wb = chn->waveBuf;
|
||||||
|
if (wb && !chn->playing)
|
||||||
|
{
|
||||||
|
chn->playing = true;
|
||||||
|
flags |= CFLAG_PLAYSTATUS;
|
||||||
|
}
|
||||||
|
while (wvcount && wb)
|
||||||
|
{
|
||||||
|
wb = wb->next;
|
||||||
|
wvcount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
int j;
|
||||||
|
for (j = chn->wavBufCount; wb && j < 5; j ++)
|
||||||
|
{
|
||||||
|
if (chn->wavBufCount == 0)
|
||||||
|
{
|
||||||
|
// This is the first buffer - set it up
|
||||||
|
chn->wavBufIdNext = 0;
|
||||||
|
st->seqId = wb->sequence_id;
|
||||||
|
st->sampleCount = ndspiRotateVal(wb->nsamples);
|
||||||
|
st->paddr = ndspiRotateVal(osConvertVirtToPhys(wb->data_vaddr));
|
||||||
|
st->cntFlags = chn->format;
|
||||||
|
st->moreFlags = (st->moreFlags &~ BIT(1)) | (wb->looping ? BIT(1) : 0);
|
||||||
|
st->unknown = 0;
|
||||||
|
if ((chn->format & NDSP_ENCODING(3)) == NDSP_ENCODING(NDSP_ENCODING_ADPCM))
|
||||||
|
{
|
||||||
|
if (wb->adpcm_data)
|
||||||
|
{
|
||||||
|
st->adpcmData.index = wb->adpcm_data->index;
|
||||||
|
st->adpcmData.history0 = wb->adpcm_data->history0;
|
||||||
|
st->adpcmData.history1 = wb->adpcm_data->history1;
|
||||||
|
st->moreFlags |= BIT(0);
|
||||||
|
} else
|
||||||
|
st->moreFlags &= ~BIT(0);
|
||||||
|
}
|
||||||
|
stflags |= 0x10 | 0x40200000;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
// Queue the next buffer
|
||||||
|
DspChnBuf* cbuf = &st->buffers[chn->wavBufIdNext];
|
||||||
|
cbuf->seqId = wb->sequence_id;
|
||||||
|
cbuf->paddr = ndspiRotateVal(osConvertVirtToPhys(wb->data_vaddr));
|
||||||
|
cbuf->sampleCount = ndspiRotateVal(wb->nsamples);
|
||||||
|
if (wb->adpcm_data)
|
||||||
|
{
|
||||||
|
cbuf->adpcmData.index = wb->adpcm_data->index;
|
||||||
|
cbuf->adpcmData.history0 = wb->adpcm_data->history0;
|
||||||
|
cbuf->adpcmData.history1 = wb->adpcm_data->history1;
|
||||||
|
cbuf->hasAdpcmData = 1;
|
||||||
|
} else
|
||||||
|
cbuf->hasAdpcmData = 0;
|
||||||
|
cbuf->looping = wb->looping ? 1 : 0;
|
||||||
|
st->activeBuffers |= BIT(chn->wavBufIdNext);
|
||||||
|
chn->wavBufIdNext = (chn->wavBufIdNext+1) & 3;
|
||||||
|
stflags |= 0x80000;
|
||||||
|
}
|
||||||
|
wb = wb->next;
|
||||||
|
chn->wavBufCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & CFLAG_SYNCCOUNT)
|
||||||
|
{
|
||||||
|
st->syncCount = chn->syncCount;
|
||||||
|
stflags |= 0x10000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & CFLAG_PLAYSTATUS)
|
||||||
|
{
|
||||||
|
u16 playStatus = st->playStatus &~ 0xFF;
|
||||||
|
if (chn->playing)
|
||||||
|
playStatus |= 1;
|
||||||
|
st->playStatus = playStatus;
|
||||||
|
stflags |= 0x10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
chn->flags = 0;
|
||||||
|
st->flags = stflags;
|
||||||
|
|
||||||
|
LightLock_Unlock(&chn->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspiReadChnState(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 24; i ++)
|
||||||
|
{
|
||||||
|
ndspChnSt* chn = &ndspChn[i];
|
||||||
|
DspChnStatus* st = ndspiGetChnStatus(i);
|
||||||
|
|
||||||
|
if (chn->syncCount == st->syncCount)
|
||||||
|
{
|
||||||
|
u16 seqId = st->curSeqId;
|
||||||
|
ndspWaveBuf* wb = chn->waveBuf;
|
||||||
|
chn->waveBufSeqPos = seqId;
|
||||||
|
chn->samplePos = ndspiRotateVal(st->samplePos);
|
||||||
|
|
||||||
|
if ((st->flags & 0xFF00) && wb)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&chn->lock);
|
||||||
|
|
||||||
|
while (wb->sequence_id != seqId)
|
||||||
|
{
|
||||||
|
chn->wavBufCount--;
|
||||||
|
bool shouldBreak = seqId == 0 && (wb->sequence_id == st->lastSeqId || st->lastSeqId == 0);
|
||||||
|
wb = wb->next;
|
||||||
|
if (shouldBreak || chn->wavBufCount == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (seqId == 0)
|
||||||
|
chn->wavBufCount = 0;
|
||||||
|
chn->waveBuf = wb;
|
||||||
|
LightLock_Unlock(&chn->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chn->playing = (st->flags & 0xFF) ? true : false;
|
||||||
|
}
|
||||||
|
}
|
107
libctru/source/ndsp/ndsp-internal.h
Normal file
107
libctru/source/ndsp/ndsp-internal.h
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <3ds/types.h>
|
||||||
|
#include <3ds/svc.h>
|
||||||
|
#include <3ds/os.h>
|
||||||
|
#include <3ds/synchronization.h>
|
||||||
|
#include <3ds/services/dsp.h>
|
||||||
|
#include <3ds/services/apt.h>
|
||||||
|
#include <3ds/ndsp/ndsp.h>
|
||||||
|
|
||||||
|
extern u16 ndspFrameId, ndspBufferCurId, ndspBufferId;
|
||||||
|
extern void* ndspVars[16][2];
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 paddr, sampleCount;
|
||||||
|
ndspAdpcmData adpcmData;
|
||||||
|
u8 hasAdpcmData, looping;
|
||||||
|
u16 seqId, padding;
|
||||||
|
} DspChnBuf;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 flags;
|
||||||
|
float mix[12];
|
||||||
|
float rate;
|
||||||
|
u8 rim[2];
|
||||||
|
u16 iirFilterType;
|
||||||
|
u16 iirFilter_mono[2];
|
||||||
|
u16 iirFilter_biquad[5];
|
||||||
|
u16 activeBuffers;
|
||||||
|
DspChnBuf buffers[4];
|
||||||
|
u32 _pad0;
|
||||||
|
u16 playStatus, syncCount;
|
||||||
|
u32 unknown;
|
||||||
|
u32 _pad1;
|
||||||
|
|
||||||
|
u32 paddr, sampleCount;
|
||||||
|
u16 cntFlags;
|
||||||
|
ndspAdpcmData adpcmData;
|
||||||
|
u16 moreFlags;
|
||||||
|
u16 seqId;
|
||||||
|
} DspChnStruct;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u16 flags, syncCount;
|
||||||
|
u32 samplePos;
|
||||||
|
u16 curSeqId, lastSeqId;
|
||||||
|
} DspChnStatus;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
u32 flags;
|
||||||
|
float masterVol;
|
||||||
|
float auxReturnVol[2];
|
||||||
|
u16 outBufCount;
|
||||||
|
u16 _pad0[2];
|
||||||
|
u16 outputMode;
|
||||||
|
u16 clippingMode;
|
||||||
|
u16 headsetConnected;
|
||||||
|
u16 surroundDepth;
|
||||||
|
u16 surroundSpeakerPos;
|
||||||
|
u16 _pad1;
|
||||||
|
u16 rearRatio;
|
||||||
|
u16 auxFrontBypass[2];
|
||||||
|
u16 auxBusEnable[2];
|
||||||
|
u16 dspDelayEffect[2][10];
|
||||||
|
u16 dspReverbEffect[2][26];
|
||||||
|
u16 syncMode;
|
||||||
|
u16 _pad2;
|
||||||
|
u32 unknown;
|
||||||
|
} DspMasterStatus;
|
||||||
|
|
||||||
|
static inline u32 ndspiRotateVal(u32 x)
|
||||||
|
{
|
||||||
|
return (x << 16) | (x >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline DspChnStruct* ndspiGetChnStruct(int id)
|
||||||
|
{
|
||||||
|
DspChnStruct* them = (DspChnStruct*)ndspVars[1][ndspFrameId&1];
|
||||||
|
return &them[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline DspChnStatus* ndspiGetChnStatus(int id)
|
||||||
|
{
|
||||||
|
DspChnStatus* them = (DspChnStatus*)ndspVars[2][ndspBufferId];
|
||||||
|
return &them[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u16* ndspiGetChnAdpcmCoefs(int id)
|
||||||
|
{
|
||||||
|
u16* them = (u16*)ndspVars[3][ndspBufferId];
|
||||||
|
return &them[id*16];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline DspMasterStatus* ndspiGetMasterStatus(void)
|
||||||
|
{
|
||||||
|
return (DspMasterStatus*)ndspVars[4][ndspBufferCurId];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspiInitChn(void);
|
||||||
|
void ndspiDirtyChn(void);
|
||||||
|
void ndspiUpdateChn(void);
|
||||||
|
void ndspiReadChnState(void);
|
543
libctru/source/ndsp/ndsp.c
Normal file
543
libctru/source/ndsp/ndsp.c
Normal file
@ -0,0 +1,543 @@
|
|||||||
|
#include "ndsp-internal.h"
|
||||||
|
#include <3ds/services/cfgu.h>
|
||||||
|
|
||||||
|
#define NDSP_THREAD_STACK_SIZE 0x1000
|
||||||
|
|
||||||
|
u16 ndspFrameId, ndspBufferCurId, ndspBufferId;
|
||||||
|
void* ndspVars[16][2];
|
||||||
|
|
||||||
|
static bool bComponentLoaded = false, bDspReady = false, bSleeping = false, bNeedsSync = false;
|
||||||
|
static u32 droppedFrames, frameCount;
|
||||||
|
|
||||||
|
static const void* componentBin;
|
||||||
|
static u32 componentSize;
|
||||||
|
static u16 componentProgMask, componentDataMask;
|
||||||
|
|
||||||
|
static aptHookCookie aptCookie;
|
||||||
|
|
||||||
|
static Handle irqEvent, dspSem, sleepEvent;
|
||||||
|
static LightLock ndspMutex;
|
||||||
|
|
||||||
|
static u8 dspVar5Backup[0x1080];
|
||||||
|
|
||||||
|
static volatile bool ndspThreadRun;
|
||||||
|
static Handle ndspThread;
|
||||||
|
static u64 ndspThreadStack[NDSP_THREAD_STACK_SIZE/8]; // u64 so that it's 8-byte aligned
|
||||||
|
|
||||||
|
static Result ndspLoadComponent(void)
|
||||||
|
{
|
||||||
|
if (!componentBin) return 1;
|
||||||
|
return DSP_LoadComponent(componentBin, componentSize, componentProgMask, componentDataMask, &bComponentLoaded);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ndspWaitForIrq(void)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&ndspMutex);
|
||||||
|
svcWaitSynchronization(irqEvent, U64_MAX);
|
||||||
|
svcClearEvent(irqEvent);
|
||||||
|
LightLock_Unlock(&ndspMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ndspSetCounter(int a, int counter)
|
||||||
|
{
|
||||||
|
*(vu16*)ndspVars[0][a] = counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int ndspGetCounter(int a)
|
||||||
|
{
|
||||||
|
return *(vu16*)ndspVars[0][a];
|
||||||
|
}
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MFLAG_MASTERVOL = BIT(0),
|
||||||
|
MFLAG_OUTPUTMODE = BIT(1),
|
||||||
|
MFLAG_CLIPPINGMODE = BIT(2),
|
||||||
|
MFLAG_OUTPUTCOUNT = BIT(3),
|
||||||
|
MFLAG_SYNCMODE = BIT(4),
|
||||||
|
MFLAG_SURR_DEPTH = BIT(5),
|
||||||
|
MFLAG_SURR_POS = BIT(6),
|
||||||
|
MFLAG_SURR_RRATIO = BIT(7),
|
||||||
|
|
||||||
|
#define MFLAG_AUX_ENABLE(i) BIT(8+(i))
|
||||||
|
#define MFLAG_AUX_BYPASS(i) BIT(10+(i))
|
||||||
|
#define MFLAG_AUX_VOLUME(i) BIT(12+(i))
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
LightLock lock;
|
||||||
|
u32 flags;
|
||||||
|
float masterVol;
|
||||||
|
u16 outputMode, clippingMode, outputCount, syncMode;
|
||||||
|
ndspWaveBuf* capture;
|
||||||
|
ndspCallback callback;
|
||||||
|
void* callbackData;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u16 depth, pos, rearRatio;
|
||||||
|
} surround;
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
u16 enable, frontBypass;
|
||||||
|
float volume;
|
||||||
|
ndspAuxCallback callback;
|
||||||
|
void* callbackData;
|
||||||
|
} aux[2];
|
||||||
|
} ndspMaster;
|
||||||
|
|
||||||
|
static void ndspDirtyMaster(void)
|
||||||
|
{
|
||||||
|
ndspMaster.flags = ~0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ndspInitMaster(void)
|
||||||
|
{
|
||||||
|
memset(&ndspMaster, 0, sizeof(ndspMaster));
|
||||||
|
LightLock_Init(&ndspMaster.lock);
|
||||||
|
ndspMaster.masterVol = 1.0f;
|
||||||
|
ndspMaster.clippingMode = 1;
|
||||||
|
ndspMaster.outputCount = 2;
|
||||||
|
ndspMaster.surround.depth = 0x7FFF;
|
||||||
|
ndspMaster.surround.rearRatio = 0x8000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ndspUpdateMaster(void)
|
||||||
|
{
|
||||||
|
DspMasterStatus* m = ndspiGetMasterStatus();
|
||||||
|
LightLock_Lock(&ndspMaster.lock);
|
||||||
|
|
||||||
|
u32 flags = m->flags, mflags = ndspMaster.flags;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
m->headsetConnected = *(vu8*)0x1FF810C0;
|
||||||
|
flags |= 0x10000000;
|
||||||
|
|
||||||
|
if (mflags & MFLAG_MASTERVOL)
|
||||||
|
{
|
||||||
|
m->masterVol = ndspMaster.masterVol;
|
||||||
|
flags |= 0x00010000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mflags & MFLAG_OUTPUTMODE)
|
||||||
|
{
|
||||||
|
m->outputMode = ndspMaster.outputMode;
|
||||||
|
flags |= 0x04000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mflags & MFLAG_CLIPPINGMODE)
|
||||||
|
{
|
||||||
|
m->clippingMode = ndspMaster.clippingMode;
|
||||||
|
flags |= 0x08000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mflags & MFLAG_OUTPUTCOUNT)
|
||||||
|
{
|
||||||
|
m->outBufCount = ndspMaster.outputCount;
|
||||||
|
flags |= 0x00008000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mflags & MFLAG_SYNCMODE)
|
||||||
|
{
|
||||||
|
m->syncMode = ndspMaster.syncMode;
|
||||||
|
m->unknown |= 0x10000; //?
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mflags & MFLAG_SURR_DEPTH)
|
||||||
|
{
|
||||||
|
m->surroundDepth = ndspMaster.surround.depth;
|
||||||
|
flags |= 0x20000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mflags & MFLAG_SURR_POS)
|
||||||
|
{
|
||||||
|
m->surroundSpeakerPos = ndspMaster.surround.pos;
|
||||||
|
flags |= 0x40000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mflags & MFLAG_SURR_RRATIO)
|
||||||
|
{
|
||||||
|
m->rearRatio = ndspMaster.surround.rearRatio;
|
||||||
|
flags |= 0x80000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 2; i ++)
|
||||||
|
{
|
||||||
|
if (mflags & MFLAG_AUX_ENABLE(i))
|
||||||
|
{
|
||||||
|
m->auxBusEnable[i] = ndspMaster.aux[i].enable;
|
||||||
|
flags |= 0x00000100 << i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mflags & MFLAG_AUX_BYPASS(i))
|
||||||
|
{
|
||||||
|
m->auxFrontBypass[i] = ndspMaster.aux[i].frontBypass;
|
||||||
|
flags |= 0x00000040 << i;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mflags & MFLAG_AUX_VOLUME(i))
|
||||||
|
{
|
||||||
|
m->auxReturnVol[i] = ndspMaster.aux[i].volume;
|
||||||
|
flags |= 0x01000000 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m->flags = flags;
|
||||||
|
ndspMaster.flags = 0;
|
||||||
|
|
||||||
|
LightLock_Unlock(&ndspMaster.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ndspUpdateCapture(s16* samples, u32 count)
|
||||||
|
{
|
||||||
|
ndspWaveBuf* buf = ndspMaster.capture;
|
||||||
|
if (!buf) return;
|
||||||
|
memcpy(&buf->data_pcm16[buf->offset*2], samples, count*4);
|
||||||
|
buf->offset += count;
|
||||||
|
if (buf->offset >= buf->nsamples)
|
||||||
|
buf->offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Result ndspInitialize(bool resume)
|
||||||
|
{
|
||||||
|
Result rc;
|
||||||
|
|
||||||
|
rc = ndspLoadComponent();
|
||||||
|
if (rc) return rc;
|
||||||
|
|
||||||
|
rc = svcCreateEvent(&irqEvent, 1);
|
||||||
|
if (rc) goto _fail1;
|
||||||
|
|
||||||
|
rc = DSP_RegisterInterruptEvents(irqEvent, 2, 2);
|
||||||
|
if (rc) goto _fail2;
|
||||||
|
|
||||||
|
rc = DSP_GetSemaphoreHandle(&dspSem);
|
||||||
|
if (rc) goto _fail3;
|
||||||
|
|
||||||
|
DSP_SetSemaphoreMask(0x2000);
|
||||||
|
|
||||||
|
u16 val = resume ? 2 : 0;
|
||||||
|
if (resume)
|
||||||
|
memcpy(ndspVars[5][0], dspVar5Backup, sizeof(dspVar5Backup));
|
||||||
|
DSP_WriteProcessPipe(2, &val, 4);
|
||||||
|
DSP_SetSemaphore(0x4000);
|
||||||
|
ndspWaitForIrq();
|
||||||
|
|
||||||
|
DSP_ReadPipeIfPossible(2, 0, &val, sizeof(val), NULL);
|
||||||
|
u16 vars[16];
|
||||||
|
DSP_ReadPipeIfPossible(2, 0, vars, val*2, NULL);
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < val; i ++)
|
||||||
|
{
|
||||||
|
DSP_ConvertProcessAddressFromDspDram(vars[i], (u32*)&ndspVars[i][0]);
|
||||||
|
DSP_ConvertProcessAddressFromDspDram(vars[i] | 0x10000, (u32*)&ndspVars[i][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
DSP_SetSemaphore(0x4000);
|
||||||
|
ndspFrameId = 4;
|
||||||
|
ndspSetCounter(0, 4);
|
||||||
|
ndspFrameId++;
|
||||||
|
svcSignalEvent(dspSem);
|
||||||
|
ndspBufferCurId = ndspFrameId & 1;
|
||||||
|
ndspBufferId = ndspFrameId & 1;
|
||||||
|
bDspReady = true;
|
||||||
|
|
||||||
|
ndspDirtyMaster();
|
||||||
|
ndspUpdateMaster();
|
||||||
|
|
||||||
|
if (resume)
|
||||||
|
{
|
||||||
|
ndspiDirtyChn();
|
||||||
|
ndspiUpdateChn();
|
||||||
|
// Force update effect params here
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
_fail3:
|
||||||
|
DSP_RegisterInterruptEvents(0, 2, 2);
|
||||||
|
_fail2:
|
||||||
|
svcCloseHandle(irqEvent);
|
||||||
|
_fail1:
|
||||||
|
DSP_UnloadComponent();
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ndspFinalize(bool suspend)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&ndspMutex);
|
||||||
|
u16 val = suspend ? 3 : 1;
|
||||||
|
DSP_WriteProcessPipe(2, &val, 4);
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
bool ready;
|
||||||
|
DSP_RecvDataIsReady(0, &ready);
|
||||||
|
if (ready)
|
||||||
|
DSP_RecvData(0, &val);
|
||||||
|
if (val == 1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (suspend)
|
||||||
|
memcpy(dspVar5Backup, ndspVars[5][0], sizeof(dspVar5Backup));
|
||||||
|
|
||||||
|
DSP_RegisterInterruptEvents(0, 2, 2);
|
||||||
|
svcCloseHandle(irqEvent);
|
||||||
|
svcCloseHandle(dspSem);
|
||||||
|
DSP_UnloadComponent();
|
||||||
|
bComponentLoaded = false;
|
||||||
|
bDspReady = false;
|
||||||
|
LightLock_Unlock(&ndspMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ndspAptHook(int hook, void* param)
|
||||||
|
{
|
||||||
|
switch (hook)
|
||||||
|
{
|
||||||
|
case APTHOOK_ONRESTORE:
|
||||||
|
case APTHOOK_ONWAKEUP:
|
||||||
|
bSleeping = false;
|
||||||
|
ndspInitialize(true);
|
||||||
|
svcSignalEvent(sleepEvent);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case APTHOOK_ONSUSPEND:
|
||||||
|
case APTHOOK_ONSLEEP:
|
||||||
|
bSleeping = true;
|
||||||
|
ndspFinalize(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ndspSync(void)
|
||||||
|
{
|
||||||
|
if (bSleeping)
|
||||||
|
{
|
||||||
|
svcWaitSynchronization(sleepEvent, U64_MAX);
|
||||||
|
svcClearEvent(sleepEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
ndspWaitForIrq();
|
||||||
|
if (bDspReady)
|
||||||
|
{
|
||||||
|
int counter = ndspGetCounter(~ndspFrameId & 1);
|
||||||
|
if (counter)
|
||||||
|
{
|
||||||
|
int next = (counter + 1) & 0xFFFF;
|
||||||
|
ndspFrameId = next ? next : 2;
|
||||||
|
ndspBufferId = ndspFrameId & 1;
|
||||||
|
ndspiReadChnState();
|
||||||
|
//memcpy(dspVar9Backup, dspVars[9][ndspBufferId], sizeof(dspVar9Backup));
|
||||||
|
ndspUpdateCapture((s16*)ndspVars[6][ndspBufferId], 160);
|
||||||
|
droppedFrames += *((u16*)ndspVars[5][ndspBufferId] + 1);
|
||||||
|
}
|
||||||
|
bNeedsSync = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ndspThreadMain(void* arg)
|
||||||
|
{
|
||||||
|
ndspThreadRun = true;
|
||||||
|
while (ndspThreadRun)
|
||||||
|
{
|
||||||
|
ndspSync();
|
||||||
|
|
||||||
|
// Call callbacks here
|
||||||
|
if (ndspMaster.callback)
|
||||||
|
ndspMaster.callback(ndspMaster.callbackData);
|
||||||
|
|
||||||
|
if (bSleeping || !bDspReady)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (bNeedsSync)
|
||||||
|
ndspSync();
|
||||||
|
|
||||||
|
ndspUpdateMaster();
|
||||||
|
// Call aux user callback here if enabled
|
||||||
|
// Execute DSP effects here
|
||||||
|
ndspiUpdateChn();
|
||||||
|
|
||||||
|
ndspSetCounter(ndspBufferCurId, ndspFrameId++);
|
||||||
|
svcSignalEvent(dspSem);
|
||||||
|
ndspBufferCurId = ndspFrameId & 1;
|
||||||
|
|
||||||
|
frameCount++;
|
||||||
|
bNeedsSync = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
svcExitThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspUseComponent(const void* binary, u32 size, u16 progMask, u16 dataMask)
|
||||||
|
{
|
||||||
|
componentBin = binary;
|
||||||
|
componentSize = size;
|
||||||
|
componentProgMask = progMask;
|
||||||
|
componentDataMask = dataMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ndspRefCount = 0;
|
||||||
|
|
||||||
|
Result ndspInit(void)
|
||||||
|
{
|
||||||
|
Result rc;
|
||||||
|
if (ndspRefCount++) return 0;
|
||||||
|
|
||||||
|
LightLock_Init(&ndspMutex);
|
||||||
|
ndspInitMaster();
|
||||||
|
ndspiInitChn();
|
||||||
|
|
||||||
|
rc = initCfgu();
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
u8 outMode;
|
||||||
|
CFGU_GetConfigInfoBlk2(sizeof(outMode), 0x70001, &outMode);
|
||||||
|
ndspMaster.outputMode = outMode;
|
||||||
|
exitCfgu();
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = dspInit();
|
||||||
|
if (rc) return rc;
|
||||||
|
|
||||||
|
rc = ndspInitialize(false);
|
||||||
|
if (rc) goto _fail1;
|
||||||
|
|
||||||
|
rc = svcCreateEvent(&sleepEvent, 0);
|
||||||
|
if (rc) goto _fail2;
|
||||||
|
|
||||||
|
rc = svcCreateThread(&ndspThread, ndspThreadMain, 0x0, (u32*)(&ndspThreadStack[NDSP_THREAD_STACK_SIZE/8]), 0x31, -2);
|
||||||
|
if (rc) goto _fail3;
|
||||||
|
|
||||||
|
aptHook(&aptCookie, ndspAptHook, NULL);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
_fail3:
|
||||||
|
svcCloseHandle(sleepEvent);
|
||||||
|
_fail2:
|
||||||
|
ndspFinalize(false);
|
||||||
|
_fail1:
|
||||||
|
dspExit();
|
||||||
|
ndspRefCount--;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspExit(void)
|
||||||
|
{
|
||||||
|
if (--ndspRefCount) return;
|
||||||
|
if (!bDspReady) return;
|
||||||
|
ndspThreadRun = false;
|
||||||
|
svcWaitSynchronization(ndspThread, U64_MAX);
|
||||||
|
svcCloseHandle(ndspThread);
|
||||||
|
svcCloseHandle(sleepEvent);
|
||||||
|
aptUnhook(&aptCookie);
|
||||||
|
ndspFinalize(false);
|
||||||
|
dspExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 ndspGetDroppedFrames(void)
|
||||||
|
{
|
||||||
|
return droppedFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 ndspGetFrameCount(void)
|
||||||
|
{
|
||||||
|
return frameCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspSetMasterVol(float volume)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&ndspMaster.lock);
|
||||||
|
ndspMaster.masterVol = volume;
|
||||||
|
ndspMaster.flags |= MFLAG_MASTERVOL;
|
||||||
|
LightLock_Unlock(&ndspMaster.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspSetOutputMode(int mode)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&ndspMaster.lock);
|
||||||
|
ndspMaster.outputMode = mode;
|
||||||
|
ndspMaster.flags |= MFLAG_OUTPUTMODE;
|
||||||
|
LightLock_Unlock(&ndspMaster.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspSetClippingMode(int mode)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&ndspMaster.lock);
|
||||||
|
ndspMaster.clippingMode = mode;
|
||||||
|
ndspMaster.flags |= MFLAG_CLIPPINGMODE;
|
||||||
|
LightLock_Unlock(&ndspMaster.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspSetOutputCount(int count)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&ndspMaster.lock);
|
||||||
|
ndspMaster.outputCount = count;
|
||||||
|
ndspMaster.flags |= MFLAG_OUTPUTCOUNT;
|
||||||
|
LightLock_Unlock(&ndspMaster.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspSetCapture(ndspWaveBuf* capture)
|
||||||
|
{
|
||||||
|
ndspMaster.capture = capture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspSetCallback(ndspCallback callback, void* data)
|
||||||
|
{
|
||||||
|
ndspMaster.callback = callback;
|
||||||
|
ndspMaster.callbackData = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspSurroundSetDepth(u16 depth)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&ndspMaster.lock);
|
||||||
|
ndspMaster.surround.depth = depth;
|
||||||
|
ndspMaster.flags |= MFLAG_SURR_DEPTH;
|
||||||
|
LightLock_Unlock(&ndspMaster.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspSurroundSetPos(u16 pos)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&ndspMaster.lock);
|
||||||
|
ndspMaster.surround.pos = pos;
|
||||||
|
ndspMaster.flags |= MFLAG_SURR_POS;
|
||||||
|
LightLock_Unlock(&ndspMaster.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspSurroundSetRearRatio(u16 ratio)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&ndspMaster.lock);
|
||||||
|
ndspMaster.surround.rearRatio = ratio;
|
||||||
|
ndspMaster.flags |= MFLAG_SURR_RRATIO;
|
||||||
|
LightLock_Unlock(&ndspMaster.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspAuxSetEnable(int id, bool enable)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&ndspMaster.lock);
|
||||||
|
ndspMaster.aux[id].enable = enable ? 1 : 0;
|
||||||
|
ndspMaster.flags |= MFLAG_AUX_ENABLE(id);
|
||||||
|
LightLock_Unlock(&ndspMaster.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspAuxSetFrontBypass(int id, bool bypass)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&ndspMaster.lock);
|
||||||
|
ndspMaster.aux[id].frontBypass = bypass ? 1 : 0;
|
||||||
|
ndspMaster.flags |= MFLAG_AUX_BYPASS(id);
|
||||||
|
LightLock_Unlock(&ndspMaster.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspAuxSetVolume(int id, float volume)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&ndspMaster.lock);
|
||||||
|
ndspMaster.aux[id].volume = volume;
|
||||||
|
ndspMaster.flags |= MFLAG_AUX_VOLUME(id);
|
||||||
|
LightLock_Unlock(&ndspMaster.lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ndspAuxSetCallback(int id, ndspAuxCallback callback, void* data)
|
||||||
|
{
|
||||||
|
ndspMaster.aux[id].callback = callback;
|
||||||
|
ndspMaster.aux[id].callbackData = data;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user