Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

File diff suppressed because it is too large Load Diff

283
audio/softsynth/opl/dbopl.h Normal file
View File

@@ -0,0 +1,283 @@
/*
* Copyright (C) 2002-2011 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// Last synch with DOSBox SVN trunk r3752
#ifndef AUDIO_SOFTSYNTH_OPL_DBOPL_H
#define AUDIO_SOFTSYNTH_OPL_DBOPL_H
#include "common/scummsys.h"
#ifndef DISABLE_DOSBOX_OPL
namespace OPL {
namespace DOSBox {
//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume
#define WAVE_HANDLER 10
//Use a logarithmic wavetable with an exponential table for volume
#define WAVE_TABLELOG 11
//Use a linear wavetable with a multiply table for volume
#define WAVE_TABLEMUL 12
//Select the type of wave generator routine
#define DBOPL_WAVE WAVE_TABLEMUL
namespace DBOPL {
// Type aliases for the DBOPL code
typedef int Bits;
typedef uint Bitu;
typedef int8 Bit8s;
typedef uint8 Bit8u;
typedef int16 Bit16s;
typedef uint16 Bit16u;
typedef int32 Bit32s;
typedef uint32 Bit32u;
#define DB_FASTCALL
#define GCC_UNLIKELY(x) (x)
#define INLINE inline
// -------------------------------
struct Chip;
struct Operator;
struct Channel;
#if (DBOPL_WAVE == WAVE_HANDLER)
typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume );
#endif
typedef Bits ( DBOPL::Operator::*VolumeHandler) ( );
typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output );
//Different synth modes that can generate blocks of data
typedef enum {
sm2AM,
sm2FM,
sm3AM,
sm3FM,
sm4Start,
sm3FMFM,
sm3AMFM,
sm3FMAM,
sm3AMAM,
sm6Start,
sm2Percussion,
sm3Percussion
} SynthMode;
//Shifts for the values contained in chandata variable
enum {
SHIFT_KSLBASE = 16,
SHIFT_KEYCODE = 24
};
struct Operator {
public:
//Masks for operator 20 values
enum {
MASK_KSR = 0x10,
MASK_SUSTAIN = 0x20,
MASK_VIBRATO = 0x40,
MASK_TREMOLO = 0x80
};
typedef enum {
OFF,
RELEASE,
SUSTAIN,
DECAY,
ATTACK
} State;
VolumeHandler volHandler;
#if (DBOPL_WAVE == WAVE_HANDLER)
WaveHandler waveHandler; //Routine that generate a wave
#else
Bit16s* waveBase;
Bit32u waveMask;
Bit32u waveStart;
#endif
Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index
Bit32u waveAdd; //The base frequency without vibrato
Bit32u waveCurrent; //waveAdd + vibratao
Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this
Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove?
Bit32u vibrato; //Scaled up vibrato strength
Bit32s sustainLevel; //When stopping at sustain level stop here
Bit32s totalLevel; //totalLevel is added to every generated volume
Bit32u currentLevel; //totalLevel + tremolo
Bit32s volume; //The currently active volume
Bit32u attackAdd; //Timers for the different states of the envelope
Bit32u decayAdd;
Bit32u releaseAdd;
Bit32u rateIndex; //Current position of the evenlope
Bit8u rateZero; //Bits for the different states of the envelope having no changes
Bit8u keyOn; //Bitmask of different values that can generate keyon
//Registers, also used to check for changes
Bit8u reg20, reg40, reg60, reg80, regE0;
//Active part of the envelope we're in
Bit8u state;
//0xff when tremolo is enabled
Bit8u tremoloMask;
//Strength of the vibrato
Bit8u vibStrength;
//Keep track of the calculated KSR so we can check for changes
Bit8u ksr;
private:
void SetState( Bit8u s );
void UpdateAttack( const Chip* chip );
void UpdateRelease( const Chip* chip );
void UpdateDecay( const Chip* chip );
public:
void UpdateAttenuation();
void UpdateRates( const Chip* chip );
void UpdateFrequency( );
void Write20( const Chip* chip, Bit8u val );
void Write40( const Chip* chip, Bit8u val );
void Write60( const Chip* chip, Bit8u val );
void Write80( const Chip* chip, Bit8u val );
void WriteE0( const Chip* chip, Bit8u val );
bool Silent() const;
void Prepare( const Chip* chip );
void KeyOn( Bit8u mask);
void KeyOff( Bit8u mask);
template< State state>
Bits TemplateVolume( );
Bit32s RateForward( Bit32u add );
Bitu ForwardWave();
Bitu ForwardVolume();
Bits GetSample( Bits modulation );
Bits GetWave( Bitu index, Bitu vol );
public:
Operator();
};
struct Channel {
Operator op[2];
inline Operator* Op( Bitu index ) {
return &( ( this + (index >> 1) )->op[ index & 1 ]);
}
SynthHandler synthHandler;
Bit32u chanData; //Frequency/octave and derived values
Bit32s old[2]; //Old data for feedback
Bit8u feedback; //Feedback shift
Bit8u regB0; //Register values to check for changes
Bit8u regC0;
//This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel
Bit8u fourMask;
Bit8s maskLeft; //Sign extended values for both channel's panning
Bit8s maskRight;
//Forward the channel data to the operators of the channel
void SetChanData( const Chip* chip, Bit32u data );
//Change in the chandata, check for new values and if we have to forward to operators
void UpdateFrequency( const Chip* chip, Bit8u fourOp );
void WriteA0( const Chip* chip, Bit8u val );
void WriteB0( const Chip* chip, Bit8u val );
void WriteC0( const Chip* chip, Bit8u val );
void ResetC0( const Chip* chip );
//call this for the first channel
template< bool opl3Mode >
void GeneratePercussion( Chip* chip, Bit32s* output );
//Generate blocks of data in specific modes
template<SynthMode mode>
Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output );
Channel();
};
struct Chip {
//This is used as the base counter for vibrato and tremolo
Bit32u lfoCounter;
Bit32u lfoAdd;
Bit32u noiseCounter;
Bit32u noiseAdd;
Bit32u noiseValue;
//Frequency scales for the different multiplications
Bit32u freqMul[16];
//Rates for decay and release for rate of this chip
Bit32u linearRates[76];
//Best match attack rates for the rate of this chip
Bit32u attackRates[76];
//18 channels with 2 operators each
Channel chan[18];
Bit8u reg104;
Bit8u reg08;
Bit8u reg04;
Bit8u regBD;
Bit8u vibratoIndex;
Bit8u tremoloIndex;
Bit8s vibratoSign;
Bit8u vibratoShift;
Bit8u tremoloValue;
Bit8u vibratoStrength;
Bit8u tremoloStrength;
//Mask for allowed wave forms
Bit8u waveFormMask;
//0 or -1 when enabled
Bit8s opl3Active;
//Return the maximum amount of samples before and LFO change
Bit32u ForwardLFO( Bit32u samples );
Bit32u ForwardNoise();
void WriteBD( Bit8u val );
void WriteReg(Bit32u reg, Bit8u val );
Bit32u WriteAddr( Bit32u port, Bit8u val );
void GenerateBlock2( Bitu samples, Bit32s* output );
void GenerateBlock3( Bitu samples, Bit32s* output );
void Generate( Bit32u samples );
void Setup( Bit32u r );
Chip();
};
void InitTables();
} //Namespace
} // End of namespace DOSBox
} // End of namespace OPL
#endif // !DISABLE_DOSBOX_OPL
#endif

View File

@@ -0,0 +1,356 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on AdLib emulation code of DOSBox
* Copyright (C) 2002-2009 The DOSBox Team
* Licensed under GPLv2+
* http://www.dosbox.com
*/
#ifndef DISABLE_DOSBOX_OPL
#include "dosbox.h"
#include "dbopl.h"
#include "audio/mixer.h"
#include "common/system.h"
#include "common/scummsys.h"
#include "common/util.h"
#include <math.h>
#include <string.h>
namespace OPL {
namespace DOSBox {
Timer::Timer() {
masked = false;
overflow = false;
enabled = false;
counter = 0;
delay = 0;
}
void Timer::update(double time) {
if (!enabled || !delay)
return;
double deltaStart = time - startTime;
// Only set the overflow flag when not masked
if (deltaStart >= 0 && !masked)
overflow = 1;
}
void Timer::reset(double time) {
overflow = false;
if (!delay || !enabled)
return;
double delta = (time - startTime);
double rem = fmod(delta, delay);
double next = delay - rem;
startTime = time + next;
}
void Timer::stop() {
enabled = false;
}
void Timer::start(double time, int scale) {
//Don't enable again
if (enabled)
return;
enabled = true;
delay = 0.001 * (256 - counter) * scale;
startTime = time + delay;
}
bool Chip::write(uint32 reg, uint8 val) {
switch (reg) {
case 0x02:
timer[0].counter = val;
return true;
case 0x03:
timer[1].counter = val;
return true;
case 0x04:
{
double time = g_system->getMillis() / 1000.0;
if (val & 0x80) {
timer[0].reset(time);
timer[1].reset(time);
} else {
timer[0].update(time);
timer[1].update(time);
if (val & 0x1)
timer[0].start(time, 80);
else
timer[0].stop();
timer[0].masked = (val & 0x40) > 0;
if (timer[0].masked)
timer[0].overflow = false;
if (val & 0x2)
timer[1].start(time, 320);
else
timer[1].stop();
timer[1].masked = (val & 0x20) > 0;
if (timer[1].masked)
timer[1].overflow = false;
}
}
return true;
default:
break;
}
return false;
}
uint8 Chip::read() {
double time = g_system->getMillis() / 1000.0;
timer[0].update(time);
timer[1].update(time);
uint8 ret = 0;
// Overflow won't be set if a channel is masked
if (timer[0].overflow) {
ret |= 0x40;
ret |= 0x80;
}
if (timer[1].overflow) {
ret |= 0x20;
ret |= 0x80;
}
return ret;
}
OPL::OPL(Config::OplType type) : _type(type), _rate(0), _emulator(nullptr) {
}
OPL::~OPL() {
stop();
free();
}
void OPL::free() {
delete _emulator;
_emulator = nullptr;
}
bool OPL::init() {
free();
memset(&_reg, 0, sizeof(_reg));
ARRAYCLEAR(_chip);
_emulator = new DBOPL::Chip();
if (!_emulator)
return false;
DBOPL::InitTables();
_rate = g_system->getMixer()->getOutputRate();
_emulator->Setup(_rate);
if (_type == Config::kDualOpl2) {
// Setup opl3 mode in the hander
_emulator->WriteReg(0x105, 1);
}
return true;
}
void OPL::reset() {
init();
}
void OPL::write(int port, int val) {
if (port&1) {
switch (_type) {
case Config::kOpl2:
case Config::kOpl3:
if (!_chip[0].write(_reg.normal, val))
_emulator->WriteReg(_reg.normal, val);
break;
case Config::kDualOpl2:
// Not a 0x??8 port, then write to a specific port
if (!(port & 0x8)) {
byte index = (port & 2) >> 1;
dualWrite(index, _reg.dual[index], val);
} else {
//Write to both ports
dualWrite(0, _reg.dual[0], val);
dualWrite(1, _reg.dual[1], val);
}
break;
default:
break;
}
} else {
// Ask the handler to write the address
// Make sure to clip them in the right range
switch (_type) {
case Config::kOpl2:
_reg.normal = _emulator->WriteAddr(port, val) & 0xff;
break;
case Config::kOpl3:
_reg.normal = _emulator->WriteAddr(port, val) & 0x1ff;
break;
case Config::kDualOpl2:
// Not a 0x?88 port, when write to a specific side
if (!(port & 0x8)) {
byte index = (port & 2) >> 1;
_reg.dual[index] = val & 0xff;
} else {
_reg.dual[0] = val & 0xff;
_reg.dual[1] = val & 0xff;
}
break;
default:
break;
}
}
}
void OPL::writeReg(int r, int v) {
int tempReg = 0;
switch (_type) {
case Config::kOpl2:
case Config::kDualOpl2:
case Config::kOpl3:
// We can't use _handler->writeReg here directly, since it would miss timer changes.
// Backup old setup register
tempReg = _reg.normal;
// We directly allow writing to secondary OPL3 registers by using
// register values >= 0x100.
if (_type == Config::kOpl3 && r >= 0x100) {
// We need to set the register we want to write to via port 0x222,
// since we want to write to the secondary register set.
write(0x222, r);
// Do the real writing to the register
write(0x223, v);
} else {
// We need to set the register we want to write to via port 0x388
write(0x388, r);
// Do the real writing to the register
write(0x389, v);
}
// Restore the old register
if (_type == Config::kOpl3 && tempReg >= 0x100) {
write(0x222, tempReg & ~0x100);
} else {
write(0x388, tempReg);
}
break;
default:
break;
};
}
void OPL::dualWrite(uint8 index, uint8 reg, uint8 val) {
// Make sure you don't use opl3 features
// Don't allow write to disable opl3
if (reg == 5)
return;
// Only allow 4 waveforms
if (reg >= 0xE0 && reg <= 0xE8)
val &= 3;
// Write to the timer?
if (_chip[index].write(reg, val))
return;
// Enabling panning
if (reg >= 0xC0 && reg <= 0xC8) {
val &= 15;
val |= index ? 0xA0 : 0x50;
}
uint32 fullReg = reg + (index ? 0x100 : 0);
_emulator->WriteReg(fullReg, val);
}
void OPL::generateSamples(int16 *buffer, int length) {
const uint bufferLength = 512;
int32 tempBuffer[bufferLength * 2];
if (isStereo()) {
// For stereo OPL cards, we divide the sample count by 2,
// to match stereo AudioStream behavior.
length >>= 1;
if (_emulator->opl3Active) {
// DUAL_OPL2 or OPL3 in OPL3 mode (stereo)
while (length > 0) {
const uint readSamples = MIN<uint>(length, bufferLength);
const uint readSamples2 = (readSamples << 1);
_emulator->GenerateBlock3(readSamples, tempBuffer);
for (uint i = 0; i < readSamples2; ++i)
buffer[i] = tempBuffer[i];
buffer += readSamples2;
length -= readSamples;
}
} else {
// OPL3 (stereo) in OPL2 compatibility mode (mono)
while (length > 0) {
const uint readSamples = MIN<uint>(length, bufferLength);
const uint readSamples2 = (readSamples << 1);
_emulator->GenerateBlock2(readSamples, tempBuffer);
for (uint i = 0, j = 0; i < readSamples; ++i, j += 2)
buffer[j] = buffer[j + 1] = tempBuffer[i];
buffer += readSamples2;
length -= readSamples;
}
}
} else {
// OPL2
while (length > 0) {
const uint readSamples = MIN<uint>(length, bufferLength << 1);
_emulator->GenerateBlock2(readSamples, tempBuffer);
for (uint i = 0; i < readSamples; ++i)
buffer[i] = tempBuffer[i];
buffer += readSamples;
length -= readSamples;
}
}
}
} // End of namespace DOSBox
} // End of namespace OPL
#endif // !DISABLE_DOSBOX_ADLIB

View File

@@ -0,0 +1,107 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Based on OPL emulation code of DOSBox
* Copyright (C) 2002-2009 The DOSBox Team
* Licensed under GPLv2+
* http://www.dosbox.com
*/
#ifndef AUDIO_SOFTSYNTH_OPL_DOSBOX_H
#define AUDIO_SOFTSYNTH_OPL_DOSBOX_H
#ifndef DISABLE_DOSBOX_OPL
#include "audio/fmopl.h"
namespace OPL {
namespace DOSBox {
struct Timer {
double startTime;
double delay;
bool enabled, overflow, masked;
uint8 counter;
Timer();
//Call update before making any further changes
void update(double time);
//On a reset make sure the start is in sync with the next cycle
void reset(double time);
void stop();
void start(double time, int scale);
};
struct Chip {
//Last selected register
Timer timer[2];
//Check for it being a write to the timer
bool write(uint32 addr, uint8 val);
//Read the current timer state, will use current double
uint8 read();
};
namespace DBOPL {
struct Chip;
} // end of namespace DBOPL
class OPL : public ::OPL::OPL, public Audio::EmulatedChip {
private:
Config::OplType _type;
uint _rate;
DBOPL::Chip *_emulator;
::OPL::DOSBox::Chip _chip[2];
union {
uint16 normal;
uint8 dual[2];
} _reg;
void free();
void dualWrite(uint8 index, uint8 reg, uint8 val);
public:
OPL(Config::OplType type);
~OPL();
bool init();
void reset();
void write(int a, int v);
void writeReg(int r, int v);
bool isStereo() const { return _type != Config::kOpl2; }
protected:
void generateSamples(int16 *buffer, int length);
};
} // End of namespace DOSBox
} // End of namespace OPL
#endif // !DISABLE_DOSBOX_OPL
#endif

1255
audio/softsynth/opl/mame.cpp Normal file

File diff suppressed because it is too large Load Diff

199
audio/softsynth/opl/mame.h Normal file
View File

@@ -0,0 +1,199 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* LGPL licensed version of MAMEs fmopl (V0.37a modified) by
* Tatsuyuki Satoh. Included from LGPL'ed AdPlug.
*
*/
#ifndef AUDIO_SOFTSYNTH_OPL_MAME_H
#define AUDIO_SOFTSYNTH_OPL_MAME_H
#include "common/scummsys.h"
#include "common/random.h"
#include "audio/fmopl.h"
namespace OPL {
namespace MAME {
enum {
FMOPL_ENV_BITS_HQ = 16,
FMOPL_ENV_BITS_MQ = 8,
FMOPL_ENV_BITS_LQ = 8,
FMOPL_EG_ENT_HQ = 4096,
FMOPL_EG_ENT_MQ = 1024,
FMOPL_EG_ENT_LQ = 128
};
typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
typedef void (*OPL_IRQHANDLER)(int param,int irq);
typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
#define OPL_TYPE_WAVESEL 0x01 /* waveform select */
/* Saving is necessary for member of the 'R' mark for suspend/resume */
/* ---------- OPL one of slot ---------- */
typedef struct fm_opl_slot {
int TL; /* total level :TL << 8 */
int TLL; /* adjusted now TL */
uint8 KSR; /* key scale rate :(shift down bit) */
int *AR; /* attack rate :&AR_TABLE[AR<<2] */
int *DR; /* decay rate :&DR_TABLE[DR<<2] */
int SL; /* sustain level :SL_TABLE[SL] */
int *RR; /* release rate :&DR_TABLE[RR<<2] */
uint8 ksl; /* keyscale level :(shift down bits) */
uint8 ksr; /* key scale rate :kcode>>KSR */
uint mul; /* multiple :ML_TABLE[ML] */
uint Cnt; /* frequency count */
uint Incr; /* frequency step */
/* envelope generator state */
uint8 eg_typ;/* envelope type flag */
uint8 evm; /* envelope phase */
int evc; /* envelope counter */
int eve; /* envelope counter end point */
int evs; /* envelope counter step */
int evsa; /* envelope step for AR :AR[ksr] */
int evsd; /* envelope step for DR :DR[ksr] */
int evsr; /* envelope step for RR :RR[ksr] */
/* LFO */
uint8 ams; /* ams flag */
uint8 vib; /* vibrate flag */
/* wave selector */
int **wavetable;
} OPL_SLOT;
/* ---------- OPL one of channel ---------- */
typedef struct fm_opl_channel {
OPL_SLOT SLOT[2];
uint8 CON; /* connection type */
uint8 FB; /* feed back :(shift down bit)*/
int *connect1; /* slot1 output pointer */
int *connect2; /* slot2 output pointer */
int op1_out[2]; /* slot1 output for selfeedback */
/* phase generator state */
uint block_fnum; /* block+fnum */
uint8 kcode; /* key code : KeyScaleCode */
uint fc; /* Freq. Increment base */
uint ksl_base; /* KeyScaleLevel Base step */
uint8 keyon; /* key on/off flag */
} OPL_CH;
/* OPL state */
typedef struct fm_opl_f {
uint8 type; /* chip type */
int clock; /* master clock (Hz) */
int rate; /* sampling rate (Hz) */
double freqbase; /* frequency base */
double TimerBase; /* Timer base time (==sampling time) */
uint8 address; /* address register */
uint8 status; /* status flag */
uint8 statusmask; /* status mask */
uint mode; /* Reg.08 : CSM , notesel,etc. */
/* Timer */
int T[2]; /* timer counter */
uint8 st[2]; /* timer enable */
/* FM channel slots */
OPL_CH *P_CH; /* pointer of CH */
int max_ch; /* maximum channel */
/* Rhythm sention */
uint8 rhythm; /* Rhythm mode , key flag */
/* time tables */
int AR_TABLE[76]; /* atttack rate tables */
int DR_TABLE[76]; /* decay rate tables */
uint FN_TABLE[1024];/* fnumber -> increment counter */
/* LFO */
int *ams_table;
int *vib_table;
int amsCnt;
int amsIncr;
int vibCnt;
int vibIncr;
/* wave selector enable flag */
uint8 wavesel;
/* external event callback handler */
OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
int TimerParam; /* TIMER parameter */
OPL_IRQHANDLER IRQHandler; /* IRQ handler */
int IRQParam; /* IRQ parameter */
OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */
int UpdateParam; /* stream update parameter */
Common::RandomSource *rnd;
} FM_OPL;
/* ---------- Generic interface section ---------- */
#define OPL_TYPE_YM3526 (0)
#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
void OPLBuildTables(int ENV_BITS_PARAM, int EG_ENT_PARAM);
FM_OPL *OPLCreate(int type, int clock, int rate);
void OPLDestroy(FM_OPL *OPL);
void OPLSetTimerHandler(FM_OPL *OPL, OPL_TIMERHANDLER TimerHandler, int channelOffset);
void OPLSetIRQHandler(FM_OPL *OPL, OPL_IRQHANDLER IRQHandler, int param);
void OPLSetUpdateHandler(FM_OPL *OPL, OPL_UPDATEHANDLER UpdateHandler, int param);
void OPLResetChip(FM_OPL *OPL);
int OPLWrite(FM_OPL *OPL, int a, int v);
unsigned char OPLRead(FM_OPL *OPL, int a);
int OPLTimerOver(FM_OPL *OPL, int c);
void OPLWriteReg(FM_OPL *OPL, int r, int v);
void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length);
// Factory method
FM_OPL *makeAdLibOPL(int rate);
// OPL API implementation
class OPL : public ::OPL::OPL, public Audio::EmulatedChip {
private:
FM_OPL *_opl;
public:
OPL() : _opl(0) {}
~OPL();
bool init();
void reset();
void write(int a, int v);
void writeReg(int r, int v);
bool isStereo() const { return false; }
protected:
void generateSamples(int16 *buffer, int length);
};
} // End of namespace MAME
} // End of namespace OPL
#endif

File diff suppressed because it is too large Load Diff

197
audio/softsynth/opl/nuked.h Normal file
View File

@@ -0,0 +1,197 @@
//
// Copyright (C) 2013-2018 Alexey Khokholov (Nuke.YKT)
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// Nuked OPL3 emulator.
// Thanks:
// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh):
// Feedback and Rhythm part calculation information.
// forums.submarine.org.uk(carbon14, opl3):
// Tremolo and phase generator calculation information.
// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
// OPL2 ROMs.
// siliconpr0n.org(John McMaster, digshadow):
// YMF262 and VRC VII decaps and die shots.
//
// version: 1.8
//
#ifndef AUDIO_SOFTSYNTH_OPL_NUKED_H
#define AUDIO_SOFTSYNTH_OPL_NUKED_H
#include "common/scummsys.h"
#include "audio/fmopl.h"
#ifndef DISABLE_NUKED_OPL
#ifndef OPL_ENABLE_STEREOEXT
#define OPL_ENABLE_STEREOEXT 0
#endif
#define OPL_WRITEBUF_SIZE 1024
#define OPL_WRITEBUF_DELAY 2
namespace OPL {
namespace NUKED {
typedef struct _opl3_slot opl3_slot;
typedef struct _opl3_channel opl3_channel;
typedef struct _opl3_chip opl3_chip;
struct _opl3_slot {
opl3_channel *channel;
opl3_chip *chip;
int16_t out;
int16_t fbmod;
int16_t *mod;
int16_t prout;
uint16_t eg_rout;
uint16_t eg_out;
uint8_t eg_inc;
uint8_t eg_gen;
uint8_t eg_rate;
uint8_t eg_ksl;
uint8_t *trem;
uint8_t reg_vib;
uint8_t reg_type;
uint8_t reg_ksr;
uint8_t reg_mult;
uint8_t reg_ksl;
uint8_t reg_tl;
uint8_t reg_ar;
uint8_t reg_dr;
uint8_t reg_sl;
uint8_t reg_rr;
uint8_t reg_wf;
uint8_t key;
uint32_t pg_reset;
uint32_t pg_phase;
uint16_t pg_phase_out;
uint8_t slot_num;
};
struct _opl3_channel {
opl3_slot *slotz[2];/*Don't use "slots" keyword to avoid conflict with Qt applications*/
opl3_channel *pair;
opl3_chip *chip;
int16_t *out[4];
#if OPL_ENABLE_STEREOEXT
int32_t leftpan;
int32_t rightpan;
#endif
uint8_t chtype;
uint16_t f_num;
uint8_t block;
uint8_t fb;
uint8_t con;
uint8_t alg;
uint8_t ksv;
uint16_t cha, chb;
uint16_t chc, chd;
uint8_t ch_num;
};
typedef struct _opl3_writebuf {
uint64_t time;
uint16_t reg;
uint8_t data;
} opl3_writebuf;
struct _opl3_chip {
opl3_channel channel[18];
opl3_slot slot[36];
uint16_t timer;
uint64_t eg_timer;
uint8_t eg_timerrem;
uint8_t eg_state;
uint8_t eg_add;
uint8_t eg_timer_lo;
uint8_t newm;
uint8_t nts;
uint8_t rhy;
uint8_t vibpos;
uint8_t vibshift;
uint8_t tremolo;
uint8_t tremolopos;
uint8_t tremoloshift;
uint32_t noise;
int16_t zeromod;
int32_t mixbuff[4];
uint8_t rm_hh_bit2;
uint8_t rm_hh_bit3;
uint8_t rm_hh_bit7;
uint8_t rm_hh_bit8;
uint8_t rm_tc_bit3;
uint8_t rm_tc_bit5;
#if OPL_ENABLE_STEREOEXT
uint8_t stereoext;
#endif
/* OPL3L */
int32_t rateratio;
int32_t samplecnt;
int16_t oldsamples[4];
int16_t samples[4];
uint64_t writebuf_samplecnt;
uint32_t writebuf_cur;
uint32_t writebuf_last;
uint64_t writebuf_lasttime;
opl3_writebuf writebuf[OPL_WRITEBUF_SIZE];
};
void OPL3_Generate(opl3_chip *chip, int16_t *buf);
void OPL3_GenerateResampled(opl3_chip *chip, int16_t *buf);
void OPL3_Reset(opl3_chip *chip, uint32_t samplerate);
void OPL3_WriteReg(opl3_chip *chip, uint16_t reg, uint8_t v);
void OPL3_WriteRegBuffered(opl3_chip *chip, uint16_t reg, uint8_t v);
void OPL3_GenerateStream(opl3_chip *chip, int16_t *sndptr, uint32_t numsamples);
void OPL3_Generate4Ch(opl3_chip *chip, int16_t *buf4);
void OPL3_Generate4ChResampled(opl3_chip *chip, int16_t *buf4);
void OPL3_Generate4ChStream(opl3_chip *chip, int16_t *sndptr1, int16_t *sndptr2, uint32_t numsamples);
class OPL : public ::OPL::OPL, public Audio::EmulatedChip {
private:
Config::OplType _type;
uint _rate;
opl3_chip chip;
uint address[2];
void dualWrite(uint8 index, uint8 reg, uint8 val);
public:
OPL(Config::OplType type);
~OPL();
bool init();
void reset();
void write(int a, int v);
void writeReg(int r, int v);
bool isStereo() const { return true; }
protected:
void generateSamples(int16 *buffer, int length);
};
}
}
#endif // !DISABLE_NUKED_OPL
#endif