#include "Nes_Fme7_Apu.h"
#include <string.h>
#include "blargg_source.h"
void Nes_Fme7_Apu::reset()
{
last_time = 0;
for ( int i = 0; i < osc_count; i++ )
oscs [i].last_amp = 0;
fme7_apu_state_t* state = this;
memset( state, 0, sizeof *state );
}
unsigned char Nes_Fme7_Apu::amp_table [16] =
{
#define ENTRY( n ) (unsigned char) (n * amp_range + 0.5)
ENTRY(0.0000), ENTRY(0.0078), ENTRY(0.0110), ENTRY(0.0156),
ENTRY(0.0221), ENTRY(0.0312), ENTRY(0.0441), ENTRY(0.0624),
ENTRY(0.0883), ENTRY(0.1249), ENTRY(0.1766), ENTRY(0.2498),
ENTRY(0.3534), ENTRY(0.4998), ENTRY(0.7070), ENTRY(1.0000)
#undef ENTRY
};
void Nes_Fme7_Apu::run_until( blip_time_t end_time )
{
require( end_time >= last_time );
for ( int index = 0; index < osc_count; index++ )
{
int mode = regs [7] >> index;
int vol_mode = regs [010 + index];
int volume = amp_table [vol_mode & 0x0f];
if ( !oscs [index].output )
continue;
#ifndef NDEBUG
if ( (mode & 011) <= 001 && vol_mode & 0x1f )
dprintf( "FME7 used unimplemented sound mode: %02X, vol_mode: %02X\n",
mode, vol_mode & 0x1f );
#endif
if ( (mode & 001) | (vol_mode & 0x10) )
volume = 0;
int const period_factor = 16;
unsigned period = (regs [index * 2 + 1] & 0x0f) * 0x100 * period_factor +
regs [index * 2] * period_factor;
if ( period < 50 )
{
volume = 0;
if ( !period )
period = period_factor;
}
int amp = volume;
if ( !phases [index] )
amp = 0;
int delta = amp - oscs [index].last_amp;
if ( delta )
{
oscs [index].last_amp = amp;
synth.offset( last_time, delta, oscs [index].output );
}
blip_time_t time = last_time + delays [index];
if ( time < end_time )
{
Blip_Buffer* const osc_output = oscs [index].output;
int delta = amp * 2 - volume;
if ( volume )
{
do
{
delta = -delta;
synth.offset_inline( time, delta, osc_output );
time += period;
}
while ( time < end_time );
oscs [index].last_amp = (delta + volume) >> 1;
phases [index] = (delta > 0);
}
else
{
int count = (end_time - time + period - 1) / period;
phases [index] ^= count & 1;
time += (long) count * period;
}
}
delays [index] = time - end_time;
}
last_time = end_time;
}