src/audio/mint/SDL_mintaudio_stfa.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 XBIOS functions (STFA driver)
    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_stfa.h"
    44 
    45 /*--- Defines ---*/
    46 
    47 #define MINT_AUDIO_DRIVER_NAME "mint_stfa"
    48 
    49 /* Debug print info */
    50 #define DEBUG_NAME "audio:stfa: "
    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 = 0;
    63 static unsigned long cookie_mch = 0;
    64 static cookie_stfa_t *cookie_stfa = NULL;
    65 
    66 static const int freqs[16] = {
    67     4995, 6269, 7493, 8192,
    68     9830, 10971, 12538, 14985,
    69     16384, 19819, 21943, 24576,
    70     30720, 32336, 43885, 49152
    71 };
    72 
    73 static void
    74 MINTSTFA_LockDevice(_THIS)
    75 {
    76     /* Stop replay */
    77     void *oldpile = (void *) Super(0);
    78     cookie_stfa->sound_enable = STFA_PLAY_DISABLE;
    79     Super(oldpile);
    80 }
    81 
    82 static void
    83 MINTSTFA_UnlockDevice(_THIS)
    84 {
    85     /* Restart replay */
    86     void *oldpile = (void *) Super(0);
    87     cookie_stfa->sound_enable = STFA_PLAY_ENABLE | STFA_PLAY_REPEAT;
    88     Super(oldpile);
    89 }
    90 
    91 static void
    92 MINTSTFA_CloseDevice(_THIS)
    93 {
    94     if (this->hidden != NULL) {
    95         /* Stop replay */
    96         void *oldpile = (void *) Super(0);
    97         cookie_stfa->sound_enable = STFA_PLAY_DISABLE;
    98         Super(oldpile);
    99 
   100         /* Wait if currently playing sound */
   101         while (SDL_MintAudio_mutex != 0) {
   102         }
   103 
   104         /* Clear buffers */
   105         if (SDL_MintAudio_audiobuf[0]) {
   106             Mfree(SDL_MintAudio_audiobuf[0]);
   107             SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
   108         }
   109 
   110         SDL_free(this->hidden);
   111         this->hidden = NULL;
   112     }
   113 }
   114 
   115 static int
   116 MINTSTFA_CheckAudio(_THIS)
   117 {
   118     int i;
   119 
   120     DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ",
   121                  SDL_AUDIO_BITSIZE(this->spec.format)));
   122     DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
   123     DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
   124     DEBUG_PRINT(("big endian=%d, ",
   125                  SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
   126     DEBUG_PRINT(("channels=%d, ", this->spec.channels));
   127     DEBUG_PRINT(("freq=%d\n", this->spec.freq));
   128 
   129     if (SDL_AUDIO_BITSIZE(this->spec.format) > 16) {
   130         this->spec.format = AUDIO_S16SYS;       /* clamp out int32/float32 ... */
   131     }
   132 
   133     if (this->spec.channels > 2) {
   134         this->spec.channels = 2;        /* no more than stereo! */
   135     }
   136 
   137     /* Check formats available */
   138     MINTAUDIO_freqcount = 0;
   139     for (i = 0; i < 16; i++) {
   140         SDL_MintAudio_AddFrequency(this, freqs[i], 0, i, -1);
   141     }
   142 
   143 #if 1
   144     for (i = 0; i < MINTAUDIO_freqcount; i++) {
   145         DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
   146                      i, MINTAUDIO_frequencies[i].frequency,
   147                      MINTAUDIO_frequencies[i].masterclock,
   148                      MINTAUDIO_frequencies[i].predivisor));
   149     }
   150 #endif
   151 
   152     MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
   153     this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
   154 
   155     DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
   156                  SDL_AUDIO_BITSIZE(this->spec.format)));
   157     DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
   158     DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
   159     DEBUG_PRINT(("big endian=%d, ",
   160                  SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
   161     DEBUG_PRINT(("channels=%d, ", this->spec.channels));
   162     DEBUG_PRINT(("freq=%d\n", this->spec.freq));
   163 
   164     return 0;
   165 }
   166 
   167 static void
   168 MINTSTFA_InitAudio(_THIS)
   169 {
   170     void *buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
   171     void *oldpile = (void *) Super(0);
   172 
   173     /* Stop replay */
   174     cookie_stfa->sound_enable = STFA_PLAY_DISABLE;
   175 
   176     /* Select replay format */
   177     cookie_stfa->sound_control =
   178         MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
   179     if (SDL_AUDIO_BITSIZE(this->spec.format) == 8) {
   180         cookie_stfa->sound_control |= STFA_FORMAT_8BIT;
   181     } else {
   182         cookie_stfa->sound_control |= STFA_FORMAT_16BIT;
   183     }
   184     if (this->spec.channels == 2) {
   185         cookie_stfa->sound_control |= STFA_FORMAT_STEREO;
   186     } else {
   187         cookie_stfa->sound_control |= STFA_FORMAT_MONO;
   188     }
   189     if (SDL_AUDIO_ISSIGNED(this->spec.format) != 0) {
   190         cookie_stfa->sound_control |= STFA_FORMAT_SIGNED;
   191     } else {
   192         cookie_stfa->sound_control |= STFA_FORMAT_UNSIGNED;
   193     }
   194     if (SDL_AUDIO_ISBIGENDIAN(this->spec.format) != 0) {
   195         cookie_stfa->sound_control |= STFA_FORMAT_BIGENDIAN;
   196     } else {
   197         cookie_stfa->sound_control |= STFA_FORMAT_LITENDIAN;
   198     }
   199 
   200     /* Set buffer */
   201     cookie_stfa->sound_start = (unsigned long) buffer;
   202     cookie_stfa->sound_end = (unsigned long) (buffer + this->spec.size);
   203 
   204     /* Set interrupt */
   205     cookie_stfa->stfa_it = SDL_MintAudio_StfaInterrupt;
   206 
   207     /* Restart replay */
   208     cookie_stfa->sound_enable = STFA_PLAY_ENABLE | STFA_PLAY_REPEAT;
   209 
   210     Super(oldpile);
   211 
   212     DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
   213 }
   214 
   215 static int
   216 MINTSTFA_OpenDevice(_THIS, const char *devname, int iscapture)
   217 {
   218     SDL_MintAudio_device = this;
   219 
   220     /* Check audio capabilities */
   221     if (MINTSTFA_CheckAudio(this) == -1) {
   222         return 0;
   223     }
   224 
   225     /* Initialize all variables that we clean on shutdown */
   226     this->hidden = (struct SDL_PrivateAudioData *)
   227         SDL_malloc((sizeof *this->hidden));
   228     if (this->hidden == NULL) {
   229         SDL_OutOfMemory();
   230         return 0;
   231     }
   232     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
   233 
   234     SDL_CalculateAudioSpec(&this->spec);
   235 
   236     /* Allocate memory for audio buffers in DMA-able RAM */
   237     DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", this->spec.size));
   238 
   239     SDL_MintAudio_audiobuf[0] =
   240         Atari_SysMalloc(this->spec.size * 2, MX_STRAM);
   241     if (SDL_MintAudio_audiobuf[0] == NULL) {
   242         SDL_OutOfMemory();
   243         SDL_free(this->hidden);
   244         this->hidden = NULL;
   245         return 0;
   246     }
   247     SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + this->spec.size;
   248     SDL_MintAudio_numbuf = 0;
   249     SDL_memset(SDL_MintAudio_audiobuf[0], this->spec.silence,
   250                this->spec.size * 2);
   251     SDL_MintAudio_audiosize = this->spec.size;
   252     SDL_MintAudio_mutex = 0;
   253 
   254     DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
   255                  SDL_MintAudio_audiobuf[0]));
   256     DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n",
   257                  SDL_MintAudio_audiobuf[1]));
   258 
   259     SDL_MintAudio_CheckFpu();
   260 
   261     /* Setup audio hardware */
   262     MINTSTFA_InitAudio(this);
   263 
   264     return 1;                   /* good to go. */
   265 }
   266 
   267 
   268 static int
   269 MINTSTFA_Init(SDL_AudioDriverImpl * impl)
   270 {
   271     /* Cookie _MCH present ? if not, assume ST machine */
   272     if (Getcookie(C__MCH, &cookie_mch) == C_NOTFOUND) {
   273         cookie_mch = MCH_ST;
   274     }
   275 
   276     /* Cookie _SND present ? if not, assume ST machine */
   277     if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
   278         cookie_snd = SND_PSG;
   279     }
   280 
   281     /* Cookie STFA present ? */
   282     if (Getcookie(C_STFA, (long *) &cookie_stfa) != C_FOUND) {
   283         SDL_SetError(DEBUG_NAME "no STFA audio");
   284         return (0);
   285     }
   286 
   287     SDL_MintAudio_stfa = cookie_stfa;
   288 
   289     DEBUG_PRINT((DEBUG_NAME "STFA audio available!\n"));
   290 
   291     /* Set the function pointers */
   292     impl->OpenDevice = MINTSTFA_OpenDevice;
   293     impl->CloseDevice = MINTSTFA_CloseDevice;
   294     impl->LockDevice = MINTSTFA_LockDevice;
   295     impl->UnlockDevice = MINTSTFA_UnlockDevice;
   296     impl->OnlyHasDefaultOutputDevice = 1;
   297     impl->ProvidesOwnCallbackThread = 1;
   298     impl->SkipMixerLock = 1;
   299 
   300     return 2;                   /* 2 == definitely has an audio device. */
   301 }
   302 
   303 AudioBootStrap MINTAUDIO_STFA_bootstrap = {
   304     MINT_AUDIO_DRIVER_NAME, "MiNT STFA audio driver", MINTSTFA_Init, 0
   305 };
   306 
   307 /* vi: set ts=4 sw=4 expandtab: */