src/audio/riscos/SDL_drenderer.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 29 May 2003 04:44:13 +0000
changeset 630 550bccdf04bd
child 769 b8d311d90021
permissions -rw-r--r--
Added initial support for RISC OS (thanks Peter Naulls!)
slouken@630
     1
/*
slouken@630
     2
    SDL - Simple DirectMedia Layer
slouken@630
     3
    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
slouken@630
     4
slouken@630
     5
    This library is free software; you can redistribute it and/or
slouken@630
     6
    modify it under the terms of the GNU Library General Public
slouken@630
     7
    License as published by the Free Software Foundation; either
slouken@630
     8
    version 2 of the License, or (at your option) any later version.
slouken@630
     9
slouken@630
    10
    This library is distributed in the hope that it will be useful,
slouken@630
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@630
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@630
    13
    Library General Public License for more details.
slouken@630
    14
slouken@630
    15
    You should have received a copy of the GNU Library General Public
slouken@630
    16
    License along with this library; if not, write to the Free
slouken@630
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@630
    18
slouken@630
    19
    Sam Lantinga
slouken@630
    20
    slouken@devolution.com
slouken@630
    21
*/
slouken@630
    22
slouken@630
    23
slouken@630
    24
#include <stdlib.h>
slouken@630
    25
#include <stdio.h>
slouken@630
    26
#include <memory.h>
slouken@630
    27
slouken@630
    28
#include <kernel.h>
slouken@630
    29
#include "swis.h"
slouken@630
    30
slouken@630
    31
#include "SDL_endian.h"
slouken@630
    32
#include "SDL_audio.h"
slouken@630
    33
#include "SDL_audio_c.h"
slouken@630
    34
#include "SDL_audiomem.h"
slouken@630
    35
#include "SDL_sysaudio.h"
slouken@630
    36
#include "SDL_drenderer.h"
slouken@630
    37
slouken@630
    38
#define DigitalRenderer_Activate    0x4F700
slouken@630
    39
#define DigitalRenderer_Deactivate	0x4F701
slouken@630
    40
#define DigitalRenderer_ReadState	0x4F705
slouken@630
    41
#define DigitalRenderer_NewSample	0x4F706
slouken@630
    42
#define DigitalRenderer_NumBuffers	0x4F709
slouken@630
    43
#define DigitalRenderer_StreamSamples  0x4F70A
slouken@630
    44
#define DigitalRenderer_Stream16BitSamples	0x4F70B
slouken@630
    45
#define DigitalRenderer_StreamStatistics	0x4F70C
slouken@630
    46
#define DigitalRenderer_StreamFlags     0x4F70D
slouken@630
    47
#define DigitalRenderer_Activate16		0x4F70F
slouken@630
    48
#define DigitalRenderer_GetFrequency	0x4F710
slouken@630
    49
slouken@630
    50
static int FillBuffer;
slouken@630
    51
extern SDL_AudioDevice *current_audio;
slouken@630
    52
slouken@630
    53
extern int riscos_audiobuffer; /* Override for audio buffer size */
slouken@630
    54
slouken@630
    55
/* Audio driver functions */
slouken@630
    56
slouken@630
    57
static void DRenderer_CloseAudio(_THIS);
slouken@630
    58
static int DRenderer_OpenAudio(_THIS, SDL_AudioSpec *spec);
slouken@630
    59
slouken@630
    60
/* Audio driver bootstrap functions */
slouken@630
    61
slouken@630
    62
/* Define following to dump stats to stdout */
slouken@630
    63
/* #define DUMP_AUDIO */
slouken@630
    64
slouken@630
    65
slouken@630
    66
static int Audio_Available(void)
slouken@630
    67
{
slouken@630
    68
	_kernel_swi_regs regs;
slouken@630
    69
	int available = 0;
slouken@630
    70
slouken@630
    71
	/* Use call to set buffers to also check if Module is loaded */
slouken@630
    72
	regs.r[0] = 0;
slouken@630
    73
	if (_kernel_swi(DigitalRenderer_NumBuffers, &regs, &regs) == 0) available = 1;
slouken@630
    74
slouken@630
    75
    return(available);
slouken@630
    76
}
slouken@630
    77
slouken@630
    78
static void Audio_DeleteDevice(SDL_AudioDevice *device)
slouken@630
    79
{
slouken@630
    80
    free(device->hidden);
slouken@630
    81
    free(device);
slouken@630
    82
}
slouken@630
    83
slouken@630
    84
static SDL_AudioDevice *Audio_CreateDevice(int devindex)
slouken@630
    85
{
slouken@630
    86
    SDL_AudioDevice *this;
slouken@630
    87
slouken@630
    88
    /* Initialize all variables that we clean on shutdown */
slouken@630
    89
    this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
slouken@630
    90
    if ( this ) {
slouken@630
    91
        memset(this, 0, (sizeof *this));
slouken@630
    92
        this->hidden = (struct SDL_PrivateAudioData *)
slouken@630
    93
                malloc((sizeof *this->hidden));
slouken@630
    94
    }
slouken@630
    95
    if ( (this == NULL) || (this->hidden == NULL) ) {
slouken@630
    96
        SDL_OutOfMemory();
slouken@630
    97
        if ( this ) {
slouken@630
    98
            free(this);
slouken@630
    99
        }
slouken@630
   100
        return(0);
slouken@630
   101
    }
slouken@630
   102
    memset(this->hidden, 0, (sizeof *this->hidden));
slouken@630
   103
slouken@630
   104
    /* Set the function pointers */
slouken@630
   105
    this->OpenAudio   = DRenderer_OpenAudio;
slouken@630
   106
    this->CloseAudio  = DRenderer_CloseAudio;
slouken@630
   107
    this->free        = Audio_DeleteDevice;
slouken@630
   108
slouken@630
   109
    return this;
slouken@630
   110
}
slouken@630
   111
slouken@630
   112
AudioBootStrap DRENDERER_bootstrap = {
slouken@630
   113
	"drenderer", "RiscOS Digital Renderer Module",
slouken@630
   114
	Audio_Available, Audio_CreateDevice
slouken@630
   115
};
slouken@630
   116
slouken@630
   117
/* Routine called to check and fill audio buffers if necessary */
slouken@630
   118
static Uint8 *buffer = NULL;
slouken@630
   119
slouken@630
   120
void DRenderer_FillBuffers()
slouken@630
   121
{
slouken@630
   122
	SDL_AudioDevice *audio = current_audio;
slouken@630
   123
slouken@630
   124
   if ( !audio || ! audio->enabled )
slouken@630
   125
   {
slouken@630
   126
      return;
slouken@630
   127
   }
slouken@630
   128
slouken@630
   129
   if ( ! audio->paused )
slouken@630
   130
   {
slouken@630
   131
	   _kernel_swi_regs regs;
slouken@630
   132
	   /* Check filled buffers count */
slouken@630
   133
	   _kernel_swi(DigitalRenderer_StreamStatistics, &regs, &regs);
slouken@630
   134
slouken@630
   135
#ifdef DUMP_AUDIO
slouken@630
   136
    if (regs.r[0] <= FillBuffer)
slouken@630
   137
    {
slouken@630
   138
       printf("Buffers in use %d\n", regs.r[0]);
slouken@630
   139
    }
slouken@630
   140
#endif
slouken@630
   141
slouken@630
   142
	   while (regs.r[0] <= FillBuffer && !audio->paused)
slouken@630
   143
	   {
slouken@630
   144
	     if ( audio->convert.needed )
slouken@630
   145
		   {
slouken@630
   146
		       int silence;
slouken@630
   147
                       if ( audio->convert.src_format == AUDIO_U8 )
slouken@630
   148
                       {
slouken@630
   149
                       	 silence = 0x80;
slouken@630
   150
                       } else {
slouken@630
   151
                       	 silence = 0;
slouken@630
   152
                       }
slouken@630
   153
                       memset(audio->convert.buf, silence, audio->convert.len);
slouken@630
   154
		       audio->spec.callback(audio->spec.userdata,
slouken@630
   155
				   (Uint8 *)audio->convert.buf,audio->convert.len);
slouken@630
   156
                       SDL_ConvertAudio(&audio->convert);
slouken@630
   157
#if 0
slouken@630
   158
			   if ( audio->convert.len_cvt != audio->spec.size ) {
slouken@630
   159
				   /* Uh oh... probably crashes here; */
slouken@630
   160
			   }
slouken@630
   161
#endif
slouken@630
   162
		       regs.r[0] = (int)audio->convert.buf;
slouken@630
   163
		       regs.r[1] = audio->spec.samples * audio->spec.channels;
slouken@630
   164
		       _kernel_swi(DigitalRenderer_Stream16BitSamples, &regs, &regs);
slouken@630
   165
slouken@630
   166
		   } else
slouken@630
   167
		   {
slouken@630
   168
			/* Fill buffer with silence */
slouken@630
   169
			memset (buffer, 0, audio->spec.size);
slouken@630
   170
slouken@630
   171
			audio->spec.callback(audio->spec.userdata,
slouken@630
   172
				   (Uint8 *)buffer, audio->spec.size);
slouken@630
   173
slouken@630
   174
			regs.r[0] = (int)buffer;
slouken@630
   175
			regs.r[1] = audio->spec.samples * audio->spec.channels;
slouken@630
   176
			 _kernel_swi(DigitalRenderer_Stream16BitSamples, &regs, &regs);
slouken@630
   177
		   }
slouken@630
   178
  		   /* Check if we have enough buffers yet */
slouken@630
   179
   		   _kernel_swi(DigitalRenderer_StreamStatistics, &regs, &regs);
slouken@630
   180
	   }
slouken@630
   181
slouken@630
   182
   }
slouken@630
   183
}
slouken@630
   184
slouken@630
   185
/* Size of DMA buffer to use */
slouken@630
   186
#define DRENDERER_BUFFER_SIZE 512
slouken@630
   187
slouken@630
   188
/* Number of centiseconds of sound to buffer.
slouken@630
   189
   Hopefully more than the maximum time between calls to the
slouken@630
   190
   FillBuffers routine above
slouken@630
   191
*/
slouken@630
   192
#define DRENDERER_CSEC_TO_BUFFER 10
slouken@630
   193
slouken@630
   194
static int DRenderer_OpenAudio(_THIS, SDL_AudioSpec *spec)
slouken@630
   195
{
slouken@630
   196
	_kernel_swi_regs regs;
slouken@630
   197
	int buffers_per_sample;
slouken@630
   198
slouken@630
   199
#ifdef DUMP_AUDIO
slouken@630
   200
    printf("Request format %d\n", spec->format);
slouken@630
   201
    printf("Request freq   %d\n", spec->freq);
slouken@630
   202
    printf("Samples        %d\n", spec->samples);
slouken@630
   203
#endif
slouken@630
   204
slouken@630
   205
	/* Only support signed 16bit format */
slouken@630
   206
	spec->format = AUDIO_S16LSB;
slouken@630
   207
slouken@630
   208
    if (spec->samples < DRENDERER_BUFFER_SIZE) spec->samples = DRENDERER_BUFFER_SIZE;
slouken@630
   209
slouken@630
   210
    SDL_CalculateAudioSpec(spec);
slouken@630
   211
slouken@630
   212
slouken@630
   213
	buffers_per_sample = spec->samples / DRENDERER_BUFFER_SIZE;
slouken@630
   214
slouken@630
   215
	if ((spec->samples % DRENDERER_BUFFER_SIZE) != 0)
slouken@630
   216
	{
slouken@630
   217
		buffers_per_sample++;
slouken@630
   218
		spec->samples = buffers_per_sample * DRENDERER_BUFFER_SIZE;
slouken@630
   219
	}
slouken@630
   220
slouken@630
   221
	/* Set number of buffers to use - the following should give enough
slouken@630
   222
	   data between calls to the sound polling.
slouken@630
   223
	*/
slouken@630
   224
slouken@630
   225
    if (riscos_audiobuffer == 0)
slouken@630
   226
    {
slouken@630
   227
    	FillBuffer = (int)((double)DRENDERER_CSEC_TO_BUFFER / ((double)DRENDERER_BUFFER_SIZE * 100.0 / (double)spec->freq)) + 1;
slouken@630
   228
    } else FillBuffer = riscos_audiobuffer/DRENDERER_BUFFER_SIZE - buffers_per_sample;
slouken@630
   229
slouken@630
   230
	if (FillBuffer < buffers_per_sample) FillBuffer = buffers_per_sample;
slouken@630
   231
	regs.r[0] = FillBuffer + buffers_per_sample;
slouken@630
   232
slouken@630
   233
#ifdef DUMP_AUDIO
slouken@630
   234
    printf("Buffers per sample %d\n", buffers_per_sample);
slouken@630
   235
    printf("Fill buffer        %d\n", FillBuffer);
slouken@630
   236
    printf("Time buffered (ms) %d\n",(int)((1000.0 * regs.r[0] * DRENDERER_BUFFER_SIZE)/(double)spec->freq));
slouken@630
   237
#endif
slouken@630
   238
slouken@630
   239
	if (_kernel_swi(DigitalRenderer_NumBuffers, &regs, &regs) != 0)
slouken@630
   240
    {
slouken@630
   241
       SDL_SetError("Can't set number of streaming sound buffers\n");
slouken@630
   242
       return -1;
slouken@630
   243
    }
slouken@630
   244
slouken@630
   245
	/* Now initialise sound system */
slouken@630
   246
	regs.r[0] = spec->channels;   /* Number of channels */
slouken@630
   247
	regs.r[1] = DRENDERER_BUFFER_SIZE; /* Samples length */
slouken@630
   248
	regs.r[2] = spec->freq; /* frequency */
slouken@630
   249
	regs.r[3] = 1;   /* Restore previous handler on exit */
slouken@630
   250
slouken@630
   251
	if (_kernel_swi(DigitalRenderer_Activate16, &regs, &regs) != 0)
slouken@630
   252
	{
slouken@630
   253
		SDL_SetError("Unable to activate digital renderer in 16 bit mode\n");
slouken@630
   254
		return -1;
slouken@630
   255
	}
slouken@630
   256
slouken@630
   257
	if (_kernel_swi(DigitalRenderer_GetFrequency, &regs, &regs) == 0)
slouken@630
   258
	{
slouken@630
   259
		spec->freq = regs.r[0];
slouken@630
   260
	}
slouken@630
   261
slouken@630
   262
#ifdef DUMP_AUDIO
slouken@630
   263
    printf("Got format %d\n", spec->format);
slouken@630
   264
    printf("Frequency  %d\n", spec->freq);
slouken@630
   265
    printf("Samples    %d\n", spec->samples);
slouken@630
   266
#endif                 
slouken@630
   267
slouken@630
   268
    /* Set to fill buffer with zero if we don't get data to it fast enough */
slouken@630
   269
    regs.r[0] = 1;
slouken@630
   270
    regs.r[1] = ~1;
slouken@630
   271
    _kernel_swi(DigitalRenderer_StreamFlags, &regs, &regs);
slouken@630
   272
slouken@630
   273
	buffer = (Uint8 *)malloc(sizeof(Uint8) * spec->size);
slouken@630
   274
	if (buffer == NULL)
slouken@630
   275
	{
slouken@630
   276
		SDL_OutOfMemory();
slouken@630
   277
		return -1;
slouken@630
   278
	}
slouken@630
   279
slouken@630
   280
   /* Hopefully returning 2 will show success, but not start up an audio thread */
slouken@630
   281
   return 2;
slouken@630
   282
}
slouken@630
   283
slouken@630
   284
static void DRenderer_CloseAudio(_THIS)
slouken@630
   285
{
slouken@630
   286
	_kernel_swi_regs regs;
slouken@630
   287
slouken@630
   288
	/* Close down the digital renderer */
slouken@630
   289
	_kernel_swi(DigitalRenderer_Deactivate, &regs, &regs);
slouken@630
   290
slouken@630
   291
	if (buffer != NULL) free(buffer);
slouken@630
   292
}
slouken@630
   293