285 lines
5.7 KiB
C++
285 lines
5.7 KiB
C++
#include "Opl_Apu.h"
|
|
|
|
#include "blargg_source.h"
|
|
|
|
extern "C" {
|
|
#include "../vgmplay/chips/mamedef.h"
|
|
#include "../vgmplay/chips/emu2413.h"
|
|
#include "../vgmplay/chips/fmopl.h"
|
|
}
|
|
|
|
static unsigned char vrc7_inst[(16 + 3) * 8] =
|
|
{
|
|
#include "../vgmplay/chips/vrc7tone.h"
|
|
};
|
|
|
|
Opl_Apu::Opl_Apu() { opl = 0; opl_memory = 0; }
|
|
|
|
blargg_err_t Opl_Apu::init( long clock, long rate, blip_time_t period, type_t type )
|
|
{
|
|
type_ = type;
|
|
clock_ = clock;
|
|
rate_ = rate;
|
|
period_ = period;
|
|
set_output( 0, 0 );
|
|
volume( 1.0 );
|
|
switch (type)
|
|
{
|
|
case type_opll:
|
|
case type_msxmusic:
|
|
case type_smsfmunit:
|
|
opl = OPLL_new( (BOOST::uint32_t) clock, (BOOST::uint32_t) rate );
|
|
OPLL_SetChipMode( (OPLL *) opl, 0);
|
|
break;
|
|
|
|
case type_vrc7:
|
|
opl = OPLL_new( (BOOST::uint32_t) clock, (BOOST::uint32_t) rate );
|
|
OPLL_SetChipMode((OPLL *) opl, 1 );
|
|
OPLL_setPatch((OPLL *) opl, vrc7_inst);
|
|
break;
|
|
|
|
case type_opl:
|
|
opl = ym3526_init( (BOOST::uint32_t) clock, (BOOST::uint32_t) rate );
|
|
break;
|
|
|
|
case type_msxaudio:
|
|
//logfile = fopen("c:\\temp\\msxaudio.log", "wb");
|
|
opl = y8950_init( (BOOST::uint32_t) clock, (BOOST::uint32_t) rate );
|
|
opl_memory = malloc( 32768 );
|
|
y8950_set_delta_t_memory( opl, opl_memory, 32768 );
|
|
break;
|
|
|
|
case type_opl2:
|
|
opl = ym3812_init( (BOOST::uint32_t) clock, (BOOST::uint32_t) rate );
|
|
break;
|
|
}
|
|
reset();
|
|
return 0;
|
|
}
|
|
|
|
Opl_Apu::~Opl_Apu()
|
|
{
|
|
if (opl)
|
|
{
|
|
switch (type_)
|
|
{
|
|
case type_opll:
|
|
case type_msxmusic:
|
|
case type_smsfmunit:
|
|
case type_vrc7:
|
|
OPLL_delete( (OPLL *) opl );
|
|
break;
|
|
|
|
case type_opl:
|
|
ym3526_shutdown( opl );
|
|
break;
|
|
|
|
case type_msxaudio:
|
|
y8950_shutdown( opl );
|
|
//free( opl_memory ); // y8950_shutdown frees deltat->memory
|
|
//fclose( logfile );
|
|
break;
|
|
|
|
case type_opl2:
|
|
ym3812_shutdown( opl );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Opl_Apu::reset()
|
|
{
|
|
addr = 0;
|
|
next_time = 0;
|
|
last_amp = 0;
|
|
|
|
switch (type_)
|
|
{
|
|
case type_opll:
|
|
case type_msxmusic:
|
|
case type_smsfmunit:
|
|
case type_vrc7:
|
|
OPLL_reset( (OPLL *) opl );
|
|
break;
|
|
|
|
case type_opl:
|
|
ym3526_reset_chip( opl );
|
|
break;
|
|
|
|
case type_msxaudio:
|
|
y8950_reset_chip( opl );
|
|
break;
|
|
|
|
case type_opl2:
|
|
ym3812_reset_chip( opl );
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Opl_Apu::write_data( blip_time_t time, int data )
|
|
{
|
|
run_until( time );
|
|
switch (type_)
|
|
{
|
|
case type_opll:
|
|
case type_msxmusic:
|
|
case type_smsfmunit:
|
|
case type_vrc7:
|
|
OPLL_writeIO( (OPLL *) opl, 0, addr );
|
|
OPLL_writeIO( (OPLL *) opl, 1, data );
|
|
break;
|
|
|
|
case type_opl:
|
|
ym3526_write( opl, 0, addr );
|
|
ym3526_write( opl, 1, data );
|
|
break;
|
|
|
|
case type_msxaudio:
|
|
/*if ( addr >= 7 && addr <= 7 + 11 )
|
|
{
|
|
unsigned char temp [2] = { addr - 7, data };
|
|
fwrite( &temp, 1, 2, logfile );
|
|
}*/
|
|
y8950_write( opl, 0, addr );
|
|
y8950_write( opl, 1, data );
|
|
break;
|
|
|
|
case type_opl2:
|
|
ym3812_write( opl, 0, addr );
|
|
ym3812_write( opl, 1, data );
|
|
break;
|
|
}
|
|
}
|
|
|
|
int Opl_Apu::read( blip_time_t time, int port )
|
|
{
|
|
run_until( time );
|
|
switch (type_)
|
|
{
|
|
case type_opll:
|
|
case type_msxmusic:
|
|
case type_smsfmunit:
|
|
case type_vrc7:
|
|
return port ? 0xFF : 0;
|
|
|
|
case type_opl:
|
|
return ym3526_read( opl, port );
|
|
|
|
case type_msxaudio:
|
|
{
|
|
int ret = y8950_read( opl, port );
|
|
/*unsigned char temp [2] = { port + 0x80, ret };
|
|
fwrite( &temp, 1, 2, logfile );*/
|
|
return ret;
|
|
}
|
|
|
|
case type_opl2:
|
|
return ym3812_read( opl, port );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void Opl_Apu::end_frame( blip_time_t time )
|
|
{
|
|
run_until( time );
|
|
next_time -= time;
|
|
|
|
if ( output_ )
|
|
output_->set_modified();
|
|
}
|
|
|
|
void Opl_Apu::run_until( blip_time_t end_time )
|
|
{
|
|
if ( end_time > next_time )
|
|
{
|
|
blip_time_t time_delta = end_time - next_time;
|
|
blip_time_t time = next_time;
|
|
unsigned count = time_delta / period_ + 1;
|
|
switch (type_)
|
|
{
|
|
case type_opll:
|
|
case type_msxmusic:
|
|
case type_smsfmunit:
|
|
case type_vrc7:
|
|
{
|
|
e_int32 bufMO[ 1024 ];
|
|
e_int32 bufRO[ 1024 ];
|
|
e_int32 * buffers[2] = { bufMO, bufRO };
|
|
|
|
while ( count > 0 )
|
|
{
|
|
unsigned todo = count;
|
|
if ( todo > 1024 ) todo = 1024;
|
|
OPLL_calc_stereo( (OPLL *) opl, buffers, todo, -1 );
|
|
|
|
if ( output_ )
|
|
{
|
|
int last_amp = this->last_amp;
|
|
for ( unsigned i = 0; i < todo; i++ )
|
|
{
|
|
int amp = bufMO [i] + bufRO [i];
|
|
int delta = amp - last_amp;
|
|
if ( delta )
|
|
{
|
|
last_amp = amp;
|
|
synth.offset_inline( time, delta, output_ );
|
|
}
|
|
time += period_;
|
|
}
|
|
this->last_amp = last_amp;
|
|
}
|
|
else time += period_ * todo;
|
|
|
|
count -= todo;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case type_opl:
|
|
case type_msxaudio:
|
|
case type_opl2:
|
|
{
|
|
OPLSAMPLE bufL[ 1024 ];
|
|
OPLSAMPLE bufR[ 1024 ];
|
|
OPLSAMPLE* buffers[2] = {bufL, bufR};
|
|
|
|
while ( count > 0 )
|
|
{
|
|
unsigned todo = count;
|
|
if ( todo > 1024 ) todo = 1024;
|
|
switch (type_)
|
|
{
|
|
case type_opl: ym3526_update_one( opl, buffers, todo ); break;
|
|
case type_msxaudio: y8950_update_one( opl, buffers, todo ); break;
|
|
case type_opl2: ym3812_update_one( opl, buffers, todo ); break;
|
|
default: break;
|
|
}
|
|
|
|
if ( output_ )
|
|
{
|
|
int last_amp = this->last_amp;
|
|
for ( unsigned i = 0; i < todo; i++ )
|
|
{
|
|
int amp = bufL [i] + bufR [i];
|
|
int delta = amp - last_amp;
|
|
if ( delta )
|
|
{
|
|
last_amp = amp;
|
|
synth.offset_inline( time, delta, output_ );
|
|
}
|
|
time += period_;
|
|
}
|
|
this->last_amp = last_amp;
|
|
}
|
|
else time += period_ * todo;
|
|
|
|
count -= todo;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
next_time = time;
|
|
}
|
|
}
|