kopia lustrzana https://github.com/Jean-MarcHarvengt/MCUME
290 wiersze
9.6 KiB
C
290 wiersze
9.6 KiB
C
/** EMULib Emulation Library *********************************/
|
|
/** **/
|
|
/** YM2413.c **/
|
|
/** **/
|
|
/** This file contains emulation for the OPLL sound chip **/
|
|
/** produced by Yamaha (also see OPL2, OPL3, OPL4 chips). **/
|
|
/** See YM2413.h for declarations. **/
|
|
/** **/
|
|
/** Copyright (C) Marat Fayzullin 1996-2005 **/
|
|
/** You are not allowed to distribute this software **/
|
|
/** commercially. Please, notify me, if you make any **/
|
|
/** changes to this file. **/
|
|
/*************************************************************/
|
|
|
|
#include "YM2413.h"
|
|
#include "Sound.h"
|
|
#include <string.h>
|
|
#include "arduinoproto.h"
|
|
|
|
/** Patches2413() ********************************************/
|
|
/** MIDI instruments corresponding to the OPLL patches. **/
|
|
/*************************************************************/
|
|
PROGMEM static const byte Patches2413[16] =
|
|
{
|
|
/*** OPLL ***/ /*** MIDI ***/
|
|
90, /* Original */ /* User (Polysynth) */
|
|
40, /* Violin */ /* Violin */
|
|
27, /* Guitar */ /* Electric Guitar (clean) */
|
|
1, /* Piano */ /* Bright Acoustic Piano */
|
|
73, /* Flute */ /* Flute */
|
|
71, /* Clarinet */ /* Clarinet */
|
|
68, /* Oboe */ /* Oboe */
|
|
56, /* Trumpet */ /* Trumpet */
|
|
20, /* Organ */ /* Reed Organ */
|
|
58, /* Horn */ /* Tuba */
|
|
50, /* Synthesizer */ /* Synth Strings 1 */
|
|
6, /* Harpsichord */ /* Harpsichord */
|
|
11, /* Vibraphone */ /* Vibraphone */
|
|
38, /* Synth Bass */ /* Synth Bass 1 */
|
|
34, /* Wood Bass */ /* Electric Bass (pick) */
|
|
33 /* Elec Guitar */ /* Electric Bass (finger) */
|
|
};
|
|
|
|
/** Drums2413() **********************************************/
|
|
/** MIDI instruments corresponding to the OPLL drums. **/
|
|
/*************************************************************/
|
|
PROGMEM static const byte Drums2413[5] =
|
|
{
|
|
/*** OPLL ***/ /*** MIDI ***/
|
|
42, /* High Hat */ /* Closed Hi Hat */
|
|
49, /* Top Cymbal */ /* Crash Cymbal 1 */
|
|
47, /* Tom-Tom */ /* Low-Mid Tom */
|
|
40, /* Snare Drum */ /* Electric Snare */
|
|
36 /* Bass Drum */ /* Bass Drum 1 */
|
|
};
|
|
|
|
/** Synth2413() **********************************************/
|
|
/** Synthesizer parameters corresponding to OPLL patches. **/
|
|
/*************************************************************/
|
|
PROGMEM static const byte Synth2413[19*16] =
|
|
{
|
|
0x49,0x4c,0x4c,0x32,0x00,0x00,0x00,0x00,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x61,0x61,0x1e,0x17,0xf0,0x7f,0x00,0x17,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x13,0x41,0x16,0x0e,0xfd,0xf4,0x23,0x23,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x03,0x01,0x9a,0x04,0xf3,0xf3,0x13,0xf3,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x11,0x61,0x0e,0x07,0xfa,0x64,0x70,0x17,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x22,0x21,0x1e,0x06,0xf0,0x76,0x00,0x28,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x21,0x22,0x16,0x05,0xf0,0x71,0x00,0x18,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x21,0x61,0x1d,0x07,0x82,0x80,0x17,0x17,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x23,0x21,0x2d,0x16,0x90,0x90,0x00,0x07,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x21,0x21,0x1b,0x06,0x64,0x65,0x10,0x17,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x21,0x21,0x0b,0x1a,0x85,0xa0,0x70,0x07,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x23,0x01,0x83,0x10,0xff,0xb4,0x10,0xf4,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x97,0xc1,0x20,0x07,0xff,0xf4,0x22,0x22,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x61,0x00,0x0c,0x05,0xc2,0xf6,0x40,0x44,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x01,0x01,0x56,0x03,0x94,0xc2,0x03,0x12,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x21,0x01,0x89,0x03,0xf1,0xe4,0xf0,0x23,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x07,0x21,0x14,0x00,0xee,0xf8,0xff,0xf8,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x01,0x31,0x00,0x00,0xf8,0xf7,0xf8,0xf7,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
|
0x25,0x11,0x00,0x00,0xf8,0xfa,0xf8,0x55,
|
|
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
|
|
};
|
|
|
|
/** Reset2413() **********************************************/
|
|
/** Reset the sound chip and use sound channels from the **/
|
|
/** one given in First. **/
|
|
/*************************************************************/
|
|
void Reset2413(register YM2413 *D,int First)
|
|
{
|
|
int J;
|
|
|
|
/* All registers filled with 0x00 by default */
|
|
memset(D->R,0x00,sizeof(D->R));
|
|
|
|
/* Set initial frequencies, volumes, and instruments */
|
|
for(J=0;J<YM2413_CHANNELS;J++)
|
|
{
|
|
SetSound(J+First,SND_MELODIC);
|
|
D->Freq[J] = 0;
|
|
D->Volume[J] = 0;
|
|
D->R[J+0x30] = 0x0F;
|
|
}
|
|
|
|
D->First = First;
|
|
D->Sync = YM2413_ASYNC;
|
|
D->Changed = 0x000;
|
|
D->PChanged = 0x000;
|
|
D->DChanged = 0x000;
|
|
D->Latch = 0;
|
|
}
|
|
|
|
/** WrCtrl2413() *********************************************/
|
|
/** Write a value V to the OPLL Control Port. **/
|
|
/*************************************************************/
|
|
void WrCtrl2413(register YM2413 *D,register byte V)
|
|
{
|
|
D->Latch=V&0x3F;
|
|
}
|
|
|
|
/** WrData2413() *********************************************/
|
|
/** Write a value V to the OPLL Data Port. **/
|
|
/*************************************************************/
|
|
void WrData2413(register YM2413 *D,register byte V)
|
|
{
|
|
Write2413(D,D->Latch,V);
|
|
}
|
|
|
|
/** Write2413() **********************************************/
|
|
/** Call this function to output a value V into the sound **/
|
|
/** chip. **/
|
|
/*************************************************************/
|
|
void Write2413(register YM2413 *D,register byte R,register byte V)
|
|
{
|
|
register byte C,Oct;
|
|
register int Frq;
|
|
|
|
/* OPLL registers are 0..63 */
|
|
R&=0x3F;
|
|
|
|
/* Lowest 4 bits are channel number */
|
|
C=R&0x0F;
|
|
|
|
switch(R>>4)
|
|
{
|
|
case 0:
|
|
switch(C)
|
|
{
|
|
case 0x0E:
|
|
if(V==D->R[R]) return;
|
|
/* Keep all drums off when drum mode is off */
|
|
if(!(V&0x20)) V&=0xE0;
|
|
/* Mark all activated drums as changed */
|
|
D->DChanged|=(V^D->R[R])&0x1F;
|
|
/* If drum mode was turned on... */
|
|
if((V^D->R[R])&V&0x20)
|
|
{
|
|
/* Turn off melodic channels 6,7,8 */
|
|
D->Freq[6]=D->Freq[7]=D->Freq[8]=0;
|
|
/* Mark channels 6,7,8 as changed */
|
|
D->Changed|=0x1C0;
|
|
}
|
|
/* Done */
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
if((C>8)||(V==D->R[R])) return;
|
|
if(!YM2413_DRUMS(D)||(C<6))
|
|
if(D->R[R+0x10]&0x10)
|
|
{
|
|
/* Set channel frequency */
|
|
Oct=D->R[R+0x10];
|
|
Frq=((int)(Oct&0x01)<<8)+V;
|
|
Oct=(Oct&0x0E)>>1;
|
|
D->Freq[C]=(3125*Frq*(1<<Oct))>>15;
|
|
|
|
/* Mark channel as changed */
|
|
D->Changed|=1<<C;
|
|
}
|
|
/* Done */
|
|
break;
|
|
|
|
case 2:
|
|
if(C>8) return;
|
|
if(!YM2413_DRUMS(D)||(C<6))
|
|
{
|
|
/* Depending on whether channel is on/off... */
|
|
if(!(V&0x10)) D->Freq[C]=0;
|
|
else
|
|
{
|
|
/* Set channel frequency */
|
|
Frq=((int)(V&0x01)<<8)+D->R[R-0x10];
|
|
Oct=(V&0x0E)>>1;
|
|
D->Freq[C]=(3125*Frq*(1<<Oct))>>15;
|
|
}
|
|
|
|
/* Mark channel as changed */
|
|
D->Changed|=1<<C;
|
|
}
|
|
/* Done */
|
|
break;
|
|
|
|
case 3:
|
|
if((C>8)||(V==D->R[R])) return;
|
|
/* Register any patch changes */
|
|
if((V^D->R[R])&0xF0) D->PChanged|=1<<C;
|
|
/* Register any volume changes */
|
|
if((V^D->R[R])&0x0F)
|
|
{
|
|
/* Set channel volume */
|
|
D->Volume[C]=255*(~V&0x0F)/15;
|
|
/* Mark channel as changed */
|
|
D->Changed|=1<<C;
|
|
}
|
|
/* Register drum volume changes */
|
|
if(YM2413_DRUMS(D))
|
|
switch(C)
|
|
{
|
|
case 6: D->DChanged|=0x10&D->R[0x0E];break;
|
|
case 7: D->DChanged|=0x09&D->R[0x0E];break;
|
|
case 8: D->DChanged|=0x06&D->R[0x0E];break;
|
|
}
|
|
/* Done */
|
|
break;
|
|
}
|
|
|
|
/* Write value into the register */
|
|
D->R[R]=V;
|
|
|
|
/* For asynchronous mode, make Sound() calls right away */
|
|
if(!D->Sync&&(D->Changed||D->PChanged||D->DChanged))
|
|
Sync2413(D,YM2413_FLUSH);
|
|
}
|
|
|
|
/** Sync2413() ***********************************************/
|
|
/** Flush all accumulated changes by issuing Sound() calls **/
|
|
/** and set the synchronization on/off. The second argument **/
|
|
/** should be YM2413_SYNC/YM2413_ASYNC to set/reset sync, **/
|
|
/** or YM2413_FLUSH to leave sync mode as it is. **/
|
|
/*************************************************************/
|
|
void Sync2413(register YM2413 *D,register byte Sync)
|
|
{
|
|
register int J,I;
|
|
|
|
/* Change sync mode as requested */
|
|
if(Sync!=YM2413_FLUSH) D->Sync=Sync;
|
|
|
|
/* Convert channel instrument changes into SetSound() calls */
|
|
for(J=0,I=D->PChanged;I&&(J<YM2413_CHANNELS);J++,I>>=1)
|
|
if(I&1) SetSound(J+D->First,SND_MIDI|Patches2413[D->R[J+0x30]>>4]);
|
|
|
|
/* Convert channel freq/volume changes into Sound() calls */
|
|
for(J=0,I=D->Changed;I&&(J<YM2413_CHANNELS);J++,I>>=1)
|
|
if(I&1) Sound(J+D->First,D->Freq[J],D->Volume[J]);
|
|
|
|
/* If there were any changes to the drums... */
|
|
I=D->DChanged;
|
|
J=D->R[0x0E];
|
|
if(I)
|
|
{
|
|
/* Turn drums on/off as requested */
|
|
if(I&0x01) Drum(DRM_MIDI|Drums2413[0],J&0x01? 255*(D->R[0x37]>>4)/15:0);
|
|
if(I&0x02) Drum(DRM_MIDI|Drums2413[1],J&0x02? 255*(D->R[0x38]&0x0F)/15:0);
|
|
if(I&0x04) Drum(DRM_MIDI|Drums2413[2],J&0x04? 255*(D->R[0x38]>>4)/15:0);
|
|
if(I&0x08) Drum(DRM_MIDI|Drums2413[3],J&0x08? 255*(D->R[0x37]&0x0F)/15:0);
|
|
if(I&0x10) Drum(DRM_MIDI|Drums2413[4],J&0x10? 255*(D->R[0x36]&0x0F)/15:0);
|
|
}
|
|
|
|
D->Changed=D->PChanged=D->DChanged=0x000;
|
|
}
|