Mercurial > sdl-ios-xcode
diff src/audio/riscos/SDL_drenderer.c @ 630:550bccdf04bd
Added initial support for RISC OS (thanks Peter Naulls!)
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Thu, 29 May 2003 04:44:13 +0000 |
parents | |
children | b8d311d90021 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/audio/riscos/SDL_drenderer.c Thu May 29 04:44:13 2003 +0000 @@ -0,0 +1,293 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997, 1998, 1999, 2000, 2001 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + + +#include <stdlib.h> +#include <stdio.h> +#include <memory.h> + +#include <kernel.h> +#include "swis.h" + +#include "SDL_endian.h" +#include "SDL_audio.h" +#include "SDL_audio_c.h" +#include "SDL_audiomem.h" +#include "SDL_sysaudio.h" +#include "SDL_drenderer.h" + +#define DigitalRenderer_Activate 0x4F700 +#define DigitalRenderer_Deactivate 0x4F701 +#define DigitalRenderer_ReadState 0x4F705 +#define DigitalRenderer_NewSample 0x4F706 +#define DigitalRenderer_NumBuffers 0x4F709 +#define DigitalRenderer_StreamSamples 0x4F70A +#define DigitalRenderer_Stream16BitSamples 0x4F70B +#define DigitalRenderer_StreamStatistics 0x4F70C +#define DigitalRenderer_StreamFlags 0x4F70D +#define DigitalRenderer_Activate16 0x4F70F +#define DigitalRenderer_GetFrequency 0x4F710 + +static int FillBuffer; +extern SDL_AudioDevice *current_audio; + +extern int riscos_audiobuffer; /* Override for audio buffer size */ + +/* Audio driver functions */ + +static void DRenderer_CloseAudio(_THIS); +static int DRenderer_OpenAudio(_THIS, SDL_AudioSpec *spec); + +/* Audio driver bootstrap functions */ + +/* Define following to dump stats to stdout */ +/* #define DUMP_AUDIO */ + + +static int Audio_Available(void) +{ + _kernel_swi_regs regs; + int available = 0; + + /* Use call to set buffers to also check if Module is loaded */ + regs.r[0] = 0; + if (_kernel_swi(DigitalRenderer_NumBuffers, ®s, ®s) == 0) available = 1; + + return(available); +} + +static void Audio_DeleteDevice(SDL_AudioDevice *device) +{ + free(device->hidden); + free(device); +} + +static SDL_AudioDevice *Audio_CreateDevice(int devindex) +{ + SDL_AudioDevice *this; + + /* Initialize all variables that we clean on shutdown */ + this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice)); + if ( this ) { + memset(this, 0, (sizeof *this)); + this->hidden = (struct SDL_PrivateAudioData *) + malloc((sizeof *this->hidden)); + } + if ( (this == NULL) || (this->hidden == NULL) ) { + SDL_OutOfMemory(); + if ( this ) { + free(this); + } + return(0); + } + memset(this->hidden, 0, (sizeof *this->hidden)); + + /* Set the function pointers */ + this->OpenAudio = DRenderer_OpenAudio; + this->CloseAudio = DRenderer_CloseAudio; + this->free = Audio_DeleteDevice; + + return this; +} + +AudioBootStrap DRENDERER_bootstrap = { + "drenderer", "RiscOS Digital Renderer Module", + Audio_Available, Audio_CreateDevice +}; + +/* Routine called to check and fill audio buffers if necessary */ +static Uint8 *buffer = NULL; + +void DRenderer_FillBuffers() +{ + SDL_AudioDevice *audio = current_audio; + + if ( !audio || ! audio->enabled ) + { + return; + } + + if ( ! audio->paused ) + { + _kernel_swi_regs regs; + /* Check filled buffers count */ + _kernel_swi(DigitalRenderer_StreamStatistics, ®s, ®s); + +#ifdef DUMP_AUDIO + if (regs.r[0] <= FillBuffer) + { + printf("Buffers in use %d\n", regs.r[0]); + } +#endif + + while (regs.r[0] <= FillBuffer && !audio->paused) + { + if ( audio->convert.needed ) + { + int silence; + if ( audio->convert.src_format == AUDIO_U8 ) + { + silence = 0x80; + } else { + silence = 0; + } + memset(audio->convert.buf, silence, audio->convert.len); + audio->spec.callback(audio->spec.userdata, + (Uint8 *)audio->convert.buf,audio->convert.len); + SDL_ConvertAudio(&audio->convert); +#if 0 + if ( audio->convert.len_cvt != audio->spec.size ) { + /* Uh oh... probably crashes here; */ + } +#endif + regs.r[0] = (int)audio->convert.buf; + regs.r[1] = audio->spec.samples * audio->spec.channels; + _kernel_swi(DigitalRenderer_Stream16BitSamples, ®s, ®s); + + } else + { + /* Fill buffer with silence */ + memset (buffer, 0, audio->spec.size); + + audio->spec.callback(audio->spec.userdata, + (Uint8 *)buffer, audio->spec.size); + + regs.r[0] = (int)buffer; + regs.r[1] = audio->spec.samples * audio->spec.channels; + _kernel_swi(DigitalRenderer_Stream16BitSamples, ®s, ®s); + } + /* Check if we have enough buffers yet */ + _kernel_swi(DigitalRenderer_StreamStatistics, ®s, ®s); + } + + } +} + +/* Size of DMA buffer to use */ +#define DRENDERER_BUFFER_SIZE 512 + +/* Number of centiseconds of sound to buffer. + Hopefully more than the maximum time between calls to the + FillBuffers routine above +*/ +#define DRENDERER_CSEC_TO_BUFFER 10 + +static int DRenderer_OpenAudio(_THIS, SDL_AudioSpec *spec) +{ + _kernel_swi_regs regs; + int buffers_per_sample; + +#ifdef DUMP_AUDIO + printf("Request format %d\n", spec->format); + printf("Request freq %d\n", spec->freq); + printf("Samples %d\n", spec->samples); +#endif + + /* Only support signed 16bit format */ + spec->format = AUDIO_S16LSB; + + if (spec->samples < DRENDERER_BUFFER_SIZE) spec->samples = DRENDERER_BUFFER_SIZE; + + SDL_CalculateAudioSpec(spec); + + + buffers_per_sample = spec->samples / DRENDERER_BUFFER_SIZE; + + if ((spec->samples % DRENDERER_BUFFER_SIZE) != 0) + { + buffers_per_sample++; + spec->samples = buffers_per_sample * DRENDERER_BUFFER_SIZE; + } + + /* Set number of buffers to use - the following should give enough + data between calls to the sound polling. + */ + + if (riscos_audiobuffer == 0) + { + FillBuffer = (int)((double)DRENDERER_CSEC_TO_BUFFER / ((double)DRENDERER_BUFFER_SIZE * 100.0 / (double)spec->freq)) + 1; + } else FillBuffer = riscos_audiobuffer/DRENDERER_BUFFER_SIZE - buffers_per_sample; + + if (FillBuffer < buffers_per_sample) FillBuffer = buffers_per_sample; + regs.r[0] = FillBuffer + buffers_per_sample; + +#ifdef DUMP_AUDIO + printf("Buffers per sample %d\n", buffers_per_sample); + printf("Fill buffer %d\n", FillBuffer); + printf("Time buffered (ms) %d\n",(int)((1000.0 * regs.r[0] * DRENDERER_BUFFER_SIZE)/(double)spec->freq)); +#endif + + if (_kernel_swi(DigitalRenderer_NumBuffers, ®s, ®s) != 0) + { + SDL_SetError("Can't set number of streaming sound buffers\n"); + return -1; + } + + /* Now initialise sound system */ + regs.r[0] = spec->channels; /* Number of channels */ + regs.r[1] = DRENDERER_BUFFER_SIZE; /* Samples length */ + regs.r[2] = spec->freq; /* frequency */ + regs.r[3] = 1; /* Restore previous handler on exit */ + + if (_kernel_swi(DigitalRenderer_Activate16, ®s, ®s) != 0) + { + SDL_SetError("Unable to activate digital renderer in 16 bit mode\n"); + return -1; + } + + if (_kernel_swi(DigitalRenderer_GetFrequency, ®s, ®s) == 0) + { + spec->freq = regs.r[0]; + } + +#ifdef DUMP_AUDIO + printf("Got format %d\n", spec->format); + printf("Frequency %d\n", spec->freq); + printf("Samples %d\n", spec->samples); +#endif + + /* Set to fill buffer with zero if we don't get data to it fast enough */ + regs.r[0] = 1; + regs.r[1] = ~1; + _kernel_swi(DigitalRenderer_StreamFlags, ®s, ®s); + + buffer = (Uint8 *)malloc(sizeof(Uint8) * spec->size); + if (buffer == NULL) + { + SDL_OutOfMemory(); + return -1; + } + + /* Hopefully returning 2 will show success, but not start up an audio thread */ + return 2; +} + +static void DRenderer_CloseAudio(_THIS) +{ + _kernel_swi_regs regs; + + /* Close down the digital renderer */ + _kernel_swi(DigitalRenderer_Deactivate, ®s, ®s); + + if (buffer != NULL) free(buffer); +} +