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;
101 /* Stop the channel (if it's already playing) */
104 /* Need to convert frequency to floating point format
105 (freq_hi is exponent, freq_lo is mantissa)
106 Formula is freq = 44100*2^freq_hi*(1+freq_lo/1024) */
107 while(freq < freq_base && freq_hi > -8) {
112 freq_lo = (freq << 10) / freq_base;
114 /* Envelope setup. The first of these is the loop point,
115 e.g., where the sample starts over when it loops. The second
116 is the loop end. This is the full length of the sample when
117 you are not looping, or the loop end point when you are (though
118 storing more than that is a waste of memory if you're not doing
119 volume enveloping). */
120 CHNREG32(ch, 8) = loopst & 0xffff;
121 CHNREG32(ch, 12) = loopend & 0xffff;
123 /* Write resulting values */
124 CHNREG32(ch, 24) = (freq_hi << 11) | (freq_lo & 1023);
126 /* Convert the incoming pan into a hardware value and set it */
127 CHNREG8(ch, 36) = calc_aica_pan(pan);
128 CHNREG8(ch, 37) = 0xf;
129 /* turn off Low Pass Filter (LPF) */
130 CHNREG8(ch, 40) = 0x24;
131 /* Convert the incoming volume into a hardware value and set it */
132 CHNREG8(ch, 41) = calc_aica_vol(vol);
134 /* If we supported volume envelopes (which we don't yet) then
135 this value would set that up. The top 4 bits determine the
136 envelope speed. f is the fastest, 1 is the slowest, and 0
137 seems to be an invalid value and does weird things). The
138 default (below) sets it into normal mode (play and terminate/loop).
139 CHNREG32(ch, 16) = 0xf010;
141 CHNREG32(ch, 16) = 0x1f; /* No volume envelope */
144 /* Set sample format, buffer address, and looping control. If
145 0x0200 mask is set on reg 0, the sample loops infinitely. If
146 it's not set, the sample plays once and terminates. We'll
147 also set the bits to start playback here. */
148 CHNREG32(ch, 4) = smpptr & 0xffff;
149 playCont = (mode << 7) | (smpptr >> 16);
155 CHNREG32(ch, 0) = playCont; /* key off */
158 CHNREG32(ch, 0) = 0xc000 | playCont; /* key on */
162 /* Start sound on all channels specified by chmap bitmap */
163 void aica_sync_play(uint32 chmap) {
168 CHNREG32(i, 0) = CHNREG32(i, 0) | 0xc000;
175 /* Stop the sound on a given channel */
176 void aica_stop(int ch) {
177 CHNREG32(ch, 0) = (CHNREG32(ch, 0) & ~0x4000) | 0x8000;
181 /* The rest of these routines can change the channel in mid-stride so you
182 can do things like vibrato and panning effects. */
184 /* Set channel volume */
185 void aica_vol(int ch) {
186 CHNREG8(ch, 41) = calc_aica_vol(chans[ch].vol);
189 /* Set channel pan */
190 void aica_pan(int ch) {
191 CHNREG8(ch, 36) = calc_aica_pan(chans[ch].pan);
194 /* Set channel frequency */
195 void aica_freq(int ch) {
196 uint32 freq = chans[ch].freq;
197 uint32 freq_lo, freq_base = 5644800;
200 while(freq < freq_base && freq_hi > -8) {
205 freq_lo = (freq << 10) / freq_base;
206 CHNREG32(ch, 24) = (freq_hi << 11) | (freq_lo & 1023);
209 /* Get channel position */
210 int aica_get_pos(int ch) {
213 /* Observe channel ch */
214 SNDREG8(0x280d) = ch;
217 for(i = 0; i < 20; i++)
218 __asm__ volatile ("nop"); /* Prevent loop from being optimized out */
220 /* Update position counters */
221 chans[ch].pos = SNDREG32(0x2814) & 0xffff;
223 return chans[ch].pos;