src/audio/mint/SDL_mintaudio_gsxb.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 28 May 2006 13:04:16 +0000
branchSDL-1.3
changeset 1662 782fd950bd46
parent 1412 a8181c4040b8
child 1668 4da1ee79c9af
permissions -rw-r--r--
Revamp of the video system in progress - adding support for multiple displays, multiple windows, and a full video mode selection API.

WARNING: None of the video drivers have been updated for the new API yet! The API is still under design and very fluid.

The code is now run through a consistent indent format:
indent -i4 -nut -nsc -br -ce

The headers are being converted to automatically generate doxygen documentation.
     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 XBIOS functions (GSXB compatible 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_gsxb.h"
    44 
    45 /*--- Defines ---*/
    46 
    47 #define MINT_AUDIO_DRIVER_NAME "mint_gsxb"
    48 
    49 /* Debug print info */
    50 #define DEBUG_NAME "audio:gsxb: "
    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_gsxb;
    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 /* GSXB callbacks */
    76 static void Mint_GsxbInterrupt (void);
    77 static void Mint_GsxbNullInterrupt (void);
    78 
    79 /*--- Audio driver bootstrap functions ---*/
    80 
    81 static int
    82 Audio_Available (void)
    83 {
    84     const char *envr = SDL_getenv ("SDL_AUDIODRIVER");
    85 
    86     /* Check if user asked a different audio driver */
    87     if ((envr) && (SDL_strcmp (envr, MINT_AUDIO_DRIVER_NAME) != 0)) {
    88         DEBUG_PRINT ((DEBUG_NAME "user asked a different audio driver\n"));
    89         return (0);
    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 16 bits audio */
    98     if ((cookie_snd & SND_16BIT) == 0) {
    99         DEBUG_PRINT ((DEBUG_NAME "no 16 bits sound\n"));
   100         return (0);
   101     }
   102 
   103     /* Cookie GSXB present ? */
   104     cookie_gsxb = (Getcookie (C_GSXB, &cookie_gsxb) == C_FOUND);
   105 
   106     /* Is it GSXB ? */
   107     if (((cookie_snd & SND_GSXB) == 0) || (cookie_gsxb == 0)) {
   108         DEBUG_PRINT ((DEBUG_NAME "no GSXB audio\n"));
   109         return (0);
   110     }
   111 
   112     /* Check if audio is lockable */
   113     if (Locksnd () != 1) {
   114         DEBUG_PRINT ((DEBUG_NAME "audio locked by other application\n"));
   115         return (0);
   116     }
   117 
   118     Unlocksnd ();
   119 
   120     DEBUG_PRINT ((DEBUG_NAME "GSXB audio available!\n"));
   121     return (1);
   122 }
   123 
   124 static void
   125 Audio_DeleteDevice (SDL_AudioDevice * device)
   126 {
   127     SDL_free (device->hidden);
   128     SDL_free (device);
   129 }
   130 
   131 static SDL_AudioDevice *
   132 Audio_CreateDevice (int devindex)
   133 {
   134     SDL_AudioDevice *this;
   135 
   136     /* Initialize all variables that we clean on shutdown */
   137     this = (SDL_AudioDevice *) SDL_malloc (sizeof (SDL_AudioDevice));
   138     if (this) {
   139         SDL_memset (this, 0, (sizeof *this));
   140         this->hidden = (struct SDL_PrivateAudioData *)
   141             SDL_malloc ((sizeof *this->hidden));
   142     }
   143     if ((this == NULL) || (this->hidden == NULL)) {
   144         SDL_OutOfMemory ();
   145         if (this) {
   146             SDL_free (this);
   147         }
   148         return (0);
   149     }
   150     SDL_memset (this->hidden, 0, (sizeof *this->hidden));
   151 
   152     /* Set the function pointers */
   153     this->OpenAudio = Mint_OpenAudio;
   154     this->CloseAudio = Mint_CloseAudio;
   155     this->LockAudio = Mint_LockAudio;
   156     this->UnlockAudio = Mint_UnlockAudio;
   157     this->free = Audio_DeleteDevice;
   158 
   159     return this;
   160 }
   161 
   162 AudioBootStrap MINTAUDIO_GSXB_bootstrap = {
   163     MINT_AUDIO_DRIVER_NAME, "MiNT GSXB audio driver",
   164     Audio_Available, Audio_CreateDevice
   165 };
   166 
   167 static void
   168 Mint_LockAudio (_THIS)
   169 {
   170     /* Stop replay */
   171     Buffoper (0);
   172 }
   173 
   174 static void
   175 Mint_UnlockAudio (_THIS)
   176 {
   177     /* Restart replay */
   178     Buffoper (SB_PLA_ENA | SB_PLA_RPT);
   179 }
   180 
   181 static void
   182 Mint_CloseAudio (_THIS)
   183 {
   184     /* Stop replay */
   185     Buffoper (0);
   186 
   187     /* Uninstall interrupt */
   188     if (NSetinterrupt (2, SI_NONE, Mint_GsxbNullInterrupt) < 0) {
   189         DEBUG_PRINT ((DEBUG_NAME "NSetinterrupt() failed in close\n"));
   190     }
   191 
   192     /* Wait if currently playing sound */
   193     while (SDL_MintAudio_mutex != 0) {
   194     }
   195 
   196     /* Clear buffers */
   197     if (SDL_MintAudio_audiobuf[0]) {
   198         Mfree (SDL_MintAudio_audiobuf[0]);
   199         SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
   200     }
   201 
   202     /* Unlock sound system */
   203     Unlocksnd ();
   204 }
   205 
   206 static int
   207 Mint_CheckAudio (_THIS, SDL_AudioSpec * spec)
   208 {
   209     long snd_format;
   210     int i, resolution, format_signed, format_bigendian;
   211 
   212     resolution = spec->format & 0x00ff;
   213     format_signed = ((spec->format & 0x8000) != 0);
   214     format_bigendian = ((spec->format & 0x1000) != 0);
   215 
   216     DEBUG_PRINT ((DEBUG_NAME "asked: %d bits, ", spec->format & 0x00ff));
   217     DEBUG_PRINT (("signed=%d, ", ((spec->format & 0x8000) != 0)));
   218     DEBUG_PRINT (("big endian=%d, ", ((spec->format & 0x1000) != 0)));
   219     DEBUG_PRINT (("channels=%d, ", spec->channels));
   220     DEBUG_PRINT (("freq=%d\n", spec->freq));
   221 
   222     /* Check formats available */
   223     snd_format = Sndstatus (SND_QUERYFORMATS);
   224     switch (resolution) {
   225     case 8:
   226         if ((snd_format & SND_FORMAT8) == 0) {
   227             SDL_SetError ("Mint_CheckAudio: 8 bits samples not supported");
   228             return -1;
   229         }
   230         snd_format = Sndstatus (SND_QUERY8BIT);
   231         break;
   232     case 16:
   233         if ((snd_format & SND_FORMAT16) == 0) {
   234             SDL_SetError ("Mint_CheckAudio: 16 bits samples not supported");
   235             return -1;
   236         }
   237         snd_format = Sndstatus (SND_QUERY16BIT);
   238         break;
   239     default:
   240         SDL_SetError ("Mint_CheckAudio: Unsupported sample resolution");
   241         return -1;
   242         break;
   243     }
   244 
   245     /* Check signed/unsigned format */
   246     if (format_signed) {
   247         if (snd_format & SND_FORMATSIGNED) {
   248             /* Ok */
   249         } else if (snd_format & SND_FORMATUNSIGNED) {
   250             /* Give unsigned format */
   251             spec->format = spec->format & (~0x8000);
   252         }
   253     } else {
   254         if (snd_format & SND_FORMATUNSIGNED) {
   255             /* Ok */
   256         } else if (snd_format & SND_FORMATSIGNED) {
   257             /* Give signed format */
   258             spec->format |= 0x8000;
   259         }
   260     }
   261 
   262     if (format_bigendian) {
   263         if (snd_format & SND_FORMATBIGENDIAN) {
   264             /* Ok */
   265         } else if (snd_format & SND_FORMATLITTLEENDIAN) {
   266             /* Give little endian format */
   267             spec->format = spec->format & (~0x1000);
   268         }
   269     } else {
   270         if (snd_format & SND_FORMATLITTLEENDIAN) {
   271             /* Ok */
   272         } else if (snd_format & SND_FORMATBIGENDIAN) {
   273             /* Give big endian format */
   274             spec->format |= 0x1000;
   275         }
   276     }
   277 
   278     /* Calculate and select the closest frequency */
   279     MINTAUDIO_freqcount = 0;
   280     for (i = 1; i < 4; i++) {
   281         SDL_MintAudio_AddFrequency (this,
   282                                     MASTERCLOCK_44K / (MASTERPREDIV_MILAN *
   283                                                        (1 << i)),
   284                                     MASTERCLOCK_44K, (1 << i) - 1, -1);
   285     }
   286 
   287 #if 1
   288     for (i = 0; i < MINTAUDIO_freqcount; i++) {
   289         DEBUG_PRINT ((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
   290                       i, MINTAUDIO_frequencies[i].frequency,
   291                       MINTAUDIO_frequencies[i].masterclock,
   292                       MINTAUDIO_frequencies[i].predivisor));
   293     }
   294 #endif
   295 
   296     MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency (this, spec->freq);
   297     spec->freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
   298 
   299     DEBUG_PRINT ((DEBUG_NAME "obtained: %d bits, ", spec->format & 0x00ff));
   300     DEBUG_PRINT (("signed=%d, ", ((spec->format & 0x8000) != 0)));
   301     DEBUG_PRINT (("big endian=%d, ", ((spec->format & 0x1000) != 0)));
   302     DEBUG_PRINT (("channels=%d, ", spec->channels));
   303     DEBUG_PRINT (("freq=%d\n", spec->freq));
   304 
   305     return 0;
   306 }
   307 
   308 static void
   309 Mint_InitAudio (_THIS, SDL_AudioSpec * spec)
   310 {
   311     int channels_mode, prediv;
   312     void *buffer;
   313 
   314     /* Stop currently playing sound */
   315     Buffoper (0);
   316 
   317     /* Set replay tracks */
   318     Settracks (0, 0);
   319     Setmontracks (0);
   320 
   321     /* Select replay format */
   322     switch (spec->format & 0xff) {
   323     case 8:
   324         if (spec->channels == 2) {
   325             channels_mode = STEREO8;
   326         } else {
   327             channels_mode = MONO8;
   328         }
   329         break;
   330     case 16:
   331         if (spec->channels == 2) {
   332             channels_mode = STEREO16;
   333         } else {
   334             channels_mode = MONO16;
   335         }
   336         break;
   337     default:
   338         channels_mode = STEREO16;
   339         break;
   340     }
   341     if (Setmode (channels_mode) < 0) {
   342         DEBUG_PRINT ((DEBUG_NAME "Setmode() failed\n"));
   343     }
   344 
   345     prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
   346     Devconnect (DMAPLAY, DAC, CLKEXT, prediv, 1);
   347 
   348     /* Set buffer */
   349     buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
   350     if (Setbuffer (0, buffer, buffer + spec->size) < 0) {
   351         DEBUG_PRINT ((DEBUG_NAME "Setbuffer() failed\n"));
   352     }
   353 
   354     /* Install interrupt */
   355     if (NSetinterrupt (2, SI_PLAY, Mint_GsxbInterrupt) < 0) {
   356         DEBUG_PRINT ((DEBUG_NAME "NSetinterrupt() failed\n"));
   357     }
   358 
   359     /* Go */
   360     Buffoper (SB_PLA_ENA | SB_PLA_RPT);
   361     DEBUG_PRINT ((DEBUG_NAME "hardware initialized\n"));
   362 }
   363 
   364 static int
   365 Mint_OpenAudio (_THIS, SDL_AudioSpec * spec)
   366 {
   367     /* Lock sound system */
   368     if (Locksnd () != 1) {
   369         SDL_SetError ("Mint_OpenAudio: Audio system already in use");
   370         return (-1);
   371     }
   372 
   373     SDL_MintAudio_device = this;
   374 
   375     /* Check audio capabilities */
   376     if (Mint_CheckAudio (this, spec) == -1) {
   377         return -1;
   378     }
   379 
   380     SDL_CalculateAudioSpec (spec);
   381 
   382     /* Allocate memory for audio buffers in DMA-able RAM */
   383     DEBUG_PRINT ((DEBUG_NAME "buffer size=%d\n", spec->size));
   384 
   385     SDL_MintAudio_audiobuf[0] = Atari_SysMalloc (spec->size * 2, MX_STRAM);
   386     if (SDL_MintAudio_audiobuf[0] == NULL) {
   387         SDL_SetError ("MINT_OpenAudio: Not enough memory for audio buffer");
   388         return (-1);
   389     }
   390     SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + spec->size;
   391     SDL_MintAudio_numbuf = 0;
   392     SDL_memset (SDL_MintAudio_audiobuf[0], spec->silence, spec->size * 2);
   393     SDL_MintAudio_audiosize = spec->size;
   394     SDL_MintAudio_mutex = 0;
   395 
   396     DEBUG_PRINT ((DEBUG_NAME "buffer 0 at 0x%08x\n",
   397                   SDL_MintAudio_audiobuf[0]));
   398     DEBUG_PRINT ((DEBUG_NAME "buffer 1 at 0x%08x\n",
   399                   SDL_MintAudio_audiobuf[1]));
   400 
   401     /* Setup audio hardware */
   402     Mint_InitAudio (this, spec);
   403 
   404     return (1);                 /* We don't use threaded audio */
   405 }
   406 
   407 static void
   408 Mint_GsxbInterrupt (void)
   409 {
   410     Uint8 *newbuf;
   411 
   412     if (SDL_MintAudio_mutex)
   413         return;
   414 
   415     SDL_MintAudio_mutex = 1;
   416 
   417     SDL_MintAudio_numbuf ^= 1;
   418     SDL_MintAudio_Callback ();
   419     newbuf = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
   420     Setbuffer (0, newbuf, newbuf + SDL_MintAudio_audiosize);
   421 
   422     SDL_MintAudio_mutex = 0;
   423 }
   424 
   425 static void
   426 Mint_GsxbNullInterrupt (void)
   427 {
   428 }
   429 
   430 /* vi: set ts=4 sw=4 expandtab: */