Mercurial > sdl-ios-xcode
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, ®s, ®s) == 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, ®s, ®s); | |
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, ®s, ®s); | |
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, ®s, ®s); | |
177 } | |
178 /* Check if we have enough buffers yet */ | |
179 _kernel_swi(DigitalRenderer_StreamStatistics, ®s, ®s); | |
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, ®s, ®s) != 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, ®s, ®s) != 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, ®s, ®s) == 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, ®s, ®s); | |
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, ®s, ®s); | |
290 | |
291 if (buffer != NULL) free(buffer); | |
292 } | |
293 |