src/audio/riscos/SDL_drenderer.c
changeset 630 550bccdf04bd
child 769 b8d311d90021
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/audio/riscos/SDL_drenderer.c	Thu May 29 04:44:13 2003 +0000
     1.3 @@ -0,0 +1,293 @@
     1.4 +/*
     1.5 +    SDL - Simple DirectMedia Layer
     1.6 +    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
     1.7 +
     1.8 +    This library is free software; you can redistribute it and/or
     1.9 +    modify it under the terms of the GNU Library General Public
    1.10 +    License as published by the Free Software Foundation; either
    1.11 +    version 2 of the License, or (at your option) any later version.
    1.12 +
    1.13 +    This library is distributed in the hope that it will be useful,
    1.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.16 +    Library General Public License for more details.
    1.17 +
    1.18 +    You should have received a copy of the GNU Library General Public
    1.19 +    License along with this library; if not, write to the Free
    1.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    1.21 +
    1.22 +    Sam Lantinga
    1.23 +    slouken@devolution.com
    1.24 +*/
    1.25 +
    1.26 +
    1.27 +#include <stdlib.h>
    1.28 +#include <stdio.h>
    1.29 +#include <memory.h>
    1.30 +
    1.31 +#include <kernel.h>
    1.32 +#include "swis.h"
    1.33 +
    1.34 +#include "SDL_endian.h"
    1.35 +#include "SDL_audio.h"
    1.36 +#include "SDL_audio_c.h"
    1.37 +#include "SDL_audiomem.h"
    1.38 +#include "SDL_sysaudio.h"
    1.39 +#include "SDL_drenderer.h"
    1.40 +
    1.41 +#define DigitalRenderer_Activate    0x4F700
    1.42 +#define DigitalRenderer_Deactivate	0x4F701
    1.43 +#define DigitalRenderer_ReadState	0x4F705
    1.44 +#define DigitalRenderer_NewSample	0x4F706
    1.45 +#define DigitalRenderer_NumBuffers	0x4F709
    1.46 +#define DigitalRenderer_StreamSamples  0x4F70A
    1.47 +#define DigitalRenderer_Stream16BitSamples	0x4F70B
    1.48 +#define DigitalRenderer_StreamStatistics	0x4F70C
    1.49 +#define DigitalRenderer_StreamFlags     0x4F70D
    1.50 +#define DigitalRenderer_Activate16		0x4F70F
    1.51 +#define DigitalRenderer_GetFrequency	0x4F710
    1.52 +
    1.53 +static int FillBuffer;
    1.54 +extern SDL_AudioDevice *current_audio;
    1.55 +
    1.56 +extern int riscos_audiobuffer; /* Override for audio buffer size */
    1.57 +
    1.58 +/* Audio driver functions */
    1.59 +
    1.60 +static void DRenderer_CloseAudio(_THIS);
    1.61 +static int DRenderer_OpenAudio(_THIS, SDL_AudioSpec *spec);
    1.62 +
    1.63 +/* Audio driver bootstrap functions */
    1.64 +
    1.65 +/* Define following to dump stats to stdout */
    1.66 +/* #define DUMP_AUDIO */
    1.67 +
    1.68 +
    1.69 +static int Audio_Available(void)
    1.70 +{
    1.71 +	_kernel_swi_regs regs;
    1.72 +	int available = 0;
    1.73 +
    1.74 +	/* Use call to set buffers to also check if Module is loaded */
    1.75 +	regs.r[0] = 0;
    1.76 +	if (_kernel_swi(DigitalRenderer_NumBuffers, &regs, &regs) == 0) available = 1;
    1.77 +
    1.78 +    return(available);
    1.79 +}
    1.80 +
    1.81 +static void Audio_DeleteDevice(SDL_AudioDevice *device)
    1.82 +{
    1.83 +    free(device->hidden);
    1.84 +    free(device);
    1.85 +}
    1.86 +
    1.87 +static SDL_AudioDevice *Audio_CreateDevice(int devindex)
    1.88 +{
    1.89 +    SDL_AudioDevice *this;
    1.90 +
    1.91 +    /* Initialize all variables that we clean on shutdown */
    1.92 +    this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
    1.93 +    if ( this ) {
    1.94 +        memset(this, 0, (sizeof *this));
    1.95 +        this->hidden = (struct SDL_PrivateAudioData *)
    1.96 +                malloc((sizeof *this->hidden));
    1.97 +    }
    1.98 +    if ( (this == NULL) || (this->hidden == NULL) ) {
    1.99 +        SDL_OutOfMemory();
   1.100 +        if ( this ) {
   1.101 +            free(this);
   1.102 +        }
   1.103 +        return(0);
   1.104 +    }
   1.105 +    memset(this->hidden, 0, (sizeof *this->hidden));
   1.106 +
   1.107 +    /* Set the function pointers */
   1.108 +    this->OpenAudio   = DRenderer_OpenAudio;
   1.109 +    this->CloseAudio  = DRenderer_CloseAudio;
   1.110 +    this->free        = Audio_DeleteDevice;
   1.111 +
   1.112 +    return this;
   1.113 +}
   1.114 +
   1.115 +AudioBootStrap DRENDERER_bootstrap = {
   1.116 +	"drenderer", "RiscOS Digital Renderer Module",
   1.117 +	Audio_Available, Audio_CreateDevice
   1.118 +};
   1.119 +
   1.120 +/* Routine called to check and fill audio buffers if necessary */
   1.121 +static Uint8 *buffer = NULL;
   1.122 +
   1.123 +void DRenderer_FillBuffers()
   1.124 +{
   1.125 +	SDL_AudioDevice *audio = current_audio;
   1.126 +
   1.127 +   if ( !audio || ! audio->enabled )
   1.128 +   {
   1.129 +      return;
   1.130 +   }
   1.131 +
   1.132 +   if ( ! audio->paused )
   1.133 +   {
   1.134 +	   _kernel_swi_regs regs;
   1.135 +	   /* Check filled buffers count */
   1.136 +	   _kernel_swi(DigitalRenderer_StreamStatistics, &regs, &regs);
   1.137 +
   1.138 +#ifdef DUMP_AUDIO
   1.139 +    if (regs.r[0] <= FillBuffer)
   1.140 +    {
   1.141 +       printf("Buffers in use %d\n", regs.r[0]);
   1.142 +    }
   1.143 +#endif
   1.144 +
   1.145 +	   while (regs.r[0] <= FillBuffer && !audio->paused)
   1.146 +	   {
   1.147 +	     if ( audio->convert.needed )
   1.148 +		   {
   1.149 +		       int silence;
   1.150 +                       if ( audio->convert.src_format == AUDIO_U8 )
   1.151 +                       {
   1.152 +                       	 silence = 0x80;
   1.153 +                       } else {
   1.154 +                       	 silence = 0;
   1.155 +                       }
   1.156 +                       memset(audio->convert.buf, silence, audio->convert.len);
   1.157 +		       audio->spec.callback(audio->spec.userdata,
   1.158 +				   (Uint8 *)audio->convert.buf,audio->convert.len);
   1.159 +                       SDL_ConvertAudio(&audio->convert);
   1.160 +#if 0
   1.161 +			   if ( audio->convert.len_cvt != audio->spec.size ) {
   1.162 +				   /* Uh oh... probably crashes here; */
   1.163 +			   }
   1.164 +#endif
   1.165 +		       regs.r[0] = (int)audio->convert.buf;
   1.166 +		       regs.r[1] = audio->spec.samples * audio->spec.channels;
   1.167 +		       _kernel_swi(DigitalRenderer_Stream16BitSamples, &regs, &regs);
   1.168 +
   1.169 +		   } else
   1.170 +		   {
   1.171 +			/* Fill buffer with silence */
   1.172 +			memset (buffer, 0, audio->spec.size);
   1.173 +
   1.174 +			audio->spec.callback(audio->spec.userdata,
   1.175 +				   (Uint8 *)buffer, audio->spec.size);
   1.176 +
   1.177 +			regs.r[0] = (int)buffer;
   1.178 +			regs.r[1] = audio->spec.samples * audio->spec.channels;
   1.179 +			 _kernel_swi(DigitalRenderer_Stream16BitSamples, &regs, &regs);
   1.180 +		   }
   1.181 +  		   /* Check if we have enough buffers yet */
   1.182 +   		   _kernel_swi(DigitalRenderer_StreamStatistics, &regs, &regs);
   1.183 +	   }
   1.184 +
   1.185 +   }
   1.186 +}
   1.187 +
   1.188 +/* Size of DMA buffer to use */
   1.189 +#define DRENDERER_BUFFER_SIZE 512
   1.190 +
   1.191 +/* Number of centiseconds of sound to buffer.
   1.192 +   Hopefully more than the maximum time between calls to the
   1.193 +   FillBuffers routine above
   1.194 +*/
   1.195 +#define DRENDERER_CSEC_TO_BUFFER 10
   1.196 +
   1.197 +static int DRenderer_OpenAudio(_THIS, SDL_AudioSpec *spec)
   1.198 +{
   1.199 +	_kernel_swi_regs regs;
   1.200 +	int buffers_per_sample;
   1.201 +
   1.202 +#ifdef DUMP_AUDIO
   1.203 +    printf("Request format %d\n", spec->format);
   1.204 +    printf("Request freq   %d\n", spec->freq);
   1.205 +    printf("Samples        %d\n", spec->samples);
   1.206 +#endif
   1.207 +
   1.208 +	/* Only support signed 16bit format */
   1.209 +	spec->format = AUDIO_S16LSB;
   1.210 +
   1.211 +    if (spec->samples < DRENDERER_BUFFER_SIZE) spec->samples = DRENDERER_BUFFER_SIZE;
   1.212 +
   1.213 +    SDL_CalculateAudioSpec(spec);
   1.214 +
   1.215 +
   1.216 +	buffers_per_sample = spec->samples / DRENDERER_BUFFER_SIZE;
   1.217 +
   1.218 +	if ((spec->samples % DRENDERER_BUFFER_SIZE) != 0)
   1.219 +	{
   1.220 +		buffers_per_sample++;
   1.221 +		spec->samples = buffers_per_sample * DRENDERER_BUFFER_SIZE;
   1.222 +	}
   1.223 +
   1.224 +	/* Set number of buffers to use - the following should give enough
   1.225 +	   data between calls to the sound polling.
   1.226 +	*/
   1.227 +
   1.228 +    if (riscos_audiobuffer == 0)
   1.229 +    {
   1.230 +    	FillBuffer = (int)((double)DRENDERER_CSEC_TO_BUFFER / ((double)DRENDERER_BUFFER_SIZE * 100.0 / (double)spec->freq)) + 1;
   1.231 +    } else FillBuffer = riscos_audiobuffer/DRENDERER_BUFFER_SIZE - buffers_per_sample;
   1.232 +
   1.233 +	if (FillBuffer < buffers_per_sample) FillBuffer = buffers_per_sample;
   1.234 +	regs.r[0] = FillBuffer + buffers_per_sample;
   1.235 +
   1.236 +#ifdef DUMP_AUDIO
   1.237 +    printf("Buffers per sample %d\n", buffers_per_sample);
   1.238 +    printf("Fill buffer        %d\n", FillBuffer);
   1.239 +    printf("Time buffered (ms) %d\n",(int)((1000.0 * regs.r[0] * DRENDERER_BUFFER_SIZE)/(double)spec->freq));
   1.240 +#endif
   1.241 +
   1.242 +	if (_kernel_swi(DigitalRenderer_NumBuffers, &regs, &regs) != 0)
   1.243 +    {
   1.244 +       SDL_SetError("Can't set number of streaming sound buffers\n");
   1.245 +       return -1;
   1.246 +    }
   1.247 +
   1.248 +	/* Now initialise sound system */
   1.249 +	regs.r[0] = spec->channels;   /* Number of channels */
   1.250 +	regs.r[1] = DRENDERER_BUFFER_SIZE; /* Samples length */
   1.251 +	regs.r[2] = spec->freq; /* frequency */
   1.252 +	regs.r[3] = 1;   /* Restore previous handler on exit */
   1.253 +
   1.254 +	if (_kernel_swi(DigitalRenderer_Activate16, &regs, &regs) != 0)
   1.255 +	{
   1.256 +		SDL_SetError("Unable to activate digital renderer in 16 bit mode\n");
   1.257 +		return -1;
   1.258 +	}
   1.259 +
   1.260 +	if (_kernel_swi(DigitalRenderer_GetFrequency, &regs, &regs) == 0)
   1.261 +	{
   1.262 +		spec->freq = regs.r[0];
   1.263 +	}
   1.264 +
   1.265 +#ifdef DUMP_AUDIO
   1.266 +    printf("Got format %d\n", spec->format);
   1.267 +    printf("Frequency  %d\n", spec->freq);
   1.268 +    printf("Samples    %d\n", spec->samples);
   1.269 +#endif                 
   1.270 +
   1.271 +    /* Set to fill buffer with zero if we don't get data to it fast enough */
   1.272 +    regs.r[0] = 1;
   1.273 +    regs.r[1] = ~1;
   1.274 +    _kernel_swi(DigitalRenderer_StreamFlags, &regs, &regs);
   1.275 +
   1.276 +	buffer = (Uint8 *)malloc(sizeof(Uint8) * spec->size);
   1.277 +	if (buffer == NULL)
   1.278 +	{
   1.279 +		SDL_OutOfMemory();
   1.280 +		return -1;
   1.281 +	}
   1.282 +
   1.283 +   /* Hopefully returning 2 will show success, but not start up an audio thread */
   1.284 +   return 2;
   1.285 +}
   1.286 +
   1.287 +static void DRenderer_CloseAudio(_THIS)
   1.288 +{
   1.289 +	_kernel_swi_regs regs;
   1.290 +
   1.291 +	/* Close down the digital renderer */
   1.292 +	_kernel_swi(DigitalRenderer_Deactivate, &regs, &regs);
   1.293 +
   1.294 +	if (buffer != NULL) free(buffer);
   1.295 +}
   1.296 +