Mercurial > hg > index.fcgi > lj > lj046
diff src/gbasound.c @ 0:c84446dfb3f5
initial add
author | paulo@localhost |
---|---|
date | Fri, 13 Mar 2009 00:39:12 -0700 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/gbasound.c Fri Mar 13 00:39:12 2009 -0700 1.3 @@ -0,0 +1,224 @@ 1.4 +#include <string.h> 1.5 +#include "ljgba.h" 1.6 +#include "pin8gba_sound.h" 1.7 +extern const unsigned short note_freqs[]; 1.8 + 1.9 +static const u16 moveEffect[] = { 1.10 + 0, 3, 1.11 + 0x516D, 0x0000, 0x0100 1.12 +}; 1.13 + 1.14 +static const u16 rotateEffect[] = { 1.15 + 1, 7, 1.16 + 0x5161, 0x0000, 0x5166, 0x0000, 0x516b, 0x0000, 0x0100 1.17 +}; 1.18 + 1.19 +static const u16 landEffect[] = { 1.20 + 1, 6, 1.21 + 0x8188, 0x7185, 0x6182, 0x5181, 0x3180, 0x0000 1.22 +}; 1.23 + 1.24 +static const u16 lockEffect[] = { 1.25 + 3, 1, 1.26 + 0x2138 1.27 +}; 1.28 + 1.29 +static const u16 lineEffect[] = { 1.30 + 0, 12, 1.31 + 0xB1A4, 0xA1A6, 0x91A9, 0x81A4, 0x71A7, 0x61A9, 1.32 + 0x61A4, 0x51A6, 0x41A9, 0x31A4, 0x21A7, 0x11A9 1.33 +}; 1.34 + 1.35 +static const u16 holdEffect[] = { 1.36 + 3, 8, 1.37 + 0x3030, 0x0000, 0x4032, 0x0000, 0x3130, 0x0000, 0x202c, 0x2128 1.38 +}; 1.39 + 1.40 +static const u16 irsRotateEffect[] = { 1.41 + 1, 12, 1.42 + 0x5161, 0x51B1, 0x5166, 0x51B6, 0x516B, 0x51BB, 0x0000, 0x0000, 1.43 + 0x0000, 0x0000, 0x0000, 0x0100 1.44 +}; 1.45 + 1.46 +static const u16 homerEffect[] = { 1.47 + 0, 22, 1.48 + 0xB1A4, 0xA1A6, 0x91A9, 0x81A4, 0x71A7, 0x61A9, 1.49 + 0x61A4, 0x51A6, 0x41A9, 0x31A4, 1.50 + 0xB1A7, 0xA1A9, 0x91AC, 0x81A7, 0x71AA, 0x61AC, 1.51 + 0x51A7, 0x41A9, 0x31AC, 0x21A7, 0x11AA, 0x01AC 1.52 +}; 1.53 + 1.54 +static const u16 streakEffect[] = { 1.55 + 0, 30, 1.56 + 0xB1A4, 0xA1A6, 0x91A9, 0x81A4, 0x71A7, 0x61A9, 1.57 + 0x61A4, 0x51A6, 0x41A9, 0x31A4, 1.58 + 0xB1A7, 0xA1A9, 0x91AC, 0x81A7, 0x71AA, 0x61AC, 1.59 + 0x51A7, 0x41A9, 0x31AC, 0x21A7, 1.60 + 0xB1AA, 0xA1AC, 0x91AF, 0x71AA, 0x61AD, 0x51AF, 1.61 + 0x31AA, 0x21AC, 0x11AF, 0x01AA 1.62 +}; 1.63 + 1.64 +static const u16 sectionEffect[] = { 1.65 + 1, 30, 1.66 + 0xB1B0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 1.67 + 0xB1B4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 1.68 + 0xB1B7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 1.69 + 0xB1BC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 1.70 + 0xB1B0, 0x0000 1.71 +}; 1.72 + 1.73 +static const u16 gameOverEffect1[] = { 1.74 + 1, 40, 1.75 + 0xF504, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 1.76 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 1.77 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 1.78 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 1.79 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 1.80 +}; 1.81 + 1.82 +static const u16 gameOverEffect2[] = { 1.83 + 3, 40, 1.84 + 0xC12C, 0xA725, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 1.85 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 1.86 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 1.87 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 1.88 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 1.89 +}; 1.90 + 1.91 +static const u16 winEffect1[] = { 1.92 + 1, 30, 1.93 + 0xA564, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 1.94 + 0xA562, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 1.95 + 0xA564, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 1.96 + 0xA566, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 1.97 + 0x0000, 0x0000 1.98 +}; 1.99 + 1.100 +static const u16 winEffect2[] = { 1.101 + 0, 30, 1.102 + 0xA568, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 1.103 + 0xA566, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 1.104 + 0xA568, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 1.105 + 0xA56A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 1.106 + 0x0000, 0x0000 1.107 +}; 1.108 + 1.109 + 1.110 +static const u16 *const effects[] = { 1.111 + moveEffect, rotateEffect, landEffect, lockEffect, lineEffect, 1.112 + holdEffect, irsRotateEffect, homerEffect, streakEffect, sectionEffect, 1.113 + gameOverEffect1, gameOverEffect2, winEffect1, winEffect2 1.114 +}; 1.115 + 1.116 +const unsigned short tri_vol_table[5] = { 1.117 + 0, 1.118 + TRILENVOL_25, 1.119 + TRILENVOL_50, 1.120 + TRILENVOL_75, 1.121 + TRILENVOL_100 1.122 +}; 1.123 + 1.124 +void play_note(unsigned int ch, unsigned int note, unsigned int instrument) { 1.125 + switch (ch) { 1.126 + case 0: 1.127 + SQR1CTRL = instrument; 1.128 + SQR1FREQ = note_freqs[note] | FREQ_RESET; 1.129 + break; 1.130 + case 1: 1.131 + SQR2CTRL = instrument; 1.132 + SQR2FREQ = note_freqs[note] | FREQ_RESET; 1.133 + break; 1.134 + case 2: 1.135 + { 1.136 + int vol = instrument >> 13; 1.137 + TRILENVOL = tri_vol_table[(vol + 1) / 2]; 1.138 + TRIFREQ = note_freqs[note] | FREQ_RESET; 1.139 + } 1.140 + break; 1.141 + case 3: 1.142 + NOISECTRL = instrument; 1.143 + { 1.144 + int octave = (note & 0x3E) << 2; 1.145 + int pitch = note & 0x03; 1.146 + NOISEFREQ = (octave | pitch) ^ (0xF7 | FREQ_RESET); 1.147 + } 1.148 + break; 1.149 + } 1.150 +} 1.151 + 1.152 +void gba_poll_sound(struct LJPCView *v) { 1.153 + for (int i = 0; i < 4; ++i) { 1.154 + if (v->sndLeft[i]) { 1.155 + unsigned int data = *v->sndData[i]; 1.156 + if (data) { 1.157 + play_note(i, data & 0x003F, data & 0xFFC0); 1.158 + } 1.159 + ++v->sndData[i]; 1.160 + --v->sndLeft[i]; 1.161 + } 1.162 + } 1.163 +} 1.164 + 1.165 +void gba_play_sound(struct LJPCView *v, int effect) { 1.166 + const u16 *data = effects[effect]; 1.167 + int ch = data[0]; 1.168 + int len = data[1]; 1.169 + 1.170 + // square waves can be played on either channel 0 or 1; 1.171 + // switch if this channel is occupied and the other is free 1.172 + if (ch < 2 1.173 + && v->sndLeft[ch] > v->sndLeft[1 - ch]) { 1.174 + ch = 1 - ch; 1.175 + } 1.176 + v->sndData[ch] = data + 2; 1.177 + v->sndLeft[ch] = len; 1.178 +} 1.179 + 1.180 +/** 1.181 + * Sets the sound bias to mid and resolution to 8-bit. 1.182 + * Setting bias is needed because some launchers (such as pogoshell) 1.183 + * set it to a state that mutes the tone generators. 1.184 + */ 1.185 +static void set_bias(void) 1.186 +{ 1.187 + asm volatile("mov r2, #2; lsl r2, #8; swi 0x19" ::: "r0", "r1", "r2", "r3"); 1.188 + SETSNDRES(1); 1.189 +} 1.190 + 1.191 +__attribute__((aligned(4))) 1.192 +static const unsigned char triangleWave[16] = { 1.193 + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 1.194 + 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 1.195 +}; 1.196 +unsigned char lastWaveBank = 0; 1.197 + 1.198 +void tri_set_waveform(const void *waveform) { 1.199 + memcpy((void *)TRIWAVERAM, waveform, 16); 1.200 + lastWaveBank = !lastWaveBank; 1.201 + TRICTRL = TRICTRL_2X32 | TRICTRL_BANK(lastWaveBank) | TRICTRL_ENABLE; 1.202 +} 1.203 + 1.204 +void install_sound(struct LJPCView *v) { 1.205 + SNDSTAT = SNDSTAT_ENABLE; 1.206 + DMGSNDCTRL = DMGSNDCTRL_LVOL(7) | DMGSNDCTRL_RVOL(7) 1.207 + | DMGSNDCTRL_LSQR1 | DMGSNDCTRL_RSQR1 1.208 + | DMGSNDCTRL_LSQR2 | DMGSNDCTRL_RSQR2 1.209 + | DMGSNDCTRL_LTRI | DMGSNDCTRL_RTRI 1.210 + | DMGSNDCTRL_LNOISE | DMGSNDCTRL_RNOISE; 1.211 + DSOUNDCTRL = DSOUNDCTRL_DMG100; 1.212 + set_bias(); 1.213 + SQR1SWEEP = SQR1SWEEP_OFF; 1.214 + 1.215 +#if 0 1.216 + TRICTRL = TRICTRL_2X32 | TRICTRL_BANK(0) | TRICTRL_ENABLE; 1.217 + tri_set_waveform(triangleWave); 1.218 + TRILENVOL = 0; 1.219 + TRIFREQ = 1024 | FREQ_RESET; 1.220 +#endif 1.221 + 1.222 + v->sndLeft[0] = 0; 1.223 + v->sndLeft[1] = 0; 1.224 + v->sndLeft[2] = 0; 1.225 + v->sndLeft[3] = 0; 1.226 +} 1.227 +