src/audio/dmedia/SDL_irixaudio.c
author Ryan C. Gordon <icculus@icculus.org>
Fri, 01 Sep 2006 00:04:07 +0000
changeset 2002 7590aaf89a60
parent 1895 c121d94672cb
child 2043 adf732f1f016
permissions -rw-r--r--
Cleaned up IRIX audio driver, added float32 support and fallbacks when
a specific audiospec isn't supported or the hardware fails.

Usual disclaimer: No IRIX box, so this may not even compile.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997-2006 Sam Lantinga
     4 
     5     This library is free software; you can redistribute it and/or
     6     modify it under the terms of the GNU Lesser General Public
     7     License as published by the Free Software Foundation; either
     8     version 2.1 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     Lesser General Public License for more details.
    14 
    15     You should have received a copy of the GNU Lesser General Public
    16     License along with this library; if not, write to the Free Software
    17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include <errno.h>
    23 #include "SDL_config.h"
    24 
    25 /* Allow access to a raw mixing buffer (For IRIX 6.5 and higher) */
    26 /* patch for IRIX 5 by Georg Schwarz 18/07/2004 */
    27 
    28 #include "SDL_timer.h"
    29 #include "SDL_audio.h"
    30 #include "../SDL_audiomem.h"
    31 #include "../SDL_audio_c.h"
    32 #include "SDL_irixaudio.h"
    33 
    34 
    35 #ifndef AL_RESOURCE             /* as a test whether we use the old IRIX audio libraries */
    36 #define OLD_IRIX_AUDIO
    37 #define alClosePort(x) ALcloseport(x)
    38 #define alFreeConfig(x) ALfreeconfig(x)
    39 #define alGetFillable(x) ALgetfillable(x)
    40 #define alNewConfig() ALnewconfig()
    41 #define alOpenPort(x,y,z) ALopenport(x,y,z)
    42 #define alSetChannels(x,y) ALsetchannels(x,y)
    43 #define alSetQueueSize(x,y) ALsetqueuesize(x,y)
    44 #define alSetSampFmt(x,y) ALsetsampfmt(x,y)
    45 #define alSetWidth(x,y) ALsetwidth(x,y)
    46 #endif
    47 
    48 /* Audio driver functions */
    49 static int AL_OpenAudio(_THIS, SDL_AudioSpec * spec);
    50 static void AL_WaitAudio(_THIS);
    51 static void AL_PlayAudio(_THIS);
    52 static Uint8 *AL_GetAudioBuf(_THIS);
    53 static void AL_CloseAudio(_THIS);
    54 
    55 /* Audio driver bootstrap functions */
    56 
    57 static int
    58 Audio_Available(void)
    59 {
    60     return 1;
    61 }
    62 
    63 static void
    64 Audio_DeleteDevice(SDL_AudioDevice * device)
    65 {
    66     SDL_free(device->hidden);
    67     SDL_free(device);
    68 }
    69 
    70 static SDL_AudioDevice *
    71 Audio_CreateDevice(int devindex)
    72 {
    73     SDL_AudioDevice *this;
    74 
    75     /* Initialize all variables that we clean on shutdown */
    76     this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
    77     if (this) {
    78         SDL_memset(this, 0, (sizeof *this));
    79         this->hidden = (struct SDL_PrivateAudioData *)
    80             SDL_malloc((sizeof *this->hidden));
    81     }
    82     if ((this == NULL) || (this->hidden == NULL)) {
    83         SDL_OutOfMemory();
    84         if (this) {
    85             SDL_free(this);
    86         }
    87         return (0);
    88     }
    89     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
    90 
    91     /* Set the function pointers */
    92     this->OpenAudio = AL_OpenAudio;
    93     this->WaitAudio = AL_WaitAudio;
    94     this->PlayAudio = AL_PlayAudio;
    95     this->GetAudioBuf = AL_GetAudioBuf;
    96     this->CloseAudio = AL_CloseAudio;
    97 
    98     this->free = Audio_DeleteDevice;
    99 
   100     return this;
   101 }
   102 
   103 AudioBootStrap DMEDIA_bootstrap = {
   104     "AL", "IRIX DMedia audio",
   105     Audio_Available, Audio_CreateDevice
   106 };
   107 
   108 
   109 void static
   110 AL_WaitAudio(_THIS)
   111 {
   112     Sint32 timeleft;
   113 
   114     timeleft = this->spec.samples - alGetFillable(audio_port);
   115     if (timeleft > 0) {
   116         timeleft /= (this->spec.freq / 1000);
   117         SDL_Delay((Uint32) timeleft);
   118     }
   119 }
   120 
   121 static void
   122 AL_PlayAudio(_THIS)
   123 {
   124     /* Write the audio data out */
   125     if (alWriteFrames(audio_port, mixbuf, this->spec.samples) < 0) {
   126         /* Assume fatal error, for now */
   127         this->enabled = 0;
   128     }
   129 }
   130 
   131 static Uint8 *
   132 AL_GetAudioBuf(_THIS)
   133 {
   134     return (mixbuf);
   135 }
   136 
   137 static void
   138 AL_CloseAudio(_THIS)
   139 {
   140     if (mixbuf != NULL) {
   141         SDL_FreeAudioMem(mixbuf);
   142         mixbuf = NULL;
   143     }
   144     if (audio_port != NULL) {
   145         alClosePort(audio_port);
   146         audio_port = NULL;
   147     }
   148 }
   149 
   150 static int
   151 AL_OpenAudio(_THIS, SDL_AudioSpec * spec)
   152 {
   153     SDL_AudioFormat test_format = SDL_FirstAudioFormat(spec->format);
   154     long width = 0;
   155     long fmt = 0;
   156     int valid = 0;
   157 
   158 #ifdef OLD_IRIX_AUDIO
   159     {
   160         long audio_param[2];
   161         audio_param[0] = AL_OUTPUT_RATE;
   162         audio_param[1] = spec->freq;
   163         valid = (ALsetparams(AL_DEFAULT_DEVICE, audio_param, 2) < 0);
   164     }
   165 #else
   166     {
   167         ALpv audio_param;
   168         audio_param.param = AL_RATE;
   169         audio_param.value.i = spec->freq;
   170         valid = (alSetParams(AL_DEFAULT_OUTPUT, &audio_param, 1) < 0);
   171     }
   172 #endif
   173 
   174     while ((!valid) && (test_format)) {
   175         valid = 1;
   176         spec->format = test_format;
   177 
   178         switch (test_format) {
   179             case AUDIO_S8:
   180                 width = AL_SAMPLE_8;
   181                 fmt = AL_SAMPFMT_TWOSCOMP;
   182                 break;
   183 
   184             case AUDIO_S16SYS:
   185                 width = AL_SAMPLE_16;
   186                 fmt = AL_SAMPFMT_TWOSCOMP;
   187                 break;
   188 
   189             case AUDIO_F32SYS:
   190                 width = 0;  /* not used here... */
   191                 fmt = AL_SAMPFMT_FLOAT;
   192                 break;
   193 
   194             /* Docs say there is int24, but not int32.... */
   195 
   196             default:
   197                 valid = 0;
   198                 test_format = SDL_NextAudioFormat();
   199                 break;
   200         }
   201 
   202         if (valid) {
   203             ALconfig audio_config = alNewConfig();
   204             valid = 0;
   205             if (audio_config) {
   206                 if (alSetChannels(audio_config, spec->channels) < 0) {
   207                     if (spec->channels > 2) {  /* can't handle > stereo? */
   208                         spec->channels = 2;  /* try again below. */
   209                     }
   210                 }
   211 
   212                 if ((alSetSampFmt(audio_config, fmt) >= 0) &&
   213                     ((!width) || (alSetWidth(audio_config, width) >= 0)) &&
   214                     (alSetQueueSize(audio_config, spec->samples * 2) >= 0) &&
   215                     (alSetChannels(audio_config, spec->channels) >= 0)) {
   216 
   217                     audio_port = alOpenPort("SDL audio", "w", audio_config);
   218                     if (audio_port == NULL) {
   219                         /* docs say AL_BAD_CHANNELS happens here, too. */
   220                         int err = oserror();
   221                         if (err == AL_BAD_CHANNELS) {
   222                             spec->channels = 2;
   223                             alSetChannels(audio_config, spec->channels);
   224                             audio_port = alOpenPort("SDL audio", "w",
   225                                                     audio_config);
   226                         }
   227                     }
   228 
   229                     if (audio_port != NULL) {
   230                         valid = 1;
   231                     }
   232                 }
   233 
   234                 alFreeConfig(audio_config);
   235             }
   236         }
   237     }
   238 
   239     if (!valid) {
   240         SDL_SetError("Unsupported audio format");
   241         return (-1);
   242     }
   243 
   244     /* Update the fragment size as size in bytes */
   245     SDL_CalculateAudioSpec(spec);
   246 
   247     /* Allocate mixing buffer */
   248     mixbuf = (Uint8 *) SDL_AllocAudioMem(spec->size);
   249     if (mixbuf == NULL) {
   250         SDL_OutOfMemory();
   251         return (-1);
   252     }
   253     SDL_memset(mixbuf, spec->silence, spec->size);
   254 
   255     /* We're ready to rock and roll. :-) */
   256     return (0);
   257 }
   258 
   259 /* vi: set ts=4 sw=4 expandtab: */