summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/audio/n3ds
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/SDL-3.2.8/src/audio/n3ds')
-rw-r--r--contrib/SDL-3.2.8/src/audio/n3ds/SDL_n3dsaudio.c287
-rw-r--r--contrib/SDL-3.2.8/src/audio/n3ds/SDL_n3dsaudio.h40
2 files changed, 327 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/audio/n3ds/SDL_n3dsaudio.c b/contrib/SDL-3.2.8/src/audio/n3ds/SDL_n3dsaudio.c
new file mode 100644
index 0000000..780b06c
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/audio/n3ds/SDL_n3dsaudio.c
@@ -0,0 +1,287 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#ifdef SDL_AUDIO_DRIVER_N3DS
24
25// N3DS Audio driver
26
27#include "../SDL_sysaudio.h"
28#include "SDL_n3dsaudio.h"
29
30#define N3DSAUDIO_DRIVER_NAME "n3ds"
31
32static dspHookCookie dsp_hook;
33static SDL_AudioDevice *audio_device;
34
35// fully local functions related to the wavebufs / DSP, not the same as the `device->lock` SDL_Mutex!
36static SDL_INLINE void contextLock(SDL_AudioDevice *device)
37{
38 LightLock_Lock(&device->hidden->lock);
39}
40
41static SDL_INLINE void contextUnlock(SDL_AudioDevice *device)
42{
43 LightLock_Unlock(&device->hidden->lock);
44}
45
46static void N3DSAUD_DspHook(DSP_HookType hook)
47{
48 if (hook == DSPHOOK_ONCANCEL) {
49 contextLock(audio_device);
50 audio_device->hidden->isCancelled = true;
51 SDL_AudioDeviceDisconnected(audio_device);
52 CondVar_Broadcast(&audio_device->hidden->cv);
53 contextUnlock(audio_device);
54 }
55}
56
57static void AudioFrameFinished(void *vdevice)
58{
59 bool shouldBroadcast = false;
60 unsigned i;
61 SDL_AudioDevice *device = (SDL_AudioDevice *)vdevice;
62
63 contextLock(device);
64
65 for (i = 0; i < NUM_BUFFERS; i++) {
66 if (device->hidden->waveBuf[i].status == NDSP_WBUF_DONE) {
67 device->hidden->waveBuf[i].status = NDSP_WBUF_FREE;
68 shouldBroadcast = true;
69 }
70 }
71
72 if (shouldBroadcast) {
73 CondVar_Broadcast(&device->hidden->cv);
74 }
75
76 contextUnlock(device);
77}
78
79static bool N3DSAUDIO_OpenDevice(SDL_AudioDevice *device)
80{
81 Result ndsp_init_res;
82 Uint8 *data_vaddr;
83 float mix[12];
84
85 device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
86 if (!device->hidden) {
87 return false;
88 }
89
90 // Initialise the DSP service
91 ndsp_init_res = ndspInit();
92 if (R_FAILED(ndsp_init_res)) {
93 if ((R_SUMMARY(ndsp_init_res) == RS_NOTFOUND) && (R_MODULE(ndsp_init_res) == RM_DSP)) {
94 return SDL_SetError("DSP init failed: dspfirm.cdc missing!");
95 } else {
96 return SDL_SetError("DSP init failed. Error code: 0x%lX", ndsp_init_res);
97 }
98 }
99
100 // Initialise internal state
101 LightLock_Init(&device->hidden->lock);
102 CondVar_Init(&device->hidden->cv);
103
104 if (device->spec.channels > 2) {
105 device->spec.channels = 2;
106 }
107
108 Uint32 format = 0;
109 SDL_AudioFormat test_format;
110 const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format);
111 while ((test_format = *(closefmts++)) != 0) {
112 if (test_format == SDL_AUDIO_S8) { // Signed 8-bit audio supported
113 format = (device->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM8 : NDSP_FORMAT_MONO_PCM8;
114 break;
115 } else if (test_format == SDL_AUDIO_S16) { // Signed 16-bit audio supported
116 format = (device->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM16 : NDSP_FORMAT_MONO_PCM16;
117 break;
118 }
119 }
120
121 if (!test_format) { // shouldn't happen, but just in case...
122 return SDL_SetError("No supported audio format found.");
123 }
124
125 device->spec.format = test_format;
126
127 // Update the fragment size as size in bytes
128 SDL_UpdatedAudioDeviceFormat(device);
129
130 // Allocate mixing buffer
131 if (device->buffer_size >= SDL_MAX_UINT32 / 2) {
132 return SDL_SetError("Mixing buffer is too large.");
133 }
134
135 device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
136 if (!device->hidden->mixbuf) {
137 return false;
138 }
139
140 SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
141
142 data_vaddr = (Uint8 *)linearAlloc(device->buffer_size * NUM_BUFFERS);
143 if (!data_vaddr) {
144 return SDL_OutOfMemory();
145 }
146
147 SDL_memset(data_vaddr, 0, device->buffer_size * NUM_BUFFERS);
148 DSP_FlushDataCache(data_vaddr, device->buffer_size * NUM_BUFFERS);
149
150 device->hidden->nextbuf = 0;
151
152 ndspChnReset(0);
153
154 ndspChnSetInterp(0, NDSP_INTERP_LINEAR);
155 ndspChnSetRate(0, device->spec.freq);
156 ndspChnSetFormat(0, format);
157
158 SDL_zeroa(mix);
159 mix[0] = mix[1] = 1.0f;
160 ndspChnSetMix(0, mix);
161
162 SDL_memset(device->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
163
164 const int sample_frame_size = SDL_AUDIO_FRAMESIZE(device->spec);
165 for (unsigned i = 0; i < NUM_BUFFERS; i++) {
166 device->hidden->waveBuf[i].data_vaddr = data_vaddr;
167 device->hidden->waveBuf[i].nsamples = device->buffer_size / sample_frame_size;
168 data_vaddr += device->buffer_size;
169 }
170
171 // Setup callback
172 audio_device = device;
173 ndspSetCallback(AudioFrameFinished, device);
174 dspHook(&dsp_hook, N3DSAUD_DspHook);
175
176 return true;
177}
178
179static bool N3DSAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
180{
181 contextLock(device);
182
183 const size_t nextbuf = device->hidden->nextbuf;
184
185 if (device->hidden->isCancelled ||
186 device->hidden->waveBuf[nextbuf].status != NDSP_WBUF_FREE) {
187 contextUnlock(device);
188 return true; // !!! FIXME: is this a fatal error? If so, this should return false.
189 }
190
191 device->hidden->nextbuf = (nextbuf + 1) % NUM_BUFFERS;
192
193 contextUnlock(device);
194
195 SDL_memcpy((void *)device->hidden->waveBuf[nextbuf].data_vaddr, buffer, buflen);
196 DSP_FlushDataCache(device->hidden->waveBuf[nextbuf].data_vaddr, buflen);
197
198 ndspChnWaveBufAdd(0, &device->hidden->waveBuf[nextbuf]);
199
200 return true;
201}
202
203static bool N3DSAUDIO_WaitDevice(SDL_AudioDevice *device)
204{
205 contextLock(device);
206 while (!device->hidden->isCancelled && !SDL_GetAtomicInt(&device->shutdown) &&
207 device->hidden->waveBuf[device->hidden->nextbuf].status != NDSP_WBUF_FREE) {
208 CondVar_Wait(&device->hidden->cv, &device->hidden->lock);
209 }
210 contextUnlock(device);
211 return true;
212}
213
214static Uint8 *N3DSAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
215{
216 return device->hidden->mixbuf;
217}
218
219static void N3DSAUDIO_CloseDevice(SDL_AudioDevice *device)
220{
221 if (!device->hidden) {
222 return;
223 }
224
225 contextLock(device);
226
227 dspUnhook(&dsp_hook);
228 ndspSetCallback(NULL, NULL);
229
230 if (!device->hidden->isCancelled) {
231 ndspChnReset(0);
232 SDL_memset(device->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
233 CondVar_Broadcast(&device->hidden->cv);
234 }
235
236 contextUnlock(device);
237
238 ndspExit();
239
240 if (device->hidden->waveBuf[0].data_vaddr) {
241 linearFree((void *)device->hidden->waveBuf[0].data_vaddr);
242 }
243
244 if (device->hidden->mixbuf) {
245 SDL_free(device->hidden->mixbuf);
246 device->hidden->mixbuf = NULL;
247 }
248
249 SDL_free(device->hidden);
250 device->hidden = NULL;
251}
252
253static void N3DSAUDIO_ThreadInit(SDL_AudioDevice *device)
254{
255 s32 current_priority = 0x30;
256 svcGetThreadPriority(&current_priority, CUR_THREAD_HANDLE);
257 current_priority--;
258 // 0x18 is reserved for video, 0x30 is the default for main thread
259 current_priority = SDL_clamp(current_priority, 0x19, 0x2F);
260 svcSetThreadPriority(CUR_THREAD_HANDLE, current_priority);
261}
262
263static bool N3DSAUDIO_Init(SDL_AudioDriverImpl *impl)
264{
265 impl->OpenDevice = N3DSAUDIO_OpenDevice;
266 impl->PlayDevice = N3DSAUDIO_PlayDevice;
267 impl->WaitDevice = N3DSAUDIO_WaitDevice;
268 impl->GetDeviceBuf = N3DSAUDIO_GetDeviceBuf;
269 impl->CloseDevice = N3DSAUDIO_CloseDevice;
270 impl->ThreadInit = N3DSAUDIO_ThreadInit;
271 impl->OnlyHasDefaultPlaybackDevice = true;
272
273 // Should be possible, but micInit would fail
274 impl->HasRecordingSupport = false;
275
276 return true;
277}
278
279AudioBootStrap N3DSAUDIO_bootstrap = {
280 N3DSAUDIO_DRIVER_NAME,
281 "SDL N3DS audio driver",
282 N3DSAUDIO_Init,
283 false,
284 false
285};
286
287#endif // SDL_AUDIO_DRIVER_N3DS
diff --git a/contrib/SDL-3.2.8/src/audio/n3ds/SDL_n3dsaudio.h b/contrib/SDL-3.2.8/src/audio/n3ds/SDL_n3dsaudio.h
new file mode 100644
index 0000000..c9ae4f8
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/audio/n3ds/SDL_n3dsaudio.h
@@ -0,0 +1,40 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21
22#ifndef SDL_n3dsaudio_h
23#define SDL_n3dsaudio_h
24
25#include <3ds.h>
26
27#define NUM_BUFFERS 3 // -- Minimum 2!
28
29struct SDL_PrivateAudioData
30{
31 // Speaker data
32 Uint8 *mixbuf;
33 Uint32 nextbuf;
34 ndspWaveBuf waveBuf[NUM_BUFFERS];
35 LightLock lock;
36 CondVar cv;
37 bool isCancelled;
38};
39
40#endif // SDL_n3dsaudio_h