]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/libsdl/contrib/src/audio/mint/SDL_mintaudio_dma8.c
update
[l4.git] / l4 / pkg / libsdl / contrib / src / audio / mint / SDL_mintaudio_dma8.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2012 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 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
74 /* Functions called in supervisor mode */
75 static void Mint_InitDma(void);
76 static void Mint_StopReplay(void);
77 static void Mint_StartReplay(void);
78
79 /*--- Audio driver bootstrap functions ---*/
80
81 static int Audio_Available(void)
82 {
83         const char *envr = SDL_getenv("SDL_AUDIODRIVER");
84
85         /* Check if user asked a different audio driver */
86         if ((envr) && (SDL_strcmp(envr, MINT_AUDIO_DRIVER_NAME)!=0)) {
87                 DEBUG_PRINT((DEBUG_NAME "user asked a different audio driver\n"));
88                 return 0;
89         }
90
91         /* Cookie _MCH present ? if not, assume ST machine */
92         if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
93                 cookie_mch = MCH_ST;
94         }
95
96         /* Cookie _SND present ? if not, assume ST machine */
97         if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
98                 cookie_snd = SND_PSG;
99         }
100
101         /* Check if we have 8 bits audio */
102         if ((cookie_snd & SND_8BIT)==0) {
103                 DEBUG_PRINT((DEBUG_NAME "no 8 bits sound\n"));
104             return(0);
105         }
106
107         /* Check if audio is lockable */
108         if (cookie_snd & SND_16BIT) {
109                 if (Locksnd()!=1) {
110                         DEBUG_PRINT((DEBUG_NAME "audio locked by other application\n"));
111                         return(0);
112                 }
113
114                 Unlocksnd();
115         }
116
117         DEBUG_PRINT((DEBUG_NAME "8 bits audio available!\n"));
118         return(1);
119 }
120
121 static void Audio_DeleteDevice(SDL_AudioDevice *device)
122 {
123     SDL_free(device->hidden);
124     SDL_free(device);
125 }
126
127 static SDL_AudioDevice *Audio_CreateDevice(int devindex)
128 {
129         SDL_AudioDevice *this;
130
131         /* Initialize all variables that we clean on shutdown */
132         this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice));
133     if ( this ) {
134         SDL_memset(this, 0, (sizeof *this));
135         this->hidden = (struct SDL_PrivateAudioData *)
136                 SDL_malloc((sizeof *this->hidden));
137     }
138     if ( (this == NULL) || (this->hidden == NULL) ) {
139         SDL_OutOfMemory();
140         if ( this ) {
141             SDL_free(this);
142         }
143         return(0);
144     }
145     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
146
147     /* Set the function pointers */
148     this->OpenAudio   = Mint_OpenAudio;
149     this->CloseAudio  = Mint_CloseAudio;
150     this->LockAudio   = Mint_LockAudio;
151     this->UnlockAudio = Mint_UnlockAudio;
152     this->free        = Audio_DeleteDevice;
153
154     return this;
155 }
156
157 AudioBootStrap MINTAUDIO_DMA8_bootstrap = {
158         MINT_AUDIO_DRIVER_NAME, "MiNT DMA 8 bits audio driver",
159         Audio_Available, Audio_CreateDevice
160 };
161
162 static void Mint_LockAudio(_THIS)
163 {
164         Supexec(Mint_StopReplay);
165 }
166
167 static void Mint_UnlockAudio(_THIS)
168 {
169         Supexec(Mint_StartReplay);
170 }
171
172 static void Mint_CloseAudio(_THIS)
173 {
174         Supexec(Mint_StopReplay);
175
176         DEBUG_PRINT((DEBUG_NAME "closeaudio: replay stopped\n"));
177
178         /* Disable interrupt */
179         Jdisint(MFP_DMASOUND);
180
181         DEBUG_PRINT((DEBUG_NAME "closeaudio: interrupt disabled\n"));
182
183         /* Wait if currently playing sound */
184         while (SDL_MintAudio_mutex != 0) {
185         }
186
187         DEBUG_PRINT((DEBUG_NAME "closeaudio: no more interrupt running\n"));
188
189         /* Clear buffers */
190         if (SDL_MintAudio_audiobuf[0]) {
191                 Mfree(SDL_MintAudio_audiobuf[0]);
192                 SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
193         }
194
195         DEBUG_PRINT((DEBUG_NAME "closeaudio: buffers freed\n"));
196 }
197
198 static int Mint_CheckAudio(_THIS, SDL_AudioSpec *spec)
199 {
200         int i, masterprediv, sfreq;
201         unsigned long masterclock;
202
203         DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",spec->format & 0x00ff));
204         DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
205         DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
206         DEBUG_PRINT(("channels=%d, ", spec->channels));
207         DEBUG_PRINT(("freq=%d\n", spec->freq));
208
209         if (spec->channels > 2)
210                 spec->channels = 2;
211
212         /* Check formats available */
213         spec->format = AUDIO_S8;
214         
215         /* Calculate and select the closest frequency */
216         sfreq=0;
217         masterclock=MASTERCLOCK_STE;
218         masterprediv=MASTERPREDIV_STE;
219         switch(cookie_mch>>16) {
220 /*
221                 case MCH_STE:
222                         masterclock=MASTERCLOCK_STE;
223                         masterprediv=MASTERPREDIV_STE;
224                         break;
225 */
226                 case MCH_TT:
227                         masterclock=MASTERCLOCK_TT;
228                         masterprediv=MASTERPREDIV_TT;
229                         break;
230                 case MCH_F30:
231                 case MCH_ARANYM:
232                         masterclock=MASTERCLOCK_FALCON1;
233                         masterprediv=MASTERPREDIV_FALCON;
234                         sfreq=1;
235                         break;
236         }
237         
238         MINTAUDIO_freqcount=0;
239         for (i=sfreq;i<4;i++) {
240                 SDL_MintAudio_AddFrequency(this, masterclock/(masterprediv*(1<<i)),
241                         masterclock, i-sfreq, -1);
242         }
243
244 #if 1
245         for (i=0; i<MINTAUDIO_freqcount; i++) {
246                 DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
247                         i, MINTAUDIO_frequencies[i].frequency, MINTAUDIO_frequencies[i].masterclock,
248                         MINTAUDIO_frequencies[i].predivisor
249                 ));
250         }
251 #endif
252
253         MINTAUDIO_numfreq=SDL_MintAudio_SearchFrequency(this, spec->freq);
254         spec->freq=MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
255
256         DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",spec->format & 0x00ff));
257         DEBUG_PRINT(("signed=%d, ", ((spec->format & 0x8000)!=0)));
258         DEBUG_PRINT(("big endian=%d, ", ((spec->format & 0x1000)!=0)));
259         DEBUG_PRINT(("channels=%d, ", spec->channels));
260         DEBUG_PRINT(("freq=%d\n", spec->freq));
261
262         return 0;
263 }
264
265 static int Mint_OpenAudio(_THIS, SDL_AudioSpec *spec)
266 {
267         SDL_MintAudio_device = this;
268
269         /* Check audio capabilities */
270         if (Mint_CheckAudio(this, spec)==-1) {
271                 return -1;
272         }
273
274         SDL_CalculateAudioSpec(spec);
275
276         /* Allocate memory for audio buffers in DMA-able RAM */
277         DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", spec->size));
278
279         SDL_MintAudio_audiobuf[0] = Atari_SysMalloc(spec->size *2, MX_STRAM);
280         if (SDL_MintAudio_audiobuf[0]==NULL) {
281                 SDL_SetError("MINT_OpenAudio: Not enough memory for audio buffer");
282                 return (-1);
283         }
284         SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size ;
285         SDL_MintAudio_numbuf=0;
286         SDL_memset(SDL_MintAudio_audiobuf[0], spec->silence, spec->size *2);
287         SDL_MintAudio_audiosize = spec->size;
288         SDL_MintAudio_mutex = 0;
289
290         DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n", SDL_MintAudio_audiobuf[0]));
291         DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n", SDL_MintAudio_audiobuf[1]));
292
293         SDL_MintAudio_CheckFpu();
294
295         /* Set replay tracks */
296         if (cookie_snd & SND_16BIT) {
297                 Settracks(0,0);
298                 Setmontracks(0);
299         }
300
301         Supexec(Mint_InitDma);
302
303         /* Set interrupt */
304         Jdisint(MFP_DMASOUND);
305         Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_Dma8Interrupt);
306         Jenabint(MFP_DMASOUND);
307
308         if (cookie_snd & SND_16BIT) {
309                 if (Setinterrupt(SI_TIMERA, SI_PLAY)<0) {
310                         DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n"));
311                 }
312         }
313
314         Supexec(Mint_StartReplay);
315
316     return(1);  /* We don't use threaded audio */
317 }
318
319 /* Functions called in supervisor mode */
320
321 static void Mint_InitDma(void)
322 {
323         unsigned long buffer;
324         unsigned char mode;
325         SDL_AudioDevice *this = SDL_MintAudio_device;
326
327         Mint_StopReplay();
328
329         /* Set buffer */
330         buffer = (unsigned long) SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
331         DMAAUDIO_IO.start_high = (buffer>>16) & 255;
332         DMAAUDIO_IO.start_mid = (buffer>>8) & 255;
333         DMAAUDIO_IO.start_low = buffer & 255;
334
335         buffer += SDL_MintAudio_audiosize;
336         DMAAUDIO_IO.end_high = (buffer>>16) & 255;
337         DMAAUDIO_IO.end_mid = (buffer>>8) & 255;
338         DMAAUDIO_IO.end_low = buffer & 255;
339
340         mode = 3-MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
341         if (this->spec.channels==1) {
342                 mode |= 1<<7;
343         }
344         DMAAUDIO_IO.sound_ctrl = mode;  
345 }
346
347 static void Mint_StopReplay(void)
348 {
349         /* Stop replay */
350         DMAAUDIO_IO.control=0;
351 }
352
353 static void Mint_StartReplay(void)
354 {
355         /* Start replay */
356         DMAAUDIO_IO.control=3;
357 }