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