29
29
#include "SDL_audio_c.h"
30
30
#include "SDL_xenonaudio.h"
31
31
32
+ #define MAX_UNPLAYED 32768
33
+ #define BUFFER_SIZE 65536
34
+
35
+ static Uint32 dma_buffer [2048 ];
36
+
37
+ static char buffer [BUFFER_SIZE ];
38
+ static unsigned int real_freq ;
39
+ static double freq_ratio ;
40
+
41
+ int buffer_size = 1024 ;
42
+
43
+ static unsigned int thread_lock __attribute__ ((aligned (128 ))) = 0 ;
32
44
45
+ static unsigned char thread_stack [0x10000 ];
46
+ static unsigned char thread_stack_get [0x10000 ];
33
47
48
+ static volatile void * thread_buffer = NULL ;
49
+ static volatile int thread_bufsize = 0 ;
50
+ static int thread_bufmaxsize = 0 ;
51
+ static volatile int thread_terminate = 0 ;
34
52
35
53
/* Audio driver functions */
36
54
static int XENON_OpenAudio (_THIS , SDL_AudioSpec * spec );
@@ -48,6 +66,49 @@ static int Audio_Available(void)
48
66
return (1 );
49
67
}
50
68
69
+ static void inline play_buffer (void )
70
+ {
71
+ int i ;
72
+
73
+ while (xenon_sound_get_unplayed ()> MAX_UNPLAYED );
74
+
75
+ for (i = 0 ;i < buffer_size /4 ;++ i ) ((int * )buffer )[i ]= bswap_32 (((int * )buffer )[i ]);
76
+
77
+ xenon_sound_submit (buffer ,buffer_size );
78
+
79
+
80
+ }
81
+
82
+ static s16 prevLastSample [2 ]= {0 ,0 };
83
+
84
+ void ResampleLinear (s16 * pStereoSamples , s32 oldsamples , s16 * pNewSamples , s32 newsamples )
85
+ {
86
+ s32 newsampL , newsampR ;
87
+ s32 i ;
88
+
89
+ for (i = 0 ; i < newsamples ; ++ i )
90
+ {
91
+ s32 io = i * oldsamples ;
92
+ s32 old = io / newsamples ;
93
+ s32 rem = io - old * newsamples ;
94
+
95
+ old *= 2 ;
96
+
97
+ if (old == 0 ){
98
+ newsampL = prevLastSample [0 ] * (newsamples - rem ) + pStereoSamples [0 ] * rem ;
99
+ newsampR = prevLastSample [1 ] * (newsamples - rem ) + pStereoSamples [1 ] * rem ;
100
+ }else {
101
+ newsampL = pStereoSamples [old - 2 ] * (newsamples - rem ) + pStereoSamples [old ] * rem ;
102
+ newsampR = pStereoSamples [old - 1 ] * (newsamples - rem ) + pStereoSamples [old + 1 ] * rem ;
103
+ }
104
+
105
+ pNewSamples [2 * i ] = newsampL / newsamples ;
106
+ pNewSamples [2 * i + 1 ] = newsampR / newsamples ;
107
+ }
108
+
109
+ prevLastSample [0 ]= pStereoSamples [oldsamples * 2 - 2 ];
110
+ prevLastSample [1 ]= pStereoSamples [oldsamples * 2 - 1 ];
111
+ }
51
112
52
113
static void XENON_Unload (void )
53
114
{
@@ -116,76 +177,123 @@ static void XENON_WaitAudio_BusyWait(_THIS)
116
177
117
178
static void XENON_PlayAudio (_THIS )
118
179
{
180
+
181
+ }
182
+
183
+ static void XENON_WaitDone (_THIS )
184
+ {
119
185
120
-
121
- //while(xenon_sound_get_unplayed()>(4*mixlen)) udelay(50);
122
-
123
-
124
- //memcpy(&pAudioBuffers[currentBuffer * mixlen], locked_buf, mixlen);
125
- //xenon_sound_submit(&pAudioBuffers[currentBuffer * mixlen], mixlen);
126
-
127
186
128
- currentBuffer ++ ;
129
- currentBuffer %= ( NUM_BUFFERS );
187
+
188
+
130
189
}
131
190
132
- static Uint8 * XENON_GetAudioBuf (_THIS )
133
- {
134
- return (locked_buf );
191
+ static void XENON_CloseAudio (_THIS )
192
+ {
193
+
194
+
135
195
}
136
196
137
- static void XENON_WaitDone ( _THIS )
197
+ static void thread_enqueue ( void * buffer , int size )
138
198
{
139
- Uint8 * stream ;
199
+ while (thread_bufsize );
200
+
201
+ lock (& thread_lock );
140
202
141
- /* Wait for the playing chunk to finish */
142
- stream = this -> GetAudioBuf (this );
143
- if ( stream != NULL ) {
144
- memset (stream , silence , mixlen );
145
- this -> PlayAudio (this );
146
- }
147
- this -> WaitAudio (this );
203
+ if (thread_bufmaxsize < size ){
204
+ thread_bufmaxsize = size ;
205
+ thread_buffer = realloc ((void * )thread_buffer ,thread_bufmaxsize );
206
+ }
148
207
149
-
150
-
208
+ thread_bufsize = size ;
209
+ memcpy ((void * )thread_buffer ,buffer ,thread_bufsize );
210
+
211
+ unlock (& thread_lock );
212
+
151
213
}
152
214
153
- static void XENON_CloseAudio (_THIS )
215
+ static void inline add_to_buffer (void * stream , unsigned int length ){
216
+ unsigned int lengthLeft = length >> 2 ;
217
+ unsigned int rlengthLeft = ceil (lengthLeft / freq_ratio );
218
+ ResampleLinear ((s16 * )stream ,lengthLeft ,(s16 * )buffer ,rlengthLeft );
219
+ buffer_size = rlengthLeft <<2 ;
220
+ play_buffer ();
221
+ }
222
+
223
+ static void thread_loop ()
154
224
{
225
+ static char * local_buffer [0x10000 ];
226
+ int local_bufsize = 0 ;
227
+ int k ;
228
+
229
+ while (!thread_terminate ){
230
+
231
+ short * stream = (short * )dma_buffer ;
232
+
233
+ // grab the audio
234
+ current_audio -> spec .callback (
235
+ current_audio -> spec .userdata ,
236
+ (Uint8 * )dma_buffer ,
237
+ 2048 );
238
+
239
+
240
+ // queue it up
241
+ thread_enqueue ((short * )stream , 2048 );
242
+
243
+ lock (& thread_lock );
244
+
245
+ if (thread_bufsize ){
246
+ local_bufsize = thread_bufsize ;
247
+ if (local_bufsize > sizeof (local_buffer )) local_bufsize = sizeof (local_buffer );
248
+ memcpy (local_buffer ,(void * )thread_buffer ,local_bufsize );
249
+ thread_bufsize -= local_bufsize ;
250
+ }
251
+
252
+ unlock (& thread_lock );
155
253
156
- if (locked_buf )
157
- {
158
- free (locked_buf );
159
- locked_buf = NULL ;
160
- }
254
+ if (local_bufsize ){
255
+ add_to_buffer (local_buffer ,local_bufsize );
256
+ local_bufsize = 0 ;
257
+ }
161
258
162
- if (pAudioBuffers )
163
- {
164
- free (pAudioBuffers );
165
- pAudioBuffers = NULL ;
166
- }
259
+ for (k = 0 ;k < 100 ;++ k ) asm volatile ("nop" );
260
+ }
261
+ }
262
+
263
+ static Uint8 * XENON_GetAudioBuf (_THIS )
264
+ {
265
+
266
+ return NULL ;
167
267
}
168
268
169
269
static int XENON_OpenAudio (_THIS , SDL_AudioSpec * spec )
170
270
{
171
-
172
- // Set up actual spec.
173
- spec -> freq = 48000 ;
271
+
272
+ spec -> freq = 32000 ;
174
273
spec -> format = AUDIO_S16MSB ;
175
- spec -> channels = 2 ;
274
+ spec -> channels = 2 ;
275
+
276
+ freq_ratio = (double )spec -> freq / 48000 ;
176
277
177
278
/* Update the fragment size as size in bytes */
178
279
SDL_CalculateAudioSpec (spec );
179
-
180
- locked_buf = (unsigned char * )malloc (spec -> size );
181
-
182
- /* Create the audio buffer to which we write */
183
- NUM_BUFFERS = 2 ;
184
-
185
-
186
- pAudioBuffers = (unsigned char * )malloc (spec -> size * NUM_BUFFERS );
280
+
281
+
187
282
playing = 0 ;
188
283
mixlen = spec -> size ;
189
284
190
- return (0 );
285
+ thread_lock = 0 ;
286
+ thread_buffer = NULL ;
287
+ thread_bufsize = 0 ;
288
+ thread_bufmaxsize = 0 ;
289
+ thread_terminate = 0 ;
290
+
291
+ // Semaphores/Mutexes dont exist yet in libXenon so we dont want libSDL to handle
292
+ // the threading. Instead create our own thread here to handle the audio.
293
+
294
+ xenon_run_thread_task (1 ,& thread_stack [sizeof (thread_stack )- 0x100 ],thread_loop );
295
+
296
+ // 1 means that libSDL wont call SDL_CreateThread();
297
+
298
+ return (1 );
191
299
}
0 commit comments