rockbox/apps/codecs/libgme/nes_vrc7_apu.c

89 lines
2 KiB
C
Raw Normal View History

#include "nes_vrc7_apu.h"
#include "blargg_source.h"
int const period = 36; // NES CPU clocks per FM clock
void Vrc7_init( struct Nes_Vrc7_Apu* this )
{
Synth_init( &this->synth );
OPLL_new ( &this->opll, 3579545, 3579545 / 72 );
OPLL_reset_patch( &this->opll, OPLL_VRC7_TONE );
this->osc.output = 0;
this->osc.last_amp = 0;
this->mask = 0;
Vrc7_volume( this, (int)FP_ONE_VOLUME );
Vrc7_reset( this );
}
void Vrc7_reset( struct Nes_Vrc7_Apu* this )
{
this->addr = 0;
this->next_time = 0;
this->osc.last_amp = 0;
OPLL_reset (&this->opll);
OPLL_setMask(&this->opll, this->mask);
}
void Vrc7_set_rate( struct Nes_Vrc7_Apu* this, int r )
{
OPLL_set_quality( &this->opll, r < 44100 ? 0 : 1 );
}
void Vrc7_write_reg( struct Nes_Vrc7_Apu* this, int data )
{
this->addr = data;
}
void Vrc7_run_until( struct Nes_Vrc7_Apu* this, blip_time_t end_time );
void Vrc7_write_data( struct Nes_Vrc7_Apu* this, blip_time_t time, int data )
{
if ( time > this->next_time )
Vrc7_run_until( this, time );
OPLL_writeIO( &this->opll, 0, this->addr );
OPLL_writeIO( &this->opll, 1, data );
}
void Vrc7_end_frame( struct Nes_Vrc7_Apu* this, blip_time_t time )
{
if ( time > this->next_time )
Vrc7_run_until( this, time );
this->next_time -= time;
assert( this->next_time >= 0 );
if ( this->osc.output )
Blip_set_modified( this->osc.output );
}
void Vrc7_run_until( struct Nes_Vrc7_Apu* this, blip_time_t end_time )
{
require( end_time > this->next_time );
blip_time_t time = this->next_time;
OPLL* opll = &this->opll; // cache
struct Blip_Buffer* const output = this-> osc.output;
if ( output )
{
do
{
int amp = OPLL_calc( opll ) << 1;
int delta = amp - this->osc.last_amp;
if ( delta )
{
this->osc.last_amp = amp;
Synth_offset_inline( &this->synth, time, delta, output );
}
time += period;
}
while ( time < end_time );
}
this->next_time = time;
}