199 lines
4.3 KiB
C
199 lines
4.3 KiB
C
|
#include "opl_apu.h"
|
||
|
|
||
|
#include "blargg_source.h"
|
||
|
|
||
|
/* NOTE: Removed unused chips ~ gama */
|
||
|
|
||
|
blargg_err_t Opl_init( struct Opl_Apu* this, long clock, long rate, blip_time_t period, enum opl_type_t type )
|
||
|
{
|
||
|
Synth_init( &this->synth );
|
||
|
|
||
|
this->type_ = type;
|
||
|
this->clock_ = clock;
|
||
|
this->rate_ = rate;
|
||
|
this->period_ = period;
|
||
|
Opl_set_output( this, 0 );
|
||
|
Opl_volume( this, 1.0 );
|
||
|
|
||
|
switch (type)
|
||
|
{
|
||
|
case type_opll:
|
||
|
case type_msxmusic:
|
||
|
case type_smsfmunit:
|
||
|
OPLL_new ( &this->opll, clock, rate );
|
||
|
OPLL_reset_patch( &this->opll, OPLL_2413_TONE );
|
||
|
break;
|
||
|
case type_vrc7:
|
||
|
OPLL_new ( &this->opll, clock, rate );
|
||
|
OPLL_reset_patch( &this->opll, OPLL_VRC7_TONE );
|
||
|
break;
|
||
|
case type_msxaudio:
|
||
|
OPL_init( &this->opl, this->opl_memory, sizeof this->opl_memory );
|
||
|
OPL_setSampleRate( &this->opl, rate, clock );
|
||
|
OPL_setInternalVolume(&this->opl, 1 << 13);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Opl_reset( this );
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void Opl_shutdown( struct Opl_Apu* this )
|
||
|
{
|
||
|
switch (this->type_)
|
||
|
{
|
||
|
case type_opll:
|
||
|
case type_msxmusic:
|
||
|
case type_smsfmunit:
|
||
|
case type_vrc7:
|
||
|
OPLL_delete( &this->opll );
|
||
|
break;
|
||
|
case type_msxaudio: break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void Opl_reset( struct Opl_Apu* this )
|
||
|
{
|
||
|
this->addr = 0;
|
||
|
this->next_time = 0;
|
||
|
this->last_amp = 0;
|
||
|
|
||
|
switch (this->type_)
|
||
|
{
|
||
|
case type_opll:
|
||
|
case type_msxmusic:
|
||
|
case type_smsfmunit:
|
||
|
case type_vrc7:
|
||
|
OPLL_reset( &this->opll );
|
||
|
OPLL_setMask( &this->opll, 0 );
|
||
|
break;
|
||
|
case type_msxaudio:
|
||
|
OPL_reset( &this->opl );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void run_until( struct Opl_Apu* this, blip_time_t end_time );
|
||
|
void Opl_write_data( struct Opl_Apu* this, blip_time_t time, int data )
|
||
|
{
|
||
|
run_until( this, time );
|
||
|
switch (this->type_)
|
||
|
{
|
||
|
case type_opll:
|
||
|
case type_msxmusic:
|
||
|
case type_smsfmunit:
|
||
|
case type_vrc7:
|
||
|
OPLL_writeIO( &this->opll, 0, this->addr );
|
||
|
OPLL_writeIO( &this->opll, 1, data );
|
||
|
break;
|
||
|
case type_msxaudio:
|
||
|
OPL_writeReg( &this->opl, this->addr, data );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int Opl_read( struct Opl_Apu* this, blip_time_t time, int port )
|
||
|
{
|
||
|
run_until( this, time );
|
||
|
switch (this->type_)
|
||
|
{
|
||
|
case type_opll:
|
||
|
case type_msxmusic:
|
||
|
case type_smsfmunit:
|
||
|
case type_vrc7:
|
||
|
return OPLL_read( &this->opll, port );
|
||
|
case type_msxaudio:
|
||
|
return OPL_readStatus( &this->opl );
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void Opl_end_frame( struct Opl_Apu* this, blip_time_t time )
|
||
|
{
|
||
|
run_until( this, time );
|
||
|
this->next_time -= time;
|
||
|
|
||
|
if ( this->output_ )
|
||
|
Blip_set_modified( this->output_ );
|
||
|
}
|
||
|
|
||
|
static void run_until( struct Opl_Apu* this, blip_time_t end_time )
|
||
|
{
|
||
|
if ( end_time > this->next_time )
|
||
|
{
|
||
|
blip_time_t time_delta = end_time - this->next_time;
|
||
|
blip_time_t time = this->next_time;
|
||
|
unsigned count = time_delta / this->period_ + 1;
|
||
|
switch (this->type_)
|
||
|
{
|
||
|
case type_opll:
|
||
|
case type_msxmusic:
|
||
|
case type_smsfmunit:
|
||
|
case type_vrc7:
|
||
|
{
|
||
|
OPLL* opll = &this->opll; // cache
|
||
|
struct Blip_Buffer* const output = this->output_;
|
||
|
while ( count > 0 )
|
||
|
{
|
||
|
unsigned todo = count;
|
||
|
if ( todo > 1024 ) todo = 1024;
|
||
|
short *buffer = OPLL_update_buffer(opll, todo);
|
||
|
|
||
|
if ( output && buffer )
|
||
|
{
|
||
|
int last_amp = this->last_amp;
|
||
|
unsigned i;
|
||
|
for ( i = 0; i < todo; i++ )
|
||
|
{
|
||
|
int amp = buffer [i];
|
||
|
int delta = amp - last_amp;
|
||
|
if ( delta )
|
||
|
{
|
||
|
last_amp = amp;
|
||
|
Synth_offset_inline( &this->synth, time, delta, output );
|
||
|
}
|
||
|
time += this->period_;
|
||
|
}
|
||
|
this->last_amp = last_amp;
|
||
|
}
|
||
|
count -= todo;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case type_msxaudio:
|
||
|
{
|
||
|
struct Y8950* opl = &this->opl;
|
||
|
struct Blip_Buffer* const output = this->output_;
|
||
|
while ( count > 0 )
|
||
|
{
|
||
|
unsigned todo = count;
|
||
|
if ( todo > 1024 ) todo = 1024;
|
||
|
int *buffer = OPL_updateBuffer(opl, todo);
|
||
|
|
||
|
if ( output && buffer )
|
||
|
{
|
||
|
int last_amp = this->last_amp;
|
||
|
unsigned i;
|
||
|
for ( i = 0; i < todo; i++ )
|
||
|
{
|
||
|
int amp = buffer [i];
|
||
|
int delta = amp - last_amp;
|
||
|
if ( delta )
|
||
|
{
|
||
|
last_amp = amp;
|
||
|
Synth_offset_inline( &this->synth, time, delta, output );
|
||
|
}
|
||
|
time += this->period_;
|
||
|
}
|
||
|
this->last_amp = last_amp;
|
||
|
}
|
||
|
count -= todo;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
this->next_time = time;
|
||
|
}
|
||
|
}
|