summaryrefslogtreecommitdiff
path: root/apps/codecs/libgme/hes_apu.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libgme/hes_apu.c')
-rw-r--r--apps/codecs/libgme/hes_apu.c306
1 files changed, 181 insertions, 125 deletions
diff --git a/apps/codecs/libgme/hes_apu.c b/apps/codecs/libgme/hes_apu.c
index 2a831426f5..054b164a9a 100644
--- a/apps/codecs/libgme/hes_apu.c
+++ b/apps/codecs/libgme/hes_apu.c
@@ -18,8 +18,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18 18
19enum { center_waves = 1 }; // reduces asymmetry and clamping when starting notes 19enum { center_waves = 1 }; // reduces asymmetry and clamping when starting notes
20 20
21static void Apu_balance_changed( struct Hes_Apu* this, struct Hes_Osc* osc ); 21static void balance_changed( struct Hes_Apu* this, struct Hes_Osc* osc )
22static void Apu_balance_changed( struct Hes_Apu* this, struct Hes_Osc* osc )
23{ 22{
24 static short const log_table [32] = { // ~1.5 db per step 23 static short const log_table [32] = { // ~1.5 db per step
25 #define ENTRY( factor ) (short) (factor * amp_range / 31.0 + 0.5) 24 #define ENTRY( factor ) (short) (factor * amp_range / 31.0 + 0.5)
@@ -42,27 +41,40 @@ static void Apu_balance_changed( struct Hes_Apu* this, struct Hes_Osc* osc )
42 int right = vol + (osc->balance << 1 & 0x1E) + (this->balance << 1 & 0x1E); 41 int right = vol + (osc->balance << 1 & 0x1E) + (this->balance << 1 & 0x1E);
43 if ( right < 0 ) right = 0; 42 if ( right < 0 ) right = 0;
44 43
45 left = log_table [left ];
46 right = log_table [right];
47
48 // optimizing for the common case of being centered also allows easy 44 // optimizing for the common case of being centered also allows easy
49 // panning using Effects_Buffer 45 // panning using Effects_Buffer
50 osc->outputs [0] = osc->chans [0]; // center 46
51 osc->outputs [1] = 0; 47 // Separate balance into center volume and additional on either left or right
52 if ( left != right ) 48 osc->output [0] = osc->outputs [0]; // center
49 osc->output [1] = osc->outputs [2]; // right
50 int base = log_table [left ];
51 int side = log_table [right] - base;
52 if ( side < 0 )
53 {
54 base += side;
55 side = -side;
56 osc->output [1] = osc->outputs [1]; // left
57 }
58
59 // Optimize when output is far left, center, or far right
60 if ( !base || osc->output [0] == osc->output [1] )
53 { 61 {
54 osc->outputs [0] = osc->chans [1]; // left 62 base += side;
55 osc->outputs [1] = osc->chans [2]; // right 63 side = 0;
64 osc->output [0] = osc->output [1];
65 osc->output [1] = NULL;
66 osc->last_amp [1] = 0;
56 } 67 }
57 68
58 if ( center_waves ) 69 if ( center_waves )
59 { 70 {
60 osc->last_amp [0] += (left - osc->volume [0]) * 16; 71 // TODO: this can leave a non-zero level in a buffer (minor)
61 osc->last_amp [1] += (right - osc->volume [1]) * 16; 72 osc->last_amp [0] += (base - osc->volume [0]) * 16;
73 osc->last_amp [1] += (side - osc->volume [1]) * 16;
62 } 74 }
63 75
64 osc->volume [0] = left; 76 osc->volume [0] = base;
65 osc->volume [1] = right; 77 osc->volume [1] = side;
66} 78}
67 79
68void Apu_init( struct Hes_Apu* this ) 80void Apu_init( struct Hes_Apu* this )
@@ -71,11 +83,11 @@ void Apu_init( struct Hes_Apu* this )
71 do 83 do
72 { 84 {
73 osc--; 85 osc--;
74 osc->outputs [0] = 0; 86 osc->output [0] = NULL;
75 osc->outputs [1] = 0; 87 osc->output [1] = NULL;
76 osc->chans [0] = 0; 88 osc->outputs [0] = NULL;
77 osc->chans [1] = 0; 89 osc->outputs [1] = NULL;
78 osc->chans [2] = 0; 90 osc->outputs [2] = NULL;
79 } 91 }
80 while ( osc != this->oscs ); 92 while ( osc != this->oscs );
81 93
@@ -92,139 +104,183 @@ void Apu_reset( struct Hes_Apu* this )
92 { 104 {
93 osc--; 105 osc--;
94 memset( osc, 0, offsetof (struct Hes_Osc,outputs) ); 106 memset( osc, 0, offsetof (struct Hes_Osc,outputs) );
95 osc->noise_lfsr = 1; 107 osc->lfsr = 1;
96 osc->control = 0x40; 108 osc->control = 0x40;
97 osc->balance = 0xFF; 109 osc->balance = 0xFF;
98 } 110 }
99 while ( osc != this->oscs ); 111 while ( osc != this->oscs );
112
113 // Only last two oscs support noise
114 this->oscs [osc_count - 2].lfsr = 0x200C3; // equivalent to 1 in Fibonacci LFSR
115 this->oscs [osc_count - 1].lfsr = 0x200C3;
100} 116}
101 117
102void Apu_osc_output( struct Hes_Apu* this, int index, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right ) 118void Apu_osc_output( struct Hes_Apu* this, int i, struct Blip_Buffer* center, struct Blip_Buffer* left, struct Blip_Buffer* right )
103{ 119{
104 require( (unsigned) index < osc_count ); 120 // Must be silent (all NULL), mono (left and right NULL), or stereo (none NULL)
105 this->oscs [index].chans [0] = center; 121 require( !center || (center && !left && !right) || (center && left && right) );
106 this->oscs [index].chans [1] = left; 122 require( (unsigned) i < osc_count ); // fails if you pass invalid osc index
107 this->oscs [index].chans [2] = right;
108 123
109 struct Hes_Osc* osc = &this->oscs [osc_count]; 124 if ( !center || !left || !right )
110 do
111 { 125 {
112 osc--; 126 left = center;
113 Apu_balance_changed( this, osc ); 127 right = center;
114 } 128 }
115 while ( osc != this->oscs ); 129
130 struct Hes_Osc* o = &this->oscs [i];
131 o->outputs [0] = center;
132 o->outputs [1] = right;
133 o->outputs [2] = left;
134 balance_changed( this, o );
116} 135}
117 136
118void Osc_run_until( struct Hes_Osc* this, struct Blip_Synth* synth_, blip_time_t end_time ) 137void run_osc( struct Hes_Osc* o, struct Blip_Synth* syn, blip_time_t end_time )
119{ 138{
120 struct Blip_Buffer* const osc_outputs_0 = this->outputs [0]; // cache often-used values 139 int vol0 = o->volume [0];
121 if ( osc_outputs_0 && this->control & 0x80 ) 140 int vol1 = o->volume [1];
141 int dac = o->dac;
142
143 struct Blip_Buffer* out0 = o->output [0]; // cache often-used values
144 struct Blip_Buffer* out1 = o->output [1];
145 if ( !(o->control & 0x80) )
146 out0 = NULL;
147
148 if ( out0 )
122 { 149 {
123 int dac = this->dac; 150 // Update amplitudes
124 151 if ( out1 )
125 int const volume_0 = this->volume [0];
126 { 152 {
127 int delta = dac * volume_0 - this->last_amp [0]; 153 int delta = dac * vol1 - o->last_amp [1];
128 if ( delta ) 154 if ( delta )
129 Synth_offset( synth_, this->last_time, delta, osc_outputs_0 ); 155 {
130 Blip_set_modified( osc_outputs_0 ); 156 Synth_offset( syn, o->last_time, delta, out1 );
157 Blip_set_modified( out1 );
158 }
131 } 159 }
132 160 int delta = dac * vol0 - o->last_amp [0];
133 struct Blip_Buffer* const osc_outputs_1 = this->outputs [1]; 161 if ( delta )
134 int const volume_1 = this->volume [1];
135 if ( osc_outputs_1 )
136 { 162 {
137 int delta = dac * volume_1 - this->last_amp [1]; 163 Synth_offset( syn, o->last_time, delta, out0 );
138 if ( delta ) 164 Blip_set_modified( out0 );
139 Synth_offset( synth_, this->last_time, delta, osc_outputs_1 );
140 Blip_set_modified( osc_outputs_1 );
141 } 165 }
142 166
143 blip_time_t time = this->last_time + this->delay; 167 // Don't generate if silent
168 if ( !(vol0 | vol1) )
169 out0 = NULL;
170 }
171
172 // Generate noise
173 int noise = 0;
174 if ( o->lfsr )
175 {
176 noise = o->noise & 0x80;
177
178 blip_time_t time = o->last_time + o->noise_delay;
144 if ( time < end_time ) 179 if ( time < end_time )
145 { 180 {
146 if ( this->noise & 0x80 ) 181 int period = (~o->noise & 0x1F) * 128;
182 if ( !period )
183 period = 64;
184
185 if ( noise && out0 )
147 { 186 {
148 if ( volume_0 | volume_1 ) 187 unsigned lfsr = o->lfsr;
188 do
149 { 189 {
150 // noise 190 int new_dac = -(lfsr & 1);
151 int const period = (32 - (this->noise & 0x1F)) * 64; // TODO: correct? 191 lfsr = (lfsr >> 1) ^ (0x30061 & new_dac);
152 unsigned noise_lfsr = this->noise_lfsr; 192
153 do 193 int delta = (new_dac &= 0x1F) - dac;
194 if ( delta )
154 { 195 {
155 int new_dac = 0x1F & -(noise_lfsr >> 1 & 1); 196 dac = new_dac;
156 // Implemented using "Galios configuration" 197 Synth_offset( syn, time, delta * vol0, out0 );
157 // TODO: find correct LFSR algorithm 198 if ( out1 )
158 noise_lfsr = (noise_lfsr >> 1) ^ (0xE008 & -(noise_lfsr & 1)); 199 Synth_offset( syn, time, delta * vol1, out1 );
159 //noise_lfsr = (noise_lfsr >> 1) ^ (0x6000 & -(noise_lfsr & 1));
160 int delta = new_dac - dac;
161 if ( delta )
162 {
163 dac = new_dac;
164 Synth_offset( synth_, time, delta * volume_0, osc_outputs_0 );
165 if ( osc_outputs_1 )
166 Synth_offset( synth_, time, delta * volume_1, osc_outputs_1 );
167 }
168 time += period;
169 } 200 }
170 while ( time < end_time ); 201 time += period;
171
172 this->noise_lfsr = noise_lfsr;
173 assert( noise_lfsr );
174 } 202 }
175 } 203 while ( time < end_time );
176 else if ( !(this->control & 0x40) ) 204
177 { 205 if ( !lfsr )
178 // wave
179 int phase = (this->phase + 1) & 0x1F; // pre-advance for optimal inner loop
180 int period = this->period * 2;
181 if ( period >= 14 && (volume_0 | volume_1) )
182 { 206 {
183 do 207 lfsr = 1;
184 { 208 check( false );
185 int new_dac = this->wave [phase];
186 phase = (phase + 1) & 0x1F;
187 int delta = new_dac - dac;
188 if ( delta )
189 {
190 dac = new_dac;
191 Synth_offset( synth_, time, delta * volume_0, osc_outputs_0 );
192 if ( osc_outputs_1 )
193 Synth_offset( synth_, time, delta * volume_1, osc_outputs_1 );
194 }
195 time += period;
196 }
197 while ( time < end_time );
198 } 209 }
199 else 210 o->lfsr = lfsr;
211
212 Blip_set_modified( out0 );
213 if ( out1 )
214 Blip_set_modified( out1 );
215 }
216 else
217 {
218 // Maintain phase when silent
219 int count = (end_time - time + period - 1) / period;
220 time += count * period;
221
222 // not worth it
223 //while ( count-- )
224 // o->lfsr = (o->lfsr >> 1) ^ (0x30061 * (o->lfsr & 1));
225 }
226 }
227 o->noise_delay = time - end_time;
228 }
229
230 // Generate wave
231 blip_time_t time = o->last_time + o->delay;
232 if ( time < end_time )
233 {
234 int phase = (o->phase + 1) & 0x1F; // pre-advance for optimal inner loop
235 int period = o->period * 2;
236
237 if ( period >= 14 && out0 && !((o->control & 0x40) | noise) )
238 {
239 do
240 {
241 int new_dac = o->wave [phase];
242 phase = (phase + 1) & 0x1F;
243 int delta = new_dac - dac;
244 if ( delta )
200 { 245 {
201 if ( !period ) 246 dac = new_dac;
202 { 247 Synth_offset( syn, time, delta * vol0, out0 );
203 // TODO: Gekisha Boy assumes that period = 0 silences wave 248 if ( out1 )
204 //period = 0x1000 * 2; 249 Synth_offset( syn, time, delta * vol1, out1 );
205 period = 1;
206 //if ( !(volume_0 | volume_1) )
207 // dprintf( "Used period 0\n" );
208 }
209
210 // maintain phase when silent
211 blargg_long count = (end_time - time + period - 1) / period;
212 phase += count; // phase will be masked below
213 time += count * period;
214 } 250 }
215 this->phase = (phase - 1) & 0x1F; // undo pre-advance 251 time += period;
216 } 252 }
253 while ( time < end_time );
254 Blip_set_modified( out0 );
255 if ( out1 )
256 Blip_set_modified( out1 );
257 }
258 else
259 {
260 // Maintain phase when silent
261 int count = end_time - time;
262 if ( !period )
263 period = 1;
264 count = (count + period - 1) / period;
265
266 phase += count; // phase will be masked below
267 time += count * period;
217 } 268 }
218 time -= end_time;
219 if ( time < 0 )
220 time = 0;
221 this->delay = time;
222 269
223 this->dac = dac; 270 // TODO: Find whether phase increments even when both volumes are zero.
224 this->last_amp [0] = dac * volume_0; 271 // CAN'T simply check for out0 being non-NULL, since it could be NULL
225 this->last_amp [1] = dac * volume_1; 272 // if channel is muted in player, but still has non-zero volume.
273 // City Hunter breaks when this check is removed.
274 if ( !(o->control & 0x40) && (vol0 | vol1) )
275 o->phase = (phase - 1) & 0x1F; // undo pre-advance
226 } 276 }
227 this->last_time = end_time; 277 o->delay = time - end_time;
278 check( o->delay >= 0 );
279
280 o->last_time = end_time;
281 o->dac = dac;
282 o->last_amp [0] = dac * vol0;
283 o->last_amp [1] = dac * vol1;
228} 284}
229 285
230void Apu_write_data( struct Hes_Apu* this, blip_time_t time, int addr, int data ) 286void Apu_write_data( struct Hes_Apu* this, blip_time_t time, int addr, int data )
@@ -243,8 +299,8 @@ void Apu_write_data( struct Hes_Apu* this, blip_time_t time, int addr, int data
243 do 299 do
244 { 300 {
245 osc--; 301 osc--;
246 Osc_run_until( osc, &this->synth, time ); 302 run_osc( osc, &this->synth, time );
247 Apu_balance_changed( this, this->oscs ); 303 balance_changed( this, this->oscs );
248 } 304 }
249 while ( osc != this->oscs ); 305 while ( osc != this->oscs );
250 } 306 }
@@ -252,7 +308,7 @@ void Apu_write_data( struct Hes_Apu* this, blip_time_t time, int addr, int data
252 else if ( this->latch < osc_count ) 308 else if ( this->latch < osc_count )
253 { 309 {
254 struct Hes_Osc* osc = &this->oscs [this->latch]; 310 struct Hes_Osc* osc = &this->oscs [this->latch];
255 Osc_run_until( osc, &this->synth, time ); 311 run_osc( osc, &this->synth, time );
256 switch ( addr ) 312 switch ( addr )
257 { 313 {
258 case 0x802: 314 case 0x802:
@@ -267,12 +323,12 @@ void Apu_write_data( struct Hes_Apu* this, blip_time_t time, int addr, int data
267 if ( osc->control & 0x40 & ~data ) 323 if ( osc->control & 0x40 & ~data )
268 osc->phase = 0; 324 osc->phase = 0;
269 osc->control = data; 325 osc->control = data;
270 Apu_balance_changed( this, osc ); 326 balance_changed( this, osc );
271 break; 327 break;
272 328
273 case 0x805: 329 case 0x805:
274 osc->balance = data; 330 osc->balance = data;
275 Apu_balance_changed( this, osc ); 331 balance_changed( this, osc );
276 break; 332 break;
277 333
278 case 0x806: 334 case 0x806:
@@ -289,9 +345,9 @@ void Apu_write_data( struct Hes_Apu* this, blip_time_t time, int addr, int data
289 break; 345 break;
290 346
291 case 0x807: 347 case 0x807:
292 if ( osc >= &this->oscs [4] ) 348 osc->noise = data;
293 osc->noise = data;
294 break; 349 break;
350
295 case 0x809: 351 case 0x809:
296 if ( !(data & 0x80) && (data & 0x03) != 0 ) { 352 if ( !(data & 0x80) && (data & 0x03) != 0 ) {
297 dprintf( "HES LFO not supported\n" ); 353 dprintf( "HES LFO not supported\n" );
@@ -307,7 +363,7 @@ void Apu_end_frame( struct Hes_Apu* this, blip_time_t end_time )
307 { 363 {
308 osc--; 364 osc--;
309 if ( end_time > osc->last_time ) 365 if ( end_time > osc->last_time )
310 Osc_run_until( osc, &this->synth, end_time ); 366 run_osc( osc, &this->synth, end_time );
311 assert( osc->last_time >= end_time ); 367 assert( osc->last_time >= end_time );
312 osc->last_time -= end_time; 368 osc->last_time -= end_time;
313 } 369 }