/src/vlc/contrib/contrib-build/game-music-emu/gme/Gb_Oscs.cpp
Line | Count | Source |
1 | | // Gb_Snd_Emu 0.1.5. http://www.slack.net/~ant/ |
2 | | |
3 | | #include "Gb_Apu.h" |
4 | | |
5 | | #include <string.h> |
6 | | |
7 | | /* Copyright (C) 2003-2006 Shay Green. This module is free software; you |
8 | | can redistribute it and/or modify it under the terms of the GNU Lesser |
9 | | General Public License as published by the Free Software Foundation; either |
10 | | version 2.1 of the License, or (at your option) any later version. This |
11 | | module is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
13 | | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
14 | | details. You should have received a copy of the GNU Lesser General Public |
15 | | License along with this module; if not, write to the Free Software Foundation, |
16 | | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ |
17 | | |
18 | | #include "blargg_source.h" |
19 | | |
20 | | // Gb_Osc |
21 | | |
22 | | void Gb_Osc::reset() |
23 | 10.4k | { |
24 | 10.4k | delay = 0; |
25 | 10.4k | last_amp = 0; |
26 | 10.4k | length = 0; |
27 | 10.4k | output_select = 3; |
28 | 10.4k | output = outputs [output_select]; |
29 | 10.4k | } |
30 | | |
31 | | void Gb_Osc::clock_length() |
32 | 20.5M | { |
33 | 20.5M | if ( (regs [4] & len_enabled_mask) && length ) |
34 | 672k | length--; |
35 | 20.5M | } |
36 | | |
37 | | // Gb_Env |
38 | | |
39 | | void Gb_Env::clock_envelope() |
40 | 3.85M | { |
41 | 3.85M | if ( env_delay && !--env_delay ) |
42 | 36.3k | { |
43 | 36.3k | env_delay = regs [2] & 7; |
44 | 36.3k | int v = volume - 1 + (regs [2] >> 2 & 2); |
45 | 36.3k | if ( (unsigned) v < 15 ) |
46 | 4.24k | volume = v; |
47 | 36.3k | } |
48 | 3.85M | } |
49 | | |
50 | | bool Gb_Env::write_register( int reg, int data ) |
51 | 277k | { |
52 | 277k | switch ( reg ) |
53 | 277k | { |
54 | 56.7k | case 1: |
55 | 56.7k | length = 64 - (regs [1] & 0x3F); |
56 | 56.7k | break; |
57 | | |
58 | 54.4k | case 2: |
59 | 54.4k | if ( !(data >> 4) ) |
60 | 33.8k | enabled = false; |
61 | 54.4k | break; |
62 | | |
63 | 55.1k | case 4: |
64 | 55.1k | if ( data & trigger ) |
65 | 23.6k | { |
66 | 23.6k | env_delay = regs [2] & 7; |
67 | 23.6k | volume = regs [2] >> 4; |
68 | 23.6k | enabled = true; |
69 | 23.6k | if ( length == 0 ) |
70 | 5.79k | length = 64; |
71 | 23.6k | return true; |
72 | 23.6k | } |
73 | 277k | } |
74 | 253k | return false; |
75 | 277k | } |
76 | | |
77 | | // Gb_Square |
78 | | |
79 | | void Gb_Square::reset() |
80 | 5.21k | { |
81 | 5.21k | phase = 0; |
82 | 5.21k | sweep_freq = 0; |
83 | 5.21k | sweep_delay = 0; |
84 | 5.21k | Gb_Env::reset(); |
85 | 5.21k | } |
86 | | |
87 | | void Gb_Square::clock_sweep() |
88 | 2.57M | { |
89 | 2.57M | int sweep_period = (regs [0] & period_mask) >> 4; |
90 | 2.57M | if ( sweep_period && sweep_delay && !--sweep_delay ) |
91 | 21.3k | { |
92 | 21.3k | sweep_delay = sweep_period; |
93 | 21.3k | regs [3] = sweep_freq & 0xFF; |
94 | 21.3k | regs [4] = (regs [4] & ~0x07) | (sweep_freq >> 8 & 0x07); |
95 | | |
96 | 21.3k | int offset = sweep_freq >> (regs [0] & shift_mask); |
97 | 21.3k | if ( regs [0] & 0x08 ) |
98 | 19.6k | offset = -offset; |
99 | 21.3k | sweep_freq += offset; |
100 | | |
101 | 21.3k | if ( sweep_freq < 0 ) |
102 | 0 | { |
103 | 0 | sweep_freq = 0; |
104 | 0 | } |
105 | 21.3k | else if ( sweep_freq >= 2048 ) |
106 | 172 | { |
107 | 172 | sweep_delay = 0; // don't modify channel frequency any further |
108 | 172 | sweep_freq = 2048; // silence sound immediately |
109 | 172 | } |
110 | 21.3k | } |
111 | 2.57M | } |
112 | | |
113 | | void Gb_Square::run( blip_time_t time, blip_time_t end_time, int playing ) |
114 | 7.02M | { |
115 | 7.02M | if ( sweep_freq == 2048 ) |
116 | 13.3k | playing = false; |
117 | | |
118 | 7.02M | static unsigned char const table [4] = { 1, 2, 4, 6 }; |
119 | 7.02M | int const duty = table [regs [1] >> 6]; |
120 | 7.02M | int amp = volume & playing; |
121 | 7.02M | if ( phase >= duty ) |
122 | 43.8k | amp = -amp; |
123 | | |
124 | 7.02M | int frequency = this->frequency(); |
125 | 7.02M | if ( unsigned (frequency - 1) > 2040 ) // frequency < 1 || frequency > 2041 |
126 | 34.5k | { |
127 | | // really high frequency results in DC at half volume |
128 | 34.5k | amp = volume >> 1; |
129 | 34.5k | playing = false; |
130 | 34.5k | } |
131 | | |
132 | 7.02M | { |
133 | 7.02M | int delta = amp - last_amp; |
134 | 7.02M | if ( delta ) |
135 | 195 | { |
136 | 195 | last_amp = amp; |
137 | 195 | synth->offset( time, delta, output ); |
138 | 195 | } |
139 | 7.02M | } |
140 | | |
141 | 7.02M | time += delay; |
142 | 7.02M | if ( !playing ) |
143 | 7.02M | time = end_time; |
144 | | |
145 | 7.02M | if ( time < end_time ) |
146 | 1.46k | { |
147 | 1.46k | int const period = (2048 - frequency) * 4; |
148 | 1.46k | Blip_Buffer* const output = this->output; |
149 | 1.46k | int phase = this->phase; |
150 | 1.46k | int delta = amp * 2; |
151 | 1.46k | do |
152 | 9.81k | { |
153 | 9.81k | phase = (phase + 1) & 7; |
154 | 9.81k | if ( phase == 0 || phase == duty ) |
155 | 2.43k | { |
156 | 2.43k | delta = -delta; |
157 | 2.43k | synth->offset_inline( time, delta, output ); |
158 | 2.43k | } |
159 | 9.81k | time += period; |
160 | 9.81k | } |
161 | 9.81k | while ( time < end_time ); |
162 | | |
163 | 1.46k | this->phase = phase; |
164 | 1.46k | last_amp = delta >> 1; |
165 | 1.46k | } |
166 | 7.02M | delay = time - end_time; |
167 | 7.02M | } |
168 | | |
169 | | // Gb_Noise |
170 | | |
171 | | void Gb_Noise::run( blip_time_t time, blip_time_t end_time, int playing ) |
172 | 3.44M | { |
173 | 3.44M | int amp = volume & playing; |
174 | 3.44M | int tap = 13 - (regs [3] & 8); |
175 | 3.44M | if ( bits >> tap & 2 ) |
176 | 3.44M | amp = -amp; |
177 | | |
178 | 3.44M | { |
179 | 3.44M | int delta = amp - last_amp; |
180 | 3.44M | if ( delta ) |
181 | 58 | { |
182 | 58 | last_amp = amp; |
183 | 58 | synth->offset( time, delta, output ); |
184 | 58 | } |
185 | 3.44M | } |
186 | | |
187 | 3.44M | time += delay; |
188 | 3.44M | if ( !playing ) |
189 | 3.44M | time = end_time; |
190 | | |
191 | 3.44M | if ( time < end_time ) |
192 | 1.98k | { |
193 | 1.98k | static unsigned char const table [8] = { 8, 16, 32, 48, 64, 80, 96, 112 }; |
194 | 1.98k | int period = table [regs [3] & 7] << (regs [3] >> 4); |
195 | | |
196 | | // keep parallel resampled time to eliminate time conversion in the loop |
197 | 1.98k | Blip_Buffer* const output = this->output; |
198 | 1.98k | const blip_resampled_time_t resampled_period = |
199 | 1.98k | output->resampled_duration( period ); |
200 | 1.98k | blip_resampled_time_t resampled_time = output->resampled_time( time ); |
201 | 1.98k | unsigned bits = this->bits; |
202 | 1.98k | int delta = amp * 2; |
203 | | |
204 | 1.98k | do |
205 | 65.8k | { |
206 | 65.8k | unsigned changed = (bits >> tap) + 1; |
207 | 65.8k | time += period; |
208 | 65.8k | bits <<= 1; |
209 | 65.8k | if ( changed & 2 ) |
210 | 32.4k | { |
211 | 32.4k | delta = -delta; |
212 | 32.4k | bits |= 1; |
213 | 32.4k | synth->offset_resampled( resampled_time, delta, output ); |
214 | 32.4k | } |
215 | 65.8k | resampled_time += resampled_period; |
216 | 65.8k | } |
217 | 65.8k | while ( time < end_time ); |
218 | | |
219 | 1.98k | this->bits = bits; |
220 | 1.98k | last_amp = delta >> 1; |
221 | 1.98k | } |
222 | 3.44M | delay = time - end_time; |
223 | 3.44M | } |
224 | | |
225 | | // Gb_Wave |
226 | | |
227 | | inline void Gb_Wave::write_register( int reg, int data ) |
228 | 92.8k | { |
229 | 92.8k | switch ( reg ) |
230 | 92.8k | { |
231 | 19.1k | case 0: |
232 | 19.1k | if ( !(data & 0x80) ) |
233 | 17.8k | enabled = false; |
234 | 19.1k | break; |
235 | | |
236 | 17.6k | case 1: |
237 | 17.6k | length = 256 - regs [1]; |
238 | 17.6k | break; |
239 | | |
240 | 19.3k | case 2: |
241 | 19.3k | volume = data >> 5 & 3; |
242 | 19.3k | break; |
243 | | |
244 | 19.1k | case 4: |
245 | 19.1k | if ( data & trigger & regs [0] ) |
246 | 936 | { |
247 | 936 | wave_pos = 0; |
248 | 936 | enabled = true; |
249 | 936 | if ( length == 0 ) |
250 | 190 | length = 256; |
251 | 936 | } |
252 | 92.8k | } |
253 | 92.8k | } |
254 | | |
255 | | void Gb_Wave::run( blip_time_t time, blip_time_t end_time, int playing ) |
256 | 3.97M | { |
257 | 3.97M | int volume_shift = (volume - 1) & 7; // volume = 0 causes shift = 7 |
258 | 3.97M | int frequency; |
259 | 3.97M | { |
260 | 3.97M | int amp = (wave [wave_pos] >> volume_shift & playing) * 2; |
261 | | |
262 | 3.97M | frequency = this->frequency(); |
263 | 3.97M | if ( unsigned (frequency - 1) > 2044 ) // frequency < 1 || frequency > 2045 |
264 | 21.4k | { |
265 | 21.4k | amp = 30 >> volume_shift & playing; |
266 | 21.4k | playing = false; |
267 | 21.4k | } |
268 | | |
269 | 3.97M | int delta = amp - last_amp; |
270 | 3.97M | if ( delta ) |
271 | 194 | { |
272 | 194 | last_amp = amp; |
273 | 194 | synth->offset( time, delta, output ); |
274 | 194 | } |
275 | 3.97M | } |
276 | | |
277 | 3.97M | time += delay; |
278 | 3.97M | if ( !playing ) |
279 | 3.93M | time = end_time; |
280 | | |
281 | 3.97M | if ( time < end_time ) |
282 | 31.0k | { |
283 | 31.0k | Blip_Buffer* const output = this->output; |
284 | 31.0k | int const period = (2048 - frequency) * 2; |
285 | 31.0k | int wave_pos = (this->wave_pos + 1) & (wave_size - 1); |
286 | | |
287 | 31.0k | do |
288 | 260k | { |
289 | 260k | int amp = (wave [wave_pos] >> volume_shift) * 2; |
290 | 260k | wave_pos = (wave_pos + 1) & (wave_size - 1); |
291 | 260k | int delta = amp - last_amp; |
292 | 260k | if ( delta ) |
293 | 209k | { |
294 | 209k | last_amp = amp; |
295 | 209k | synth->offset_inline( time, delta, output ); |
296 | 209k | } |
297 | 260k | time += period; |
298 | 260k | } |
299 | 260k | while ( time < end_time ); |
300 | | |
301 | 31.0k | this->wave_pos = (wave_pos - 1) & (wave_size - 1); |
302 | 31.0k | } |
303 | 3.97M | delay = time - end_time; |
304 | 3.97M | } |
305 | | |
306 | | // Gb_Apu::write_osc |
307 | | |
308 | | void Gb_Apu::write_osc( int index, int reg, int data ) |
309 | 370k | { |
310 | 370k | reg -= index * 5; |
311 | 370k | Gb_Square* sq = &square2; |
312 | 370k | switch ( index ) |
313 | 370k | { |
314 | 93.3k | case 0: |
315 | 93.3k | sq = &square1; // FALLTHRU |
316 | 185k | case 1: |
317 | 185k | if ( sq->write_register( reg, data ) && index == 0 ) |
318 | 6.49k | { |
319 | 6.49k | square1.sweep_freq = square1.frequency(); |
320 | 6.49k | if ( (regs [0] & sq->period_mask) && (regs [0] & sq->shift_mask) ) |
321 | 678 | { |
322 | 678 | square1.sweep_delay = 1; // cause sweep to recalculate now |
323 | 678 | square1.clock_sweep(); |
324 | 678 | } |
325 | 6.49k | } |
326 | 185k | break; |
327 | | |
328 | 92.8k | case 2: |
329 | 92.8k | wave.write_register( reg, data ); |
330 | 92.8k | break; |
331 | | |
332 | 92.2k | case 3: |
333 | 92.2k | if ( noise.write_register( reg, data ) ) |
334 | 8.41k | noise.bits = 0x7FFF; |
335 | 370k | } |
336 | 370k | } |