Hi,
Woo-hoo! The list appears to be working again! :-)
I don't have the slightest clue as to when it ceased to function, though;
please re-submit any mail that may have been lost before I found out that
things were broken once again.
SFAI.
---------- Forwarded message ----------
Date: Sun, 15 Oct 2000 23:12:21 +0200 (MET DST)
From: Christoph Reichenbach <[EMAIL PROTECTED]>
To: [EMAIL PROTECTED]
Subject: Repost: OPL/2 patches and software sequencer [was: FreeSCI Sound
System (fwd)]
Hi,
(Now that's a subject line...)
I sent this earlier today, but it appears to have been lost. I changed
some settings in the mailing list's config file, so, maybe it'll work
now.
SFAI.
---------- Forwarded message ----------
Date: Sun, 15 Oct 2000 10:08:30 +0200 (MET DST)
From: Christoph Reichenbach <[EMAIL PROTECTED]>
To: [EMAIL PROTECTED]
Subject: OPL/2 patches and software sequencer [was: FreeSCI Sound System (fwd)]
Hi,
Philip Hassey recently contacted me, offering some code to read out the
OPL/2 patch resource (resource.003), and pointing out that MAME
(http://www.mame.net) comes with a software OPL/2 emulator (fm.h,
fmopl.[hc]). This should make it possible to add an Emulator for
Adlib-style music eventually.
Here's his code:
[snip]
//Here's code to load the instruments:
int load_sierra_ins(midPlayer *p)
{
long i,j,k,l;
int tins=0;
FILE *stream;
unsigned char ins[28];
char pfilename[256];
sprintf(pfilename,p->fname);
j=0;
for (i=strlen(pfilename)-1; i>=0; i--)
if (pfilename[i]=='/' ||
pfilename[i]=='\\') {j=i+1; i=-1;}
sprintf(pfilename+j+3,"patch.003");
stream=fopen(pfilename,"rb");
fgetc(stream);
fgetc(stream);
for (i=0; i<2; i++)
{
for (k=0; k<48; k++)
{
l=i*48+k;
for (j=0; j<28; j++)
ins[j]=fgetc(stream);
p->myinsbank[l][0]=
(ins[9]*0x80) + (ins[10]*0x40) +
(ins[5]*0x20) + (ins[11]*0x10) +
ins[1]; //1=ins5
p->myinsbank[l][1]=
(ins[22]*0x80) + (ins[23]*0x40) +
(ins[18]*0x20) + (ins[24]*0x10) +
ins[14]; //1=ins18
p->myinsbank[l][2]=(ins[0]<<6)+ins[8];
p->myinsbank[l][3]=(ins[13]<<6)+ins[21];
p->myinsbank[l][4]=(ins[3]<<4)+ins[6];
p->myinsbank[l][5]=(ins[16]<<4)+ins[19];
p->myinsbank[l][6]=(ins[4]<<4)+ins[7];
p->myinsbank[l][7]=(ins[17]<<4)+ins[20];
p->myinsbank[l][8]=ins[26];
p->myinsbank[l][9]=ins[27];
p->myinsbank[l][10]=((ins[2]<<1))+(1-(ins[12]&1));
tins++;
}
fgetc(stream);fgetc(stream);
}
fclose(stream);
return(tins);
}
//If anything is unclear as to what is going on up there, just ask.
//
//Here's some basic AdLib code:
//You'll note that SIERRA_STYLE changes a few things about how
// the adlib is used. So you can change the code so it always
// assumes SIERRA STYLE to be true for your purposes.
static void midi_write_adlib(unsigned int r, unsigned char v, midPlayer *p)
{
adlibwrite(p->OPL,r,v);
p->adlib_data[r]=v;
}
unsigned char adlib_opadd[] = {
0x00 ,0x01 ,0x02 ,0x08 ,0x09 ,0x0A ,0x10 ,0x11 ,0x12 };
int ops[] = {
0x20,0x20,0x40,0x40,0x60,0x60,0x80,0x80,0xe0,0xe0,0xc0 };
static void midi_fm_instrument(int voice, unsigned char *inst, midPlayer *p)
{
if ((p->adlib_style&SIERRA_STYLE)!=0)
midi_write_adlib(0xbd,0,p); //just gotta make sure this happens..
//'cause who knows when it'll be
//reset otherwise.
midi_write_adlib(0x20+adlib_opadd[voice],inst[0],p);
midi_write_adlib(0x23+adlib_opadd[voice],inst[1],p);
if ((p->adlib_style&LUCAS_STYLE)!=0)
{
midi_write_adlib(0x43+adlib_opadd[voice],0x3f,p);
if ((inst[10] & 1)==0)
midi_write_adlib(0x40+adlib_opadd[voice],inst[2],p);
else
midi_write_adlib(0x40+adlib_opadd[voice],0x3f,p);
}
else
{
if ((p->adlib_style&SIERRA_STYLE)!=0)
{
midi_write_adlib(0x40+adlib_opadd[voice],inst[2],p);
midi_write_adlib(0x43+adlib_opadd[voice],inst[3],p);
}
else
{
midi_write_adlib(0x40+adlib_opadd[voice],inst[2],p);
if ((inst[10] & 1)==0)
midi_write_adlib(0x43+adlib_opadd[voice],inst[3],p);
else
midi_write_adlib(0x43+adlib_opadd[voice],0,p);
}
}
midi_write_adlib(0x60+adlib_opadd[voice],inst[4],p);
midi_write_adlib(0x63+adlib_opadd[voice],inst[5],p);
midi_write_adlib(0x80+adlib_opadd[voice],inst[6],p);
midi_write_adlib(0x83+adlib_opadd[voice],inst[7],p);
midi_write_adlib(0xe0+adlib_opadd[voice],inst[8],p);
midi_write_adlib(0xe3+adlib_opadd[voice],inst[9],p);
midi_write_adlib(0xc0+voice,inst[10],p);
}
static void midi_fm_volume(int voice, int volume, midPlayer *p)
{
int vol;
if ((p->adlib_style&SIERRA_STYLE)==0) //sierra likes it loud!
{
vol=volume>>2;
if ((p->adlib_style&LUCAS_STYLE)!=0)
{
if ((p->adlib_data[0xc0+voice]&1)==1)
midi_write_adlib(0x40+adlib_opadd[voice], (unsigned
char)((63-vol) |
(p->adlib_data[0x40+adlib_opadd[voice]]&0xc0)),p);
midi_write_adlib(0x43+adlib_opadd[voice], (unsigned char)((63-vol) |
(p->adlib_data[0x43+adlib_opadd[voice]]&0xc0)),p);
}
else
{
if ((p->adlib_data[0xc0+voice]&1)==1)
midi_write_adlib(0x40+adlib_opadd[voice], (unsigned
char)((63-vol) |
(p->adlib_data[0x40+adlib_opadd[voice]]&0xc0)),p);
midi_write_adlib(0x43+adlib_opadd[voice], (unsigned char)((63-vol) |
(p->adlib_data[0x43+adlib_opadd[voice]]&0xc0)),p);
}
}
}
int fnums[] = {
0x16b,0x181,0x198,0x1b0,0x1ca,0x1e5,0x202,0x220,0x241,0x263,0x287,0x2ae
};
int sierra_fnums[] = {
0xB6,0xC1,0xCD,0xD9,0xE6,0xF3,0x102,0x111,0x122,0x133,0x145,0x158
};
static void midi_fm_playnote(int voice, int note, int volume, midPlayer *p)
{
int freq=fnums[note%12];
int oct=note/12;
int c;
if ((p->adlib_style&SIERRA_STYLE)!=0)
{
oct++;
freq=sierra_fnums[note%12];
}
midi_fm_volume(voice,volume,p);
midi_write_adlib(0xa0+voice,(unsigned char)(freq&0xff),p);
c=((freq&0x300) >> 8)+(oct<<2) + (1<<5);
midi_write_adlib(0xb0+voice,(unsigned char)c,p);
}
static void midi_fm_endnote(int voice, midPlayer *p)
{
//midi_fm_volume(voice,0);
//midi_write_adlib(0xb0+voice,0);
midi_write_adlib(0xb0+voice,(unsigned
char)(p->adlib_data[0xb0+voice]&(255-32)),p);
}
static void midi_fm_reset(midPlayer *p)
{
int i;
for (i=0; i<256; i++)
midi_write_adlib(i,0,p);
midi_write_adlib(0x01, 0x20,p);
midi_write_adlib(0xBD,0xc0,p);
}
[snip]
I haven't looked at it very thoroughly yet, but it appears to contain
sufficient information to get this to work. (Note that, if we want to use
the code, the LUCAS_STYLE stuff would have to be removed, findResource()
would have to be used instead of the various file operations, and comments
would have to be changed from // to /* */ to support older compilers.
There may be less obvious stuff that needs changing, though.)
llap,
Christoph