156 lines
3.1 KiB
C++
156 lines
3.1 KiB
C++
// Game_Music_Emu $vers. http://www.slack.net/~ant/
|
|
|
|
#include "Ym2203_Emu.h"
|
|
#include "fm.h"
|
|
#include <string.h>
|
|
|
|
static void psg_set_clock(void *param, int clock)
|
|
{
|
|
Ym2203_Emu *info = (Ym2203_Emu *)param;
|
|
info->psg_set_clock( clock );
|
|
}
|
|
|
|
static void psg_write(void *param, int address, int data)
|
|
{
|
|
Ym2203_Emu *info = (Ym2203_Emu *)param;
|
|
info->psg_write( address, data );
|
|
}
|
|
|
|
static int psg_read(void *param)
|
|
{
|
|
Ym2203_Emu *info = (Ym2203_Emu *)param;
|
|
return info->psg_read();
|
|
}
|
|
|
|
static void psg_reset(void *param)
|
|
{
|
|
Ym2203_Emu *info = (Ym2203_Emu *)param;
|
|
info->psg_reset();
|
|
}
|
|
|
|
static const ssg_callbacks psgintf =
|
|
{
|
|
psg_set_clock,
|
|
psg_write,
|
|
psg_read,
|
|
psg_reset
|
|
};
|
|
|
|
Ym2203_Emu::Ym2203_Emu() { opn = 0; psg.set_type( Ay_Apu::Ym2203 ); }
|
|
|
|
Ym2203_Emu::~Ym2203_Emu()
|
|
{
|
|
if ( opn ) ym2203_shutdown( opn );
|
|
}
|
|
|
|
int Ym2203_Emu::set_rate( int sample_rate, int clock_rate )
|
|
{
|
|
if ( opn )
|
|
{
|
|
ym2203_shutdown( opn );
|
|
opn = 0;
|
|
}
|
|
|
|
opn = ym2203_init( this, clock_rate, sample_rate, &psgintf );
|
|
if ( !opn )
|
|
return 1;
|
|
|
|
this->sample_rate = sample_rate;
|
|
psg_clock = clock_rate * 2;
|
|
|
|
buffer.set_sample_rate( sample_rate );
|
|
buffer.clock_rate( psg_clock );
|
|
|
|
psg.volume( 1.0 );
|
|
|
|
reset();
|
|
return 0;
|
|
}
|
|
|
|
void Ym2203_Emu::reset()
|
|
{
|
|
psg.reset();
|
|
ym2203_reset_chip( opn );
|
|
mute_voices( 0 );
|
|
}
|
|
|
|
static stream_sample_t* DUMMYBUF[0x02] = {(stream_sample_t*)NULL, (stream_sample_t*)NULL};
|
|
|
|
void Ym2203_Emu::write( int addr, int data )
|
|
{
|
|
ym2203_update_one( opn, DUMMYBUF, 0 );
|
|
ym2203_write( opn, 0, addr );
|
|
ym2203_write( opn, 1, data );
|
|
}
|
|
|
|
void Ym2203_Emu::mute_voices( int mask )
|
|
{
|
|
ym2203_set_mutemask( opn, mask );
|
|
for ( unsigned i = 0, j = 1 << 3; i < 3; i++, j <<= 1)
|
|
{
|
|
Blip_Buffer * buf = ( mask & j ) ? NULL : &buffer;
|
|
psg.set_output( i, buf );
|
|
}
|
|
}
|
|
|
|
void Ym2203_Emu::run( int pair_count, sample_t* out )
|
|
{
|
|
blip_sample_t buf[ 1024 ];
|
|
FMSAMPLE bufL[ 1024 ];
|
|
FMSAMPLE bufR[ 1024 ];
|
|
FMSAMPLE * buffers[2] = { bufL, bufR };
|
|
|
|
blip_time_t psg_end_time = pair_count * psg_clock / sample_rate;
|
|
psg.end_frame( psg_end_time );
|
|
buffer.end_frame( psg_end_time );
|
|
|
|
while (pair_count > 0)
|
|
{
|
|
int todo = pair_count;
|
|
if (todo > 1024) todo = 1024;
|
|
ym2203_update_one( opn, buffers, todo );
|
|
|
|
int sample_count = buffer.read_samples( buf, todo );
|
|
memset( buf + sample_count, 0, ( todo - sample_count ) * sizeof( blip_sample_t ) );
|
|
|
|
for (int i = 0; i < todo; i++)
|
|
{
|
|
int output_l, output_r;
|
|
int output = buf [i];
|
|
output_l = output + bufL [i];
|
|
output_r = output + bufR [i];
|
|
output_l += out [0];
|
|
output_r += out [1];
|
|
if ( (short)output_l != output_l ) output_l = 0x7FFF ^ ( output_l >> 31 );
|
|
if ( (short)output_r != output_r ) output_r = 0x7FFF ^ ( output_r >> 31 );
|
|
out [0] = output_l;
|
|
out [1] = output_r;
|
|
out += 2;
|
|
}
|
|
|
|
pair_count -= todo;
|
|
}
|
|
}
|
|
|
|
void Ym2203_Emu::psg_set_clock( int clock )
|
|
{
|
|
psg_clock = clock * 2;
|
|
buffer.clock_rate( psg_clock );
|
|
}
|
|
|
|
void Ym2203_Emu::psg_write( int addr, int data )
|
|
{
|
|
if ( !(addr & 1) ) psg.write_addr( data );
|
|
else psg.write_data( 0, data );
|
|
}
|
|
|
|
int Ym2203_Emu::psg_read()
|
|
{
|
|
return psg.read();
|
|
}
|
|
|
|
void Ym2203_Emu::psg_reset()
|
|
{
|
|
psg.reset();
|
|
}
|