// From https://github.com/tslabs/zx-evo/blob/master/pentevo/unreal/Unreal/sound/dev_moonsound.cpp
#include "../std.h"
#include "../emul.h"
#include "../vars.h"
#include "../util.h"
#include "dev_moonsound.h"
#define MASTER_CLOCK 33868800
inline EmuTime SystemTime()
{
return cpu.t + comp.frame_counter * conf.frame;
}
ZXMMoonSound_priv::ZXMMoonSound_priv() : ymf262(0, 0), ymf278(0, 4096, 2048*1024, 0)
{
EmuTime systemTime = 0;
// ymf262 = new YMF262(0, systemTime);
ymf262.setSampleRate(44100, 1);
ymf262.setVolume(32767 * 2 / 10);
// ymf278 = new YMF278(0, 4096, 2048*1024, systemTime);
ymf278.setSampleRate(44100, 1);
ymf278.setVolume(32767 * 2 / 10);
}
ZXMMoonSound_priv::~ZXMMoonSound_priv()
{
// delete ymf262;
// delete ymf278;
}
/* */
ZXMMoonSound::ZXMMoonSound() :
system_clock_rate( 0 )
{
// d = new ZXMMoonSound_priv();
reset();
}
int ZXMMoonSound::load_rom(char *path)
{
u8 * moon_rom;
moon_rom = d.ymf278.getRom();
if( !moon_rom )
return -1;
FILE *fp = fopen( path, "rb" );
if ( !fp )
{
return -2;
}
if( 1 != fread( moon_rom, d.ymf278.getRomSize(), 1, fp ) )
{
fclose(fp);
return -3;
}
fclose( fp );
return 0;
}
void ZXMMoonSound::reset()
{
unsigned tStatesPerSecond = conf.frame * conf.intfq;
EmuTime systemTime = SystemTime();
d.ymf262.reset( systemTime, tStatesPerSecond );
d.ymf278.reset( systemTime );
}
bool ZXMMoonSound::wr_opl3( u8 port, u8 val )
{
EmuTime systemTime = SystemTime();
if ( !(port & 0xFC) )
{
switch (port & 0x03) {
case 0:
d.opl3latch = val;
break;
case 2: // select register bank 1
d.opl3latch = val | 0x100;
break;
case 1:
case 3: // write fm register
d.ymf262.writeReg(d.opl3latch, val, systemTime);
break;
}
return true;
}
return false;
}
bool ZXMMoonSound::wr_opl4( u8 port, u8 val )
{
EmuTime systemTime = SystemTime();
if ( !(port & 0xFE) )
{
switch (port & 0x01) {
case 0: // select register
d.opl4latch = val;
break;
case 1:
d.ymf278.writeRegOPL4(d.opl4latch, val, systemTime);
break;
}
return true;
}
return false;
}
bool ZXMMoonSound::rd_opl3( u8 port, u8 &val )
{
EmuTime systemTime = SystemTime();
if( !(port & 0xFC) )
{
switch (port & 0x03) {
case 0: // read status
case 2:
val = d.ymf262.readStatus(systemTime) | d.ymf278.readStatus(systemTime);
break;
case 1:
case 3: // read fm register
val = d.ymf262.readReg(d.opl3latch);
break;
}
return true;
}
return false;
}
bool ZXMMoonSound::rd_opl4( u8 port, u8 &val )
{
EmuTime systemTime = SystemTime();
if ( !(port & 0xFE) )
{
switch (port & 0x01) {
case 1: // read wave register
val = d.ymf278.readRegOPL4(d.opl4latch, systemTime);
break;
}
return true;
}
return false;
}
void ZXMMoonSound::set_timings(unsigned system_clock_rate, unsigned chip_clock_rate, unsigned sample_rate)
{
d.ymf262.setSampleRate( sample_rate, 1 );
d.ymf262.setVolume((u16)(1 * (conf.sound.moonsound_vol / 8192.0))); // doesn't work
d.ymf278.setSampleRate( sample_rate, 1 );
d.ymf278.setVolume((u16)(2000 * (conf.sound.moonsound_vol / 8192.0)));
chip_clock_rate = sample_rate;
ZXMMoonSound::system_clock_rate = system_clock_rate;
ZXMMoonSound::chip_clock_rate = chip_clock_rate;
SNDRENDER::set_timings(chip_clock_rate, sample_rate);
passed_chip_ticks = passed_clk_ticks = 0;
t = 0;
}
void ZXMMoonSound::start_frame(bufptr_t dst)
{
SNDRENDER::start_frame(dst);
}
unsigned ZXMMoonSound::end_frame(unsigned clk_ticks)
{
u64 end_chip_tick = ((passed_clk_ticks + clk_ticks) * chip_clock_rate) / system_clock_rate;
flush((unsigned)(end_chip_tick - passed_chip_ticks));
unsigned Val = SNDRENDER::end_frame(t);
passed_clk_ticks += clk_ticks;
passed_chip_ticks += t;
t = 0;
return Val;
}
void ZXMMoonSound::flush(unsigned chiptick)
{
while (t < chiptick)
{
int buffer[2] = { 0, 0 };
int *buf;
t++;
buf = d.ymf262.updateBuffer(1);
if ( buf )
{
buffer[0] += buf[0] / 10;
buffer[1] += buf[1] / 10;
}
buf = d.ymf278.updateBuffer(1);
if ( buf )
{
buffer[0] += buf[0];
buffer[1] += buf[1];
}
SNDRENDER::update( t, buffer[0], buffer[1] );
}
}
ZXMMoonSound zxmmoonsound;