1
// Game_Music_Emu 0.5.2. http://www.slack.net/~ant/
7
/* Copyright (C) 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 */
18
#include "blargg_source.h"
20
bool const center_waves = true; // reduces asymmetry and clamping when starting notes
24
Hes_Osc* osc = &oscs [osc_count];
34
while ( osc != oscs );
44
Hes_Osc* osc = &oscs [osc_count];
48
memset( osc, 0, offsetof (Hes_Osc,outputs) );
53
while ( osc != oscs );
56
void Hes_Apu::osc_output( int index, Blip_Buffer* center, Blip_Buffer* left, Blip_Buffer* right )
58
require( (unsigned) index < osc_count );
59
oscs [index].chans [0] = center;
60
oscs [index].chans [1] = left;
61
oscs [index].chans [2] = right;
63
Hes_Osc* osc = &oscs [osc_count];
67
balance_changed( *osc );
69
while ( osc != oscs );
72
void Hes_Osc::run_until( synth_t& synth_, blip_time_t end_time )
74
Blip_Buffer* const osc_outputs_0 = outputs [0]; // cache often-used values
75
if ( osc_outputs_0 && control & 0x80 )
79
int const volume_0 = volume [0];
81
int delta = dac * volume_0 - last_amp [0];
83
synth_.offset( last_time, delta, osc_outputs_0 );
84
osc_outputs_0->set_modified();
87
Blip_Buffer* const osc_outputs_1 = outputs [1];
88
int const volume_1 = volume [1];
91
int delta = dac * volume_1 - last_amp [1];
93
synth_.offset( last_time, delta, osc_outputs_1 );
94
osc_outputs_1->set_modified();
97
blip_time_t time = last_time + delay;
98
if ( time < end_time )
102
if ( volume_0 | volume_1 )
105
int const period = (32 - (noise & 0x1F)) * 64; // TODO: correct?
106
unsigned noise_lfsr = this->noise_lfsr;
109
int new_dac = 0x1F & -(noise_lfsr >> 1 & 1);
110
// Implemented using "Galios configuration"
111
// TODO: find correct LFSR algorithm
112
noise_lfsr = (noise_lfsr >> 1) ^ (0xE008 & -(noise_lfsr & 1));
113
//noise_lfsr = (noise_lfsr >> 1) ^ (0x6000 & -(noise_lfsr & 1));
114
int delta = new_dac - dac;
118
synth_.offset( time, delta * volume_0, osc_outputs_0 );
120
synth_.offset( time, delta * volume_1, osc_outputs_1 );
124
while ( time < end_time );
126
this->noise_lfsr = noise_lfsr;
127
assert( noise_lfsr );
130
else if ( !(control & 0x40) )
133
int phase = (this->phase + 1) & 0x1F; // pre-advance for optimal inner loop
134
int period = this->period * 2;
135
if ( period >= 14 && (volume_0 | volume_1) )
139
int new_dac = wave [phase];
140
phase = (phase + 1) & 0x1F;
141
int delta = new_dac - dac;
145
synth_.offset( time, delta * volume_0, osc_outputs_0 );
147
synth_.offset( time, delta * volume_1, osc_outputs_1 );
151
while ( time < end_time );
157
// TODO: Gekisha Boy assumes that period = 0 silences wave
158
//period = 0x1000 * 2;
160
//if ( !(volume_0 | volume_1) )
161
// dprintf( "Used period 0\n" );
164
// maintain phase when silent
165
blargg_long count = (end_time - time + period - 1) / period;
166
phase += count; // phase will be masked below
167
time += count * period;
169
this->phase = (phase - 1) & 0x1F; // undo pre-advance
178
last_amp [0] = dac * volume_0;
179
last_amp [1] = dac * volume_1;
181
last_time = end_time;
184
void Hes_Apu::balance_changed( Hes_Osc& osc )
186
static short const log_table [32] = { // ~1.5 db per step
187
#define ENTRY( factor ) short (factor * Hes_Osc::amp_range / 31.0 + 0.5)
188
ENTRY( 0.000000 ),ENTRY( 0.005524 ),ENTRY( 0.006570 ),ENTRY( 0.007813 ),
189
ENTRY( 0.009291 ),ENTRY( 0.011049 ),ENTRY( 0.013139 ),ENTRY( 0.015625 ),
190
ENTRY( 0.018581 ),ENTRY( 0.022097 ),ENTRY( 0.026278 ),ENTRY( 0.031250 ),
191
ENTRY( 0.037163 ),ENTRY( 0.044194 ),ENTRY( 0.052556 ),ENTRY( 0.062500 ),
192
ENTRY( 0.074325 ),ENTRY( 0.088388 ),ENTRY( 0.105112 ),ENTRY( 0.125000 ),
193
ENTRY( 0.148651 ),ENTRY( 0.176777 ),ENTRY( 0.210224 ),ENTRY( 0.250000 ),
194
ENTRY( 0.297302 ),ENTRY( 0.353553 ),ENTRY( 0.420448 ),ENTRY( 0.500000 ),
195
ENTRY( 0.594604 ),ENTRY( 0.707107 ),ENTRY( 0.840896 ),ENTRY( 1.000000 ),
199
int vol = (osc.control & 0x1F) - 0x1E * 2;
201
int left = vol + (osc.balance >> 3 & 0x1E) + (balance >> 3 & 0x1E);
202
if ( left < 0 ) left = 0;
204
int right = vol + (osc.balance << 1 & 0x1E) + (balance << 1 & 0x1E);
205
if ( right < 0 ) right = 0;
207
left = log_table [left ];
208
right = log_table [right];
210
// optimizing for the common case of being centered also allows easy
211
// panning using Effects_Buffer
212
osc.outputs [0] = osc.chans [0]; // center
216
osc.outputs [0] = osc.chans [1]; // left
217
osc.outputs [1] = osc.chans [2]; // right
222
osc.last_amp [0] += (left - osc.volume [0]) * 16;
223
osc.last_amp [1] += (right - osc.volume [1]) * 16;
226
osc.volume [0] = left;
227
osc.volume [1] = right;
230
void Hes_Apu::write_data( blip_time_t time, int addr, int data )
236
else if ( addr == 0x801 )
238
if ( balance != data )
242
Hes_Osc* osc = &oscs [osc_count];
246
osc->run_until( synth, time );
247
balance_changed( *oscs );
249
while ( osc != oscs );
252
else if ( latch < osc_count )
254
Hes_Osc& osc = oscs [latch];
255
osc.run_until( synth, time );
259
osc.period = (osc.period & 0xF00) | data;
263
osc.period = (osc.period & 0x0FF) | ((data & 0x0F) << 8);
267
if ( osc.control & 0x40 & ~data )
270
balance_changed( osc );
275
balance_changed( osc );
280
if ( !(osc.control & 0x40) )
282
osc.wave [osc.phase] = data;
283
osc.phase = (osc.phase + 1) & 0x1F;
285
else if ( osc.control & 0x80 )
292
if ( &osc >= &oscs [4] )
297
if ( !(data & 0x80) && (data & 0x03) != 0 )
298
dprintf( "HES LFO not supported\n" );
303
void Hes_Apu::end_frame( blip_time_t end_time )
305
Hes_Osc* osc = &oscs [osc_count];
309
if ( end_time > osc->last_time )
310
osc->run_until( synth, end_time );
311
assert( osc->last_time >= end_time );
312
osc->last_time -= end_time;
314
while ( osc != oscs );