comparison src/Input/console/Gb_Apu.cxx @ 0:13389e613d67 trunk

[svn] - initial import of audacious-plugins tree (lots to do)
author nenolod
date Mon, 18 Sep 2006 01:11:49 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:13389e613d67
1
2 // Gb_Snd_Emu 0.1.4. http://www.slack.net/~ant/
3
4 #include "Gb_Apu.h"
5
6 #include <string.h>
7
8 /* Copyright (C) 2003-2006 Shay Green. This module is free software; you
9 can redistribute it and/or modify it under the terms of the GNU Lesser
10 General Public License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version. This
12 module is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15 more details. You should have received a copy of the GNU Lesser General
16 Public License along with this module; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18
19 #include BLARGG_SOURCE_BEGIN
20
21 const unsigned vol_reg = 0xFF24;
22 const unsigned status_reg = 0xFF26;
23
24 Gb_Apu::Gb_Apu()
25 {
26 square1.synth = &square_synth;
27 square2.synth = &square_synth;
28 wave.synth = &other_synth;
29 noise.synth = &other_synth;
30
31 oscs [0] = &square1;
32 oscs [1] = &square2;
33 oscs [2] = &wave;
34 oscs [3] = &noise;
35
36 for ( int i = 0; i < osc_count; i++ )
37 {
38 Gb_Osc& osc = *oscs [i];
39 osc.regs = &regs [i * 5];
40 osc.output = NULL;
41 osc.outputs [0] = NULL;
42 osc.outputs [1] = NULL;
43 osc.outputs [2] = NULL;
44 osc.outputs [3] = NULL;
45 }
46
47 volume( 1.0 );
48 reset();
49 }
50
51 Gb_Apu::~Gb_Apu()
52 {
53 }
54
55 void Gb_Apu::treble_eq( const blip_eq_t& eq )
56 {
57 square_synth.treble_eq( eq );
58 other_synth.treble_eq( eq );
59 }
60
61 void Gb_Apu::osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right )
62 {
63 require( (unsigned) index < osc_count );
64 require( (center && left && right) || (!center && !left && !right) );
65 Gb_Osc& osc = *oscs [index];
66 osc.outputs [1] = right;
67 osc.outputs [2] = left;
68 osc.outputs [3] = center;
69 osc.output = osc.outputs [osc.output_select];
70 }
71
72 void Gb_Apu::output( Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right )
73 {
74 for ( int i = 0; i < osc_count; i++ )
75 osc_output( i, center, left, right );
76 }
77
78 void Gb_Apu::update_volume()
79 {
80 // to do: doesn't handle differing left/right global volume
81 int data = regs [vol_reg - start_addr];
82 double vol = (max( data & 7, data >> 4 & 7 ) + 1) * volume_unit;
83 square_synth.volume( vol );
84 other_synth.volume( vol );
85 }
86
87 static unsigned char const powerup_regs [0x30] = {
88 0x80,0x3F,0x00,0xFF,0xBF, // square 1
89 0xFF,0x3F,0x00,0xFF,0xBF, // square 2
90 0x7F,0xFF,0x9F,0xFF,0xBF, // wave
91 0xFF,0xFF,0x00,0x00,0xBF, // noise
92 0x00, // left/right enables
93 0x77, // master volume
94 0x80, // power
95 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
96 0x84,0x40,0x43,0xAA,0x2D,0x78,0x92,0x3C, // wave table
97 0x60,0x59,0x59,0xB0,0x34,0xB8,0x2E,0xDA
98 };
99
100 void Gb_Apu::reset()
101 {
102 next_frame_time = 0;
103 last_time = 0;
104 frame_count = 0;
105 stereo_found = false;
106
107 square1.reset();
108 square2.reset();
109 wave.reset();
110 noise.reset();
111 noise.bits = 1;
112 wave.wave_pos = 0;
113
114 // avoid click at beginning
115 regs [vol_reg - start_addr] = 0x77;
116 update_volume();
117
118 regs [status_reg - start_addr] = 0x01; // force power
119 write_register( 0, status_reg, 0x00 );
120 }
121
122 // to do: remove
123 static unsigned long abs_time;
124
125 void Gb_Apu::run_until( gb_time_t end_time )
126 {
127 require( end_time >= last_time ); // end_time must not be before previous time
128 if ( end_time == last_time )
129 return;
130
131 while ( true )
132 {
133 gb_time_t time = next_frame_time;
134 if ( time > end_time )
135 time = end_time;
136
137 // run oscillators
138 for ( int i = 0; i < osc_count; ++i )
139 {
140 Gb_Osc& osc = *oscs [i];
141 if ( osc.output )
142 {
143 int playing = false;
144 if ( osc.enabled && osc.volume &&
145 (!(osc.regs [4] & osc.len_enabled_mask) || osc.length) )
146 playing = -1;
147 if ( osc.output != osc.outputs [3] )
148 stereo_found = true;
149 switch ( i )
150 {
151 case 0: square1.run( last_time, time, playing ); break;
152 case 1: square2.run( last_time, time, playing ); break;
153 case 2: wave .run( last_time, time, playing ); break;
154 case 3: noise .run( last_time, time, playing ); break;
155 }
156 }
157 }
158 last_time = time;
159
160 if ( time == end_time )
161 break;
162
163 next_frame_time += 4194304 / 256; // 256 Hz
164
165 // 256 Hz actions
166 square1.clock_length();
167 square2.clock_length();
168 wave.clock_length();
169 noise.clock_length();
170
171 frame_count = (frame_count + 1) & 3;
172 if ( frame_count == 0 )
173 {
174 // 64 Hz actions
175 square1.clock_envelope();
176 square2.clock_envelope();
177 noise.clock_envelope();
178 }
179
180 if ( frame_count & 1 )
181 square1.clock_sweep(); // 128 Hz action
182 }
183 }
184
185 bool Gb_Apu::end_frame( gb_time_t end_time )
186 {
187 if ( end_time > last_time )
188 run_until( end_time );
189
190 abs_time += end_time;
191
192 assert( next_frame_time >= end_time );
193 next_frame_time -= end_time;
194
195 assert( last_time >= end_time );
196 last_time -= end_time;
197
198 bool result = stereo_found;
199 stereo_found = false;
200 return result;
201 }
202
203 void Gb_Apu::write_register( gb_time_t time, gb_addr_t addr, int data )
204 {
205 require( (unsigned) data < 0x100 );
206
207 int reg = addr - start_addr;
208 if ( (unsigned) reg >= register_count )
209 return;
210
211 run_until( time );
212
213 int old_reg = regs [reg];
214 regs [reg] = data;
215
216 if ( addr < vol_reg )
217 {
218 write_osc( reg / 5, reg, data );
219 }
220 else if ( addr == vol_reg && data != old_reg ) // global volume
221 {
222 // return all oscs to 0
223 for ( int i = 0; i < osc_count; i++ )
224 {
225 Gb_Osc& osc = *oscs [i];
226 int amp = osc.last_amp;
227 osc.last_amp = 0;
228 if ( amp && osc.enabled && osc.output )
229 other_synth.offset( time, -amp, osc.output );
230 }
231
232 if ( wave.outputs [3] )
233 other_synth.offset( time, 30, wave.outputs [3] );
234
235 update_volume();
236
237 if ( wave.outputs [3] )
238 other_synth.offset( time, -30, wave.outputs [3] );
239
240 // oscs will update with new amplitude when next run
241 }
242 else if ( addr == 0xFF25 || addr == status_reg )
243 {
244 int mask = (regs [status_reg - start_addr] & 0x80) ? ~0 : 0;
245 int flags = regs [0xFF25 - start_addr] & mask;
246
247 // left/right assignments
248 for ( int i = 0; i < osc_count; i++ )
249 {
250 Gb_Osc& osc = *oscs [i];
251 osc.enabled &= mask;
252 int bits = flags >> i;
253 Blip_Buffer* old_output = osc.output;
254 osc.output_select = (bits >> 3 & 2) | (bits & 1);
255 osc.output = osc.outputs [osc.output_select];
256 if ( osc.output != old_output )
257 {
258 int amp = osc.last_amp;
259 osc.last_amp = 0;
260 if ( amp && old_output )
261 other_synth.offset( time, -amp, old_output );
262 }
263 }
264
265 if ( addr == status_reg && data != old_reg )
266 {
267 if ( !(data & 0x80) )
268 {
269 for ( int i = 0; i < (int) sizeof powerup_regs; i++ )
270 {
271 if ( i != status_reg - start_addr )
272 write_register( time, i + start_addr, powerup_regs [i] );
273 }
274 }
275 else
276 {
277 //dprintf( "APU powered on\n" );
278 }
279 }
280 }
281 else if ( addr >= 0xFF30 )
282 {
283
284 int index = (addr & 0x0F) * 2;
285 wave.wave [index] = data >> 4;
286 wave.wave [index + 1] = data & 0x0F;
287 }
288 }
289
290 int Gb_Apu::read_register( gb_time_t time, gb_addr_t addr )
291 {
292 run_until( time );
293
294 int index = addr - start_addr;
295 require( (unsigned) index < register_count );
296 int data = regs [index];
297
298 if ( addr == status_reg )
299 {
300 data = (data & 0x80) | 0x70;
301 for ( int i = 0; i < osc_count; i++ )
302 {
303 const Gb_Osc& osc = *oscs [i];
304 if ( osc.enabled && (osc.length || !(osc.regs [4] & osc.len_enabled_mask)) )
305 data |= 1 << i;
306 }
307 }
308
309 return data;
310 }
311