1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #define FORBIDDEN_SYMBOL_EXCEPTION_printf
24
25 #include <malloc.h>
26
27 #include "osystem.h"
28
29 #define SFX_THREAD_STACKSIZE (1024 * 128)
30 #define SFX_THREAD_PRIO 80
31 #define SFX_THREAD_FRAG_SIZE (1024 * 8)
32 #define SFX_BUFFERS 3
33
34 static lwpq_t sfx_queue;
35 static lwp_t sfx_thread;
36 static u8 *sfx_stack;
37 static bool sfx_thread_running = false;
38 static bool sfx_thread_quit = false;
39
40 static u32 sb_hw;
41 static u8 *sound_buffer[SFX_BUFFERS];
42
audio_switch_buffers()43 static void audio_switch_buffers() {
44 sb_hw = (sb_hw + 1) % SFX_BUFFERS;
45 AUDIO_InitDMA((u32) sound_buffer[sb_hw], SFX_THREAD_FRAG_SIZE);
46 LWP_ThreadSignal(sfx_queue);
47 }
48
sfx_thread_func(void * arg)49 static void * sfx_thread_func(void *arg) {
50 Audio::MixerImpl *mixer = (Audio::MixerImpl *) arg;
51 u8 sb_sw;
52
53 while (true) {
54 LWP_ThreadSleep(sfx_queue);
55
56 if (sfx_thread_quit)
57 break;
58
59 // the hardware uses two buffers: a front and a back buffer
60 // we use 3 buffers here: two are beeing pushed to the DSP,
61 // and the free one is where our mixer writes to
62 // thus the latency of our stream is:
63 // 8192 [frag size] / 48000 / 2 [16bit] / 2 [stereo] * 2 [hw buffers]
64 // -> 85.3ms
65 sb_sw = (sb_hw + 1) % SFX_BUFFERS;
66 mixer->mixCallback(sound_buffer[sb_sw], SFX_THREAD_FRAG_SIZE);
67 DCFlushRange(sound_buffer[sb_sw], SFX_THREAD_FRAG_SIZE);
68 }
69
70 return NULL;
71 }
72
initSfx()73 void OSystem_Wii::initSfx() {
74 _mixer = new Audio::MixerImpl(48000);
75
76 sfx_thread_running = false;
77 sfx_thread_quit = false;
78
79 sfx_stack = (u8 *) memalign(32, SFX_THREAD_STACKSIZE);
80
81 if (sfx_stack) {
82 memset(sfx_stack, 0, SFX_THREAD_STACKSIZE);
83
84 LWP_InitQueue(&sfx_queue);
85
86 s32 res = LWP_CreateThread(&sfx_thread, sfx_thread_func, _mixer, sfx_stack,
87 SFX_THREAD_STACKSIZE, SFX_THREAD_PRIO);
88
89 if (res) {
90 printf("ERROR creating sfx thread: %d\n", res);
91 LWP_CloseQueue(sfx_queue);
92 return;
93 }
94
95 sfx_thread_running = true;
96 }
97
98 for (u32 i = 0; i < SFX_BUFFERS; ++i) {
99 sound_buffer[i] = (u8 *) memalign(32, SFX_THREAD_FRAG_SIZE);
100 memset(sound_buffer[i], 0, SFX_THREAD_FRAG_SIZE);
101 DCFlushRange(sound_buffer[i], SFX_THREAD_FRAG_SIZE);
102 }
103
104 _mixer->setReady(true);
105
106 sb_hw = 0;
107
108 AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ);
109 AUDIO_RegisterDMACallback(audio_switch_buffers);
110 AUDIO_InitDMA((u32) sound_buffer[sb_hw], SFX_THREAD_FRAG_SIZE);
111 AUDIO_StartDMA();
112 }
113
deinitSfx()114 void OSystem_Wii::deinitSfx() {
115 if (_mixer)
116 _mixer->setReady(false);
117
118 AUDIO_StopDMA();
119 AUDIO_RegisterDMACallback(NULL);
120
121 if (sfx_thread_running) {
122 sfx_thread_quit = true;
123 LWP_ThreadBroadcast(sfx_queue);
124
125 LWP_JoinThread(sfx_thread, NULL);
126 LWP_CloseQueue(sfx_queue);
127
128 free(sfx_stack);
129 sfx_thread_running = false;
130
131 for (u32 i = 0; i < SFX_BUFFERS; ++i)
132 free(sound_buffer[i]);
133 }
134 }
135