掌機 - Nintendo 3DS - C/C++ - Audio(Streaming)



參考資訊:
https://hub.docker.com/r/greatwizard/devkitarm-3ds

main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <3ds.h>

#define SAMPLERATE      22050
#define SAMPLESPERBUF   (SAMPLERATE / 30)
#define BYTESPERSAMPLE  4

void fill_buffer(void *audioBuffer, size_t offset, size_t size, int frequency)
{
    u32 *dest = (u32 *)audioBuffer;

    for (int i=0; i<size; i++) {
        s16 sample = INT16_MAX * sin(frequency * (2 * M_PI) * (offset + i) / SAMPLERATE);
        dest[i] = (sample << 16) | (sample & 0xffff);
    }
    DSP_FlushDataCache(audioBuffer, size);
}

int main(void)
{
    int note = 4;
    bool fillBlock = false;
    u32 *audioBuffer = NULL;
    size_t stream_offset = 0;
    float vol[12] = { 1.0, 1.0 };
    ndspWaveBuf waveBuf[2] = { 0 };

    gfxInitDefault();
    audioBuffer = (u32 *)linearAlloc(SAMPLESPERBUF * BYTESPERSAMPLE * 2);

    ndspInit();
    ndspSetOutputMode(NDSP_OUTPUT_STEREO);
    ndspChnSetInterp(0, NDSP_INTERP_LINEAR);
    ndspChnSetRate(0, SAMPLERATE);
    ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16);
    ndspChnSetMix(0, vol);

    waveBuf[0].data_vaddr = &audioBuffer[0];
    waveBuf[0].nsamples = SAMPLESPERBUF;
    waveBuf[1].data_vaddr = &audioBuffer[SAMPLESPERBUF];
    waveBuf[1].nsamples = SAMPLESPERBUF;
    ndspChnWaveBufAdd(0, &waveBuf[0]);
    ndspChnWaveBufAdd(0, &waveBuf[1]);

    while (aptMainLoop()) {
        gfxSwapBuffers();
        gfxFlushBuffers();
        gspWaitForVBlank();

        if (waveBuf[fillBlock].status == NDSP_WBUF_DONE) {
            fill_buffer(waveBuf[fillBlock].data_pcm16, stream_offset, waveBuf[fillBlock].nsamples, 440);
            ndspChnWaveBufAdd(0, &waveBuf[fillBlock]);
            stream_offset += waveBuf[fillBlock].nsamples;
            fillBlock = !fillBlock;
        }
    }

    ndspExit();
    linearFree(audioBuffer);
    gfxExit();
    return 0;
}