- Disable ZDoom mode.
- Used statically allocated intermediate integer buffer. - Adjust DOSBox output scaling and add clamping.
This commit is contained in:
parent
63aa06b044
commit
0309b92e97
8 changed files with 1319 additions and 50 deletions
|
@ -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"
|
||||
|
|
|
@ -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 -3.0 -1.5 -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"/>
|
||||
|
|
|
@ -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.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
1018
Source/nkopl3.cpp
Normal file
File diff suppressed because it is too large
Load diff
238
Source/nkopl3.h
Normal file
238
Source/nkopl3.h
Normal 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);
|
||||
};
|
Loading…
Reference in a new issue