src/audio/mint/SDL_mintaudio_gsxb.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 (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 /* GSXB callbacks */
    67 static void MINTGSXB_GsxbInterrupt(void);
    68 static void MINTGSXB_GsxbNullInterrupt(void);
    69 
    70 static void
    71 MINTGSXB_LockDevice(_THIS)
    72 {
    73     /* Stop replay */
    74     Buffoper(0);
    75 }
    76 
    77 static void
    78 MINTGSXB_UnlockDevice(_THIS)
    79 {
    80     /* Restart replay */
    81     Buffoper(SB_PLA_ENA | SB_PLA_RPT);
    82 }
    83 
    84 static void
    85 MINTGSXB_CloseDevice(_THIS)
    86 {
    87     if (this->hidden != NULL) {
    88         /* Stop replay */
    89         Buffoper(0);
    90 
    91         /* Uninstall interrupt */
    92         if (NSetinterrupt(2, SI_NONE, MINTGSXB_GsxbNullInterrupt) < 0) {
    93             DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed in close\n"));
    94         }
    95 
    96         /* Wait if currently playing sound */
    97         while (SDL_MintAudio_mutex != 0) {
    98         }
    99 
   100         /* Clear buffers */
   101         if (SDL_MintAudio_audiobuf[0]) {
   102             Mfree(SDL_MintAudio_audiobuf[0]);
   103             SDL_MintAudio_audiobuf[0] = SDL_MintAudio_audiobuf[1] = NULL;
   104         }
   105 
   106         /* Unlock sound system */
   107         Unlocksnd();
   108 
   109         SDL_free(this->hidden);
   110         this->hidden = NULL;
   111     }
   112 }
   113 
   114 static int
   115 MINTGSXB_CheckAudio(_THIS)
   116 {
   117     long snd_format;
   118     int i, resolution, format_signed, format_bigendian;
   119     SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
   120     int valid_datatype = 0;
   121 
   122     resolution = SDL_AUDIO_BITSIZE(this->spec.format);
   123     format_signed = SDL_AUDIO_ISSIGNED(this->spec.format);
   124     format_bigendian = SDL_AUDIO_ISBIGENDIAN(this->spec.format);
   125 
   126     DEBUG_PRINT((DEBUG_NAME "asked: %d bits, ", resolution));
   127     DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
   128     DEBUG_PRINT(("signed=%d, ", format_signed));
   129     DEBUG_PRINT(("big endian=%d, ", format_bigendian));
   130     DEBUG_PRINT(("channels=%d, ", this->spec.channels));
   131     DEBUG_PRINT(("freq=%d\n", this->spec.freq));
   132 
   133     if (this->spec.channels > 2) {
   134         this->spec.channels = 2;        /* no more than stereo! */
   135     }
   136 
   137     while ((!valid_datatype) && (test_format)) {
   138         /* Check formats available */
   139         snd_format = Sndstatus(SND_QUERYFORMATS);
   140         this->spec.format = test_format;
   141         resolution = SDL_AUDIO_BITSIZE(this->spec.format);
   142         format_signed = SDL_AUDIO_ISSIGNED(this->spec.format);
   143         format_bigendian = SDL_AUDIO_ISBIGENDIAN(this->spec.format);
   144         switch (test_format) {
   145         case AUDIO_U8:
   146         case AUDIO_S8:
   147             if (snd_format & SND_FORMAT8) {
   148                 valid_datatype = 1;
   149                 snd_format = Sndstatus(SND_QUERY8BIT);
   150             }
   151             break;
   152 
   153         case AUDIO_U16LSB:
   154         case AUDIO_S16LSB:
   155         case AUDIO_U16MSB:
   156         case AUDIO_S16MSB:
   157             if (snd_format & SND_FORMAT16) {
   158                 valid_datatype = 1;
   159                 snd_format = Sndstatus(SND_QUERY16BIT);
   160             }
   161             break;
   162 
   163         case AUDIO_S32LSB:
   164         case AUDIO_S32MSB:
   165             if (snd_format & SND_FORMAT32) {
   166                 valid_datatype = 1;
   167                 snd_format = Sndstatus(SND_QUERY32BIT);
   168             }
   169             break;
   170 
   171             /* no float support... */
   172 
   173         default:
   174             test_format = SDL_NextAudioFormat();
   175             break;
   176         }
   177     }
   178 
   179     if (!valid_datatype) {
   180         SDL_SetError("Unsupported audio format");
   181         return (-1);
   182     }
   183 
   184     /* Check signed/unsigned format */
   185     if (format_signed) {
   186         if (snd_format & SND_FORMATSIGNED) {
   187             /* Ok */
   188         } else if (snd_format & SND_FORMATUNSIGNED) {
   189             /* Give unsigned format */
   190             this->spec.format = this->spec.format & (~SDL_AUDIO_MASK_SIGNED);
   191         }
   192     } else {
   193         if (snd_format & SND_FORMATUNSIGNED) {
   194             /* Ok */
   195         } else if (snd_format & SND_FORMATSIGNED) {
   196             /* Give signed format */
   197             this->spec.format |= SDL_AUDIO_MASK_SIGNED;
   198         }
   199     }
   200 
   201     if (format_bigendian) {
   202         if (snd_format & SND_FORMATBIGENDIAN) {
   203             /* Ok */
   204         } else if (snd_format & SND_FORMATLITTLEENDIAN) {
   205             /* Give little endian format */
   206             this->spec.format = this->spec.format & (~SDL_AUDIO_MASK_ENDIAN);
   207         }
   208     } else {
   209         if (snd_format & SND_FORMATLITTLEENDIAN) {
   210             /* Ok */
   211         } else if (snd_format & SND_FORMATBIGENDIAN) {
   212             /* Give big endian format */
   213             this->spec.format |= SDL_AUDIO_MASK_ENDIAN;
   214         }
   215     }
   216 
   217     /* Calculate and select the closest frequency */
   218     MINTAUDIO_freqcount = 0;
   219     for (i = 1; i < 4; i++) {
   220         SDL_MintAudio_AddFrequency(this,
   221                                    MASTERCLOCK_44K / (MASTERPREDIV_MILAN *
   222                                                       (1 << i)),
   223                                    MASTERCLOCK_44K, (1 << i) - 1, -1);
   224     }
   225 
   226 #if 1
   227     for (i = 0; i < MINTAUDIO_freqcount; i++) {
   228         DEBUG_PRINT((DEBUG_NAME "freq %d: %lu Hz, clock %lu, prediv %d\n",
   229                      i, MINTAUDIO_frequencies[i].frequency,
   230                      MINTAUDIO_frequencies[i].masterclock,
   231                      MINTAUDIO_frequencies[i].predivisor));
   232     }
   233 #endif
   234 
   235     MINTAUDIO_numfreq = SDL_MintAudio_SearchFrequency(this, this->spec.freq);
   236     this->spec.freq = MINTAUDIO_frequencies[MINTAUDIO_numfreq].frequency;
   237 
   238     DEBUG_PRINT((DEBUG_NAME "obtained: %d bits, ",
   239                  SDL_AUDIO_BITSIZE(this->spec.format)));
   240     DEBUG_PRINT(("float=%d, ", SDL_AUDIO_ISFLOAT(this->spec.format)));
   241     DEBUG_PRINT(("signed=%d, ", SDL_AUDIO_ISSIGNED(this->spec.format)));
   242     DEBUG_PRINT(("big endian=%d, ",
   243                  SDL_AUDIO_ISBIGENDIAN(this->spec.format)));
   244     DEBUG_PRINT(("channels=%d, ", this->spec.channels));
   245     DEBUG_PRINT(("freq=%d\n", this->spec.freq));
   246 
   247     return 0;
   248 }
   249 
   250 static void
   251 MINTGSXB_InitAudio(_THIS)
   252 {
   253     int channels_mode, prediv;
   254     void *buffer;
   255 
   256     /* Stop currently playing sound */
   257     Buffoper(0);
   258 
   259     /* Set replay tracks */
   260     Settracks(0, 0);
   261     Setmontracks(0);
   262 
   263     /* Select replay format */
   264     switch (SDL_AUDIO_BITSIZE(this->spec.format)) {
   265     case 8:
   266         if (this->spec.channels == 2) {
   267             channels_mode = STEREO8;
   268         } else {
   269             channels_mode = MONO8;
   270         }
   271         break;
   272     case 16:
   273         if (this->spec.channels == 2) {
   274             channels_mode = STEREO16;
   275         } else {
   276             channels_mode = MONO16;
   277         }
   278         break;
   279     case 32:
   280         if (this->spec.channels == 2) {
   281             channels_mode = STEREO32;
   282         } else {
   283             channels_mode = MONO32;
   284         }
   285         break;
   286     default:
   287         channels_mode = STEREO16;
   288         break;
   289     }
   290     if (Setmode(channels_mode) < 0) {
   291         DEBUG_PRINT((DEBUG_NAME "Setmode() failed\n"));
   292     }
   293 
   294     prediv = MINTAUDIO_frequencies[MINTAUDIO_numfreq].predivisor;
   295     Devconnect(DMAPLAY, DAC, CLKEXT, prediv, 1);
   296 
   297     /* Set buffer */
   298     buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
   299     if (Setbuffer(0, buffer, buffer + this->spec.size) < 0) {
   300         DEBUG_PRINT((DEBUG_NAME "Setbuffer() failed\n"));
   301     }
   302 
   303     /* Install interrupt */
   304     if (NSetinterrupt(2, SI_PLAY, MINTGSXB_GsxbInterrupt) < 0) {
   305         DEBUG_PRINT((DEBUG_NAME "NSetinterrupt() failed\n"));
   306     }
   307 
   308     /* Go */
   309     Buffoper(SB_PLA_ENA | SB_PLA_RPT);
   310     DEBUG_PRINT((DEBUG_NAME "hardware initialized\n"));
   311 }
   312 
   313 static int
   314 MINTGSXB_OpenDevice(_THIS, const char *devname, int iscapture)
   315 {
   316     /* Lock sound system */
   317     if (Locksnd() != 1) {
   318         SDL_SetError("MINTGSXB_OpenDevice: Audio system already in use");
   319         return 0;
   320     }
   321 
   322     SDL_MintAudio_device = this;
   323 
   324     /* Check audio capabilities */
   325     if (MINTGSXB_CheckAudio(this) == -1) {
   326         return 0;
   327     }
   328 
   329     /* Initialize all variables that we clean on shutdown */
   330     this->hidden = (struct SDL_PrivateAudioData *)
   331         SDL_malloc((sizeof *this->hidden));
   332     if (this->hidden == NULL) {
   333         SDL_OutOfMemory();
   334         return 0;
   335     }
   336     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
   337 
   338     SDL_CalculateAudioSpec(&this->spec);
   339 
   340     /* Allocate memory for audio buffers in DMA-able RAM */
   341     DEBUG_PRINT((DEBUG_NAME "buffer size=%d\n", this->spec.size));
   342 
   343     SDL_MintAudio_audiobuf[0] =
   344         Atari_SysMalloc(this->spec.size * 2, MX_STRAM);
   345     if (SDL_MintAudio_audiobuf[0] == NULL) {
   346         SDL_free(this->hidden);
   347         this->hidden = NULL;
   348         SDL_OutOfMemory();
   349         return 0;
   350     }
   351     SDL_MintAudio_audiobuf[1] = SDL_MintAudio_audiobuf[0] + this->spec.size;
   352     SDL_MintAudio_numbuf = 0;
   353     SDL_memset(SDL_MintAudio_audiobuf[0], this->spec.silence,
   354                this->spec.size * 2);
   355     SDL_MintAudio_audiosize = this->spec.size;
   356     SDL_MintAudio_mutex = 0;
   357 
   358     DEBUG_PRINT((DEBUG_NAME "buffer 0 at 0x%08x\n",
   359                  SDL_MintAudio_audiobuf[0]));
   360     DEBUG_PRINT((DEBUG_NAME "buffer 1 at 0x%08x\n",
   361                  SDL_MintAudio_audiobuf[1]));
   362 
   363     SDL_MintAudio_CheckFpu();
   364 
   365     /* Setup audio hardware */
   366     MINTGSXB_InitAudio(this);
   367 
   368     return 1;                   /* good to go. */
   369 }
   370 
   371 static void
   372 MINTGSXB_GsxbInterrupt(void)
   373 {
   374     Uint8 *newbuf;
   375 
   376     if (SDL_MintAudio_mutex)
   377         return;
   378 
   379     SDL_MintAudio_mutex = 1;
   380 
   381     SDL_MintAudio_numbuf ^= 1;
   382     SDL_MintAudio_Callback();
   383     newbuf = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
   384     Setbuffer(0, newbuf, newbuf + SDL_MintAudio_audiosize);
   385 
   386     SDL_MintAudio_mutex = 0;
   387 }
   388 
   389 static void
   390 MINTGSXB_GsxbNullInterrupt(void)
   391 {
   392 }
   393 
   394 static int
   395 MINTGSXB_Init(SDL_AudioDriverImpl * impl)
   396 {
   397     /* Cookie _SND present ? if not, assume ST machine */
   398     if (Getcookie(C__SND, &cookie_snd) == C_NOTFOUND) {
   399         cookie_snd = SND_PSG;
   400     }
   401 
   402     /* Check if we have 16 bits audio */
   403     if ((cookie_snd & SND_16BIT) == 0) {
   404         SDL_SetError(DEBUG_NAME "no 16-bit sound");
   405         return 0;
   406     }
   407 
   408     /* Cookie GSXB present ? */
   409     cookie_gsxb = (Getcookie(C_GSXB, &cookie_gsxb) == C_FOUND);
   410 
   411     /* Is it GSXB ? */
   412     if (((cookie_snd & SND_GSXB) == 0) || (cookie_gsxb == 0)) {
   413         SDL_SetError(DEBUG_NAME "no GSXB audio");
   414         return 0;
   415     }
   416 
   417     /* Check if audio is lockable */
   418     if (Locksnd() != 1) {
   419         SDL_SetError(DEBUG_NAME "audio locked by other application");
   420         return 0;
   421     }
   422 
   423     Unlocksnd();
   424 
   425     DEBUG_PRINT((DEBUG_NAME "GSXB audio available!\n"));
   426 
   427     /* Set the function pointers */
   428     impl->OpenDevice = MINTGSXB_OpenDevice;
   429     impl->CloseDevice = MINTGSXB_CloseDevice;
   430     impl->LockDevice = MINTGSXB_LockDevice;
   431     impl->UnlockDevice = MINTGSXB_UnlockDevice;
   432     impl->OnlyHasDefaultOutputDevice = 1;
   433     impl->ProvidesOwnCallbackThread = 1;
   434     impl->SkipMixerLock = 1;
   435 
   436     return 2;                   /* 2 == definitely has an audio device. */
   437 }
   438 
   439 AudioBootStrap MINTAUDIO_GSXB_bootstrap = {
   440     MINT_AUDIO_DRIVER_NAME, "MiNT GSXB audio driver", MINTGSXB_Init, 0
   441 };
   442 
   443 /* vi: set ts=4 sw=4 expandtab: */