Skip to content

Commit ea51918

Browse files
committed
rework modplug example for streaming audio
1 parent 65661df commit ea51918

1 file changed

Lines changed: 141 additions & 181 deletions

File tree

  • audio/modplug-decoding/source
Lines changed: 141 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -1,181 +1,141 @@
1-
#include <3ds.h>
2-
#include <stdio.h>
3-
4-
#include <sys/stat.h>
5-
#include <malloc.h>
6-
7-
#include <string.h>
8-
9-
#include <libmodplug/modplug.h>
10-
11-
typedef struct
12-
{
13-
ModPlugFile *plug;
14-
ModPlug_Settings settings;
15-
} ModplugDecoder;
16-
17-
typedef struct
18-
{
19-
void* data;
20-
size_t size;
21-
} StaticDataBuffer;
22-
23-
void staticDataBufferInit(StaticDataBuffer* buffer, void* data, size_t size)
24-
{
25-
buffer->data = (int16_t*)linearAlloc(size);
26-
buffer->size = size;
27-
28-
memcpy(buffer->data, data, size);
29-
}
30-
31-
void staticDataBufferDestroy(StaticDataBuffer* buffer)
32-
{
33-
if (buffer)
34-
linearFree(buffer->data);
35-
}
36-
37-
void audioCallback(void *const data) {
38-
ndspWaveBuf *wbuf = data;
39-
40-
if(wbuf->status == NDSP_WBUF_DONE) {
41-
printf("Playback complete, press Start to exit\n");
42-
wbuf->status = NDSP_WBUF_FREE;
43-
return;
44-
}
45-
}
46-
47-
int main(int argc, char **argv)
48-
{
49-
gfxInitDefault();
50-
51-
consoleInit(GFX_TOP, NULL);
52-
53-
ndspInit();
54-
romfsInit();
55-
56-
ModplugDecoder decoder;
57-
58-
/* set up ModPlug settings */
59-
decoder.settings.mFlags = MODPLUG_ENABLE_OVERSAMPLING | MODPLUG_ENABLE_NOISE_REDUCTION;
60-
decoder.settings.mChannels = 2;
61-
decoder.settings.mBits = 16;
62-
decoder.settings.mFrequency = 44100;
63-
decoder.settings.mResamplingMode = MODPLUG_RESAMPLE_LINEAR;
64-
65-
/* Fill with modplug defaults */
66-
decoder.settings.mStereoSeparation = 128;
67-
decoder.settings.mMaxMixChannels = 32;
68-
decoder.settings.mReverbDepth = 0;
69-
decoder.settings.mReverbDelay = 0;
70-
decoder.settings.mBassAmount = 0;
71-
decoder.settings.mBassRange = 0;
72-
decoder.settings.mSurroundDepth = 0;
73-
decoder.settings.mSurroundDelay = 0;
74-
decoder.settings.mLoopCount = -1;
75-
76-
ModPlug_SetSettings(&decoder.settings);
77-
78-
/* Get the file size via stat */
79-
80-
struct stat fileStat;
81-
stat("romfs:/space_debris.mod", &fileStat);
82-
size_t bufferSize = fileStat.st_size;
83-
84-
/* Open the file for reading */
85-
86-
FILE* file = fopen("romfs:/space_debris.mod", "rb");
87-
88-
/* Read the file into a buffer */
89-
90-
void* buffer = (void*)malloc(bufferSize);
91-
fread(buffer, bufferSize, 1, file);
92-
93-
/* Load the ModPlug file from the buffer */
94-
95-
decoder.plug = ModPlug_Load(buffer, bufferSize);
96-
97-
/* Free the useless buffer now and close the file handle */
98-
99-
free(buffer);
100-
fclose(file);
101-
102-
if (decoder.plug == 0)
103-
printf("Well shit, could not load file!\n");
104-
else
105-
ModPlug_SetMasterVolume(decoder.plug, 128);
106-
107-
/* Create a new ndspWaveBuf */
108-
109-
ndspWaveBuf waveBuf;
110-
111-
/*
112-
** Create static buffer data and use
113-
** a redundant size for the test.
114-
**
115-
** == WARNING ==
116-
** Do not actually do this.
117-
**
118-
** The decoder size should be looping
119-
** through calls to ModPlug_Read until nothing
120-
** can be read anymore.
121-
**
122-
** Memory *may* get exhausted if too much is allocated.
123-
** Implement a way to check that, realloc, etc until a limit
124-
** of streaming data is hit.
125-
*/
126-
size_t decoderSize = 524288 * 50;
127-
void* decodedBuffer = (void*)malloc(decoderSize);
128-
129-
size_t decoded = ModPlug_Read(decoder.plug, decodedBuffer, decoderSize);
130-
131-
StaticDataBuffer staticDataBuffer = {0};
132-
staticDataBufferInit(&staticDataBuffer, decodedBuffer, decoded);
133-
134-
printf("Decoded Size: %zu\n", decoded);
135-
136-
waveBuf.nsamples = ((decoded / 2) / sizeof(int16_t));
137-
waveBuf.looping = false;
138-
139-
waveBuf.data_pcm16 = (int16_t*)staticDataBuffer.data;
140-
DSP_FlushDataCache(waveBuf.data_pcm16, decoded);
141-
142-
ndspChnReset(0);
143-
ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16);
144-
ndspChnSetRate(0, 44100);
145-
ndspChnSetInterp(0, NDSP_INTERP_POLYPHASE);
146-
147-
printf("Playing modplug file!\n");
148-
ndspChnWaveBufAdd(0, &waveBuf);
149-
ndspSetCallback(audioCallback, &waveBuf);
150-
151-
// Main loop
152-
while (aptMainLoop())
153-
{
154-
hidScanInput();
155-
156-
u32 kDown = hidKeysDown();
157-
158-
if (kDown & KEY_START)
159-
break; // break in order to return to hbmenu
160-
161-
// Flush and swap framebuffers
162-
gfxFlushBuffers();
163-
gfxSwapBuffers();
164-
165-
//Wait for VBlank
166-
gspWaitForVBlank();
167-
}
168-
169-
if (decoder.plug != 0)
170-
ModPlug_Unload(decoder.plug);
171-
172-
staticDataBufferDestroy(&staticDataBuffer);
173-
174-
romfsExit();
175-
176-
ndspExit();
177-
178-
gfxExit();
179-
180-
return 0;
181-
}
1+
#include <3ds.h>
2+
#include <stdio.h>
3+
4+
#include <sys/stat.h>
5+
#include <malloc.h>
6+
7+
#include <string.h>
8+
9+
#include <libmodplug/modplug.h>
10+
11+
typedef struct
12+
{
13+
ModPlugFile *plug;
14+
ModPlug_Settings settings;
15+
} ModplugDecoder;
16+
17+
// roughly a video frame's worth of audio
18+
static const size_t decoderBufSize = 800 * 2 * 2;
19+
static ModplugDecoder decoder;
20+
static ndspWaveBuf wavebufs[2];
21+
static int nextBuf = 0;
22+
23+
void audioCallback(void *const data) {
24+
if(wavebufs[nextBuf].status == NDSP_WBUF_DONE) {
25+
size_t decoded = ModPlug_Read(decoder.plug, wavebufs[nextBuf].data_pcm16, decoderBufSize);
26+
if (decoded!=0) {
27+
wavebufs[nextBuf].nsamples = ((decoded / 2) / sizeof(int16_t));
28+
DSP_FlushDataCache(wavebufs[nextBuf].data_pcm16, decoded);
29+
30+
ndspChnWaveBufAdd(0, &wavebufs[nextBuf]);
31+
32+
nextBuf ^= 1;
33+
}
34+
}
35+
}
36+
37+
int main(int argc, char **argv)
38+
{
39+
gfxInitDefault();
40+
41+
consoleInit(GFX_TOP, NULL);
42+
43+
ndspInit();
44+
romfsInit();
45+
46+
decoder.settings.mFlags = MODPLUG_ENABLE_OVERSAMPLING | MODPLUG_ENABLE_NOISE_REDUCTION;
47+
decoder.settings.mChannels = 2;
48+
decoder.settings.mBits = 16;
49+
decoder.settings.mFrequency = 44100;
50+
decoder.settings.mResamplingMode = MODPLUG_RESAMPLE_LINEAR;
51+
52+
/* Fill with modplug defaults */
53+
decoder.settings.mStereoSeparation = 128;
54+
decoder.settings.mMaxMixChannels = 32;
55+
decoder.settings.mReverbDepth = 0;
56+
decoder.settings.mReverbDelay = 0;
57+
decoder.settings.mBassAmount = 0;
58+
decoder.settings.mBassRange = 0;
59+
decoder.settings.mSurroundDepth = 0;
60+
decoder.settings.mSurroundDelay = 0;
61+
decoder.settings.mLoopCount = -1;
62+
63+
ModPlug_SetSettings(&decoder.settings);
64+
65+
struct stat fileStat;
66+
stat("romfs:/space_debris.mod", &fileStat);
67+
size_t bufferSize = fileStat.st_size;
68+
69+
FILE* file = fopen("romfs:/space_debris.mod", "rb");
70+
71+
void* buffer = (void*)malloc(bufferSize);
72+
fread(buffer, bufferSize, 1, file);
73+
74+
decoder.plug = ModPlug_Load(buffer, bufferSize);
75+
76+
free(buffer);
77+
fclose(file);
78+
79+
if (decoder.plug == 0) {
80+
printf("Couldn't load mod file!\n");
81+
} else {
82+
ModPlug_SetMasterVolume(decoder.plug, 128);
83+
84+
ndspChnReset(0);
85+
ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16);
86+
ndspChnSetRate(0, 44100);
87+
ndspChnSetInterp(0, NDSP_INTERP_POLYPHASE);
88+
89+
// Set up audiobuffers using linearAlloc
90+
// This ensures audio data is in contiguous physical ram
91+
wavebufs[0].data_pcm16 = (int16_t*)linearAlloc(decoderBufSize);
92+
wavebufs[0].looping = false;
93+
wavebufs[0].status = NDSP_WBUF_DONE;
94+
95+
wavebufs[1].data_pcm16 = (int16_t*)linearAlloc(decoderBufSize);
96+
wavebufs[1].looping = false;
97+
wavebufs[1].status = NDSP_WBUF_DONE;
98+
99+
printf("Playing modplug file!\n");
100+
101+
// Fill the two audio buffers
102+
audioCallback(NULL);
103+
audioCallback(NULL);
104+
105+
// and chain the rest of the audio using the callback
106+
ndspSetCallback(audioCallback, NULL);
107+
}
108+
109+
// Main loop
110+
while (aptMainLoop())
111+
{
112+
hidScanInput();
113+
114+
u32 kDown = hidKeysDown();
115+
116+
if (kDown & KEY_START)
117+
break; // break in order to return to hbmenu
118+
119+
// Flush and swap framebuffers
120+
gfxFlushBuffers();
121+
gfxSwapBuffers();
122+
123+
//Wait for VBlank
124+
gspWaitForVBlank();
125+
}
126+
127+
if (decoder.plug != 0) {
128+
ModPlug_Unload(decoder.plug);
129+
linearFree(wavebufs[0].data_pcm16);
130+
linearFree(wavebufs[1].data_pcm16);
131+
}
132+
133+
134+
romfsExit();
135+
136+
ndspExit();
137+
138+
gfxExit();
139+
140+
return 0;
141+
}

0 commit comments

Comments
 (0)