2
0
Fork 0

- Disable ZDoom mode.

- Used statically allocated intermediate integer buffer.
- Adjust DOSBox output scaling and add clamping.
This commit is contained in:
bsutherland 2016-02-07 19:22:18 +09:00
parent 63aa06b044
commit 0309b92e97
8 changed files with 1319 additions and 50 deletions

View File

@ -1,14 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<JUCERPROJECT id="wUKQiT" name="JuceOPLVSTi" projectType="audioplug" version="0.11.1"
<JUCERPROJECT id="wUKQiT" name="JuceOPLVSTi" projectType="audioplug" version="0.12.1"
bundleIdentifier="com.plainweave.JuceOPLVSTi" buildVST="1" buildAU="1"
pluginName="JuceOPLVSTi" pluginDesc="JuceOPLVSTi" pluginManufacturer="Plainweave Software"
pluginManufacturerCode="Pwve" pluginCode="JOPL" pluginChannelConfigs="{0, 1}"
pluginIsSynth="1" pluginWantsMidiIn="1" pluginProducesMidiOut="0"
pluginSilenceInIsSilenceOut="0" pluginEditorRequiresKeys="0"
pluginAUExportPrefix="JuceOPLVSTiAU" pluginRTASCategory="" aaxIdentifier="com.plainweave.JuceOPLVSTi"
pluginAAXCategory="AAX_ePlugInCategory_Dynamics" jucerVersion="3.1.0"
buildVST3="0" buildRTAS="0" buildAAX="0" includeBinaryInAppConfig="1">
pluginAAXCategory="AAX_ePlugInCategory_Dynamics" jucerVersion="4.1.0"
buildVST3="0" buildRTAS="0" buildAAX="0" includeBinaryInAppConfig="1"
pluginIsMidiEffectPlugin="0">
<MAINGROUP id="TOefyq" name="JuceOPLVSTi">
<GROUP id="{DCA755EB-7953-0641-E719-95C7850E5B2B}" name="Source">
<FILE id="o0sULY" name="DROMultiplexer.cpp" compile="1" resource="0"

View File

@ -7,12 +7,12 @@
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Introjucer version: 3.1.0
Created with Introjucer version: 4.1.0
------------------------------------------------------------------------------
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-13 by Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
==============================================================================
*/
@ -153,6 +153,9 @@ void PluginGui::setRecordButtonState(bool recording) {
PluginGui::PluginGui (AdlibBlasterAudioProcessor* ownerFilter)
: AudioProcessorEditor (ownerFilter)
{
//[Constructor_pre] You can add your own custom stuff here..
//[/Constructor_pre]
addAndMakeVisible (groupComponent = new GroupComponent ("new group",
TRANS("Modulator")));
groupComponent->setTextLabelPosition (Justification::centredLeft);
@ -162,7 +165,7 @@ PluginGui::PluginGui (AdlibBlasterAudioProcessor* ownerFilter)
addAndMakeVisible (frequencyComboBox = new ComboBox ("frequency combo box"));
frequencyComboBox->setEditableText (false);
frequencyComboBox->setJustificationType (Justification::centredLeft);
frequencyComboBox->setTextWhenNothingSelected (String::empty);
frequencyComboBox->setTextWhenNothingSelected (String());
frequencyComboBox->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
frequencyComboBox->addListener (this);
@ -391,7 +394,7 @@ PluginGui::PluginGui (AdlibBlasterAudioProcessor* ownerFilter)
addAndMakeVisible (frequencyComboBox2 = new ComboBox ("frequency combo box"));
frequencyComboBox2->setEditableText (false);
frequencyComboBox2->setJustificationType (Justification::centredLeft);
frequencyComboBox2->setTextWhenNothingSelected (String::empty);
frequencyComboBox2->setTextWhenNothingSelected (String());
frequencyComboBox2->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
frequencyComboBox2->addListener (this);
@ -690,7 +693,7 @@ PluginGui::PluginGui (AdlibBlasterAudioProcessor* ownerFilter)
addAndMakeVisible (velocityComboBox = new ComboBox ("velocity combo box"));
velocityComboBox->setEditableText (false);
velocityComboBox->setJustificationType (Justification::centredLeft);
velocityComboBox->setTextWhenNothingSelected (String::empty);
velocityComboBox->setTextWhenNothingSelected (String());
velocityComboBox->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
velocityComboBox->addItem (TRANS("Off"), 1);
velocityComboBox->addItem (TRANS("Light"), 2);
@ -710,7 +713,7 @@ PluginGui::PluginGui (AdlibBlasterAudioProcessor* ownerFilter)
addAndMakeVisible (velocityComboBox2 = new ComboBox ("velocity combo box"));
velocityComboBox2->setEditableText (false);
velocityComboBox2->setJustificationType (Justification::centredLeft);
velocityComboBox2->setTextWhenNothingSelected (String::empty);
velocityComboBox2->setTextWhenNothingSelected (String());
velocityComboBox2->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
velocityComboBox2->addItem (TRANS("Off"), 1);
velocityComboBox2->addItem (TRANS("Light"), 2);
@ -802,7 +805,7 @@ PluginGui::PluginGui (AdlibBlasterAudioProcessor* ownerFilter)
addAndMakeVisible (algorithmComboBox = new ComboBox ("algorithm combo box"));
algorithmComboBox->setEditableText (false);
algorithmComboBox->setJustificationType (Justification::centredLeft);
algorithmComboBox->setTextWhenNothingSelected (String::empty);
algorithmComboBox->setTextWhenNothingSelected (String());
algorithmComboBox->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
algorithmComboBox->addItem (TRANS("FM"), 1);
algorithmComboBox->addItem (TRANS("Additive"), 2);
@ -831,7 +834,7 @@ PluginGui::PluginGui (AdlibBlasterAudioProcessor* ownerFilter)
addAndMakeVisible (keyscaleAttenuationComboBox2 = new ComboBox ("keyscale combo box"));
keyscaleAttenuationComboBox2->setEditableText (false);
keyscaleAttenuationComboBox2->setJustificationType (Justification::centredLeft);
keyscaleAttenuationComboBox2->setTextWhenNothingSelected (String::empty);
keyscaleAttenuationComboBox2->setTextWhenNothingSelected (String());
keyscaleAttenuationComboBox2->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
keyscaleAttenuationComboBox2->addItem (TRANS("-0.0"), 1);
keyscaleAttenuationComboBox2->addItem (TRANS("-3.0"), 2);
@ -842,7 +845,7 @@ PluginGui::PluginGui (AdlibBlasterAudioProcessor* ownerFilter)
addAndMakeVisible (keyscaleAttenuationComboBox = new ComboBox ("keyscale combo box"));
keyscaleAttenuationComboBox->setEditableText (false);
keyscaleAttenuationComboBox->setJustificationType (Justification::centredLeft);
keyscaleAttenuationComboBox->setTextWhenNothingSelected (String::empty);
keyscaleAttenuationComboBox->setTextWhenNothingSelected (String());
keyscaleAttenuationComboBox->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
keyscaleAttenuationComboBox->addItem (TRANS("-0.0"), 1);
keyscaleAttenuationComboBox->addItem (TRANS("-3.0"), 2);
@ -857,7 +860,7 @@ PluginGui::PluginGui (AdlibBlasterAudioProcessor* ownerFilter)
groupComponent4->setColour (GroupComponent::textColourId, Colour (0xff007f00));
addAndMakeVisible (groupComponent5 = new GroupComponent ("new group",
TRANS("Emulator")));
TRANS("Emulator (currently locked)")));
groupComponent5->setTextLabelPosition (Justification::centredLeft);
groupComponent5->setColour (GroupComponent::outlineColourId, Colour (0xff007f00));
groupComponent5->setColour (GroupComponent::textColourId, Colour (0xff007f00));
@ -902,7 +905,7 @@ PluginGui::PluginGui (AdlibBlasterAudioProcessor* ownerFilter)
addAndMakeVisible (percussionComboBox = new ComboBox ("percussion combo box"));
percussionComboBox->setEditableText (false);
percussionComboBox->setJustificationType (Justification::centredLeft);
percussionComboBox->setTextWhenNothingSelected (String::empty);
percussionComboBox->setTextWhenNothingSelected (String());
percussionComboBox->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
percussionComboBox->addItem (TRANS("Off"), 1);
percussionComboBox->addItem (TRANS("Bass drum"), 2);
@ -1254,18 +1257,18 @@ void PluginGui::resized()
dbLabel4->setBounds (760, 156, 72, 16);
keyscaleAttenuationComboBox2->setBounds (688, 152, 72, 24);
keyscaleAttenuationComboBox->setBounds (264, 152, 72, 24);
groupComponent4->setBounds (440, 8, 408, 64);
groupComponent5->setBounds (16, 8, 408, 64);
emulatorSlider->setBounds (200, 32, 40, 24);
emulatorLabel->setBounds (112, 32, 72, 24);
emulatorLabel2->setBounds (248, 32, 72, 24);
groupComponent4->setBounds (16, 8, 832, 64);
groupComponent5->setBounds (24, 624, 408, 64);
emulatorSlider->setBounds (208, 648, 40, 24);
emulatorLabel->setBounds (120, 648, 72, 24);
emulatorLabel2->setBounds (256, 648, 72, 24);
recordButton->setBounds (24, 560, 296, 24);
percussionComboBox->setBounds (256, 488, 112, 24);
percussionLabel->setBounds (40, 488, 163, 24);
exportButton->setBounds (40, 456, 168, 24);
//[UserResized] Add your own custom resize handling here..
for (unsigned int i = 0; i < channels.size(); ++i)
channels[i]->setBounds(456+44*i+4, 36, 20, 20);
channels[i]->setBounds(68+88*i, 36, 20, 20);
//[/UserResized]
}
@ -1424,7 +1427,6 @@ void PluginGui::sliderValueChanged (Slider* sliderThatWasMoved)
else if (sliderThatWasMoved == emulatorSlider)
{
//[UserSliderCode_emulatorSlider] -- add your slider handling code here..
processor->setEnumParameter("Emulator", sliderThatWasMoved->getValue() < 0.5 ? 0 : 1);
//[/UserSliderCode_emulatorSlider]
}
@ -2053,24 +2055,24 @@ BEGIN_JUCER_METADATA
layout="33" items="-0.0&#10;-3.0&#10;-1.5&#10;-6.0" textWhenNonSelected=""
textWhenNoItems="(no choices)"/>
<GROUPCOMPONENT name="new group" id="52f9803abb342980" memberName="groupComponent4"
virtualName="" explicitFocusOrder="0" pos="440 8 408 64" outlinecol="ff007f00"
virtualName="" explicitFocusOrder="0" pos="16 8 832 64" outlinecol="ff007f00"
textcol="ff007f00" title="Channels" textpos="33"/>
<GROUPCOMPONENT name="new group" id="7abc643f4d6a2dbf" memberName="groupComponent5"
virtualName="" explicitFocusOrder="0" pos="16 8 408 64" outlinecol="ff007f00"
textcol="ff007f00" title="Emulator" textpos="33"/>
virtualName="" explicitFocusOrder="0" pos="24 624 408 64" outlinecol="ff007f00"
textcol="ff007f00" title="Emulator (currently locked)" textpos="33"/>
<SLIDER name="emulator slider" id="88ec3755c4760ed9" memberName="emulatorSlider"
virtualName="" explicitFocusOrder="0" pos="200 32 40 24" thumbcol="ff00af00"
virtualName="" explicitFocusOrder="0" pos="208 648 40 24" thumbcol="ff00af00"
trackcol="7f007f00" textboxtext="ff007f00" textboxbkgd="ff000000"
textboxhighlight="ff00af00" min="0" max="1" int="1" style="LinearHorizontal"
textBoxPos="NoTextBox" textBoxEditable="0" textBoxWidth="44"
textBoxHeight="20" skewFactor="1"/>
<LABEL name="emulator label" id="22c2c30d0f337081" memberName="emulatorLabel"
virtualName="" explicitFocusOrder="0" pos="112 32 72 24" tooltip="Use the OPL emulator from the DOSBox project"
virtualName="" explicitFocusOrder="0" pos="120 648 72 24" tooltip="Use the OPL emulator from the DOSBox project"
textCol="ff007f00" edTextCol="ff000000" edBkgCol="0" labelText="DOSBox"
editableSingleClick="0" editableDoubleClick="0" focusDiscardsChanges="0"
fontname="Default font" fontsize="15" bold="0" italic="0" justification="34"/>
<LABEL name="emulator label" id="4f8869b5724c0195" memberName="emulatorLabel2"
virtualName="" explicitFocusOrder="0" pos="248 32 72 24" tooltip="Use the OPL emulator from the ZDoom project"
virtualName="" explicitFocusOrder="0" pos="256 648 72 24" tooltip="Use the OPL emulator from the ZDoom project"
textCol="ff007f00" edTextCol="ff000000" edBkgCol="0" labelText="ZDoom"
editableSingleClick="0" editableDoubleClick="0" focusDiscardsChanges="0"
fontname="Default font" fontsize="15" bold="0" italic="0" justification="33"/>

View File

@ -7,12 +7,12 @@
the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
and re-saved.
Created with Introjucer version: 3.1.0
Created with Introjucer version: 4.1.0
------------------------------------------------------------------------------
The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-13 by Raw Material Software Ltd.
Copyright (c) 2015 - ROLI Ltd.
==============================================================================
*/

View File

@ -3,7 +3,6 @@
#include "EnumFloatParameter.h"
#include "IntFloatParameter.h"
#include "SbiLoader.h"
#include "SbiWriter.h"
const char *AdlibBlasterAudioProcessor::PROGRAM_INDEX = "Program Index";
@ -13,7 +12,7 @@ AdlibBlasterAudioProcessor::AdlibBlasterAudioProcessor()
{
// Initalize OPL
velocity = false;
Opl = new Hiopl(44100); // 1 second at 44100
Opl = new Hiopl();
Opl->SetSampleRate(44100);
Opl->EnableWaveformControl();
dro = new DROMultiplexer();

View File

@ -5,11 +5,11 @@
// A wrapper around the DOSBox and ZDoom OPL emulators.
Hiopl::Hiopl(int buflen, Emulator emulator) {
Hiopl::Hiopl(Emulator emulator) {
//InitCaptureVariables();
adlib = new DBOPL::Handler();
zdoom = JavaOPLCreate(false);
//zdoom = JavaOPLCreate(false);
// channels reordered to match
// 'in-memory' order in DOSBox emulator
@ -48,19 +48,21 @@ void Hiopl::SetEmulator(Emulator emulator) {
}
void Hiopl::Generate(int length, float* buffer) {
// This would be better done using Juce's built in audio format conversion.
if (DOSBOX == emulator) {
Bit32s* buf32 = new Bit32s[length];
adlib->Generate(length, buf32);
for (int i = 0; i < length; i++) {
// The magic divisor is tuned to match to ZDoom output amplitude.
buffer[i] = (float)(buf32[i])/8200.0f;
}
delete buf32;
} else if (ZDOOM == emulator) {
// ZDoom hacked to write mono samples
zdoom->Update(buffer, length);
intermediateBufIdx = (intermediateBufIdx + 1) % INTERMEDIATE_BUF_N;
Bit32s *iBuf = intermediateBuf[intermediateBufIdx];
adlib->Generate(length, iBuf);
for (int i = 0; i < length; i++) {
// Magic divisor taken from ZDoom wrapper for DOSBox emulator, line 892
// https://github.com/rheit/zdoom/blob/master/src/oplsynth/dosbox/opl.cpp
const float y = (float)(iBuf[i]) / 10240.0f;
// http://stackoverflow.com/questions/427477/fastest-way-to-clamp-a-real-fixed-floating-point-value
const float z = y < -1.0f ? -1.0f : y;
buffer[i] = z > 1.0f ? 1.0f : z;
}
//} else if (ZDOOM == emulator) {
// ZDoom hacked to write mono samples
// zdoom->Update(buffer, length);
//}
}
void Hiopl::SetSampleRate(int hz) {
@ -75,7 +77,7 @@ void Hiopl::_WriteReg(Bit32u reg, Bit8u value, Bit8u mask) {
//if (DOSBOX == emulator) {
adlib->WriteReg(reg, value);
//} else if (ZDOOM == emulator) {
zdoom->WriteReg(reg, value);
// zdoom->WriteReg(reg, value);
//}
regCache[reg] = value;
}
@ -212,9 +214,9 @@ void Hiopl::SetFrequency(int ch, float frqHz, bool keyOn) {
unsigned int fnum, block;
int offset = this->_GetOffset(ch);
// ZDoom emulator seems to be tuned down by two semitones for some reason. Sample rate difference?
if (ZDOOM == emulator) {
frqHz *= 1.122461363636364f;
}
//if (ZDOOM == emulator) {
// frqHz *= 1.122461363636364f;
//}
_milliHertzToFnum((unsigned int)(frqHz * 1000.0), &fnum, &block);
_WriteReg(0xa0+offset, fnum % 0x100);
uint8 trig = (regCache[0xb0+offset] & 0x20) | (keyOn ? 0x20 : 0x00);

View File

@ -4,6 +4,13 @@
#include "adlib.h"
#include "dbopl.h"
#include "zdopl.h"
// Integer buffer used by DOSBox OPL emulator, later converted to floating point.
// Number of 32-bit samples to use. ~1 MB per buffer. Probably excessive, but should be safe.
// In future, consider using samplesPerBlock value in AdlibBlasterAudioProcessor::prepareToPlay
#define INTERMEDIATE_BUF_SAMPLES 100000
// Number of static buffers to use. Again probably excessive, but let's be safe.
#define INTERMEDIATE_BUF_N 4
enum Waveform
{
@ -29,7 +36,7 @@ class Hiopl {
public:
static const int CHANNELS = 9;
static const int OSCILLATORS = 2;
Hiopl(int buflen, Emulator emulator = ZDOOM);
Hiopl(Emulator emulator = DOSBOX);
void SetEmulator(Emulator emulator);
void SetPercussionMode(bool enable);
void HitPercussion(Drum drum);
@ -82,6 +89,8 @@ class Hiopl {
DBOPL::Handler *adlib;
OPLEmul *zdoom;
Bit8u regCache[256];
int intermediateBufIdx;
Bit32s intermediateBuf[INTERMEDIATE_BUF_N][INTERMEDIATE_BUF_SAMPLES];
bool _CheckParams(int ch, int osc);
void _milliHertzToFnum(unsigned int milliHertz, unsigned int *fnum, unsigned int *block, unsigned int conversionFactor=49716);
void _ClearRegisters();

1018
Source/nkopl3.cpp Normal file

File diff suppressed because it is too large Load Diff

238
Source/nkopl3.h Normal file
View File

@ -0,0 +1,238 @@
/*
* Copyright (C) 2013-2015 Nuke.YKT(Alexey Khokholov)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
Nuked Yamaha YMF262(aka 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.
*/
//version 1.6
//#include "opl.h"
// for typedefs
#include "config.h"
/*
typedef uintptr_t Bitu;
typedef intptr_t Bits;
typedef DWORD Bit32u;
typedef SDWORD Bit32s;
typedef WORD Bit16u;
typedef SWORD Bit16s;
typedef BYTE Bit8u;
typedef SBYTE Bit8s;
*/
// Channel types
enum {
ch_2op = 0,
ch_4op = 1,
ch_4op2 = 2,
ch_drum = 3
};
// Envelope key types
enum {
egk_norm = 0x01,
egk_drum = 0x02
};
//
// logsin table
//
static const Bit16u logsinrom[256] = {
0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365,
0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261,
0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd,
0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166,
0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118,
0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db,
0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9,
0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081,
0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060,
0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045,
0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f,
0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e,
0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011,
0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007,
0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002,
0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000
};
//
// exp table
//
static const Bit16u exprom[256] = {
0x000, 0x003, 0x006, 0x008, 0x00b, 0x00e, 0x011, 0x014, 0x016, 0x019, 0x01c, 0x01f, 0x022, 0x025, 0x028, 0x02a,
0x02d, 0x030, 0x033, 0x036, 0x039, 0x03c, 0x03f, 0x042, 0x045, 0x048, 0x04b, 0x04e, 0x051, 0x054, 0x057, 0x05a,
0x05d, 0x060, 0x063, 0x066, 0x069, 0x06c, 0x06f, 0x072, 0x075, 0x078, 0x07b, 0x07e, 0x082, 0x085, 0x088, 0x08b,
0x08e, 0x091, 0x094, 0x098, 0x09b, 0x09e, 0x0a1, 0x0a4, 0x0a8, 0x0ab, 0x0ae, 0x0b1, 0x0b5, 0x0b8, 0x0bb, 0x0be,
0x0c2, 0x0c5, 0x0c8, 0x0cc, 0x0cf, 0x0d2, 0x0d6, 0x0d9, 0x0dc, 0x0e0, 0x0e3, 0x0e7, 0x0ea, 0x0ed, 0x0f1, 0x0f4,
0x0f8, 0x0fb, 0x0ff, 0x102, 0x106, 0x109, 0x10c, 0x110, 0x114, 0x117, 0x11b, 0x11e, 0x122, 0x125, 0x129, 0x12c,
0x130, 0x134, 0x137, 0x13b, 0x13e, 0x142, 0x146, 0x149, 0x14d, 0x151, 0x154, 0x158, 0x15c, 0x160, 0x163, 0x167,
0x16b, 0x16f, 0x172, 0x176, 0x17a, 0x17e, 0x181, 0x185, 0x189, 0x18d, 0x191, 0x195, 0x199, 0x19c, 0x1a0, 0x1a4,
0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc, 0x1c0, 0x1c4, 0x1c8, 0x1cc, 0x1d0, 0x1d4, 0x1d8, 0x1dc, 0x1e0, 0x1e4,
0x1e8, 0x1ec, 0x1f0, 0x1f5, 0x1f9, 0x1fd, 0x201, 0x205, 0x209, 0x20e, 0x212, 0x216, 0x21a, 0x21e, 0x223, 0x227,
0x22b, 0x230, 0x234, 0x238, 0x23c, 0x241, 0x245, 0x249, 0x24e, 0x252, 0x257, 0x25b, 0x25f, 0x264, 0x268, 0x26d,
0x271, 0x276, 0x27a, 0x27f, 0x283, 0x288, 0x28c, 0x291, 0x295, 0x29a, 0x29e, 0x2a3, 0x2a8, 0x2ac, 0x2b1, 0x2b5,
0x2ba, 0x2bf, 0x2c4, 0x2c8, 0x2cd, 0x2d2, 0x2d6, 0x2db, 0x2e0, 0x2e5, 0x2e9, 0x2ee, 0x2f3, 0x2f8, 0x2fd, 0x302,
0x306, 0x30b, 0x310, 0x315, 0x31a, 0x31f, 0x324, 0x329, 0x32e, 0x333, 0x338, 0x33d, 0x342, 0x347, 0x34c, 0x351,
0x356, 0x35b, 0x360, 0x365, 0x36a, 0x370, 0x375, 0x37a, 0x37f, 0x384, 0x38a, 0x38f, 0x394, 0x399, 0x39f, 0x3a4,
0x3a9, 0x3ae, 0x3b4, 0x3b9, 0x3bf, 0x3c4, 0x3c9, 0x3cf, 0x3d4, 0x3da, 0x3df, 0x3e4, 0x3ea, 0x3ef, 0x3f5, 0x3fa
};
//
// freq mult table multiplied by 2
//
// 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15
//
static const Bit8u mt[16] = { 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 };
//
// ksl table
//
static const Bit8u kslrom[16] = { 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 };
static const Bit8u kslshift[4] = { 8, 1, 2, 0 };
//
// LFO vibrato
//
static const Bit8u vib_table[8] = { 3, 1, 0, 1, 3, 1, 0, 1 };
static const Bit8s vibsgn_table[8] = { 1, 1, 1, 1, -1, -1, -1, -1 };
//
// envelope generator constants
//
static const Bit8u eg_incstep[3][4][8] = {
{ { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } },
{ { 0, 1, 0, 1, 0, 1, 0, 1 }, { 0, 1, 0, 1, 1, 1, 0, 1 }, { 0, 1, 1, 1, 0, 1, 1, 1 }, { 0, 1, 1, 1, 1, 1, 1, 1 } },
{ { 1, 1, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 1, 1, 1, 1 }, { 2, 2, 1, 1, 2, 2, 1, 1 }, { 2, 2, 2, 2, 2, 2, 1, 1 } }
};
static const Bit8u eg_incdesc[16] = {
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2
};
static const Bit8s eg_incsh[16] = {
0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -1, -2
};
//
// address decoding
//
static const Bit8s ad_slot[0x20] = { 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
static const Bit8u ch_slot[18] = { 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 };
struct opl_chip;
struct opl_slot;
struct opl_channel;
struct opl_slot {
opl_channel *channel;
opl_chip *chip;
Bit16s out;
Bit16s fbmod;
Bit16s *mod;
Bit16s prout[2];
Bit16s eg_rout;
Bit16s eg_out;
Bit8u eg_inc;
Bit8u eg_gen;
Bit8u eg_rate;
Bit8u eg_ksl;
Bit8u *trem;
Bit8u reg_vib;
Bit8u reg_type;
Bit8u reg_ksr;
Bit8u reg_mult;
Bit8u reg_ksl;
Bit8u reg_tl;
Bit8u reg_ar;
Bit8u reg_dr;
Bit8u reg_sl;
Bit8u reg_rr;
Bit8u reg_wf;
Bit8u key;
Bit32u pg_phase;
};
struct opl_channel {
opl_slot *slots[2];
opl_channel *pair;
opl_chip *chip;
Bit16s *out[4];
Bit8u chtype;
Bit16u f_num;
Bit8u block;
Bit8u fb;
Bit8u con;
Bit8u alg;
Bit8u ksv;
Bit16u cha, chb;
float fcha, fchb;
};
struct opl_chip {
opl_channel channel[18];
opl_slot slot[36];
Bit16u timer;
Bit8u newm;
Bit8u nts;
Bit8u dvb;
Bit8u dam;
Bit8u rhy;
Bit8u vibpos;
Bit8u tremval;
Bit8u tremtval;
Bit8u tremdir;
Bit32u noise;
Bit16s zeromod;
Bit32s mixbuff[2];
Bit8u FullPan;
};
class NukedOPL3 { // (from ZDoom) : public OPLEmul {
private:
opl_chip opl3;
bool FullPan;
public:
void Reset();
void Update(float* sndptr, int numsamples);
void WriteReg(Bit32u reg, Bit8u v);
void SetPanning(int c, float left, float right);
NukedOPL3(bool stereo);
};