|
1 /* |
|
2 SDL - Simple DirectMedia Layer |
|
3 Copyright (C) 1997-2004 Sam Lantinga |
|
4 |
|
5 This library is free software; you can redistribute it and/or |
|
6 modify it under the terms of the GNU Library General Public |
|
7 License as published by the Free Software Foundation; either |
|
8 version 2 of the License, or (at your option) any later version. |
|
9 |
|
10 This library is distributed in the hope that it will be useful, |
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
13 Library General Public License for more details. |
|
14 |
|
15 You should have received a copy of the GNU Library General Public |
|
16 License along with this library; if not, write to the Free |
|
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
18 |
|
19 Sam Lantinga |
|
20 slouken@libsdl.org |
|
21 */ |
|
22 #include "SDL_config.h" |
|
23 |
|
24 /* |
|
25 MiNT audio driver |
|
26 using DMA 8bits (hardware access) |
|
27 |
|
28 Patrice Mandin |
|
29 */ |
|
30 |
|
31 /* Mint includes */ |
|
32 #include <mint/osbind.h> |
|
33 #include <mint/falcon.h> |
|
34 #include <mint/cookie.h> |
|
35 |
|
36 #include "SDL_audio.h" |
|
37 #include "../SDL_audio_c.h" |
|
38 #include "../SDL_sysaudio.h" |
|
39 |
|
40 #include "../../video/ataricommon/SDL_atarimxalloc_c.h" |
|
41 |
|
42 #include "SDL_mintaudio.h" |
|
43 #include "SDL_mintaudio_dma8.h" |
|
44 |
|
45 /*--- Defines ---*/ |
|
46 |
|
47 #define MINT_AUDIO_DRIVER_NAME "mint_dma8" |
|
48 |
|
49 /* Debug print info */ |
|
50 #define DEBUG_NAME "audio:dma8: " |
|
51 #if 0 |
|
52 #define DEBUG_PRINT(what) \ |
|
53 { \ |
|
54 printf what; \ |
|
55 } |
|
56 #else |
|
57 #define DEBUG_PRINT(what) |
|
58 #endif |
|
59 |
|
60 /*--- Static variables ---*/ |
|
61 |
|
62 static unsigned long cookie_snd, cookie_mch; |
|
63 |
|
64 /*--- Audio driver functions ---*/ |
|
65 |
|
66 static void Mint_CloseAudio(_THIS); |
|
67 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec); |
|
68 static void Mint_LockAudio(_THIS); |
|
69 static void Mint_UnlockAudio(_THIS); |
|
70 |
|
71 /* To check/init hardware audio */ |
|
72 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec); |
|
73 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec); |
|
74 |
|
75 /*--- Audio driver bootstrap functions ---*/ |
|
76 |
|
77 static int Audio_Available(void) |
|
78 { |
|
79 const char *envr = SDL_getenv("SDL_AUDIODRIVER"); |
|
80 |
|
81 /* Check if user asked a different audio driver */ |
|
82 if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) { |
|
83 DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n")); |
|
84 return 0; |
|
85 } |
|
86 |
|
87 /* Cookie _MCH present ? if not, assume ST machine */ |
|
88 if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) { |
|
89 cookie_mch = MCH_ST; |
|
90 } |
|
91 |
|
92 /* Cookie _SND present ? if not, assume ST machine */ |
|
93 if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) { |
|
94 cookie_snd = SND_PSG; |
|
95 } |
|
96 |
|
97 /* Check if we have 8 bits audio */ |
|
98 if ((cookie_snd & SND_8BIT)==0) { |
|
99 DEBUG_PRINT((DEBUG_NAME "no 8 bits sound\n")); |
|
100 return(0); |
|
101 } |
|
102 |
|
103 /* Check if audio is lockable */ |
|
104 if (cookie_snd & SND_16BIT) { |
|
105 if (Locksnd()!=1) { |
|
106 DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n")); |
|
107 return(0); |
|
108 } |
|
109 |
|
110 Unlocksnd(); |
|
111 } |
|
112 |
|
113 DEBUG_PRINT((DEBUG_NAME "8 bits audio available!\n")); |
|
114 return(1); |
|
115 } |
|
116 |
|
117 static void Audio_DeleteDevice(SDL_AudioDevice *device) |
|
118 { |
|
119 SDL_free(device->hidden); |
|
120 SDL_free(device); |
|
121 } |
|
122 |
|
123 static SDL_AudioDevice *Audio_CreateDevice(int devindex) |
|
124 { |
|
125 SDL_AudioDevice *this; |
|
126 |
|
127 /* Initialize all variables that we clean on shutdown */ |
|
128 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); |
|
129 if ( this ) { |
|
130 SDL_memset(this, 0, (sizeof *this)); |
|
131 this->hidden = (struct SDL_PrivateAudioData *) |
|
132 SDL_malloc((sizeof *this->hidden)); |
|
133 } |
|
134 if ( (this == NULL) || (this->hidden == NULL) ) { |
|
135 SDL_OutOfMemory(); |
|
136 if ( this ) { |
|
137 SDL_free(this); |
|
138 } |
|
139 return(0); |
|
140 } |
|
141 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); |
|
142 |
|
143 /* Set the function pointers */ |
|
144 this->OpenAudio = Mint_OpenAudio; |
|
145 this->CloseAudio = Mint_CloseAudio; |
|
146 this->LockAudio = Mint_LockAudio; |
|
147 this->UnlockAudio = Mint_UnlockAudio; |
|
148 this->free = Audio_DeleteDevice; |
|
149 |
|
150 return this; |
|
151 } |
|
152 |
|
153 AudioBootStrap MINTAUDIO_DMA8_bootstrap = { |
|
154 MINT_AUDIO_DRIVER_NAME, "MiNT DMA 8 bits audio driver", |
|
155 Audio_Available, Audio_CreateDevice |
|
156 }; |
|
157 |
|
158 static void Mint_LockAudio(_THIS) |
|
159 { |
|
160 void *oldpile; |
|
161 |
|
162 /* Stop replay */ |
|
163 oldpile=(void *)Super(0); |
|
164 DMAAUDIO_IO.control=0; |
|
165 Super(oldpile); |
|
166 } |
|
167 |
|
168 static void Mint_UnlockAudio(_THIS) |
|
169 { |
|
170 void *oldpile; |
|
171 |
|
172 /* Restart replay */ |
|
173 oldpile=(void *)Super(0); |
|
174 DMAAUDIO_IO.control=3; |
|
175 Super(oldpile); |
|
176 } |
|
177 |
|
178 static void Mint_CloseAudio(_THIS) |
|
179 { |
|
180 void *oldpile; |
|
181 |
|
182 /* Stop replay */ |
|
183 oldpile=(void *)Super(0); |
|
184 DMAAUDIO_IO.control=0; |
|
185 Super(oldpile); |
|
186 |
|
187 DEBUG_PRINT((DEBUG_NAME "closeaudio: replay stopped\n")); |
|
188 |
|
189 /* Disable interrupt */ |
|
190 Jdisint(MFP_DMASOUND); |
|
191 |
|
192 DEBUG_PRINT((DEBUG_NAME "closeaudio: interrupt disabled\n")); |
|
193 |
|
194 /* Wait if currently playing sound */ |
|
195 while (SDL_MintAudio_mutex != 0) { |
|
196 } |
|
197 |
|
198 DEBUG_PRINT((DEBUG_NAME "closeaudio: no more interrupt running\n")); |
|
199 |
|
200 /* Clear buffers */ |
|
201 if (SDL_MintAudio_audiobuf[0]) { |
|
202 Mfree(SDL_MintAudio_audiobuf[0]); |
|
203 SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL; |
|
204 } |
|
205 |
|
206 DEBUG_PRINT((DEBUG_NAME "closeaudio: buffers freed\n")); |
|
207 } |
|
208 |
|
209 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec) |
|
210 { |
|
211 int i, masterprediv, sfreq; |
|
212 unsigned long masterclock; |
|
213 |
|
214 DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff)); |
|
215 DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0))); |
|
216 DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0))); |
|
217 DEBUG_PRINT(("channels=%d, ", spec->channels)); |
|
218 DEBUG_PRINT(("freq=%d\n", spec->freq)); |
|
219 |
|
220 if (spec->channels > 2) |
|
221 spec->channels = 2; |
|
222 |
|
223 /* Check formats available */ |
|
224 spec->format = AUDIO_S8; |
|
225 |
|
226 /* Calculate and select the closest frequency */ |
|
227 sfreq=0; |
|
228 masterclock=MASTERCLOCK_STE; |
|
229 masterprediv=MASTERPREDIV_STE; |
|
230 switch(cookie_mch>>16) { |
|
231 /* |
|
232 case MCH_STE: |
|
233 masterclock=MASTERCLOCK_STE; |
|
234 masterprediv=MASTERPREDIV_STE; |
|
235 break; |
|
236 */ |
|
237 case MCH_TT: |
|
238 masterclock=MASTERCLOCK_TT; |
|
239 masterprediv=MASTERPREDIV_TT; |
|
240 break; |
|
241 case MCH_F30: |
|
242 case MCH_ARANYM: |
|
243 masterclock=MASTERCLOCK_FALCON1; |
|
244 masterprediv=MASTERPREDIV_FALCON; |
|
245 sfreq=1; |
|
246 break; |
|
247 } |
|
248 |
|
249 MINTAUDIO_freqcount=0; |
|
250 for (i=sfreq;i<4;i++) { |
|
251 SDL_MintAudio_AddFrequency(this, masterclock/(masterprediv*(1<<i)), |
|
252 masterclock, i-sfreq, -1); |
|
253 } |
|
254 |
|
255 #if 1 |
|
256 for (i=0; i<MINTAUDIO_freqcount; i++) { |
|
257 DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n", |
|
258 i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock, |
|
259 MINTAUDIO_frequencies[i].predivisor |
|
260 )); |
|
261 } |
|
262 #endif |
|
263 |
|
264 MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq); |
|
265 spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency; |
|
266 |
|
267 DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff)); |
|
268 DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0))); |
|
269 DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0))); |
|
270 DEBUG_PRINT(("channels=%d, ", spec->channels)); |
|
271 DEBUG_PRINT(("freq=%d\n", spec->freq)); |
|
272 |
|
273 return 0; |
|
274 } |
|
275 |
|
276 static void Mint_InitAudio(_THIS, SDL_AudioSpec *spec) |
|
277 { |
|
278 void *oldpile; |
|
279 unsigned long buffer; |
|
280 unsigned char mode; |
|
281 |
|
282 /* Set replay tracks */ |
|
283 if (cookie_snd & SND_16BIT) { |
|
284 Settracks(0,0); |
|
285 Setmontracks(0); |
|
286 } |
|
287 |
|
288 oldpile=(void *)Super(0); |
|
289 |
|
290 /* Stop currently playing sound */ |
|
291 DMAAUDIO_IO.control=0; |
|
292 |
|
293 /* Set buffer */ |
|
294 buffer = (unsigned long) SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf]; |
|
295 DMAAUDIO_IO.start_high = (buffer>>16) & 255; |
|
296 DMAAUDIO_IO.start_mid = (buffer>>8) & 255; |
|
297 DMAAUDIO_IO.start_low = buffer & 255; |
|
298 |
|
299 buffer += SDL_MintAudio_audiosize; |
|
300 DMAAUDIO_IO.end_high = (buffer>>16) & 255; |
|
301 DMAAUDIO_IO.end_mid = (buffer>>8) & 255; |
|
302 DMAAUDIO_IO.end_low = buffer & 255; |
|
303 |
|
304 mode = 3-MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor; |
|
305 if (spec->channels==1) { |
|
306 mode |= 1<<7; |
|
307 } |
|
308 DMAAUDIO_IO.sound_ctrl = mode; |
|
309 |
|
310 /* Set interrupt */ |
|
311 Jdisint(MFP_DMASOUND); |
|
312 Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_Dma8Interrupt); |
|
313 Jenabint(MFP_DMASOUND); |
|
314 |
|
315 if (cookie_snd & SND_16BIT) { |
|
316 if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) { |
|
317 DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n")); |
|
318 } |
|
319 } |
|
320 |
|
321 /* Go */ |
|
322 DMAAUDIO_IO.control = 3; /* playback + repeat */ |
|
323 |
|
324 Super(oldpile); |
|
325 } |
|
326 |
|
327 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec) |
|
328 { |
|
329 SDL_MintAudio_device = this; |
|
330 |
|
331 /* Check audio capabilities */ |
|
332 if (Mint_CheckAudio(this, spec)==-1) { |
|
333 return -1; |
|
334 } |
|
335 |
|
336 SDL_CalculateAudioSpec(spec); |
|
337 |
|
338 /* Allocate memory for audio buffers in DMA-able RAM */ |
|
339 DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size)); |
|
340 |
|
341 SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM); |
|
342 if (SDL_MintAudio_audiobuf[0]==NULL) { |
|
343 SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer"); |
|
344 return (-1); |
|
345 } |
|
346 SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ; |
|
347 SDL_MintAudio_numbuf=0; |
|
348 SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2); |
|
349 SDL_MintAudio_audiosize = spec->size; |
|
350 SDL_MintAudio_mutex = 0; |
|
351 |
|
352 DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0])); |
|
353 DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1])); |
|
354 |
|
355 SDL_MintAudio_CheckFpu(); |
|
356 |
|
357 /* Setup audio hardware */ |
|
358 Mint_InitAudio(this, spec); |
|
359 |
|
360 return(1); /* We don't use threaded audio */ |
|
361 } |