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