Nintendo 3DS >> C/C++
Audio (Opus)
參考資訊:
1. libctru doc
2. 3ds-examples
說明:
API |
---|
int op_read_stereo(OggOpusFile *_of, opus_int16 *_pcm, int _buf_size) |
void LightEvent_Signal(LightEvent *event) |
void LightEvent_Init(LightEvent *event, ResetType reset_type) |
OggOpusFile *op_open_file(const char *_path, int *_error) |
void ndspChnReset(int id) |
void ndspSetCallback(ndspCallback callback, void *data) |
void LightEvent_Wait(LightEvent *event) |
void LightEvent_Signal(LightEvent *event) |
void ndspChnReset(int id) |
void op_free(OggOpusFile *_of) |
main.c
#include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <3ds.h> #include <opusfile.h> #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define SAMPLE_RATE 48000 #define SAMPLE_BUF (SAMPLE_RATE * 120 / 1000) #define CHANNEL 2 #define WAVEBUF_SIZE (SAMPLE_BUF * CHANNEL * sizeof(int16_t)) LightEvent event = {0}; int16_t *audio_buffer = NULL; ndspWaveBuf wave_buffer[3]= {0}; bool fillBuffer(OggOpusFile *opusFile, ndspWaveBuf *waveBuf) { int totalSamples = 0; while (totalSamples < SAMPLE_BUF) { int16_t *buffer = waveBuf->data_pcm16 + (totalSamples * CHANNEL); const size_t bufferSize = (SAMPLE_BUF - totalSamples) * CHANNEL; const int samples = op_read_stereo(opusFile, buffer, bufferSize); if (samples <= 0) { break; } totalSamples += samples; } if (totalSamples == 0) { return false; } waveBuf->nsamples = totalSamples; ndspChnWaveBufAdd(0, waveBuf); DSP_FlushDataCache(waveBuf->data_pcm16, totalSamples * CHANNEL * sizeof(int16_t)); return true; } void audioCallback(void *const argv) { LightEvent_Signal(&event); } int main(void) { int rc = 0, i = 0; gfxInitDefault(); LightEvent_Init(&event, RESET_ONESHOT); OggOpusFile *opusFile = op_open_file("sdmc:/3ds/main.opus", &rc); const size_t bufferSize = WAVEBUF_SIZE * ARRAY_SIZE(wave_buffer); audio_buffer = (int16_t*)linearAlloc(bufferSize); if (!audio_buffer) { return 0; } memset(&wave_buffer, 0, sizeof(wave_buffer)); int16_t *buffer = audio_buffer; for (i=0; i<ARRAY_SIZE(wave_buffer); i++) { wave_buffer[i].data_vaddr = buffer; wave_buffer[i].status = NDSP_WBUF_DONE; buffer += WAVEBUF_SIZE / sizeof(buffer[0]); } ndspInit(); ndspChnReset(0); ndspSetOutputMode(NDSP_OUTPUT_STEREO); ndspChnSetInterp(0, NDSP_INTERP_POLYPHASE); ndspChnSetRate(0, SAMPLE_RATE); ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16); ndspSetCallback(audioCallback, NULL); while (aptMainLoop()) { for (i=0; i<ARRAY_SIZE(wave_buffer); i++) { if (wave_buffer[i].status != NDSP_WBUF_DONE) { continue; } if (!fillBuffer(opusFile, &wave_buffer[i])) { break; } } LightEvent_Wait(&event); } LightEvent_Signal(&event); ndspChnReset(0); linearFree(audio_buffer); ndspExit(); op_free(opusFile); gfxExit(); return 0; }