1 /* KallistiOS ##version##
4 (c)2000-2002 Dan Potter
6 ARM support routines for using the wavetable channels
9 #include "aica_cmd_iface.h"
12 extern volatile aica_channel_t *chans;
17 /* Initialize AICA channels */
18 SNDREG32(0x2800) = 0x0000;
20 for(i = 0; i < 64; i++) {
21 CHNREG32(i, 0) = 0x8000;
23 for(j = 4; j < 0x80; j += 4)
26 CHNREG32(i, 20) = 0x1f;
29 SNDREG32(0x2800) = 0x000f;
32 /* Translates a volume from linear form to logarithmic form (required by
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
56 static inline int calc_aica_vol(int x) {
57 return 0xff - logs[x & 0xff];
60 static inline int calc_aica_pan(int x) {
64 return 0x10 | ((0x7f - x) >> 3);
67 return (x - 0x80) >> 3;
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.
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.
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;
97 uint32 freq_lo, freq_base = 5644800;
102 /* Stop the channel (if it's already playing) */
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) {
113 freq_lo = (freq << 10) / freq_base;
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;
124 /* Write resulting values */
125 CHNREG32(ch, 24) = (freq_hi << 11) | (freq_lo & 1023);
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;
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;
143 CHNREG32(ch, 16) = 0x1f; /* No volume envelope */
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);
158 CHNREG32(ch, 0) = playCont; /* key off */
159 CHNREG8(ch, 41) = vol;
162 CHNREG32(ch, 0) = 0xc000 | playCont; /* key on */
164 /* ramp up the volume */
165 for(i = 0xff; i >= vol; i--)
170 /* Start sound on all channels specified by chmap bitmap */
171 void aica_sync_play(uint32 chmap) {
176 CHNREG32(i, 0) = CHNREG32(i, 0) | 0xc000;
183 /* Stop the sound on a given channel */
184 void aica_stop(int ch) {
185 CHNREG32(ch, 0) = (CHNREG32(ch, 0) & ~0x4000) | 0x8000;
189 /* The rest of these routines can change the channel in mid-stride so you
190 can do things like vibrato and panning effects. */
192 /* Set channel volume */
193 void aica_vol(int ch) {
194 CHNREG8(ch, 41) = calc_aica_vol(chans[ch].vol);
197 /* Set channel pan */
198 void aica_pan(int ch) {
199 CHNREG8(ch, 36) = calc_aica_pan(chans[ch].pan);
202 /* Set channel frequency */
203 void aica_freq(int ch) {
204 uint32 freq = chans[ch].freq;
205 uint32 freq_lo, freq_base = 5644800;
208 while(freq < freq_base && freq_hi > -8) {
213 freq_lo = (freq << 10) / freq_base;
214 CHNREG32(ch, 24) = (freq_hi << 11) | (freq_lo & 1023);
217 /* Get channel position */
218 int aica_get_pos(int ch) {
221 /* Observe channel ch */
222 SNDREG8(0x280d) = ch;
225 for(i = 0; i < 20; i++)
226 __asm__ volatile ("nop"); /* Prevent loop from being optimized out */
228 /* Update position counters */
229 chans[ch].pos = SNDREG32(0x2814) & 0xffff;
231 return chans[ch].pos;