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 } 272