#include <cstring>
#include "rat.h"
#include "debug.h"
const unsigned char CxadratPlayer::rat_adlib_bases[18] =
{
0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12,
0x03, 0x04, 0x05, 0x0B, 0x0C, 0x0D, 0x13, 0x14, 0x15
};
const unsigned short CxadratPlayer::rat_notes[16] =
{
0x157, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287,
0x000, 0x000, 0x000, 0x000 };
CPlayer *CxadratPlayer::factory(Copl *newopl)
{
return new CxadratPlayer(newopl);
}
bool CxadratPlayer::xadplayer_load()
{
if(xad.fmt != RAT)
return false;
memcpy(&rat.hdr, &tune[0], sizeof(rat_header));
if (strncmp(rat.hdr.id,"RAT",3))
return false;
if (rat.hdr.version != 0x10)
return false;
rat.order = &tune[0x40];
rat.inst = (rat_instrument *)&tune[0x140];
unsigned short patseg = (rat.hdr.patseg[1] << 8) + rat.hdr.patseg[0];
unsigned char *event_ptr = &tune[patseg << 4];
for(int i=0;i<rat.hdr.numpat;i++)
for(int j=0;j<64;j++)
for(int k=0;k<rat.hdr.numchan;k++)
{
memcpy(&rat.tracks[i][j][k], event_ptr, sizeof(rat_event));
event_ptr += sizeof(rat_event);
}
return true;
}
void CxadratPlayer::xadplayer_rewind(int subsong)
{
int i;
rat.order_pos = rat.hdr.order_start;
rat.pattern_pos = 0;
rat.volume = rat.hdr.volume;
plr.speed = rat.hdr.speed;
memset(&rat.channel, 0, sizeof(rat.channel[0])*9);
opl_write(0x01, 0x20);
opl_write(0x08, 0x00);
opl_write(0xBD, 0x00);
for(i=0;i<9;i++)
{
opl_write(0xA0+i, 0x00);
opl_write(0xA3+i, 0x00);
opl_write(0xB0+i, 0x00);
opl_write(0xB3+i, 0x00);
}
for(i=0;i<0x1F;i++)
opl_write(0x40+i, 0x3F);
}
void CxadratPlayer::xadplayer_update()
{
int i;
rat_event event;
for(i=0;i<rat.hdr.numchan;i++)
{
memcpy(&event,&rat.tracks[rat.order[rat.order_pos]][rat.pattern_pos][i],sizeof(rat_event));
#ifdef DEBUG
AdPlug_LogWrite("order %02X, pattern %02X, row %02X, channel %02X, event %02X %02X %02X %02X %02X:\n",
rat.order_pos, rat.order[rat.order_pos], rat.pattern_pos, i, event.note, event.instrument, event.volume, event.fx, event.fxp
);
#endif
if (event.instrument != 0xFF)
{
rat.channel[i].instrument = event.instrument - 1;
rat.channel[i].volume = rat.inst[event.instrument - 1].volume;
}
if (event.volume != 0xFF)
rat.channel[i].volume = event.volume;
if (event.note != 0xFF)
{
opl_write(0xB0+i, 0x00);
opl_write(0xA0+i, 0x00);
if (event.note != 0xFE)
{
unsigned char ins = rat.channel[i].instrument;
opl_write(0xC0+i, rat.inst[ins].connect);
opl_write(0x20+rat_adlib_bases[i], rat.inst[ins].mod_ctrl);
opl_write(0x20+rat_adlib_bases[i+9], rat.inst[ins].car_ctrl);
opl_write(0x40+rat_adlib_bases[i], __rat_calc_volume(rat.inst[ins].mod_volume,rat.channel[i].volume,rat.volume));
opl_write(0x40+rat_adlib_bases[i+9], __rat_calc_volume(rat.inst[ins].car_volume,rat.channel[i].volume,rat.volume));
opl_write(0x60+rat_adlib_bases[i], rat.inst[ins].mod_AD);
opl_write(0x60+rat_adlib_bases[i+9], rat.inst[ins].car_AD);
opl_write(0x80+rat_adlib_bases[i], rat.inst[ins].mod_SR);
opl_write(0x80+rat_adlib_bases[i+9], rat.inst[ins].car_SR);
opl_write(0xE0+rat_adlib_bases[i], rat.inst[ins].mod_wave);
opl_write(0xE0+rat_adlib_bases[i+9], rat.inst[ins].car_wave);
unsigned short insfreq = (rat.inst[ins].freq[1] << 8) + rat.inst[ins].freq[0];
unsigned short freq = insfreq * rat_notes[event.note & 0x0F] / 0x20AB;
opl_write(0xA0+i, freq & 0xFF);
opl_write(0xB0+i, (freq >> 8) | ((event.note & 0xF0) >> 2) | 0x20);
}
}
if (event.fx != 0xFF)
{
rat.channel[i].fx = event.fx;
rat.channel[i].fxp = event.fxp;
}
}
rat.pattern_pos++;
for(i=0;i<rat.hdr.numchan;i++)
{
unsigned char old_order_pos = rat.order_pos;
switch (rat.channel[i].fx)
{
case 0x01: plr.speed = rat.channel[i].fxp;
break;
case 0x02: if (rat.channel[i].fxp < rat.hdr.order_end)
rat.order_pos = rat.channel[i].fxp;
else
rat.order_pos = 0;
if (rat.order_pos <= old_order_pos)
plr.looping = 1;
rat.pattern_pos = 0;
break;
case 0x03: rat.pattern_pos = 0x40;
break;
}
rat.channel[i].fx = 0;
}
if (rat.pattern_pos >= 0x40)
{
rat.pattern_pos = 0;
rat.order_pos++;
if (rat.order_pos == rat.hdr.order_end)
{
rat.order_pos = rat.hdr.order_loop;
plr.looping = 1;
}
}
}
float CxadratPlayer::xadplayer_getrefresh()
{
return 60.0f;
}
std::string CxadratPlayer::xadplayer_gettype()
{
return (std::string("xad: rat player"));
}
std::string CxadratPlayer::xadplayer_gettitle()
{
return (std::string(rat.hdr.title,32));
}
unsigned int CxadratPlayer::xadplayer_getinstruments()
{
return rat.hdr.numinst;
}
unsigned char CxadratPlayer::__rat_calc_volume(unsigned char ivol, unsigned char cvol, unsigned char gvol)
{
#ifdef DEBUG
AdPlug_LogWrite("volumes: instrument %02X, channel %02X, global %02X:\n", ivol, cvol, gvol);
#endif
unsigned short vol;
vol = ivol;
vol &= 0x3F;
vol ^= 0x3F;
vol *= cvol;
vol >>= 6;
vol *= gvol;
vol >>= 6;
vol ^= 0x3F;
vol |= ivol & 0xC0;
return vol;
}