comparison src/audio/dc/aica.c @ 509:dad72daf44b3

Added initial support for Dreamcast (thanks HERO!)
author Sam Lantinga <slouken@libsdl.org>
date Sat, 05 Oct 2002 16:50:56 +0000
parents
children 11134dc42da8
comparison
equal deleted inserted replaced
508:9ff7e90aaa94 509:dad72daf44b3
1 /* This file is part of the Dreamcast function library.
2 * Please see libdream.c for further details.
3 *
4 * (c)2000 Dan Potter
5 * modify BERO
6 */
7 #include "aica.h"
8
9 /* #define dc_snd_base ((volatile unsigned char *)0x00800000) */ /* arm side */
10 #define dc_snd_base ((volatile unsigned char *)0xa0700000) /* dc side */
11
12 /* Some convienence macros */
13 #define SNDREGADDR(x) (0xa0700000 + (x))
14 #define CHNREGADDR(ch,x) SNDREGADDR(0x80*(ch)+(x))
15
16
17 #define SNDREG32(x) (*(volatile unsigned long *)SNDREGADDR(x))
18 #define SNDREG8(x) (*(volatile unsigned char *)SNDREGADDR(x))
19 #define CHNREG32(ch, x) (*(volatile unsigned long *)CHNREGADDR(ch,x))
20 #define CHNREG8(ch, x) (*(volatile unsigned long *)CHNREGADDR(ch,x))
21
22 #define G2_LOCK(OLD) \
23 do { \
24 if (!irq_inside_int()) \
25 OLD = irq_disable(); \
26 /* suspend any G2 DMA here... */ \
27 while((*(volatile unsigned int *)0xa05f688c) & 0x20) \
28 ; \
29 } while(0)
30
31 #define G2_UNLOCK(OLD) \
32 do { \
33 /* resume any G2 DMA here... */ \
34 if (!irq_inside_int()) \
35 irq_restore(OLD); \
36 } while(0)
37
38
39 void aica_init() {
40 int i, j, old;
41
42 /* Initialize AICA channels */
43 G2_LOCK(old);
44 SNDREG32(0x2800) = 0x0000;
45
46 for (i=0; i<64; i++) {
47 for (j=0; j<0x80; j+=4) {
48 if ((j&31)==0) g2_fifo_wait();
49 CHNREG32(i, j) = 0;
50 }
51 g2_fifo_wait();
52 CHNREG32(i,0) = 0x8000;
53 CHNREG32(i,20) = 0x1f;
54 }
55
56 SNDREG32(0x2800) = 0x000f;
57 g2_fifo_wait();
58 G2_UNLOCK(old);
59 }
60
61 /* Translates a volume from linear form to logarithmic form (required by
62 the AICA chip */
63 /* int logs[] = {
64
65 0, 40, 50, 58, 63, 68, 73, 77, 80, 83, 86, 89, 92, 94, 97, 99, 101, 103,
66 105, 107, 109, 111, 112, 114, 116, 117, 119, 120, 122, 123, 125, 126, 127,
67 129, 130, 131, 133, 134, 135, 136, 137, 139, 140, 141, 142, 143, 144, 145,
68 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
69 160, 161, 162, 162, 163, 164, 165, 166, 166, 167, 168, 169, 170, 170, 171,
70 172, 172, 173, 174, 175, 175, 176, 177, 177, 178, 179, 180, 180, 181, 182,
71 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 188, 189, 190, 190, 191,
72 191, 192, 193, 193, 194, 194, 195, 196, 196, 197, 197, 198, 198, 199, 199,
73 200, 201, 201, 202, 202, 203, 203, 204, 204, 205, 205, 206, 206, 207, 207,
74 208, 208, 209, 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215,
75 215, 216, 216, 217, 217, 217, 218, 218, 219, 219, 220, 220, 221, 221, 222,
76 222, 222, 223, 223, 224, 224, 225, 225, 225, 226, 226, 227, 227, 228, 228,
77 228, 229, 229, 230, 230, 230, 231, 231, 232, 232, 232, 233, 233, 234, 234,
78 234, 235, 235, 236, 236, 236, 237, 237, 238, 238, 238, 239, 239, 240, 240,
79 240, 241, 241, 241, 242, 242, 243, 243, 243, 244, 244, 244, 245, 245, 245,
80 246, 246, 247, 247, 247, 248, 248, 248, 249, 249, 249, 250, 250, 250, 251,
81 251, 251, 252, 252, 252, 253, 253, 253, 254, 254, 254, 255
82
83 }; */
84
85 const static unsigned char logs[] = {
86 0, 15, 22, 27, 31, 35, 39, 42, 45, 47, 50, 52, 55, 57, 59, 61,
87 63, 65, 67, 69, 71, 73, 74, 76, 78, 79, 81, 82, 84, 85, 87, 88,
88 90, 91, 92, 94, 95, 96, 98, 99, 100, 102, 103, 104, 105, 106,
89 108, 109, 110, 111, 112, 113, 114, 116, 117, 118, 119, 120, 121,
90 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
91 135, 136, 137, 138, 138, 139, 140, 141, 142, 143, 144, 145, 146,
92 146, 147, 148, 149, 150, 151, 152, 152, 153, 154, 155, 156, 156,
93 157, 158, 159, 160, 160, 161, 162, 163, 164, 164, 165, 166, 167,
94 167, 168, 169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176,
95 177, 178, 178, 179, 180, 181, 181, 182, 183, 183, 184, 185, 185,
96 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 193, 194,
97 195, 195, 196, 197, 197, 198, 199, 199, 200, 200, 201, 202, 202,
98 203, 204, 204, 205, 205, 206, 207, 207, 208, 209, 209, 210, 210,
99 211, 212, 212, 213, 213, 214, 215, 215, 216, 216, 217, 217, 218,
100 219, 219, 220, 220, 221, 221, 222, 223, 223, 224, 224, 225, 225,
101 226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 232, 232, 233,
102 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 239, 239, 240,
103 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246,
104 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 254, 255
105 };
106
107 /* For the moment this is going to have to suffice, until we really
108 figure out what these mean. */
109 #define AICA_PAN(x) ((x)==0x80?(0):((x)<0x80?(0x1f):(0x0f)))
110 #define AICA_VOL(x) (0xff - logs[128 + (((x) & 0xff) / 2)])
111 //#define AICA_VOL(x) (0xff - logs[x&255])
112
113 static inline unsigned AICA_FREQ(unsigned freq) {
114 unsigned long freq_lo, freq_base = 5644800;
115 int freq_hi = 7;
116
117 /* Need to convert frequency to floating point format
118 (freq_hi is exponent, freq_lo is mantissa)
119 Formula is ferq = 44100*2^freq_hi*(1+freq_lo/1024) */
120 while (freq < freq_base && freq_hi > -8) {
121 freq_base >>= 1;
122 --freq_hi;
123 }
124 while (freq < freq_base && freq_hi > -8) {
125 freq_base >>= 1;
126 freq_hi--;
127 }
128 freq_lo = (freq<<10) / freq_base;
129 return (freq_hi << 11) | (freq_lo & 1023);
130 }
131
132 /* Sets up a sound channel completely. This is generally good if you want
133 a quick and dirty way to play notes. If you want a more comprehensive
134 set of routines (more like PC wavetable cards) see below.
135
136 ch is the channel to play on (0 - 63)
137 smpptr is the pointer to the sound data; if you're running off the
138 SH4, then this ought to be (ptr - 0xa0800000); otherwise it's just
139 ptr. Basically, it's an offset into sound ram.
140 mode is one of the mode constants (16 bit, 8 bit, ADPCM)
141 nsamp is the number of samples to play (not number of bytes!)
142 freq is the sampling rate of the sound
143 vol is the volume, 0 to 0xff (0xff is louder)
144 pan is a panning constant -- 0 is left, 128 is center, 255 is right.
145
146 This routine (and the similar ones) owe a lot to Marcus' sound example --
147 I hadn't gotten quite this far into dissecting the individual regs yet. */
148 void aica_play(int ch,int mode,unsigned long smpptr,int loopst,int loopend,int freq,int vol,int pan,int loopflag) {
149 int i;
150 int val;
151 int old;
152
153 /* Stop the channel (if it's already playing) */
154 aica_stop(ch);
155 /* doesn't seem to be needed, but it's here just in case */
156 /*
157 for (i=0; i<256; i++) {
158 asm("nop");
159 asm("nop");
160 asm("nop");
161 asm("nop");
162 }
163 */
164 G2_LOCK(old);
165 /* Envelope setup. The first of these is the loop point,
166 e.g., where the sample starts over when it loops. The second
167 is the loop end. This is the full length of the sample when
168 you are not looping, or the loop end point when you are (though
169 storing more than that is a waste of memory if you're not doing
170 volume enveloping). */
171 CHNREG32(ch, 8) = loopst & 0xffff;
172 CHNREG32(ch, 12) = loopend & 0xffff;
173
174 /* Write resulting values */
175 CHNREG32(ch, 24) = AICA_FREQ(freq);
176
177 /* Set volume, pan, and some other things that we don't know what
178 they do =) */
179 CHNREG32(ch, 36) = AICA_PAN(pan) | (0xf<<8);
180 /* Convert the incoming volume and pan into hardware values */
181 /* Vol starts at zero so we can ramp */
182 vol = AICA_VOL(vol);
183 CHNREG32(ch, 40) = 0x24 | (vol<<8);
184 /* Convert the incoming volume and pan into hardware values */
185 /* Vol starts at zero so we can ramp */
186
187 /* If we supported volume envelopes (which we don't yet) then
188 this value would set that up. The top 4 bits determine the
189 envelope speed. f is the fastest, 1 is the slowest, and 0
190 seems to be an invalid value and does weird things). The
191 default (below) sets it into normal mode (play and terminate/loop).
192 CHNREG32(ch, 16) = 0xf010;
193 */
194 CHNREG32(ch, 16) = 0x1f; /* No volume envelope */
195
196
197 /* Set sample format, buffer address, and looping control. If
198 0x0200 mask is set on reg 0, the sample loops infinitely. If
199 it's not set, the sample plays once and terminates. We'll
200 also set the bits to start playback here. */
201 CHNREG32(ch, 4) = smpptr & 0xffff;
202 val = 0xc000 | 0x0000 | (mode<<7) | (smpptr >> 16);
203 if (loopflag) val|=0x200;
204
205 CHNREG32(ch, 0) = val;
206
207 G2_UNLOCK(old);
208
209 /* Enable playback */
210 /* CHNREG32(ch, 0) |= 0xc000; */
211 g2_fifo_wait();
212
213 #if 0
214 for (i=0xff; i>=vol; i--) {
215 if ((i&7)==0) g2_fifo_wait();
216 CHNREG32(ch, 40) = 0x24 | (i<<8);;
217 }
218
219 g2_fifo_wait();
220 #endif
221 }
222
223 /* Stop the sound on a given channel */
224 void aica_stop(int ch) {
225 g2_write_32(CHNREGADDR(ch, 0),(g2_read_32(CHNREGADDR(ch, 0)) & ~0x4000) | 0x8000);
226 g2_fifo_wait();
227 }
228
229
230 /* The rest of these routines can change the channel in mid-stride so you
231 can do things like vibrato and panning effects. */
232
233 /* Set channel volume */
234 void aica_vol(int ch,int vol) {
235 // g2_write_8(CHNREGADDR(ch, 41),AICA_VOL(vol));
236 g2_write_32(CHNREGADDR(ch, 40),(g2_read_32(CHNREGADDR(ch, 40))&0xffff00ff)|(AICA_VOL(vol)<<8) );
237 g2_fifo_wait();
238 }
239
240 /* Set channel pan */
241 void aica_pan(int ch,int pan) {
242 // g2_write_8(CHNREGADDR(ch, 36),AICA_PAN(pan));
243 g2_write_32(CHNREGADDR(ch, 36),(g2_read_32(CHNREGADDR(ch, 36))&0xffffff00)|(AICA_PAN(pan)) );
244 g2_fifo_wait();
245 }
246
247 /* Set channel frequency */
248 void aica_freq(int ch,int freq) {
249 g2_write_32(CHNREGADDR(ch, 24),AICA_FREQ(freq));
250 g2_fifo_wait();
251 }
252
253 /* Get channel position */
254 int aica_get_pos(int ch) {
255 #if 1
256 /* Observe channel ch */
257 g2_write_32(SNDREGADDR(0x280c),(g2_read_32(SNDREGADDR(0x280c))&0xffff00ff) | (ch<<8));
258 g2_fifo_wait();
259 /* Update position counters */
260 return g2_read_32(SNDREGADDR(0x2814)) & 0xffff;
261 #else
262 /* Observe channel ch */
263 g2_write_8(SNDREGADDR(0x280d),ch);
264 /* Update position counters */
265 return g2_read_32(SNDREGADDR(0x2814)) & 0xffff;
266 #endif
267 }