Makefile: Add atusb to 'all'
[linux-libre-firmware.git] / aica / arm / aica.c
1 /* KallistiOS ##version##
2
3    aica.c
4    (c)2000-2002 Dan Potter
5
6    ARM support routines for using the wavetable channels
7 */
8
9 #include "aica_cmd_iface.h"
10 #include "aica.h"
11
12 extern volatile aica_channel_t *chans;
13
14 void aica_init() {
15     int i, j;
16
17     /* Initialize AICA channels */
18     SNDREG32(0x2800) = 0x0000;
19
20     for(i = 0; i < 64; i++) {
21         CHNREG32(i, 0) = 0x8000;
22
23         for(j = 4; j < 0x80; j += 4)
24             CHNREG32(i, j) = 0;
25
26         CHNREG32(i, 20) = 0x1f;
27     }
28
29     SNDREG32(0x2800) = 0x000f;
30 }
31
32 /* Translates a volume from linear form to logarithmic form (required by
33    the AICA chip */
34 static int logs[] = {
35     0, 15, 22, 27, 31, 35, 39, 42, 45, 47, 50, 52, 55, 57, 59, 61,
36     63, 65, 67, 69, 71, 73, 74, 76, 78, 79, 81, 82, 84, 85, 87, 88,
37     90, 91, 92, 94, 95, 96, 98, 99, 100, 102, 103, 104, 105, 106,
38     108, 109, 110, 111, 112, 113, 114, 116, 117, 118, 119, 120, 121,
39     122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
40     135, 136, 137, 138, 138, 139, 140, 141, 142, 143, 144, 145, 146,
41     146, 147, 148, 149, 150, 151, 152, 152, 153, 154, 155, 156, 156,
42     157, 158, 159, 160, 160, 161, 162, 163, 164, 164, 165, 166, 167,
43     167, 168, 169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176,
44     177, 178, 178, 179, 180, 181, 181, 182, 183, 183, 184, 185, 185,
45     186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193, 193, 194,
46     195, 195, 196, 197, 197, 198, 199, 199, 200, 200, 201, 202, 202,
47     203, 204, 204, 205, 205, 206, 207, 207, 208, 209, 209, 210, 210,
48     211, 212, 212, 213, 213, 214, 215, 215, 216, 216, 217, 217, 218,
49     219, 219, 220, 220, 221, 221, 222, 223, 223, 224, 224, 225, 225,
50     226, 227, 227, 228, 228, 229, 229, 230, 230, 231, 232, 232, 233,
51     233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 239, 239, 240,
52     240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246,
53     247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 254, 255
54 };
55
56 static inline int calc_aica_vol(int x) {
57     return 0xff - logs[x & 0xff];
58 }
59
60 static inline int calc_aica_pan(int x) {
61     if(x == 0x80)
62         return 0;
63     else if(x < 0x80) {
64         return 0x10 | ((0x7f - x) >> 3);
65     }
66     else {
67         return (x - 0x80) >> 3;
68     }
69 }
70
71 /* Sets up a sound channel completely. This is generally good if you want
72    a quick and dirty way to play notes. If you want a more comprehensive
73    set of routines (more like PC wavetable cards) see below.
74
75    ch is the channel to play on (0 - 63)
76    smpptr is the pointer to the sound data; if you're running off the
77      SH4, then this ought to be (ptr - 0xa0800000); otherwise it's just
78      ptr. Basically, it's an offset into sound ram.
79    mode is one of the mode constants (16 bit, 8 bit, ADPCM)
80    nsamp is the number of samples to play (not number of bytes!)
81    freq is the sampling rate of the sound
82    vol is the volume, 0 to 0xff (0xff is louder)
83    pan is a panning constant -- 0 is left, 128 is center, 255 is right.
84
85    This routine (and the similar ones) owe a lot to Marcus' sound example --
86    I hadn't gotten quite this far into dissecting the individual regs yet. */
87 void aica_play(int ch, int delay) {
88     uint32 smpptr   = chans[ch].base;
89     uint32 mode     = chans[ch].type;
90     uint32 loopst   = chans[ch].loopstart;
91     uint32 loopend  = chans[ch].loopend;
92     uint32 freq     = chans[ch].freq;
93     uint32 vol      = chans[ch].vol;
94     uint32 pan      = chans[ch].pan;
95     uint32 loopflag = chans[ch].loop;
96
97     uint32 freq_lo, freq_base = 5644800;
98     int freq_hi = 7;
99     uint32 i;
100     uint32 playCont;
101
102     /* Stop the channel (if it's already playing) */
103     aica_stop(ch);
104
105     /* Need to convert frequency to floating point format
106        (freq_hi is exponent, freq_lo is mantissa)
107        Formula is freq = 44100*2^freq_hi*(1+freq_lo/1024) */
108     while(freq < freq_base && freq_hi > -8) {
109         freq_base >>= 1;
110         --freq_hi;
111     }
112
113     freq_lo = (freq << 10) / freq_base;
114
115     /* Envelope setup. The first of these is the loop point,
116        e.g., where the sample starts over when it loops. The second
117        is the loop end. This is the full length of the sample when
118        you are not looping, or the loop end point when you are (though
119        storing more than that is a waste of memory if you're not doing
120        volume enveloping). */
121     CHNREG32(ch, 8) = loopst & 0xffff;
122     CHNREG32(ch, 12) = loopend & 0xffff;
123
124     /* Write resulting values */
125     CHNREG32(ch, 24) = (freq_hi << 11) | (freq_lo & 1023);
126
127     /* Set volume, pan */
128     CHNREG8(ch, 36) = calc_aica_pan(pan);
129     CHNREG8(ch, 37) = 0xf;
130     /* turn off Low Pass Filter (LPF) */
131     CHNREG8(ch, 40) = 0x24;
132     /* Convert the incoming volume and pan into hardware values */
133     /* Vol starts at zero so we can ramp */
134     CHNREG8(ch, 41) = 0xff;
135
136     /* If we supported volume envelopes (which we don't yet) then
137        this value would set that up. The top 4 bits determine the
138        envelope speed. f is the fastest, 1 is the slowest, and 0
139        seems to be an invalid value and does weird things). The
140        default (below) sets it into normal mode (play and terminate/loop).
141     CHNREG32(ch, 16) = 0xf010;
142     */
143     CHNREG32(ch, 16) = 0x1f;    /* No volume envelope */
144
145
146     /* Set sample format, buffer address, and looping control. If
147        0x0200 mask is set on reg 0, the sample loops infinitely. If
148        it's not set, the sample plays once and terminates. We'll
149        also set the bits to start playback here. */
150     CHNREG32(ch, 4) = smpptr & 0xffff;
151     playCont = (mode << 7) | (smpptr >> 16);
152     vol = calc_aica_vol(vol);
153
154     if(loopflag)
155         playCont |= 0x0200;
156
157     if(delay) {
158         CHNREG32(ch, 0) = playCont;         /* key off */
159         CHNREG8(ch, 41) = vol;
160     }
161     else {
162         CHNREG32(ch, 0) = 0xc000 | playCont;    /* key on */
163
164         /* ramp up the volume */
165         for(i = 0xff; i >= vol; i--)
166             CHNREG8(ch, 41) = i;
167     }
168 }
169
170 /* Start sound on all channels specified by chmap bitmap */
171 void aica_sync_play(uint32 chmap) {
172     int i = 0;
173
174     while(chmap) {
175         if(chmap & 0x1)
176             CHNREG32(i, 0) = CHNREG32(i, 0) | 0xc000;
177
178         i++;
179         chmap >>= 1;
180     }
181 }
182
183 /* Stop the sound on a given channel */
184 void aica_stop(int ch) {
185     CHNREG32(ch, 0) = (CHNREG32(ch, 0) & ~0x4000) | 0x8000;
186 }
187
188
189 /* The rest of these routines can change the channel in mid-stride so you
190    can do things like vibrato and panning effects. */
191
192 /* Set channel volume */
193 void aica_vol(int ch) {
194     CHNREG8(ch, 41) = calc_aica_vol(chans[ch].vol);
195 }
196
197 /* Set channel pan */
198 void aica_pan(int ch) {
199     CHNREG8(ch, 36) = calc_aica_pan(chans[ch].pan);
200 }
201
202 /* Set channel frequency */
203 void aica_freq(int ch) {
204     uint32 freq = chans[ch].freq;
205     uint32 freq_lo, freq_base = 5644800;
206     int freq_hi = 7;
207
208     while(freq < freq_base && freq_hi > -8) {
209         freq_base >>= 1;
210         freq_hi--;
211     }
212
213     freq_lo = (freq << 10) / freq_base;
214     CHNREG32(ch, 24) = (freq_hi << 11) | (freq_lo & 1023);
215 }
216
217 /* Get channel position */
218 int aica_get_pos(int ch) {
219     int i;
220
221     /* Observe channel ch */
222     SNDREG8(0x280d) = ch;
223
224     /* Wait a while */
225     for(i = 0; i < 20; i++)
226         __asm__ volatile ("nop");  /* Prevent loop from being optimized out */
227
228     /* Update position counters */
229     chans[ch].pos = SNDREG32(0x2814) & 0xffff;
230
231     return chans[ch].pos;
232 }