This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_dcaudio.c
254 lines (221 loc) · 6.86 KB
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2006 Sam Lantinga
4
5
This library is free software; you can redistribute it and/or
6
modify it under the terms of the GNU Lesser General Public
7
License as published by the Free Software Foundation; either
8
version 2.1 of the License, or (at your option) any later version.
9
10
11
12
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
13
Lesser General Public License for more details.
14
15
16
17
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19
20
Sam Lantinga
slouken@libsdl.org
21
22
*/
23
#include "SDL_config.h"
24
25
26
/* Output dreamcast aica */
27
#include "SDL_timer.h"
28
#include "SDL_audio.h"
29
30
31
#include "../SDL_audiomem.h"
#include "../SDL_audio_c.h"
#include "../SDL_audiodev_c.h"
32
33
34
35
36
37
#include "SDL_dcaudio.h"
#include "aica.h"
#include <dc/spu.h>
/* Audio driver functions */
38
39
40
41
42
static int DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec);
static void DCAUD_WaitAudio(_THIS);
static void DCAUD_PlayAudio(_THIS);
static Uint8 *DCAUD_GetAudioBuf(_THIS);
static void DCAUD_CloseAudio(_THIS);
43
44
/* Audio driver bootstrap functions */
45
static int
46
DCAUD_Available(void)
47
{
48
return 1;
49
50
}
51
static void
52
DCAUD_DeleteDevice(SDL_AudioDevice * device)
53
{
54
55
SDL_free(device->hidden);
SDL_free(device);
56
57
}
58
static SDL_AudioDevice *
59
DCAUD_CreateDevice(int devindex)
60
{
61
62
63
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
64
this = (SDL_AudioDevice *) SDL_malloc(sizeof(SDL_AudioDevice));
65
if (this) {
66
SDL_memset(this, 0, (sizeof *this));
67
this->hidden = (struct SDL_PrivateAudioData *)
68
SDL_malloc((sizeof *this->hidden));
69
70
}
if ((this == NULL) || (this->hidden == NULL)) {
71
SDL_OutOfMemory();
72
if (this) {
73
SDL_free(this);
74
75
76
}
return (0);
}
77
SDL_memset(this->hidden, 0, (sizeof *this->hidden));
78
79
80
81
82
83
84
85
86
87
/* Set the function pointers */
this->OpenAudio = DCAUD_OpenAudio;
this->WaitAudio = DCAUD_WaitAudio;
this->PlayAudio = DCAUD_PlayAudio;
this->GetAudioBuf = DCAUD_GetAudioBuf;
this->CloseAudio = DCAUD_CloseAudio;
this->free = DCAUD_DeleteDevice;
88
spu_init();
89
90
return this;
91
92
93
}
AudioBootStrap DCAUD_bootstrap = {
94
95
"dcaudio", "Dreamcast AICA audio",
DCAUD_Available, DCAUD_CreateDevice
96
97
98
};
/* This function waits until it is possible to write a full sound buffer */
99
static void
100
DCAUD_WaitAudio(_THIS)
101
{
102
103
if (this->hidden->playing) {
/* wait */
104
105
while (aica_get_pos(0) / this->spec.samples == this->hidden->nextbuf) {
thd_pass();
106
107
}
}
108
109
110
111
}
#define SPU_RAM_BASE 0xa0800000
112
static void
113
spu_memload_stereo8(int leftpos, int rightpos, void *src0, size_t size)
114
{
115
116
117
118
119
120
121
122
123
124
125
126
127
128
uint8 *src = src0;
uint32 *left = (uint32 *) (leftpos + SPU_RAM_BASE);
uint32 *right = (uint32 *) (rightpos + SPU_RAM_BASE);
size = (size + 7) / 8;
while (size--) {
unsigned lval, rval;
lval = *src++;
rval = *src++;
lval |= (*src++) << 8;
rval |= (*src++) << 8;
lval |= (*src++) << 16;
rval |= (*src++) << 16;
lval |= (*src++) << 24;
rval |= (*src++) << 24;
129
130
131
g2_write_32(left++, lval);
g2_write_32(right++, rval);
g2_fifo_wait();
132
}
133
134
}
135
static void
136
spu_memload_stereo16(int leftpos, int rightpos, void *src0, size_t size)
137
{
138
139
140
141
142
143
144
145
146
147
uint16 *src = src0;
uint32 *left = (uint32 *) (leftpos + SPU_RAM_BASE);
uint32 *right = (uint32 *) (rightpos + SPU_RAM_BASE);
size = (size + 7) / 8;
while (size--) {
unsigned lval, rval;
lval = *src++;
rval = *src++;
lval |= (*src++) << 16;
rval |= (*src++) << 16;
148
149
150
g2_write_32(left++, lval);
g2_write_32(right++, rval);
g2_fifo_wait();
151
}
152
153
}
154
static void
155
DCAUD_PlayAudio(_THIS)
156
{
157
158
159
160
161
SDL_AudioSpec *spec = &this->spec;
unsigned int offset;
if (this->hidden->playing) {
/* wait */
162
163
while (aica_get_pos(0) / spec->samples == this->hidden->nextbuf) {
thd_pass();
164
165
166
167
168
169
170
}
}
offset = this->hidden->nextbuf * spec->size;
this->hidden->nextbuf ^= 1;
/* Write the audio data, checking for EAGAIN on broken audio drivers */
if (spec->channels == 1) {
171
172
spu_memload(this->hidden->leftpos + offset, this->hidden->mixbuf,
this->hidden->mixlen);
173
174
175
} else {
offset /= 2;
if ((this->spec.format & 255) == 8) {
176
177
178
179
180
spu_memload_stereo8(this->hidden->leftpos + offset,
this->hidden->rightpos + offset,
this->hidden->mixbuf, this->hidden->mixlen);
} else {
spu_memload_stereo16(this->hidden->leftpos + offset,
181
182
183
184
185
186
187
188
189
190
this->hidden->rightpos + offset,
this->hidden->mixbuf, this->hidden->mixlen);
}
}
if (!this->hidden->playing) {
int mode;
this->hidden->playing = 1;
mode = (spec->format == AUDIO_S8) ? SM_8BIT : SM_16BIT;
if (spec->channels == 1) {
191
192
aica_play(0, mode, this->hidden->leftpos, 0,
spec->samples * 2, spec->freq, 255, 128, 1);
193
} else {
194
195
196
197
aica_play(0, mode, this->hidden->leftpos, 0,
spec->samples * 2, spec->freq, 255, 0, 1);
aica_play(1, mode, this->hidden->rightpos, 0,
spec->samples * 2, spec->freq, 255, 255, 1);
198
199
}
}
200
201
}
202
static Uint8 *
203
DCAUD_GetAudioBuf(_THIS)
204
{
205
return (this->hidden->mixbuf);
206
207
}
208
static void
209
DCAUD_CloseAudio(_THIS)
210
{
211
aica_stop(0);
212
if (this->spec.channels == 2)
213
aica_stop(1);
214
if (this->hidden->mixbuf != NULL) {
215
SDL_FreeAudioMem(this->hidden->mixbuf);
216
217
this->hidden->mixbuf = NULL;
}
218
219
}
220
static int
221
DCAUD_OpenAudio(_THIS, SDL_AudioSpec * spec)
222
{
223
224
225
226
227
228
229
230
switch (spec->format & 0xff) {
case 8:
spec->format = AUDIO_S8;
break;
case 16:
spec->format = AUDIO_S16LSB;
break;
default:
231
SDL_SetError("Unsupported audio format");
232
233
234
235
return (-1);
}
/* Update the fragment size as size in bytes */
236
SDL_CalculateAudioSpec(spec);
237
238
239
/* Allocate mixing buffer */
this->hidden->mixlen = spec->size;
240
this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
241
242
243
if (this->hidden->mixbuf == NULL) {
return (-1);
}
244
SDL_memset(this->hidden->mixbuf, spec->silence, spec->size);
245
246
247
248
249
250
251
this->hidden->leftpos = 0x11000;
this->hidden->rightpos = 0x11000 + spec->size;
this->hidden->playing = 0;
this->hidden->nextbuf = 0;
/* We're ready to rock and roll. :-) */
return (0);
252
}
253
254
/* vi: set ts=4 sw=4 expandtab: */