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