mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-13 07:57:58 +00:00
- 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:
parent
93bd380fee
commit
5627a7ebd7
5 changed files with 67 additions and 45 deletions
|
@ -53,7 +53,7 @@
|
||||||
|
|
||||||
static FRandom pr_opl3;
|
static FRandom pr_opl3;
|
||||||
|
|
||||||
#define VOLUME_MUL 0.25
|
#define VOLUME_MUL 0.3333
|
||||||
|
|
||||||
class Operator;
|
class Operator;
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ public:
|
||||||
|
|
||||||
double leftPan, rightPan;
|
double leftPan, rightPan;
|
||||||
|
|
||||||
Channel (int baseAddress);
|
Channel (int baseAddress, double startvol);
|
||||||
void update_2_KON1_BLOCK3_FNUMH2(class OPL3 *OPL3);
|
void update_2_KON1_BLOCK3_FNUMH2(class OPL3 *OPL3);
|
||||||
void update_FNUML8(class OPL3 *OPL3);
|
void update_FNUML8(class OPL3 *OPL3);
|
||||||
void update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(class OPL3 *OPL3);
|
void update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(class OPL3 *OPL3);
|
||||||
|
@ -107,7 +107,7 @@ class Channel2op : public Channel
|
||||||
public:
|
public:
|
||||||
Operator *op1, *op2;
|
Operator *op1, *op2;
|
||||||
|
|
||||||
Channel2op (int baseAddress, Operator *o1, Operator *o2);
|
Channel2op (int baseAddress, double startvol, Operator *o1, Operator *o2);
|
||||||
double getChannelOutput(class OPL3 *OPL3);
|
double getChannelOutput(class OPL3 *OPL3);
|
||||||
|
|
||||||
void keyOn();
|
void keyOn();
|
||||||
|
@ -121,7 +121,7 @@ class Channel4op : public Channel
|
||||||
public:
|
public:
|
||||||
Operator *op1, *op2, *op3, *op4;
|
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);
|
double getChannelOutput(class OPL3 *OPL3);
|
||||||
|
|
||||||
void keyOn();
|
void keyOn();
|
||||||
|
@ -133,7 +133,7 @@ public:
|
||||||
class DisabledChannel : public Channel
|
class DisabledChannel : public Channel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DisabledChannel() : Channel(0) { }
|
DisabledChannel() : Channel(0, 0) { }
|
||||||
double getChannelOutput(class OPL3 *OPL3) { return 0; }
|
double getChannelOutput(class OPL3 *OPL3) { return 0; }
|
||||||
void keyOn() { }
|
void keyOn() { }
|
||||||
void keyOff() { }
|
void keyOff() { }
|
||||||
|
@ -244,8 +244,8 @@ protected:
|
||||||
class RhythmChannel : public Channel2op
|
class RhythmChannel : public Channel2op
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RhythmChannel(int baseAddress, Operator *o1, Operator *o2)
|
RhythmChannel(int baseAddress, double startvol, Operator *o1, Operator *o2)
|
||||||
: Channel2op(baseAddress, o1, o2)
|
: Channel2op(baseAddress, startvol, o1, o2)
|
||||||
{ }
|
{ }
|
||||||
double getChannelOutput(class OPL3 *OPL3);
|
double getChannelOutput(class OPL3 *OPL3);
|
||||||
|
|
||||||
|
@ -258,16 +258,16 @@ public:
|
||||||
class HighHatSnareDrumChannel : public RhythmChannel {
|
class HighHatSnareDrumChannel : public RhythmChannel {
|
||||||
static const int highHatSnareDrumChannelBaseAddress = 7;
|
static const int highHatSnareDrumChannelBaseAddress = 7;
|
||||||
public:
|
public:
|
||||||
HighHatSnareDrumChannel(Operator *o1, Operator *o2)
|
HighHatSnareDrumChannel(double startvol, Operator *o1, Operator *o2)
|
||||||
: RhythmChannel(highHatSnareDrumChannelBaseAddress, o1, o2)
|
: RhythmChannel(highHatSnareDrumChannelBaseAddress, startvol, o1, o2)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
class TomTomTopCymbalChannel : public RhythmChannel {
|
class TomTomTopCymbalChannel : public RhythmChannel {
|
||||||
static const int tomTomTopCymbalChannelBaseAddress = 8;
|
static const int tomTomTopCymbalChannelBaseAddress = 8;
|
||||||
public:
|
public:
|
||||||
TomTomTopCymbalChannel(Operator *o1, Operator *o2)
|
TomTomTopCymbalChannel(double startvol, Operator *o1, Operator *o2)
|
||||||
: RhythmChannel(tomTomTopCymbalChannelBaseAddress, o1, o2)
|
: RhythmChannel(tomTomTopCymbalChannelBaseAddress, startvol, o1, o2)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -308,7 +308,7 @@ class BassDrumChannel : public Channel2op {
|
||||||
Operator my_op1, my_op2;
|
Operator my_op1, my_op2;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BassDrumChannel();
|
BassDrumChannel(double startvol);
|
||||||
double getChannelOutput(class OPL3 *OPL3);
|
double getChannelOutput(class OPL3 *OPL3);
|
||||||
|
|
||||||
// Key ON and OFF are unused in rhythm channels.
|
// 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 nts, dam, dvb, ryt, bd, sd, tom, tc, hh, _new, connectionsel;
|
||||||
int vibratoIndex, tremoloIndex;
|
int vibratoIndex, tremoloIndex;
|
||||||
|
|
||||||
|
bool FullPan;
|
||||||
|
|
||||||
static OperatorData *OperatorData;
|
static OperatorData *OperatorData;
|
||||||
static OPL3Data *OPL3Data;
|
static OPL3Data *OPL3Data;
|
||||||
|
@ -565,7 +567,7 @@ public:
|
||||||
//void read(float output[2]);
|
//void read(float output[2]);
|
||||||
void write(int array, int address, int data);
|
void write(int array, int address, int data);
|
||||||
|
|
||||||
OPL3();
|
OPL3(bool fullpan);
|
||||||
~OPL3();
|
~OPL3();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -708,10 +710,12 @@ void OPL3::write(int array, int address, int data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OPL3::OPL3()
|
OPL3::OPL3(bool fullpan)
|
||||||
: highHatSnareDrumChannel(&highHatOperator, &snareDrumOperator),
|
: bassDrumChannel(fullpan ? CENTER_PANNING_POWER : 1),
|
||||||
tomTomTopCymbalChannel(&tomTomOperator, &topCymbalOperator)
|
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;
|
nts = dam = dvb = ryt = bd = sd = tom = tc = hh = _new = connectionsel = 0;
|
||||||
vibratoIndex = tremoloIndex = 0;
|
vibratoIndex = tremoloIndex = 0;
|
||||||
|
|
||||||
|
@ -784,27 +788,28 @@ void OPL3::initChannels2op() {
|
||||||
// The YMF262 has 18 2-op channels.
|
// The YMF262 has 18 2-op channels.
|
||||||
// Each 2-op channel can be at a serial or parallel operator configuration:
|
// Each 2-op channel can be at a serial or parallel operator configuration:
|
||||||
memset(channels2op, 0, sizeof(channels2op));
|
memset(channels2op, 0, sizeof(channels2op));
|
||||||
|
double startvol = FullPan ? CENTER_PANNING_POWER : 1;
|
||||||
for(int array=0; array<2; array++)
|
for(int array=0; array<2; array++)
|
||||||
for(int channelNumber=0; channelNumber<3; channelNumber++) {
|
for(int channelNumber=0; channelNumber<3; channelNumber++) {
|
||||||
int baseAddress = (array<<8) | channelNumber;
|
int baseAddress = (array<<8) | channelNumber;
|
||||||
// Channels 1, 2, 3 -> Operator offsets 0x0,0x3; 0x1,0x4; 0x2,0x5
|
// 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
|
// 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
|
// 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() {
|
void OPL3::initChannels4op() {
|
||||||
// The YMF262 has 3 4-op channels in each array:
|
// The YMF262 has 3 4-op channels in each array:
|
||||||
memset(channels4op, 0, sizeof(channels4op));
|
memset(channels4op, 0, sizeof(channels4op));
|
||||||
|
double startvol = FullPan ? CENTER_PANNING_POWER : 1;
|
||||||
for(int array=0; array<2; array++)
|
for(int array=0; array<2; array++)
|
||||||
for(int channelNumber=0; channelNumber<3; channelNumber++) {
|
for(int channelNumber=0; channelNumber<3; channelNumber++) {
|
||||||
int baseAddress = (array<<8) | channelNumber;
|
int baseAddress = (array<<8) | channelNumber;
|
||||||
// Channels 1, 2, 3 -> Operators 0x0,0x3,0x8,0xB; 0x1,0x4,0x9,0xC; 0x2,0x5,0xA,0xD;
|
// 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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel::Channel (int baseAddress) {
|
Channel::Channel (int baseAddress, double startvol) {
|
||||||
channelBaseAddress = baseAddress;
|
channelBaseAddress = baseAddress;
|
||||||
fnuml = fnumh = kon = block = fb = cnt = 0;
|
fnuml = fnumh = kon = block = fb = cnt = 0;
|
||||||
feedback[0] = feedback[1] = 0;
|
feedback[0] = feedback[1] = 0;
|
||||||
leftPan = rightPan = 1;
|
leftPan = rightPan = startvol;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Channel::update_2_KON1_BLOCK3_FNUMH2(OPL3 *OPL3) {
|
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) {
|
void Channel::updatePan(OPL3 *OPL3) {
|
||||||
if (OPL3->_new == 0)
|
if (!OPL3->FullPan)
|
||||||
{
|
{
|
||||||
leftPan = VOLUME_MUL;
|
if (OPL3->_new == 0)
|
||||||
rightPan = VOLUME_MUL;
|
{
|
||||||
}
|
leftPan = VOLUME_MUL;
|
||||||
else
|
rightPan = VOLUME_MUL;
|
||||||
{
|
}
|
||||||
leftPan = cha * VOLUME_MUL;
|
else
|
||||||
rightPan = chb * VOLUME_MUL;
|
{
|
||||||
|
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);
|
update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(OPL3);
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel2op::Channel2op (int baseAddress, Operator *o1, Operator *o2)
|
Channel2op::Channel2op (int baseAddress, double startvol, Operator *o1, Operator *o2)
|
||||||
: Channel(baseAddress)
|
: Channel(baseAddress, startvol)
|
||||||
{
|
{
|
||||||
op1 = o1;
|
op1 = o1;
|
||||||
op2 = o2;
|
op2 = o2;
|
||||||
|
@ -1086,8 +1094,8 @@ void Channel2op::updateOperators(OPL3 *OPL3) {
|
||||||
op2->updateOperator(OPL3, keyScaleNumber, f_number, block);
|
op2->updateOperator(OPL3, keyScaleNumber, f_number, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
Channel4op::Channel4op (int baseAddress, Operator *o1, Operator *o2, Operator *o3, Operator *o4)
|
Channel4op::Channel4op (int baseAddress, double startvol, Operator *o1, Operator *o2, Operator *o3, Operator *o4)
|
||||||
: Channel(baseAddress)
|
: Channel(baseAddress, startvol)
|
||||||
{
|
{
|
||||||
op1 = o1;
|
op1 = o1;
|
||||||
op2 = o2;
|
op2 = o2;
|
||||||
|
@ -1665,8 +1673,8 @@ double SnareDrumOperator::getOperatorOutput(OPL3 *OPL3, double modulator) {
|
||||||
return operatorOutput*2;
|
return operatorOutput*2;
|
||||||
}
|
}
|
||||||
|
|
||||||
BassDrumChannel::BassDrumChannel()
|
BassDrumChannel::BassDrumChannel(double startvol)
|
||||||
: Channel2op(bassDrumChannelBaseAddress, &my_op1, &my_op2),
|
: Channel2op(bassDrumChannelBaseAddress, startvol, &my_op1, &my_op2),
|
||||||
my_op1(op1BaseAddress), my_op2(op2BaseAddress)
|
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)
|
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)
|
OPLEmul *JavaOPLCreate(bool stereo)
|
||||||
{
|
{
|
||||||
return new OPL3;
|
return new OPL3(stereo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,6 @@ typedef SBYTE Bit8s;
|
||||||
|
|
||||||
#include "opl.h"
|
#include "opl.h"
|
||||||
|
|
||||||
#define CENTER_PANNING_POWER 0.70710678118f
|
|
||||||
|
|
||||||
static Bit16s wavtable[WAVEPREC*3]; // wave form table
|
static Bit16s wavtable[WAVEPREC*3]; // wave form table
|
||||||
|
|
||||||
// key scale levels
|
// key scale levels
|
||||||
|
@ -506,7 +504,7 @@ void DBOPL::Reset() {
|
||||||
#if defined(OPLTYPE_IS_OPL3)
|
#if defined(OPLTYPE_IS_OPL3)
|
||||||
op[i].is_4op = false;
|
op[i].is_4op = false;
|
||||||
op[i].is_4op_attached = 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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,8 +126,6 @@ typedef signed int INT32; /* signed 32bit */
|
||||||
#define INLINE __inline
|
#define INLINE __inline
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CENTER_PANNING_POWER 0.70710678118 /* [RH] volume at center for EQP */
|
|
||||||
|
|
||||||
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
|
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
|
||||||
#define EG_SH 16 /* 16.16 fixed point (EG timing) */
|
#define EG_SH 16 /* 16.16 fixed point (EG timing) */
|
||||||
#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */
|
#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */
|
||||||
|
|
|
@ -23,5 +23,7 @@ OPLEmul *DBOPLCreate(bool stereo);
|
||||||
OPLEmul *JavaOPLCreate(bool stereo);
|
OPLEmul *JavaOPLCreate(bool stereo);
|
||||||
|
|
||||||
#define OPL_SAMPLE_RATE 49716.0
|
#define OPL_SAMPLE_RATE 49716.0
|
||||||
|
#define CENTER_PANNING_POWER 0.70710678118 /* [RH] volume at center for EQP */
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -1402,8 +1402,9 @@ OptionValue GusMemory
|
||||||
|
|
||||||
OptionValue OplCores
|
OptionValue OplCores
|
||||||
{
|
{
|
||||||
0, "MAME"
|
0, "MAME OPL2"
|
||||||
1, "DOSBox"
|
1, "DOSBox OPL3"
|
||||||
|
2, "Java OPL3"
|
||||||
}
|
}
|
||||||
|
|
||||||
OptionMenu AdvSoundOptions
|
OptionMenu AdvSoundOptions
|
||||||
|
|
Loading…
Reference in a new issue