mirror of https://github.com/yaz0r/FITD.git
1305 lines
24 KiB
C++
1305 lines
24 KiB
C++
#include "common.h"
|
|
|
|
bool g_gameUseCDA = false;
|
|
|
|
int musicVolume = 0x7F;
|
|
|
|
unsigned int musicChrono;
|
|
|
|
typedef int(*musicDrvFunctionType)(void * ptr);
|
|
|
|
#ifndef AITD_UE4
|
|
struct FM_OPL* virtualOpl;
|
|
#endif
|
|
|
|
char OPLinitialized = 0;
|
|
|
|
#define OPL_INTERNAL_FREQ 3579545
|
|
|
|
void callMusicUpdate(void);
|
|
|
|
struct channelTable2Element
|
|
{
|
|
u16 index;
|
|
struct channelTable2Element *var2;
|
|
u16 var4;
|
|
u8* dataPtr;
|
|
u8* commandPtr;
|
|
s16 varE;
|
|
u16 var10;
|
|
u8 var12;
|
|
u16 var13;
|
|
u16 var15;
|
|
u8 var17;
|
|
u16 var18;
|
|
u8 var1A;
|
|
u8 var1B;
|
|
u8 var1C;
|
|
u8 var1D;
|
|
u8 var1E;
|
|
};
|
|
|
|
typedef struct channelTable2Element channelTable2Element;
|
|
|
|
typedef void(*musicCommandType)(channelTable2Element* entry, int param,u8* ptr);
|
|
|
|
struct channelTableElement
|
|
{
|
|
u16 var0;
|
|
u16 var2;
|
|
u8 var4;
|
|
u8 var5;
|
|
u8 var6;
|
|
u8 var7;
|
|
u16 var8;
|
|
};
|
|
|
|
typedef struct channelTableElement channelTableElement;
|
|
|
|
channelTableElement channelDataTable[11] =
|
|
{
|
|
{0xFFFF, 0x40, 0xFF, 0xFF, 0xFF, 0x9C, 0xFFFF},
|
|
{0xFFFF, 0x40, 0xFF, 0xFF, 0xFF, 0x9C, 0xFFFF},
|
|
{0xFFFF, 0x40, 0xFF, 0xFF, 0xFF, 0x9C, 0xFFFF},
|
|
{0xFFFF, 0x40, 0xFF, 0xFF, 0xFF, 0x9C, 0xFFFF},
|
|
{0xFFFF, 0x40, 0xFF, 0xFF, 0xFF, 0x9C, 0xFFFF},
|
|
{0xFFFF, 0x40, 0xFF, 0xFF, 0xFF, 0x9C, 0xFFFF},
|
|
{0xFFFF, 0x40, 0xFF, 0xFF, 0xFF, 0x9C, 0xFFFF},
|
|
{0xFFFF, 0x40, 0xFF, 0xFF, 0xFF, 0x9C, 0xFFFF},
|
|
{0xFFFF, 0x40, 0xFF, 0xFF, 0xFF, 0x9C, 0xFFFF},
|
|
{0xFFFF, 0x40, 0xFF, 0xFF, 0xFF, 0x9C, 0xFFFF},
|
|
{0xFFFF, 0x40, 0xFF, 0xFF, 0xFF, 0x9C, 0xFFFF}
|
|
};
|
|
|
|
extern channelTable2Element channelTable3[11];
|
|
extern channelTable2Element channelTable2[11];
|
|
|
|
channelTable2Element channelTable3[11] =
|
|
{
|
|
{ 0, &channelTable2[0],0x8040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 1, &channelTable2[1],0x8040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 2, &channelTable2[2],0x8040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 3, &channelTable2[3],0x8040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 4, &channelTable2[4],0x8040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 5, &channelTable2[5],0x8040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 6, &channelTable2[6],0x8040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 7, &channelTable2[7],0x8040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 8, &channelTable2[8],0x8040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 9, &channelTable2[9],0x8040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{10,&channelTable2[10],0x8040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0}
|
|
};
|
|
|
|
channelTable2Element channelTable2[11] =
|
|
{
|
|
{ 0, &channelTable3[0],0x0040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 1, &channelTable3[1],0x0040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 2, &channelTable3[2],0x0040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 3, &channelTable3[3],0x0040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 4, &channelTable3[4],0x0040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 5, &channelTable3[5],0x0040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 6, &channelTable3[6],0x0040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 7, &channelTable3[7],0x0040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 8, &channelTable3[8],0x0040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{ 9, &channelTable3[9],0x0040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
{10,&channelTable3[10],0x0040,NULL,NULL,0,0,0,0,0,0,0,0x7F,1,1,0x7F,0},
|
|
};
|
|
|
|
unsigned char regBDConf = 0xC0;
|
|
|
|
unsigned char channelTableMelodic[] =
|
|
{
|
|
0x00,
|
|
0x03,
|
|
0x01,
|
|
0x04,
|
|
0x02,
|
|
0x05,
|
|
0x08,
|
|
0x0B,
|
|
0x09,
|
|
0x0C,
|
|
0x0A,
|
|
0x0D,
|
|
0x10,
|
|
0x13,
|
|
0x11,
|
|
0x14,
|
|
0x12,
|
|
0x15,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF
|
|
};
|
|
|
|
unsigned char channelTableRythme[] =
|
|
{
|
|
0x00,
|
|
0x03,
|
|
0x01,
|
|
0x04,
|
|
0x02,
|
|
0x05,
|
|
0x08,
|
|
0x0B,
|
|
0x09,
|
|
0x0C,
|
|
0x0A,
|
|
0x0D,
|
|
0x10,
|
|
0x13,
|
|
0x14,
|
|
0xFF,
|
|
0x12,
|
|
0xFF,
|
|
0x15,
|
|
0xFF,
|
|
0x11,
|
|
0xFF
|
|
};
|
|
|
|
unsigned char* channelTable;
|
|
|
|
// global table is 300 entry long
|
|
u16 globTableEntry[300] = {
|
|
0x157,
|
|
0x158,
|
|
0x159,
|
|
0x15A,
|
|
0x15A,
|
|
0x15B,
|
|
0x15C,
|
|
0x15D,
|
|
0x15E,
|
|
0x15F,
|
|
0x15F,
|
|
0x160,
|
|
0x161,
|
|
0x162,
|
|
0x163,
|
|
0x164,
|
|
0x164,
|
|
0x165,
|
|
0x166,
|
|
0x167,
|
|
0x168,
|
|
0x168,
|
|
0x169,
|
|
0x16A,
|
|
0x16B,
|
|
0x16C,
|
|
0x16D,
|
|
0x16D,
|
|
0x16E,
|
|
0x16F,
|
|
0x170,
|
|
0x171,
|
|
0x172,
|
|
0x173,
|
|
0x174,
|
|
0x174,
|
|
0x175,
|
|
0x176,
|
|
0x177,
|
|
0x178,
|
|
0x179,
|
|
0x17A,
|
|
0x17B,
|
|
0x17B,
|
|
0x17C,
|
|
0x17D,
|
|
0x17E,
|
|
0x17F,
|
|
0x180,
|
|
0x181,
|
|
0x181,
|
|
0x183,
|
|
0x183,
|
|
0x184,
|
|
0x185,
|
|
0x186,
|
|
0x187,
|
|
0x188,
|
|
0x189,
|
|
0x18A,
|
|
0x18B,
|
|
0x18C,
|
|
0x18D,
|
|
0x18E,
|
|
0x18E,
|
|
0x18F,
|
|
0x190,
|
|
0x191,
|
|
0x192,
|
|
0x193,
|
|
0x194,
|
|
0x195,
|
|
0x196,
|
|
0x197,
|
|
0x198,
|
|
0x198,
|
|
0x19A,
|
|
0x19A,
|
|
0x19B,
|
|
0x19C,
|
|
0x19D,
|
|
0x19F,
|
|
0x19F,
|
|
0x1A0,
|
|
0x1A1,
|
|
0x1A2,
|
|
0x1A3,
|
|
0x1A4,
|
|
0x1A5,
|
|
0x1A6,
|
|
0x1A7,
|
|
0x1A8,
|
|
0x1A9,
|
|
0x1AA,
|
|
0x1AB,
|
|
0x1AC,
|
|
0x1AD,
|
|
0x1AE,
|
|
0x1AF,
|
|
0x1B0,
|
|
0x1B1,
|
|
0x1B2,
|
|
0x1B3,
|
|
0x1B4,
|
|
0x1B5,
|
|
0x1B6,
|
|
0x1B7,
|
|
0x1B8,
|
|
0x1B9,
|
|
0x1BA,
|
|
0x1BB,
|
|
0x1BC,
|
|
0x1BD,
|
|
0x1BF,
|
|
0x1C0,
|
|
0x1C1,
|
|
0x1C2,
|
|
0x1C3,
|
|
0x1C4,
|
|
0x1C5,
|
|
0x1C6,
|
|
0x1C7,
|
|
0x1C8,
|
|
0x1C9,
|
|
0x1CA,
|
|
0x1CB,
|
|
0x1CC,
|
|
0x1CD,
|
|
0x1CE,
|
|
0x1CF,
|
|
0x1D0,
|
|
0x1D2,
|
|
0x1D3,
|
|
0x1D4,
|
|
0x1D5,
|
|
0x1D6,
|
|
0x1D7,
|
|
0x1D8,
|
|
0x1D9,
|
|
0x1DA,
|
|
0x1DB,
|
|
0x1DD,
|
|
0x1DE,
|
|
0x1DF,
|
|
0x1E0,
|
|
0x1E1,
|
|
0x1E2,
|
|
0x1E3,
|
|
0x1E4,
|
|
0x1E5,
|
|
0x1E6,
|
|
0x1E8,
|
|
0x1E9,
|
|
0x1EA,
|
|
0x1EB,
|
|
0x1EC,
|
|
0x1ED,
|
|
0x1EF,
|
|
0x1F0,
|
|
0x1F1,
|
|
0x1F2,
|
|
0x1F3,
|
|
0x1F4,
|
|
0x1F6,
|
|
0x1F7,
|
|
0x1F8,
|
|
0x1F9,
|
|
0x1FA,
|
|
0x1FB,
|
|
0x1FD,
|
|
0x1FE,
|
|
0x1FF,
|
|
0x200,
|
|
0x201,
|
|
0x202,
|
|
0x203,
|
|
0x205,
|
|
0x206,
|
|
0x207,
|
|
0x208,
|
|
0x20A,
|
|
0x20B,
|
|
0x20C,
|
|
0x20D,
|
|
0x20F,
|
|
0x210,
|
|
0x211,
|
|
0x212,
|
|
0x214,
|
|
0x215,
|
|
0x216,
|
|
0x217,
|
|
0x219,
|
|
0x21A,
|
|
0x21B,
|
|
0x21C,
|
|
0x21D,
|
|
0x21F,
|
|
0x220,
|
|
0x221,
|
|
0x222,
|
|
0x224,
|
|
0x225,
|
|
0x226,
|
|
0x227,
|
|
0x229,
|
|
0x22A,
|
|
0x22C,
|
|
0x22D,
|
|
0x22E,
|
|
0x22F,
|
|
0x231,
|
|
0x232,
|
|
0x234,
|
|
0x235,
|
|
0x236,
|
|
0x237,
|
|
0x239,
|
|
0x23A,
|
|
0x23B,
|
|
0x23C,
|
|
0x23E,
|
|
0x23F,
|
|
0x241,
|
|
0x242,
|
|
0x243,
|
|
0x245,
|
|
0x246,
|
|
0x247,
|
|
0x248,
|
|
0x24A,
|
|
0x24B,
|
|
0x24D,
|
|
0x24E,
|
|
0x250,
|
|
0x251,
|
|
0x252,
|
|
0x254,
|
|
0x255,
|
|
0x257,
|
|
0x258,
|
|
0x259,
|
|
0x25B,
|
|
0x25C,
|
|
0x25E,
|
|
0x25F,
|
|
0x260,
|
|
0x262,
|
|
0x263,
|
|
0x264,
|
|
0x266,
|
|
0x267,
|
|
0x269,
|
|
0x26A,
|
|
0x26B,
|
|
0x26D,
|
|
0x26E,
|
|
0x270,
|
|
0x271,
|
|
0x273,
|
|
0x274,
|
|
0x276,
|
|
0x277,
|
|
0x279,
|
|
0x27A,
|
|
0x27C,
|
|
0x27D,
|
|
0x27F,
|
|
0x280,
|
|
0x282,
|
|
0x283,
|
|
0x285,
|
|
0x286,
|
|
0x288,
|
|
0x289,
|
|
0x28A,
|
|
0x28C,
|
|
0x28D,
|
|
0x28F,
|
|
0x291,
|
|
0x292,
|
|
0x294,
|
|
0x295,
|
|
0x297,
|
|
0x299,
|
|
0x29A,
|
|
0x29C,
|
|
0x29D,
|
|
0x29F,
|
|
0x2A0,
|
|
0x2A2,
|
|
0x2A3,
|
|
0x2A5,
|
|
0x2A7,
|
|
0x2A8,
|
|
0x2AA,
|
|
0x2AB,
|
|
0x2AD,
|
|
0x2AF,
|
|
0x2B0,
|
|
};
|
|
|
|
u16* globTable[13] =
|
|
{
|
|
&globTableEntry[0],
|
|
&globTableEntry[25],
|
|
&globTableEntry[50],
|
|
&globTableEntry[75],
|
|
&globTableEntry[100],
|
|
&globTableEntry[125],
|
|
&globTableEntry[150],
|
|
&globTableEntry[175],
|
|
&globTableEntry[200],
|
|
&globTableEntry[225],
|
|
&globTableEntry[250],
|
|
&globTableEntry[275],
|
|
};
|
|
|
|
unsigned char musicParam1 = 0;
|
|
|
|
u8* currentMusicPtr = NULL;
|
|
u8* currentMusicPtr2 = NULL;
|
|
u8* currentMusicPtr3 = NULL;
|
|
u8 generalVolume = 0;
|
|
|
|
void sendAdlib(int regIdx, int value)
|
|
{
|
|
YM3812Write(0,0,regIdx);
|
|
YM3812Write(0,1,value);
|
|
}
|
|
|
|
#define musicSync 1500
|
|
int musicTimer = 0;
|
|
int nextUpdateTimer = musicSync;
|
|
|
|
int musicUpdate(void *udata, uint8 *stream, int len)
|
|
{
|
|
if(OPLinitialized)
|
|
{
|
|
int fillStatus = 0;
|
|
|
|
while(fillStatus < len)
|
|
{
|
|
int timeBeforNextUpdate = nextUpdateTimer - musicTimer;
|
|
|
|
if(timeBeforNextUpdate > (len - fillStatus))
|
|
{
|
|
timeBeforNextUpdate = len-fillStatus;
|
|
}
|
|
|
|
if(timeBeforNextUpdate) // generate
|
|
{
|
|
YM3812UpdateOne(0,(int16*)(stream+fillStatus),(timeBeforNextUpdate)/2);
|
|
fillStatus+=timeBeforNextUpdate;
|
|
musicTimer+=timeBeforNextUpdate;
|
|
}
|
|
|
|
if(musicTimer == nextUpdateTimer)
|
|
{
|
|
callMusicUpdate();
|
|
|
|
nextUpdateTimer += musicSync;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void createDefaultChannel(int index)
|
|
{
|
|
channelDataTable[index].var5 = 0xFF;
|
|
channelDataTable[index].var4 = 0xFF;
|
|
channelDataTable[index].var2 = 0x40;
|
|
channelDataTable[index].var0 = 0xFFFF;
|
|
channelDataTable[index].var7 = 0x9C;
|
|
channelDataTable[index].var8 = 0xFFFF;
|
|
}
|
|
|
|
void resetChannelFrequency(int channelIdx)
|
|
{
|
|
sendAdlib(0xA0+channelIdx,0);
|
|
sendAdlib(0xB0+channelIdx,0);
|
|
}
|
|
|
|
void setupChannelFrequency(int channelIdx, int cl, int dx,int bp)
|
|
{
|
|
u16* di;
|
|
u16 frequency;
|
|
u8 frequencyLow;
|
|
u8 frequencyHigh;
|
|
|
|
u8 blockNumber;
|
|
|
|
if(!(bp&0x8000))
|
|
{
|
|
sendAdlib(0xB0+channelIdx, 0);
|
|
}
|
|
|
|
di = globTable[cl&0xF];
|
|
|
|
if(bp & 0x80)
|
|
{
|
|
// assert(0);
|
|
}
|
|
|
|
if(cl & 0x80)
|
|
{
|
|
dx = 0x40;
|
|
}
|
|
|
|
frequency = di[bp&0xFF];
|
|
|
|
frequencyLow = frequency&0xFF;
|
|
|
|
sendAdlib(0xA0+channelIdx,frequencyLow);
|
|
|
|
blockNumber = (cl&0x70)>>2;
|
|
|
|
frequencyHigh = ((frequency>>8)&0x3)|blockNumber;
|
|
|
|
if(!(dx&0x40))
|
|
{
|
|
frequencyHigh |= 0x20; // set key on
|
|
}
|
|
|
|
sendAdlib(0xB0+channelIdx,frequencyHigh);
|
|
}
|
|
|
|
int musicStart(void* dummy)
|
|
{
|
|
int i;
|
|
|
|
sendAdlib(1,0x20);
|
|
sendAdlib(8,0);
|
|
sendAdlib(0xBD,regBDConf);
|
|
|
|
for(i=0;i<18;i++)
|
|
{
|
|
sendAdlib(0x60+channelTableMelodic[i],0xFF);
|
|
sendAdlib(0x80+channelTableMelodic[i],0xFF);
|
|
}
|
|
|
|
for(i=0;i<9;i++)
|
|
{
|
|
resetChannelFrequency(i);
|
|
}
|
|
|
|
for(i=0;i<11;i++)
|
|
{
|
|
createDefaultChannel(i);
|
|
}
|
|
|
|
if(!musicParam1)
|
|
{
|
|
resetChannelFrequency(6);
|
|
setupChannelFrequency(6,0,0x40,0);
|
|
|
|
resetChannelFrequency(7);
|
|
setupChannelFrequency(7,7,0x40,0);
|
|
|
|
resetChannelFrequency(8);
|
|
setupChannelFrequency(8,0,0x40,0);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int musicLoad(void* ptr)
|
|
{
|
|
int i;
|
|
u8 flag1;
|
|
|
|
u8* musicPtr = (u8*)ptr;
|
|
|
|
channelTable = channelTableMelodic;
|
|
|
|
flag1 = musicPtr[0x3C] & 0xC0;
|
|
musicParam1 = musicPtr[0x3D];
|
|
|
|
if(!musicParam1)
|
|
{
|
|
flag1 |= 0x20;
|
|
channelTable = channelTableRythme;
|
|
}
|
|
|
|
regBDConf = flag1;
|
|
|
|
for(i=0;i<11;i++)
|
|
{
|
|
unsigned long int offset;
|
|
|
|
offset = READ_LE_U32(musicPtr + i*4 + 8);
|
|
|
|
if(offset)
|
|
{
|
|
channelTable2[i].dataPtr = musicPtr + offset;
|
|
}
|
|
else
|
|
{
|
|
channelTable2[i].dataPtr = NULL;
|
|
}
|
|
|
|
channelTable2[i].var4 |= 0x40;
|
|
}
|
|
|
|
currentMusicPtr = musicPtr + READ_LE_U16(musicPtr + 0x34);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int initialialize(void* dummy)
|
|
{
|
|
int i;
|
|
|
|
//OPLBuildTables(FMOPL_ENV_BITS_HQ, FMOPL_EG_ENT_HQ);
|
|
|
|
YM3812Init(1,OPL_INTERNAL_FREQ,44100);
|
|
/* virtualOpl = OPLCreate(OPL_TYPE_YM3812, OPL_INTERNAL_FREQ, 44100);
|
|
|
|
if(!virtualOpl)
|
|
return 0; */
|
|
|
|
for(i=0;i<11;i++)
|
|
{
|
|
channelTable2[i].var4 |= 0x20;
|
|
channelTable2[i].var2->var4 |= 0x20;
|
|
|
|
createDefaultChannel(i);
|
|
}
|
|
|
|
musicStart(NULL);
|
|
|
|
OPLinitialized = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int getSignature(void* dummy)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
void commandNop(channelTable2Element* entry, int param,u8* ptr)
|
|
{
|
|
}
|
|
|
|
void command0(channelTable2Element* entry, int param,u8* ptr)
|
|
{
|
|
entry->var4 |= 2;
|
|
|
|
if(entry->var4 & 0x20)
|
|
{
|
|
return;
|
|
}
|
|
|
|
entry->var4 |= 0x40;
|
|
|
|
if(!(entry->var4 & 0x8000))
|
|
{
|
|
return;
|
|
}
|
|
|
|
entry->var2->var4 &= 0xFFFB;
|
|
}
|
|
|
|
void command1(channelTable2Element* entry, int param,u8* ptr)
|
|
{
|
|
u16 ax;
|
|
|
|
ax = READ_LE_U16(ptr-1);
|
|
|
|
entry->var10 = entry->varE = ax+entry->var13;
|
|
|
|
entry->commandPtr ++;
|
|
}
|
|
|
|
void command2(channelTable2Element* entry, int param,u8* ptr)
|
|
{
|
|
entry->var18++;
|
|
entry->var15 = param;
|
|
}
|
|
|
|
void command3(channelTable2Element* entry, int param,u8* ptr)
|
|
{
|
|
entry->var12 = param;
|
|
}
|
|
|
|
void command4(channelTable2Element* entry, int param,u8* ptr)
|
|
{
|
|
entry->var1E = param;
|
|
}
|
|
|
|
void command5(channelTable2Element* entry, int param,u8* ptr)
|
|
{
|
|
entry->var17 = param;
|
|
}
|
|
|
|
void command6(channelTable2Element* entry, int param,u8* ptr)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
musicCommandType musicCommandTable[10] =
|
|
{
|
|
command0,
|
|
command1,
|
|
command2,
|
|
command3,
|
|
command4,
|
|
command5,
|
|
command6,
|
|
commandNop,
|
|
commandNop,
|
|
commandNop,
|
|
};
|
|
|
|
void executeMusicCommand(channelTable2Element* entry)
|
|
{
|
|
u16 opcode;
|
|
|
|
if(entry->var4&0x40)
|
|
return;
|
|
|
|
if(entry->var4&0x02) // start channel
|
|
{
|
|
entry->commandPtr = entry->dataPtr;
|
|
entry->var4 &= 0xFFFD;
|
|
entry->var18 = 0;
|
|
}
|
|
else
|
|
{
|
|
if(entry->var1A != entry->var1D)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
entry->varE--; // voice delay
|
|
|
|
if(entry->varE<=0)
|
|
{
|
|
entry->varE = entry->var10;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
do
|
|
{
|
|
opcode = READ_LE_U16(entry->commandPtr);
|
|
entry->commandPtr+=2;
|
|
|
|
ASSERT(musicCommandTable[opcode&0x7F]);
|
|
ASSERT((opcode&0x7F)<=10);
|
|
|
|
musicCommandTable[opcode&0x7F](entry,opcode>>8,entry->commandPtr);
|
|
}while(!(opcode&0x80));
|
|
}
|
|
|
|
u8 smallTable[] = { 0x10, 8, 4, 2, 1 };
|
|
|
|
void applyDirectFrequency(int index, int param1, int param2, int param3)
|
|
{
|
|
if(musicParam1)
|
|
{
|
|
setupChannelFrequency(index,param1,param2,param3);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
int ah;
|
|
|
|
if(index<6)
|
|
{
|
|
setupChannelFrequency(index,param1,param2,param3);
|
|
return;
|
|
}
|
|
|
|
if(index==6)
|
|
{
|
|
setupChannelFrequency(index,param1,0x40,param3);
|
|
}
|
|
else
|
|
if(index==8 && !(param1&0x80))
|
|
{
|
|
int indexBackup = index;
|
|
int param1Backup = param1;
|
|
|
|
setupChannelFrequency(8,param1,0x40,param3);
|
|
{
|
|
int al = param1&0x70;
|
|
|
|
index = 7;
|
|
|
|
param1 &= 0xF;
|
|
param1+=7;
|
|
|
|
if(param1 >= 0xC)
|
|
{
|
|
param1 -= 0xC;
|
|
|
|
if(al != 0x70)
|
|
al += 0x10;
|
|
}
|
|
|
|
setupChannelFrequency( index, param1, 0x40,param3);
|
|
|
|
}
|
|
|
|
param1 = param1Backup;
|
|
index = indexBackup;
|
|
}
|
|
|
|
ah = (~(smallTable[index-6])) & regBDConf;
|
|
|
|
sendAdlib(0xBD,ah);
|
|
|
|
if(!(param2 & 0x40) && !(param1 & 0x80))
|
|
{
|
|
ah |= smallTable[index-6];
|
|
|
|
sendAdlib(0xBD,ah);
|
|
}
|
|
|
|
regBDConf = ah;
|
|
}
|
|
}
|
|
|
|
unsigned char smallData2[] =
|
|
{
|
|
0,
|
|
1,
|
|
2,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
3 ,
|
|
4 ,
|
|
5 ,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
6 ,
|
|
7 ,
|
|
8 ,
|
|
0xFF,
|
|
0xFF,
|
|
0xFF,
|
|
};
|
|
|
|
|
|
void configChannel(u8 value, u8* data)
|
|
{
|
|
if(smallData2[value] != 0xFF)
|
|
{
|
|
sendAdlib(0xC0 + smallData2[value], data[2]);
|
|
}
|
|
|
|
sendAdlib(0x60 + value, data[4]); // Attack Rate Decay Rate
|
|
sendAdlib(0x80 + value, data[5]); // Sustain Level Release Rate
|
|
sendAdlib(0x20 + value, data[1]); // Tremolo Vibrato Sustain KSR Frequency Multiplication Factor
|
|
sendAdlib(0xE0 + value, data[3]); // Waveform Select
|
|
}
|
|
|
|
void changeOuputLevel(u8 value, u8* data,int bp)
|
|
{
|
|
int keyScaleLevel;
|
|
int outputLevel;
|
|
|
|
if(value == 0xFF)
|
|
return;
|
|
|
|
data++;
|
|
|
|
outputLevel = (*data)&0x3F;
|
|
|
|
outputLevel = 0x3F - ((((outputLevel*bp)*2) + 0x7F)/0xFE);
|
|
|
|
ASSERT((outputLevel & 0x3F) == outputLevel);
|
|
|
|
keyScaleLevel = data[0]&0xC0;
|
|
|
|
sendAdlib(0x40+value,(data[0]&0xC0) | (outputLevel&0x3F));
|
|
}
|
|
|
|
void applyMusicCommandToOPL(channelTable2Element* element2, channelTableElement* element)
|
|
{
|
|
char al;
|
|
u16 dx;
|
|
u16 bp;
|
|
|
|
u8 operator1;
|
|
u8 operator2;
|
|
|
|
if((element2->var4 & 0x40) != element->var2)
|
|
{
|
|
element->var2 = element2->var4 & 0x40;
|
|
|
|
if(element2->var4 & 0x40)
|
|
{
|
|
applyDirectFrequency(element2->index,element2->var15 | 0x80, 0x40, element2->var17);
|
|
createDefaultChannel(element2->index);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(element2->var4 & 0x40)
|
|
return;
|
|
|
|
if((element->var8 & 1) || (element->var8 != (element2->var4&0x8000)))
|
|
{
|
|
element->var8 = element2->var4&0x8000;
|
|
element->var5 = 0xFF;
|
|
element->var4 = 0xFF;
|
|
element->var0 = 0xFFFF;
|
|
element->var7 = 0x9C;
|
|
}
|
|
|
|
operator1 = channelTable[element2->index*2];
|
|
operator2 = channelTable[(element2->index*2)+1];
|
|
|
|
if(operator1 == 0xFF && operator2 == 0xFF) // do we have an operator ?
|
|
return;
|
|
|
|
if(element2->var12 != element->var4) // change channel main config
|
|
{
|
|
element->var4 = element2->var12;
|
|
|
|
configChannel(operator1,(currentMusicPtr2+0xD*element2->var12)+1);
|
|
|
|
if(operator2 != 0xFF)
|
|
{
|
|
configChannel(operator2,(currentMusicPtr2+0xD*element2->var12)+7);
|
|
}
|
|
|
|
element->var5 = 0xFF;
|
|
}
|
|
|
|
// Ouput level handling
|
|
|
|
al = element2->var1D - element2->var1E;
|
|
|
|
if(al < 0)
|
|
al = 0;
|
|
|
|
if(element->var5 != al)
|
|
{
|
|
int dx;
|
|
|
|
element->var5 = al;
|
|
|
|
dx = element2->var1D;
|
|
|
|
if(operator2==0xFF)
|
|
{
|
|
dx = element->var5;
|
|
}
|
|
|
|
changeOuputLevel(operator1,currentMusicPtr2+0xD*element2->var12,dx);
|
|
|
|
if(operator2 != 0xFF)
|
|
{
|
|
changeOuputLevel(operator2,(currentMusicPtr2+0xD*element2->var12)+6,element->var5);
|
|
}
|
|
}
|
|
|
|
////
|
|
|
|
bp = dx = element2->var17;
|
|
|
|
if(element2->var17 != element->var7)
|
|
{
|
|
element->var7 = element2->var17;
|
|
|
|
if(element2->var15 == element->var0)
|
|
{
|
|
bp |= 0x8000;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(element2->var15 == element->var0)
|
|
return;
|
|
}
|
|
|
|
element->var0 = element2->var15 = element2->var15 | 0x8000;
|
|
|
|
applyDirectFrequency(element2->index,element->var0&0xFF,element2->var4,bp);
|
|
}
|
|
|
|
int update(void* dummy)
|
|
{
|
|
int i;
|
|
|
|
channelTable2Element* si;
|
|
|
|
if(generalVolume & 0xFF)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
for(i=0;i<11;i++)
|
|
{
|
|
currentMusicPtr2 = currentMusicPtr;
|
|
|
|
executeMusicCommand(&channelTable2[i]);
|
|
|
|
si = &channelTable2[i];
|
|
|
|
if(channelTable2[i].var4 & 4)
|
|
{
|
|
currentMusicPtr2 = currentMusicPtr3;
|
|
|
|
si = channelTable2[i].var2;
|
|
executeMusicCommand(channelTable2[i].var2);
|
|
}
|
|
|
|
applyMusicCommandToOPL(si,&channelDataTable[i]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int musicFade(void * param)
|
|
{
|
|
int i;
|
|
int cx;
|
|
int si;
|
|
int dx;
|
|
int bp;
|
|
|
|
cx = ((int*)param)[0];
|
|
si = ((int*)param)[1];
|
|
dx = ((int*)param)[2];
|
|
|
|
bp = si;
|
|
|
|
si = -1;
|
|
|
|
if(!bp)
|
|
bp = 0x7FF;
|
|
|
|
for(i=0;i<11;i++)
|
|
{
|
|
// if((bp&i))
|
|
{
|
|
if(channelTable2[i].dataPtr)
|
|
{
|
|
if(dx & 0x100)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
if(dx & 0x40)
|
|
{
|
|
if(!(channelTable2[i].var4&0x40))
|
|
channelTable2[i].var4|=0x40;
|
|
}
|
|
|
|
if(dx & 0x80) // start all
|
|
{
|
|
channelTable2[i].var4 = 0x40;
|
|
cx &= 0x7F;
|
|
|
|
channelTable2[i].var1D = cx;
|
|
channelTable2[i].var1A = cx;
|
|
|
|
channelTable2[i].var1E = 0;
|
|
|
|
createDefaultChannel(channelTable2[i].index);
|
|
|
|
channelTable2[i].var4 = 2;
|
|
}
|
|
|
|
if(dx & 0x20)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
if(dx & 0x2000)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
if(dx & 0x8000)
|
|
{
|
|
channelTable2[i].var1A = cx;
|
|
}
|
|
|
|
if(dx & 0x1000)
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
if(dx & 0x10) // still running ?
|
|
{
|
|
if(!(dx & 0x2000))
|
|
{
|
|
if(!(channelTable2[i].var4 & 0x40))
|
|
{
|
|
if(si < channelTable2[i].var18)
|
|
si = channelTable2[i].var18;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(channelTable2[i].var1D != cx)
|
|
{
|
|
si = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return si;
|
|
}
|
|
|
|
musicDrvFunctionType musicDrvFunc[14]=
|
|
{
|
|
update,
|
|
initialialize,
|
|
musicStart,
|
|
musicLoad,
|
|
NULL,
|
|
musicFade,
|
|
NULL,
|
|
NULL,
|
|
getSignature,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
};
|
|
|
|
int callMusicDrv(int commandArg,void* ptr)
|
|
{
|
|
if(!musicDrvFunc[commandArg])
|
|
{
|
|
assert(0);
|
|
}
|
|
|
|
return musicDrvFunc[commandArg](ptr);
|
|
}
|
|
|
|
int initMusicDriver(void)
|
|
{
|
|
callMusicDrv(1,NULL);
|
|
|
|
return callMusicDrv(8,NULL);
|
|
}
|
|
|
|
void loadMusic(int param, char* musicPtr)
|
|
{
|
|
callMusicDrv(3,musicPtr);
|
|
callMusicDrv(2,NULL);
|
|
}
|
|
|
|
int fadeParam[3];
|
|
|
|
int fadeMusic(int param1, int param2, int param3)
|
|
{
|
|
fadeParam[0] = param1;
|
|
fadeParam[1] = param2;
|
|
fadeParam[2] = param3;
|
|
|
|
return callMusicDrv(5,&fadeParam);
|
|
}
|
|
|
|
void playMusic(int musicNumber)
|
|
{
|
|
if(currentMusic == musicNumber)
|
|
return;
|
|
|
|
currentMusic = musicNumber;
|
|
|
|
int trackNumber = musicNumber;
|
|
|
|
if(g_gameId == AITD2)
|
|
{
|
|
trackNumber = AITD2MusicToTrackMapping[musicNumber];
|
|
}
|
|
|
|
if(osystem_playTrack(trackNumber))
|
|
return;
|
|
|
|
// if(musicEnabled)
|
|
{
|
|
//if(currentMusic != musicNumber)
|
|
{
|
|
char* musicPtr;
|
|
|
|
currentMusic = musicNumber;
|
|
|
|
if(musicNumber>=0)
|
|
{
|
|
fadeMusic(0,0,0x40);
|
|
|
|
musicPtr = HQR_Get(listMus,musicNumber);
|
|
|
|
if(musicPtr)
|
|
{
|
|
loadMusic(0,musicPtr);
|
|
|
|
fadeMusic(musicVolume,0,0x80);
|
|
#ifndef TARGET_OS_IPHONE
|
|
osystem_playAdlib();
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int updateLoop = 0;
|
|
|
|
int oldTimer = 0;
|
|
|
|
void callMusicUpdate(void)
|
|
{
|
|
if(OPLinitialized)
|
|
{
|
|
callMusicDrv(0,NULL);
|
|
}
|
|
}
|
|
|
|
void destroyMusicDriver(void)
|
|
{
|
|
YM3812Shutdown();
|
|
}
|