Mercurial > hg > index.fcgi > lj > lj046
comparison src/gbasound.c @ 0:c84446dfb3f5
initial add
author | paulo@localhost |
---|---|
date | Fri, 13 Mar 2009 00:39:12 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a52ebaf4ec88 |
---|---|
1 #include <string.h> | |
2 #include "ljgba.h" | |
3 #include "pin8gba_sound.h" | |
4 extern const unsigned short note_freqs[]; | |
5 | |
6 static const u16 moveEffect[] = { | |
7 0, 3, | |
8 0x516D, 0x0000, 0x0100 | |
9 }; | |
10 | |
11 static const u16 rotateEffect[] = { | |
12 1, 7, | |
13 0x5161, 0x0000, 0x5166, 0x0000, 0x516b, 0x0000, 0x0100 | |
14 }; | |
15 | |
16 static const u16 landEffect[] = { | |
17 1, 6, | |
18 0x8188, 0x7185, 0x6182, 0x5181, 0x3180, 0x0000 | |
19 }; | |
20 | |
21 static const u16 lockEffect[] = { | |
22 3, 1, | |
23 0x2138 | |
24 }; | |
25 | |
26 static const u16 lineEffect[] = { | |
27 0, 12, | |
28 0xB1A4, 0xA1A6, 0x91A9, 0x81A4, 0x71A7, 0x61A9, | |
29 0x61A4, 0x51A6, 0x41A9, 0x31A4, 0x21A7, 0x11A9 | |
30 }; | |
31 | |
32 static const u16 holdEffect[] = { | |
33 3, 8, | |
34 0x3030, 0x0000, 0x4032, 0x0000, 0x3130, 0x0000, 0x202c, 0x2128 | |
35 }; | |
36 | |
37 static const u16 irsRotateEffect[] = { | |
38 1, 12, | |
39 0x5161, 0x51B1, 0x5166, 0x51B6, 0x516B, 0x51BB, 0x0000, 0x0000, | |
40 0x0000, 0x0000, 0x0000, 0x0100 | |
41 }; | |
42 | |
43 static const u16 homerEffect[] = { | |
44 0, 22, | |
45 0xB1A4, 0xA1A6, 0x91A9, 0x81A4, 0x71A7, 0x61A9, | |
46 0x61A4, 0x51A6, 0x41A9, 0x31A4, | |
47 0xB1A7, 0xA1A9, 0x91AC, 0x81A7, 0x71AA, 0x61AC, | |
48 0x51A7, 0x41A9, 0x31AC, 0x21A7, 0x11AA, 0x01AC | |
49 }; | |
50 | |
51 static const u16 streakEffect[] = { | |
52 0, 30, | |
53 0xB1A4, 0xA1A6, 0x91A9, 0x81A4, 0x71A7, 0x61A9, | |
54 0x61A4, 0x51A6, 0x41A9, 0x31A4, | |
55 0xB1A7, 0xA1A9, 0x91AC, 0x81A7, 0x71AA, 0x61AC, | |
56 0x51A7, 0x41A9, 0x31AC, 0x21A7, | |
57 0xB1AA, 0xA1AC, 0x91AF, 0x71AA, 0x61AD, 0x51AF, | |
58 0x31AA, 0x21AC, 0x11AF, 0x01AA | |
59 }; | |
60 | |
61 static const u16 sectionEffect[] = { | |
62 1, 30, | |
63 0xB1B0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
64 0xB1B4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
65 0xB1B7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
66 0xB1BC, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
67 0xB1B0, 0x0000 | |
68 }; | |
69 | |
70 static const u16 gameOverEffect1[] = { | |
71 1, 40, | |
72 0xF504, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
73 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
74 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
75 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
76 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 | |
77 }; | |
78 | |
79 static const u16 gameOverEffect2[] = { | |
80 3, 40, | |
81 0xC12C, 0xA725, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
82 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
83 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
84 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
85 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 | |
86 }; | |
87 | |
88 static const u16 winEffect1[] = { | |
89 1, 30, | |
90 0xA564, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, | |
91 0xA562, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, | |
92 0xA564, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, | |
93 0xA566, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
94 0x0000, 0x0000 | |
95 }; | |
96 | |
97 static const u16 winEffect2[] = { | |
98 0, 30, | |
99 0xA568, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, | |
100 0xA566, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, | |
101 0xA568, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, | |
102 0xA56A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, | |
103 0x0000, 0x0000 | |
104 }; | |
105 | |
106 | |
107 static const u16 *const effects[] = { | |
108 moveEffect, rotateEffect, landEffect, lockEffect, lineEffect, | |
109 holdEffect, irsRotateEffect, homerEffect, streakEffect, sectionEffect, | |
110 gameOverEffect1, gameOverEffect2, winEffect1, winEffect2 | |
111 }; | |
112 | |
113 const unsigned short tri_vol_table[5] = { | |
114 0, | |
115 TRILENVOL_25, | |
116 TRILENVOL_50, | |
117 TRILENVOL_75, | |
118 TRILENVOL_100 | |
119 }; | |
120 | |
121 void play_note(unsigned int ch, unsigned int note, unsigned int instrument) { | |
122 switch (ch) { | |
123 case 0: | |
124 SQR1CTRL = instrument; | |
125 SQR1FREQ = note_freqs[note] | FREQ_RESET; | |
126 break; | |
127 case 1: | |
128 SQR2CTRL = instrument; | |
129 SQR2FREQ = note_freqs[note] | FREQ_RESET; | |
130 break; | |
131 case 2: | |
132 { | |
133 int vol = instrument >> 13; | |
134 TRILENVOL = tri_vol_table[(vol + 1) / 2]; | |
135 TRIFREQ = note_freqs[note] | FREQ_RESET; | |
136 } | |
137 break; | |
138 case 3: | |
139 NOISECTRL = instrument; | |
140 { | |
141 int octave = (note & 0x3E) << 2; | |
142 int pitch = note & 0x03; | |
143 NOISEFREQ = (octave | pitch) ^ (0xF7 | FREQ_RESET); | |
144 } | |
145 break; | |
146 } | |
147 } | |
148 | |
149 void gba_poll_sound(struct LJPCView *v) { | |
150 for (int i = 0; i < 4; ++i) { | |
151 if (v->sndLeft[i]) { | |
152 unsigned int data = *v->sndData[i]; | |
153 if (data) { | |
154 play_note(i, data & 0x003F, data & 0xFFC0); | |
155 } | |
156 ++v->sndData[i]; | |
157 --v->sndLeft[i]; | |
158 } | |
159 } | |
160 } | |
161 | |
162 void gba_play_sound(struct LJPCView *v, int effect) { | |
163 const u16 *data = effects[effect]; | |
164 int ch = data[0]; | |
165 int len = data[1]; | |
166 | |
167 // square waves can be played on either channel 0 or 1; | |
168 // switch if this channel is occupied and the other is free | |
169 if (ch < 2 | |
170 && v->sndLeft[ch] > v->sndLeft[1 - ch]) { | |
171 ch = 1 - ch; | |
172 } | |
173 v->sndData[ch] = data + 2; | |
174 v->sndLeft[ch] = len; | |
175 } | |
176 | |
177 /** | |
178 * Sets the sound bias to mid and resolution to 8-bit. | |
179 * Setting bias is needed because some launchers (such as pogoshell) | |
180 * set it to a state that mutes the tone generators. | |
181 */ | |
182 static void set_bias(void) | |
183 { | |
184 asm volatile("mov r2, #2; lsl r2, #8; swi 0x19" ::: "r0", "r1", "r2", "r3"); | |
185 SETSNDRES(1); | |
186 } | |
187 | |
188 __attribute__((aligned(4))) | |
189 static const unsigned char triangleWave[16] = { | |
190 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, | |
191 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 | |
192 }; | |
193 unsigned char lastWaveBank = 0; | |
194 | |
195 void tri_set_waveform(const void *waveform) { | |
196 memcpy((void *)TRIWAVERAM, waveform, 16); | |
197 lastWaveBank = !lastWaveBank; | |
198 TRICTRL = TRICTRL_2X32 | TRICTRL_BANK(lastWaveBank) | TRICTRL_ENABLE; | |
199 } | |
200 | |
201 void install_sound(struct LJPCView *v) { | |
202 SNDSTAT = SNDSTAT_ENABLE; | |
203 DMGSNDCTRL = DMGSNDCTRL_LVOL(7) | DMGSNDCTRL_RVOL(7) | |
204 | DMGSNDCTRL_LSQR1 | DMGSNDCTRL_RSQR1 | |
205 | DMGSNDCTRL_LSQR2 | DMGSNDCTRL_RSQR2 | |
206 | DMGSNDCTRL_LTRI | DMGSNDCTRL_RTRI | |
207 | DMGSNDCTRL_LNOISE | DMGSNDCTRL_RNOISE; | |
208 DSOUNDCTRL = DSOUNDCTRL_DMG100; | |
209 set_bias(); | |
210 SQR1SWEEP = SQR1SWEEP_OFF; | |
211 | |
212 #if 0 | |
213 TRICTRL = TRICTRL_2X32 | TRICTRL_BANK(0) | TRICTRL_ENABLE; | |
214 tri_set_waveform(triangleWave); | |
215 TRILENVOL = 0; | |
216 TRIFREQ = 1024 | FREQ_RESET; | |
217 #endif | |
218 | |
219 v->sndLeft[0] = 0; | |
220 v->sndLeft[1] = 0; | |
221 v->sndLeft[2] = 0; | |
222 v->sndLeft[3] = 0; | |
223 } | |
224 |