src/audio/mint/SDL_mintaudio_dma8.c
author Sam Lantinga
Sat, 19 Sep 2009 13:29:40 +0000
changeset 3280 00cace2d9080
parent 2942 1e431c2631ee
permissions -rw-r--r--
Merged a cleaned up version of Jiang's code changes from Google Summer of Code 2009
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2009 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 static void
    65 MINTDMA8_LockDevice(_THIS)
    66 {
    67     void *oldpile;
    68 
    69     /* Stop replay */
    70     oldpile = (void *) Super(0);
    71     DMAAUDIO_IO.control = 0;
    72     Super(oldpile);
    73 }
    74 
    75 static void
    76 MINTDMA8_UnlockDevice(_THIS)
    77 {
    78     void *oldpile;
    79 
    80     /* Restart replay */
    81     oldpile = (void *) Super(0);
    82     DMAAUDIO_IO.control = 3;
    83     Super(oldpile);
    84 }
    85 
    86 static void
    87 MINTDMA8_CloseDevice(_THIS)
    88 {
    89     if (this->hidden != NULL) {
    90         /* Stop replay */
    91         void *oldpile = (void *) Super(0);
    92 
    93         DMAAUDIO_IO.control = 0;
    94         Super(oldpile);
    95 
    96         DEBUG_PRINT((DEBUG_NAME "closeaudio: replay stopped\n"));
    97 
    98         /* Disable interrupt */
    99         Jdisint(MFP_DMASOUND);
   100 
   101         DEBUG_PRINT((DEBUG_NAME "closeaudio: interrupt disabled\n"));
   102 
   103         /* Wait if currently playing sound */
   104         while (SDL_MintAudio_mutex != 0) {
   105         }
   106 
   107         DEBUG_PRINT((DEBUG_NAME "closeaudio: no more interrupt running\n"));
   108 
   109         /* Clear buffers */
   110         if (SDL_MintAudio_audiobuf[0]) {
   111             Mfree(SDL_MintAudio_audiobuf[0]);
   112             SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
   113         }
   114 
   115         DEBUG_PRINT((DEBUG_NAME "closeaudio: buffers freed\n"));
   116         SDL_free(this->hidden);
   117         this->hidden = NULL;
   118     }
   119 }
   120 
   121 static int
   122 MINTDMA8_CheckAudio(_THIS)
   123 {
   124     int i, masterprediv, sfreq;
   125     unsigned long masterclock;
   126 
   127     DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",
   128                  SDL_AUDIO_BITSIZE(this->spec.format)));
   129     DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
   130     DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
   131     DEBUG_PRINT(("big endian=%d, ",
   132                  SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
   133     DEBUG_PRINT(("channels=%d, ", this->spec.channels));
   134     DEBUG_PRINT(("freq=%d\n", this->spec.freq));
   135 
   136     if (this->spec.channels > 2) {
   137         this->spec.channels = 2;        /* no more than stereo! */
   138     }
   139 
   140     /* Check formats available */
   141     this->spec.format = AUDIO_S8;
   142 
   143     /* Calculate and select the closest frequency */
   144     sfreq = 0;
   145     masterclock = MASTERCLOCK_STE;
   146     masterprediv = MASTERPREDIV_STE;
   147     switch (cookie_mch >> 16) {
   148 /*
   149 		case MCH_STE:
   150 			masterclock=MASTERCLOCK_STE;
   151 			masterprediv=MASTERPREDIV_STE;
   152 			break;
   153 */
   154     case MCH_TT:
   155         masterclock = MASTERCLOCK_TT;
   156         masterprediv = MASTERPREDIV_TT;
   157         break;
   158     case MCH_F30:
   159     case MCH_ARANYM:
   160         masterclock = MASTERCLOCK_FALCON1;
   161         masterprediv = MASTERPREDIV_FALCON;
   162         sfreq = 1;
   163         break;
   164     }
   165 
   166     MINTAUDIO_freqcount = 0;
   167     for (i = sfreq; i < 4; i++) {
   168         SDL_MintAudio_AddFrequency(this,
   169                                    masterclock / (masterprediv * (1 << i)),
   170                                    masterclock, i - sfreq, -1);
   171     }
   172 
   173 #if 1
   174     for (i = 0; i < MINTAUDIO_freqcount; i++) {
   175         DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
   176                      i, MINTAUDIO_frequencies[i].frequency,
   177                      MINTAUDIO_frequencies[i].masterclock,
   178                      MINTAUDIO_frequencies[i].predivisor));
   179     }
   180 #endif
   181 
   182     MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
   183     this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
   184 
   185     DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
   186                  SDL_AUDIO_BITSIZE(this->spec.format)));
   187     DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
   188     DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
   189     DEBUG_PRINT(("big endian=%d, ",
   190                  SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
   191     DEBUG_PRINT(("channels=%d, ", this->spec.channels));
   192     DEBUG_PRINT(("freq=%d\n", this->spec.freq));
   193 
   194     return 0;
   195 }
   196 
   197 static void
   198 MINTDMA8_InitAudio(_THIS)
   199 {
   200     void *oldpile;
   201     unsigned long buffer;
   202     unsigned char mode;
   203 
   204     /* Set replay tracks */
   205     if (cookie_snd & SND_16BIT) {
   206         Settracks(0, 0);
   207         Setmontracks(0);
   208     }
   209 
   210     oldpile = (void *) Super(0);
   211 
   212     /* Stop currently playing sound */
   213     DMAAUDIO_IO.control = 0;
   214 
   215     /* Set buffer */
   216     buffer = (unsigned long) SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
   217     DMAAUDIO_IO.start_high = (buffer >> 16) & 255;
   218     DMAAUDIO_IO.start_mid = (buffer >> 8) & 255;
   219     DMAAUDIO_IO.start_low = buffer & 255;
   220 
   221     buffer += SDL_MintAudio_audiosize;
   222     DMAAUDIO_IO.end_high = (buffer >> 16) & 255;
   223     DMAAUDIO_IO.end_mid = (buffer >> 8) & 255;
   224     DMAAUDIO_IO.end_low = buffer & 255;
   225 
   226     mode = 3 - MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
   227     if (this->spec.channels == 1) {
   228         mode |= 1 << 7;
   229     }
   230     DMAAUDIO_IO.sound_ctrl = mode;
   231 
   232     /* Set interrupt */
   233     Jdisint(MFP_DMASOUND);
   234     Xbtimer(XB_TIMERA, 8, 1, SDL_MintAudio_Dma8Interrupt);
   235     Jenabint(MFP_DMASOUND);
   236 
   237     if (cookie_snd & SND_16BIT) {
   238         if (Setinterrupt(SI_TIMERA, SI_PLAY) < 0) {
   239             DEBUG_PRINT((DEBUG_NAME "Setinterrupt() failed\n"));
   240         }
   241     }
   242 
   243     /* Go */
   244     DMAAUDIO_IO.control = 3;    /* playback + repeat */
   245 
   246     Super(oldpile);
   247 }
   248 
   249 static int
   250 MINTDMA8_OpenDevice(_THIS, const char *devname, int iscapture)
   251 {
   252     SDL_MintAudio_device = this;
   253 
   254     /* Check audio capabilities */
   255     if (MINTDMA8_CheckAudio(this) == -1) {
   256         return 0;
   257     }
   258 
   259     /* Initialize all variables that we clean on shutdown */
   260     this->hidden = (struct SDL_PrivateAudioData *)
   261         SDL_malloc((sizeof *this->hidden));
   262     if (this->hidden == NULL) {
   263         SDL_OutOfMemory();
   264         return 0;
   265     }
   266     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
   267 
   268     SDL_CalculateAudioSpec(&this->spec);
   269 
   270     /* Allocate memory for audio buffers in DMA-able RAM */
   271     DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", this->spec.size));
   272 
   273     SDL_MintAudio_audiobuf[0] =
   274         Atari_SysMalloc(this->spec.size * 2, MX_STRAM);
   275     if (SDL_MintAudio_audiobuf[0] == NULL) {
   276         SDL_free(this->hidden);
   277         this->hidden = NULL;
   278         SDL_OutOfMemory();
   279         return 0;
   280     }
   281     SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + this->spec.size;
   282     SDL_MintAudio_numbuf = 0;
   283     SDL_memset(SDL_MintAudio_audiobuf[0], this->spec.silence,
   284                this->spec.size * 2);
   285     SDL_MintAudio_audiosize = this->spec.size;
   286     SDL_MintAudio_mutex = 0;
   287 
   288     DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
   289                  SDL_MintAudio_audiobuf[0]));
   290     DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n",
   291                  SDL_MintAudio_audiobuf[1]));
   292 
   293     SDL_MintAudio_CheckFpu();
   294 
   295     /* Setup audio hardware */
   296     MINTDMA8_InitAudio(this);
   297 
   298     return 1;                   /* good to go. */
   299 }
   300 
   301 static int
   302 MINTDMA8_Init(SDL_AudioDriverImpl * impl)
   303 {
   304     /* Cookie _MCH present ? if not, assume ST machine */
   305     if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
   306         cookie_mch = MCH_ST;
   307     }
   308 
   309     /* Cookie _SND present ? if not, assume ST machine */
   310     if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
   311         cookie_snd = SND_PSG;
   312     }
   313 
   314     /* Check if we have 8 bits audio */
   315     if ((cookie_snd & SND_8BIT) == 0) {
   316         SDL_SetError(DEBUG_NAME "no 8 bits sound");
   317         return 0;
   318     }
   319 
   320     /* Check if audio is lockable */
   321     if (cookie_snd & SND_16BIT) {
   322         if (Locksnd() != 1) {
   323             SDL_SetError(DEBUG_NAME "audio locked by other application");
   324             return 0;
   325         }
   326 
   327         Unlocksnd();
   328     }
   329 
   330     DEBUG_PRINT((DEBUG_NAME "8 bits audio available!\n"));
   331 
   332     /* Set the function pointers */
   333     impl->OpenDevice = MINTDMA8_OpenDevice;
   334     impl->CloseDevice = MINTDMA8_CloseDevice;
   335     impl->LockDevice = MINTDMA8_LockDevice;
   336     impl->UnlockDevice = MINTDMA8_UnlockDevice;
   337     impl->OnlyHasDefaultOutputDevice = 1;
   338     impl->ProvidesOwnCallbackThread = 1;
   339     impl->SkipMixerLock = 1;
   340 
   341     return 2;                   /* 2 == definitely has an audio device. */
   342 }
   343 
   344 AudioBootStrap MINTAUDIO_DMA8_bootstrap = {
   345     MINT_AUDIO_DRIVER_NAME, "MiNT DMA 8 bits audio driver", MINTDMA8_Init, 0
   346 };
   347 
   348 /* vi: set ts=4 sw=4 expandtab: */