- Added the Java OPL3 emulator to the menu.

- Added full panning support to the Java OPL3 emulator.

SVN r3969 (trunk)
This commit is contained in:
Randy Heit 2012-11-17 05:26:03 +00:00
parent 93bd380fee
commit 5627a7ebd7
5 changed files with 67 additions and 45 deletions

View file

@ -53,7 +53,7 @@
static FRandom pr_opl3;
#define VOLUME_MUL 0.25
#define VOLUME_MUL 0.3333
class Operator;
@ -88,7 +88,7 @@ public:
double leftPan, rightPan;
Channel (int baseAddress);
Channel (int baseAddress, double startvol);
void update_2_KON1_BLOCK3_FNUMH2(class OPL3 *OPL3);
void update_FNUML8(class OPL3 *OPL3);
void update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(class OPL3 *OPL3);
@ -107,7 +107,7 @@ class Channel2op : public Channel
public:
Operator *op1, *op2;
Channel2op (int baseAddress, Operator *o1, Operator *o2);
Channel2op (int baseAddress, double startvol, Operator *o1, Operator *o2);
double getChannelOutput(class OPL3 *OPL3);
void keyOn();
@ -121,7 +121,7 @@ class Channel4op : public Channel
public:
Operator *op1, *op2, *op3, *op4;
Channel4op (int baseAddress, Operator *o1, Operator *o2, Operator *o3, Operator *o4);
Channel4op (int baseAddress, double startvol, Operator *o1, Operator *o2, Operator *o3, Operator *o4);
double getChannelOutput(class OPL3 *OPL3);
void keyOn();
@ -133,7 +133,7 @@ public:
class DisabledChannel : public Channel
{
public:
DisabledChannel() : Channel(0) { }
DisabledChannel() : Channel(0, 0) { }
double getChannelOutput(class OPL3 *OPL3) { return 0; }
void keyOn() { }
void keyOff() { }
@ -244,8 +244,8 @@ protected:
class RhythmChannel : public Channel2op
{
public:
RhythmChannel(int baseAddress, Operator *o1, Operator *o2)
: Channel2op(baseAddress, o1, o2)
RhythmChannel(int baseAddress, double startvol, Operator *o1, Operator *o2)
: Channel2op(baseAddress, startvol, o1, o2)
{ }
double getChannelOutput(class OPL3 *OPL3);
@ -258,16 +258,16 @@ public:
class HighHatSnareDrumChannel : public RhythmChannel {
static const int highHatSnareDrumChannelBaseAddress = 7;
public:
HighHatSnareDrumChannel(Operator *o1, Operator *o2)
: RhythmChannel(highHatSnareDrumChannelBaseAddress, o1, o2)
HighHatSnareDrumChannel(double startvol, Operator *o1, Operator *o2)
: RhythmChannel(highHatSnareDrumChannelBaseAddress, startvol, o1, o2)
{ }
};
class TomTomTopCymbalChannel : public RhythmChannel {
static const int tomTomTopCymbalChannelBaseAddress = 8;
public:
TomTomTopCymbalChannel(Operator *o1, Operator *o2)
: RhythmChannel(tomTomTopCymbalChannelBaseAddress, o1, o2)
TomTomTopCymbalChannel(double startvol, Operator *o1, Operator *o2)
: RhythmChannel(tomTomTopCymbalChannelBaseAddress, startvol, o1, o2)
{ }
};
@ -308,7 +308,7 @@ class BassDrumChannel : public Channel2op {
Operator my_op1, my_op2;
public:
BassDrumChannel();
BassDrumChannel(double startvol);
double getChannelOutput(class OPL3 *OPL3);
// Key ON and OFF are unused in rhythm channels.
@ -552,6 +552,8 @@ public:
int nts, dam, dvb, ryt, bd, sd, tom, tc, hh, _new, connectionsel;
int vibratoIndex, tremoloIndex;
bool FullPan;
static OperatorData *OperatorData;
static OPL3Data *OPL3Data;
@ -565,7 +567,7 @@ public:
//void read(float output[2]);
void write(int array, int address, int data);
OPL3();
OPL3(bool fullpan);
~OPL3();
private:
@ -708,10 +710,12 @@ void OPL3::write(int array, int address, int data) {
}
}
OPL3::OPL3()
: highHatSnareDrumChannel(&highHatOperator, &snareDrumOperator),
tomTomTopCymbalChannel(&tomTomOperator, &topCymbalOperator)
OPL3::OPL3(bool fullpan)
: bassDrumChannel(fullpan ? CENTER_PANNING_POWER : 1),
highHatSnareDrumChannel(fullpan ? CENTER_PANNING_POWER : 1, &highHatOperator, &snareDrumOperator),
tomTomTopCymbalChannel(fullpan ? CENTER_PANNING_POWER : 1, &tomTomOperator, &topCymbalOperator)
{
FullPan = fullpan;
nts = dam = dvb = ryt = bd = sd = tom = tc = hh = _new = connectionsel = 0;
vibratoIndex = tremoloIndex = 0;
@ -784,27 +788,28 @@ void OPL3::initChannels2op() {
// The YMF262 has 18 2-op channels.
// Each 2-op channel can be at a serial or parallel operator configuration:
memset(channels2op, 0, sizeof(channels2op));
double startvol = FullPan ? CENTER_PANNING_POWER : 1;
for(int array=0; array<2; array++)
for(int channelNumber=0; channelNumber<3; channelNumber++) {
int baseAddress = (array<<8) | channelNumber;
// Channels 1, 2, 3 -> Operator offsets 0x0,0x3; 0x1,0x4; 0x2,0x5
channels2op[array][channelNumber] = new Channel2op(baseAddress, operators[array][channelNumber], operators[array][channelNumber+0x3]);
channels2op[array][channelNumber] = new Channel2op(baseAddress, startvol, operators[array][channelNumber], operators[array][channelNumber+0x3]);
// Channels 4, 5, 6 -> Operator offsets 0x8,0xB; 0x9,0xC; 0xA,0xD
channels2op[array][channelNumber+3] = new Channel2op(baseAddress+3, operators[array][channelNumber+0x8], operators[array][channelNumber+0xB]);
channels2op[array][channelNumber+3] = new Channel2op(baseAddress+3, startvol, operators[array][channelNumber+0x8], operators[array][channelNumber+0xB]);
// Channels 7, 8, 9 -> Operators 0x10,0x13; 0x11,0x14; 0x12,0x15
channels2op[array][channelNumber+6] = new Channel2op(baseAddress+6, operators[array][channelNumber+0x10], operators[array][channelNumber+0x13]);
channels2op[array][channelNumber+6] = new Channel2op(baseAddress+6, startvol, operators[array][channelNumber+0x10], operators[array][channelNumber+0x13]);
}
}
void OPL3::initChannels4op() {
// The YMF262 has 3 4-op channels in each array:
memset(channels4op, 0, sizeof(channels4op));
double startvol = FullPan ? CENTER_PANNING_POWER : 1;
for(int array=0; array<2; array++)
for(int channelNumber=0; channelNumber<3; channelNumber++) {
int baseAddress = (array<<8) | channelNumber;
// Channels 1, 2, 3 -> Operators 0x0,0x3,0x8,0xB; 0x1,0x4,0x9,0xC; 0x2,0x5,0xA,0xD;
channels4op[array][channelNumber] = new Channel4op(baseAddress, operators[array][channelNumber], operators[array][channelNumber+0x3], operators[array][channelNumber+0x8], operators[array][channelNumber+0xB]);
channels4op[array][channelNumber] = new Channel4op(baseAddress, startvol, operators[array][channelNumber], operators[array][channelNumber+0x3], operators[array][channelNumber+0x8], operators[array][channelNumber+0xB]);
}
}
@ -967,11 +972,11 @@ static double EnvelopeFromDB(double db)
#endif
}
Channel::Channel (int baseAddress) {
Channel::Channel (int baseAddress, double startvol) {
channelBaseAddress = baseAddress;
fnuml = fnumh = kon = block = fb = cnt = 0;
feedback[0] = feedback[1] = 0;
leftPan = rightPan = 1;
leftPan = rightPan = startvol;
}
void Channel::update_2_KON1_BLOCK3_FNUMH2(OPL3 *OPL3) {
@ -1013,15 +1018,18 @@ void Channel::update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(OPL3 *OPL3) {
}
void Channel::updatePan(OPL3 *OPL3) {
if (OPL3->_new == 0)
if (!OPL3->FullPan)
{
leftPan = VOLUME_MUL;
rightPan = VOLUME_MUL;
}
else
{
leftPan = cha * VOLUME_MUL;
rightPan = chb * VOLUME_MUL;
if (OPL3->_new == 0)
{
leftPan = VOLUME_MUL;
rightPan = VOLUME_MUL;
}
else
{
leftPan = cha * VOLUME_MUL;
rightPan = chb * VOLUME_MUL;
}
}
}
@ -1031,8 +1039,8 @@ void Channel::updateChannel(OPL3 *OPL3) {
update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(OPL3);
}
Channel2op::Channel2op (int baseAddress, Operator *o1, Operator *o2)
: Channel(baseAddress)
Channel2op::Channel2op (int baseAddress, double startvol, Operator *o1, Operator *o2)
: Channel(baseAddress, startvol)
{
op1 = o1;
op2 = o2;
@ -1086,8 +1094,8 @@ void Channel2op::updateOperators(OPL3 *OPL3) {
op2->updateOperator(OPL3, keyScaleNumber, f_number, block);
}
Channel4op::Channel4op (int baseAddress, Operator *o1, Operator *o2, Operator *o3, Operator *o4)
: Channel(baseAddress)
Channel4op::Channel4op (int baseAddress, double startvol, Operator *o1, Operator *o2, Operator *o3, Operator *o4)
: Channel(baseAddress, startvol)
{
op1 = o1;
op2 = o2;
@ -1665,8 +1673,8 @@ double SnareDrumOperator::getOperatorOutput(OPL3 *OPL3, double modulator) {
return operatorOutput*2;
}
BassDrumChannel::BassDrumChannel()
: Channel2op(bassDrumChannelBaseAddress, &my_op1, &my_op2),
BassDrumChannel::BassDrumChannel(double startvol)
: Channel2op(bassDrumChannelBaseAddress, startvol, &my_op1, &my_op2),
my_op1(op1BaseAddress), my_op2(op2BaseAddress)
{ }
@ -1834,9 +1842,24 @@ void OPL3::WriteReg(int reg, int v)
void OPL3::SetPanning(int c, float left, float right)
{
if (FullPan)
{
Channel *channel;
if (c < 9)
{
channel = channels[0][c];
}
else
{
channel = channels[1][c - 9];
}
channel->leftPan = left;
channel->rightPan = right;
}
}
OPLEmul *JavaOPLCreate(bool stereo)
{
return new OPL3;
return new OPL3(stereo);
}

View file

@ -46,8 +46,6 @@ typedef SBYTE Bit8s;
#include "opl.h"
#define CENTER_PANNING_POWER 0.70710678118f
static Bit16s wavtable[WAVEPREC*3]; // wave form table
// key scale levels
@ -506,7 +504,7 @@ void DBOPL::Reset() {
#if defined(OPLTYPE_IS_OPL3)
op[i].is_4op = false;
op[i].is_4op_attached = false;
op[i].right_pan = op[i].left_pan = FullPan ? CENTER_PANNING_POWER : 1;
op[i].right_pan = op[i].left_pan = FullPan ? (float)CENTER_PANNING_POWER : 1;
#endif
}

View file

@ -126,8 +126,6 @@ typedef signed int INT32; /* signed 32bit */
#define INLINE __inline
#endif
#define CENTER_PANNING_POWER 0.70710678118 /* [RH] volume at center for EQP */
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
#define EG_SH 16 /* 16.16 fixed point (EG timing) */
#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */

View file

@ -23,5 +23,7 @@ OPLEmul *DBOPLCreate(bool stereo);
OPLEmul *JavaOPLCreate(bool stereo);
#define OPL_SAMPLE_RATE 49716.0
#define CENTER_PANNING_POWER 0.70710678118 /* [RH] volume at center for EQP */
#endif

View file

@ -1402,8 +1402,9 @@ OptionValue GusMemory
OptionValue OplCores
{
0, "MAME"
1, "DOSBox"
0, "MAME OPL2"
1, "DOSBox OPL3"
2, "Java OPL3"
}
OptionMenu AdvSoundOptions