diff --git a/CMakeLists.txt b/CMakeLists.txt index 264b9eaef..8dfead964 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -381,7 +381,6 @@ set( LZMA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/lzma/C" ) set( GDTOA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/gdtoa" ) set( ZMUSIC_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/zmusic" ) set( TIMIDITYPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/timidityplus" ) -set( OPLSYNTH_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/oplsynth" ) set( GME_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries/game-music-emu" ) if( NOT CMAKE_CROSSCOMPILING ) @@ -403,7 +402,6 @@ endif() add_subdirectory( libraries/lzma ) add_subdirectory( libraries/dumb ) add_subdirectory( libraries/game-music-emu) -add_subdirectory( libraries/oplsynth ) add_subdirectory( libraries/timidityplus ) add_subdirectory( libraries/zmusic ) add_subdirectory( tools ) diff --git a/libraries/oplsynth/CMakeLists.txt b/libraries/oplsynth/CMakeLists.txt deleted file mode 100644 index 379e72f83..000000000 --- a/libraries/oplsynth/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -cmake_minimum_required( VERSION 2.8.7 ) - -use_fast_math() -require_stricmp() -require_strnicmp() - -if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -fomit-frame-pointer" ) - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" ) -endif() - -include_directories( oplsynth ) - -file( GLOB HEADER_FILES - oplsynth/*.h - ) -add_library( oplsynth STATIC - fmopl.cpp - musicblock.cpp - nukedopl3.cpp - opl_mus_player.cpp - OPL3.cpp - oplio.cpp - dosbox/opl.cpp - ) -target_link_libraries( oplsynth ) diff --git a/libraries/oplsynth/OPL3.cpp b/libraries/oplsynth/OPL3.cpp deleted file mode 100644 index be1c717e6..000000000 --- a/libraries/oplsynth/OPL3.cpp +++ /dev/null @@ -1,1875 +0,0 @@ -/* - * File: OPL3.java - * Software implementation of the Yamaha YMF262 sound generator. - * Copyright (C) 2008 Robson Cozendey - * - * 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 - * - * One of the objectives of this emulator is to stimulate further research in the - * OPL3 chip emulation. There was an explicit effort in making no optimizations, - * and making the code as legible as possible, so that a new programmer - * interested in modify and improve upon it could do so more easily. - * This emulator's main body of information was taken from reverse engineering of - * the OPL3 chip, from the YMF262 Datasheet and from the OPL3 section in the - * YMF278b Application's Manual, - * together with the vibrato table information, eighth waveform parameter - * information and feedback averaging information provided in MAME's YMF262 and - * YM3812 emulators, by Jarek Burczynski and Tatsuyuki Satoh. - * This emulator has a high degree of accuracy, and most of music files sound - * almost identical, exception made in some games which uses specific parts of - * the rhythm section. In this respect, some parts of the rhythm mode are still - * only an approximation of the real chip. - * The other thing to note is that this emulator was done through recordings of - * the SB16 DAC, so it has not bitwise precision. Additional equipment should be - * used to verify the samples directly from the chip, and allow this exact - * per-sample correspondence. As a good side-effect, since this emulator uses - * floating point and has a more fine-grained envelope generator, it can produce - * sometimes a crystal-clear, denser kind of OPL3 sound that, because of that, - * may be useful for creating new music. - * - * Version 1.0.6 - * - */ - -#include -#include -#include -#include - -#include "opl.h" -#include "opl3_Float.h" - -#define VOLUME_MUL 0.3333 - -static const double OPL_PI = 3.14159265358979323846; // matches value in gcc v2 math.h - -namespace JavaOPL3 -{ - -class Operator; - -static inline double StripIntPart(double num) -{ -#if 0 - double dontcare; - return modf(num, &dontcare); -#else - return num - xs_RoundToInt(num); -#endif -} - -// -// Channels -// - - -class Channel -{ -protected: - double feedback[2]; - - int fnuml, fnumh, kon, block, fb, cha, chb, cnt; - - // Factor to convert between normalized amplitude to normalized - // radians. The amplitude maximum is equivalent to 8*Pi radians. -#define toPhase (4.f) - -public: - int channelBaseAddress; - - double leftPan, rightPan; - - Channel (int baseAddress, double startvol); - virtual ~Channel() {} - void update_2_KON1_BLOCK3_FNUMH2(class OPL3 *OPL3); - void update_FNUML8(class OPL3 *OPL3); - void update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(class OPL3 *OPL3); - void updateChannel(class OPL3 *OPL3); - void updatePan(class OPL3 *OPL3); - virtual double getChannelOutput(class OPL3 *OPL3) = 0; - - virtual void keyOn() = 0; - virtual void keyOff() = 0; - virtual void updateOperators(class OPL3 *OPL3) = 0; -}; - - -class Channel2op : public Channel -{ -public: - Operator *op1, *op2; - - Channel2op (int baseAddress, double startvol, Operator *o1, Operator *o2); - double getChannelOutput(class OPL3 *OPL3); - - void keyOn(); - void keyOff(); - void updateOperators(class OPL3 *OPL3); -}; - - -class Channel4op : public Channel -{ -public: - Operator *op1, *op2, *op3, *op4; - - Channel4op (int baseAddress, double startvol, Operator *o1, Operator *o2, Operator *o3, Operator *o4); - double getChannelOutput(class OPL3 *OPL3); - - void keyOn(); - void keyOff(); - void updateOperators(class OPL3 *OPL3); -}; - -// There's just one instance of this class, that fills the eventual gaps in the Channel array; -class DisabledChannel : public Channel -{ -public: - DisabledChannel() : Channel(0, 0) { } - double getChannelOutput(class OPL3 *OPL3) { return 0; } - void keyOn() { } - void keyOff() { } - void updateOperators(class OPL3 *OPL3) { } -}; - - - -// -// Envelope Generator -// - - -class EnvelopeGenerator -{ -public: - enum Stage {ATTACK,DECAY,SUSTAIN,RELEASE,OFF}; - Stage stage; - int actualAttackRate, actualDecayRate, actualReleaseRate; - double xAttackIncrement, xMinimumInAttack; - double dBdecayIncrement; - double dBreleaseIncrement; - double attenuation, totalLevel, sustainLevel; - double x, envelope; - -public: - EnvelopeGenerator(); - void setActualSustainLevel(int sl); - void setTotalLevel(int tl); - void setAtennuation(int f_number, int block, int ksl); - void setActualAttackRate(int attackRate, int ksr, int keyScaleNumber); - void setActualDecayRate(int decayRate, int ksr, int keyScaleNumber); - void setActualReleaseRate(int releaseRate, int ksr, int keyScaleNumber); -private: - int calculateActualRate(int rate, int ksr, int keyScaleNumber); -public: - double getEnvelope(OPL3 *OPL3, int egt, int am); - void keyOn(); - void keyOff(); - -private: - static double dBtoX(double dB); - static double percentageToDB(double percentage); - static double percentageToX(double percentage); -}; - - -// -// Phase Generator -// - - -class PhaseGenerator { - double phase, phaseIncrement; - -public: - PhaseGenerator(); - void setFrequency(int f_number, int block, int mult); - double getPhase(class OPL3 *OPL3, int vib); - void keyOn(); -}; - - -// -// Operators -// - - -class Operator -{ -public: - PhaseGenerator phaseGenerator; - EnvelopeGenerator envelopeGenerator; - - double envelope, phase; - - int operatorBaseAddress; - int am, vib, ksr, egt, mult, ksl, tl, ar, dr, sl, rr, ws; - int keyScaleNumber, f_number, block; - - static const double noModulator; - -public: - Operator(int baseAddress); - void update_AM1_VIB1_EGT1_KSR1_MULT4(class OPL3 *OPL3); - void update_KSL2_TL6(class OPL3 *OPL3); - void update_AR4_DR4(class OPL3 *OPL3); - void update_SL4_RR4(class OPL3 *OPL3); - void update_5_WS3(class OPL3 *OPL3); - double getOperatorOutput(class OPL3 *OPL3, double modulator); - - void keyOn(); - void keyOff(); - void updateOperator(class OPL3 *OPL3, int ksn, int f_num, int blk); -protected: - double getOutput(double modulator, double outputPhase, double *waveform); -}; - - -// -// Rhythm -// - -// The getOperatorOutput() method in TopCymbalOperator, HighHatOperator and SnareDrumOperator -// were made through purely empyrical reverse engineering of the OPL3 output. - -class RhythmChannel : public Channel2op -{ -public: - RhythmChannel(int baseAddress, double startvol, Operator *o1, Operator *o2) - : Channel2op(baseAddress, startvol, o1, o2) - { } - double getChannelOutput(class OPL3 *OPL3); - - // Rhythm channels are always running, - // only the envelope is activated by the user. - void keyOn() { } - void keyOff() { } -}; - -class HighHatSnareDrumChannel : public RhythmChannel { - static const int highHatSnareDrumChannelBaseAddress = 7; -public: - HighHatSnareDrumChannel(double startvol, Operator *o1, Operator *o2) - : RhythmChannel(highHatSnareDrumChannelBaseAddress, startvol, o1, o2) - { } -}; - -class TomTomTopCymbalChannel : public RhythmChannel { - static const int tomTomTopCymbalChannelBaseAddress = 8; -public: - TomTomTopCymbalChannel(double startvol, Operator *o1, Operator *o2) - : RhythmChannel(tomTomTopCymbalChannelBaseAddress, startvol, o1, o2) - { } -}; - -class TopCymbalOperator : public Operator { - static const int topCymbalOperatorBaseAddress = 0x15; -public: - TopCymbalOperator(int baseAddress); - TopCymbalOperator(); - double getOperatorOutput(class OPL3 *OPL3, double modulator); - double getOperatorOutput(class OPL3 *OPL3, double modulator, double externalPhase); -}; - -class HighHatOperator : public TopCymbalOperator { - static const int highHatOperatorBaseAddress = 0x11; -public: - HighHatOperator(); - double getOperatorOutput(class OPL3 *OPL3, double modulator); -}; - -class SnareDrumOperator : public Operator { - static const int snareDrumOperatorBaseAddress = 0x14; -public: - SnareDrumOperator(); - double getOperatorOutput(class OPL3 *OPL3, double modulator); -}; - -class TomTomOperator : public Operator { - static const int tomTomOperatorBaseAddress = 0x12; -public: - TomTomOperator() : Operator(tomTomOperatorBaseAddress) { } -}; - -class BassDrumChannel : public Channel2op { - static const int bassDrumChannelBaseAddress = 6; - static const int op1BaseAddress = 0x10; - static const int op2BaseAddress = 0x13; - - Operator my_op1, my_op2; - -public: - BassDrumChannel(double startvol); - double getChannelOutput(class OPL3 *OPL3); - - // Key ON and OFF are unused in rhythm channels. - void keyOn() { } - void keyOff() { } -}; - - -// -// OPl3 Data -// - - -struct OPL3DataStruct -{ -public: - // OPL3-wide registers offsets: - static const int - _1_NTS1_6_Offset = 0x08, - DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1_Offset = 0xBD, - _7_NEW1_Offset = 0x105, - _2_CONNECTIONSEL6_Offset = 0x104; - - // The OPL3 tremolo repetition rate is 3.7 Hz. - #define tremoloFrequency (3.7) - - static const int tremoloTableLength = (int)(OPL_SAMPLE_RATE/tremoloFrequency); - static const int vibratoTableLength = 8192; - - OPL3DataStruct() - { - loadVibratoTable(); - loadTremoloTable(); - } - - // The first array is used when DVB=0 and the second array is used when DVB=1. - double vibratoTable[2][vibratoTableLength]; - - // First array used when AM = 0 and second array used when AM = 1. - double tremoloTable[2][tremoloTableLength]; - - static double calculateIncrement(double begin, double end, double period) { - return (end-begin)/OPL_SAMPLE_RATE * (1/period); - } - -private: - void loadVibratoTable(); - void loadTremoloTable(); -}; - - -// -// Channel Data -// - - -struct ChannelData -{ - static const int - _2_KON1_BLOCK3_FNUMH2_Offset = 0xB0, - FNUML8_Offset = 0xA0, - CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset = 0xC0; - - // Feedback rate in fractions of 2*Pi, normalized to (0,1): - // 0, Pi/16, Pi/8, Pi/4, Pi/2, Pi, 2*Pi, 4*Pi turns to be: - static const float feedback[8]; -}; -const float ChannelData::feedback[8] = {0,1/32.f,1/16.f,1/8.f,1/4.f,1/2.f,1,2}; - - -// -// Operator Data -// - - -struct OperatorDataStruct -{ - static const int - AM1_VIB1_EGT1_KSR1_MULT4_Offset = 0x20, - KSL2_TL6_Offset = 0x40, - AR4_DR4_Offset = 0x60, - SL4_RR4_Offset = 0x80, - _5_WS3_Offset = 0xE0; - - enum type {NO_MODULATION, CARRIER, FEEDBACK}; - - static const int waveLength = 1024; - - static const float multTable[16]; - static const float ksl3dBtable[16][8]; - - //OPL3 has eight waveforms: - double waveforms[8][waveLength]; - -#define MIN_DB (-120.0) -#define DB_TABLE_RES (4.0) -#define DB_TABLE_SIZE (int)(-MIN_DB * DB_TABLE_RES) - - double dbpow[DB_TABLE_SIZE]; - -#define ATTACK_MIN (-5.0) -#define ATTACK_MAX (8.0) -#define ATTACK_RES (0.03125) -#define ATTACK_TABLE_SIZE (int)((ATTACK_MAX - ATTACK_MIN) / ATTACK_RES) - - double attackTable[ATTACK_TABLE_SIZE]; - - OperatorDataStruct() - { - loadWaveforms(); - loaddBPowTable(); - loadAttackTable(); - } - - static double log2(double x) { - return log(x)/log(2.0); - } -private: - void loadWaveforms(); - void loaddBPowTable(); - void loadAttackTable(); -}; -const float OperatorDataStruct::multTable[16] = {0.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15}; - -const float OperatorDataStruct::ksl3dBtable[16][8] = { - {0,0,0,0,0,0,0,0}, - {0,0,0,0,0,-3,-6,-9}, - {0,0,0,0,-3,-6,-9,-12}, - {0,0,0, -1.875, -4.875, -7.875, -10.875, -13.875}, - - {0,0,0,-3,-6,-9,-12,-15}, - {0,0, -1.125, -4.125, -7.125, -10.125, -13.125, -16.125}, - {0,0, -1.875, -4.875, -7.875, -10.875, -13.875, -16.875}, - {0,0, -2.625, -5.625, -8.625, -11.625, -14.625, -17.625}, - - {0,0,-3,-6,-9,-12,-15,-18}, - {0, -0.750, -3.750, -6.750, -9.750, -12.750, -15.750, -18.750}, - {0, -1.125, -4.125, -7.125, -10.125, -13.125, -16.125, -19.125}, - {0, -1.500, -4.500, -7.500, -10.500, -13.500, -16.500, -19.500}, - - {0, -1.875, -4.875, -7.875, -10.875, -13.875, -16.875, -19.875}, - {0, -2.250, -5.250, -8.250, -11.250, -14.250, -17.250, -20.250}, - {0, -2.625, -5.625, -8.625, -11.625, -14.625, -17.625, -20.625}, - {0,-3,-6,-9,-12,-15,-18,-21} -}; - -// -// Envelope Generator Data -// - - -namespace EnvelopeGeneratorData -{ - static const double MUGEN = std::numeric_limits::infinity(); - // This table is indexed by the value of Operator.ksr - // and the value of ChannelRegister.keyScaleNumber. - static const int rateOffset[2][16] = { - {0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3}, - {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} - }; - // These attack periods in miliseconds were taken from the YMF278B manual. - // The attack actual rates range from 0 to 63, with different data for - // 0%-100% and for 10%-90%: - static const double attackTimeValuesTable[64][2] = { - {MUGEN,MUGEN}, {MUGEN,MUGEN}, {MUGEN,MUGEN}, {MUGEN,MUGEN}, - {2826.24,1482.75}, {2252.80,1155.07}, {1884.16,991.23}, {1597.44,868.35}, - {1413.12,741.38}, {1126.40,577.54}, {942.08,495.62}, {798.72,434.18}, - {706.56,370.69}, {563.20,288.77}, {471.04,247.81}, {399.36,217.09}, - - {353.28,185.34}, {281.60,144.38}, {235.52,123.90}, {199.68,108.54}, - {176.76,92.67}, {140.80,72.19}, {117.76,61.95}, {99.84,54.27}, - {88.32,46.34}, {70.40,36.10}, {58.88,30.98}, {49.92,27.14}, - {44.16,23.17}, {35.20,18.05}, {29.44,15.49}, {24.96,13.57}, - - {22.08,11.58}, {17.60,9.02}, {14.72,7.74}, {12.48,6.78}, - {11.04,5.79}, {8.80,4.51}, {7.36,3.87}, {6.24,3.39}, - {5.52,2.90}, {4.40,2.26}, {3.68,1.94}, {3.12,1.70}, - {2.76,1.45}, {2.20,1.13}, {1.84,0.97}, {1.56,0.85}, - - {1.40,0.73}, {1.12,0.61}, {0.92,0.49}, {0.80,0.43}, - {0.70,0.37}, {0.56,0.31}, {0.46,0.26}, {0.42,0.22}, - {0.38,0.19}, {0.30,0.14}, {0.24,0.11}, {0.20,0.11}, - {0.00,0.00}, {0.00,0.00}, {0.00,0.00}, {0.00,0.00} - }; - - // These decay and release periods in milliseconds were taken from the YMF278B manual. - // The rate index range from 0 to 63, with different data for - // 0%-100% and for 10%-90%: - static const double decayAndReleaseTimeValuesTable[64][2] = { - {MUGEN,MUGEN}, {MUGEN,MUGEN}, {MUGEN,MUGEN}, {MUGEN,MUGEN}, - {39280.64,8212.48}, {31416.32,6574.08}, {26173.44,5509.12}, {22446.08,4730.88}, - {19640.32,4106.24}, {15708.16,3287.04}, {13086.72,2754.56}, {11223.04,2365.44}, - {9820.16,2053.12}, {7854.08,1643.52}, {6543.36,1377.28}, {5611.52,1182.72}, - - {4910.08,1026.56}, {3927.04,821.76}, {3271.68,688.64}, {2805.76,591.36}, - {2455.04,513.28}, {1936.52,410.88}, {1635.84,344.34}, {1402.88,295.68}, - {1227.52,256.64}, {981.76,205.44}, {817.92,172.16}, {701.44,147.84}, - {613.76,128.32}, {490.88,102.72}, {488.96,86.08}, {350.72,73.92}, - - {306.88,64.16}, {245.44,51.36}, {204.48,43.04}, {175.36,36.96}, - {153.44,32.08}, {122.72,25.68}, {102.24,21.52}, {87.68,18.48}, - {76.72,16.04}, {61.36,12.84}, {51.12,10.76}, {43.84,9.24}, - {38.36,8.02}, {30.68,6.42}, {25.56,5.38}, {21.92,4.62}, - - {19.20,4.02}, {15.36,3.22}, {12.80,2.68}, {10.96,2.32}, - {9.60,2.02}, {7.68,1.62}, {6.40,1.35}, {5.48,1.15}, - {4.80,1.01}, {3.84,0.81}, {3.20,0.69}, {2.74,0.58}, - {2.40,0.51}, {2.40,0.51}, {2.40,0.51}, {2.40,0.51} - }; -}; - -class OPL3 : public OPLEmul -{ -public: - uint8_t registers[0x200]; - - Operator *operators[2][0x20]; - Channel2op *channels2op[2][9]; - Channel4op *channels4op[2][3]; - Channel *channels[2][9]; - - // Unique instance to fill future gaps in the Channel array, - // when there will be switches between 2op and 4op mode. - DisabledChannel disabledChannel; - - // Specific operators to switch when in rhythm mode: - HighHatOperator highHatOperator; - SnareDrumOperator snareDrumOperator; - TomTomOperator tomTomOperator; - TomTomTopCymbalChannel tomTomTopCymbalChannel; - - // Rhythm channels - BassDrumChannel bassDrumChannel; - HighHatSnareDrumChannel highHatSnareDrumChannel; - TopCymbalOperator topCymbalOperator; - - Operator *highHatOperatorInNonRhythmMode; - Operator *snareDrumOperatorInNonRhythmMode; - Operator *tomTomOperatorInNonRhythmMode; - Operator *topCymbalOperatorInNonRhythmMode; - - int nts, dam, dvb, ryt, bd, sd, tom, tc, hh, _new, connectionsel; - int vibratoIndex, tremoloIndex; - - bool FullPan; - - static OperatorDataStruct *OperatorData; - static OPL3DataStruct *OPL3Data; - - // The methods read() and write() are the only - // ones needed by the user to interface with the emulator. - // read() returns one frame at a time, to be played at 49700 Hz, - // with each frame being four 16-bit samples, - // corresponding to the OPL3 four output channels CHA...CHD. -public: - //void read(float output[2]); - void write(int array, int address, int data); - - OPL3(bool fullpan); - ~OPL3(); - -private: - void initOperators(); - void initChannels2op(); - void initChannels4op(); - void initRhythmChannels(); - void initChannels(); - void update_1_NTS1_6(); - void update_DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1(); - void update_7_NEW1(); - void setEnabledChannels(); - void updateChannelPans(); - void update_2_CONNECTIONSEL6(); - void set4opConnections(); - void setRhythmMode(); - - static int InstanceCount; - - // OPLEmul interface -public: - void Reset(); - void WriteReg(int reg, int v); - void Update(float *buffer, int length); - void SetPanning(int c, float left, float right); -}; - -OperatorDataStruct *OPL3::OperatorData; -OPL3DataStruct *OPL3::OPL3Data; -int OPL3::InstanceCount; - -void OPL3::Update(float *output, int numsamples) { - while (numsamples--) { - // If _new = 0, use OPL2 mode with 9 channels. If _new = 1, use OPL3 18 channels; - for(int array=0; array < (_new + 1); array++) - for(int channelNumber=0; channelNumber < 9; channelNumber++) { - // Reads output from each OPL3 channel, and accumulates it in the output buffer: - Channel *channel = channels[array][channelNumber]; - if (channel != &disabledChannel) - { - double channelOutput = channel->getChannelOutput(this); - output[0] += float(channelOutput * channel->leftPan); - output[1] += float(channelOutput * channel->rightPan); - } - } - - // Advances the OPL3-wide vibrato index, which is used by - // PhaseGenerator.getPhase() in each Operator. - vibratoIndex = (vibratoIndex + 1) & (OPL3DataStruct::vibratoTableLength - 1); - // Advances the OPL3-wide tremolo index, which is used by - // EnvelopeGenerator.getEnvelope() in each Operator. - tremoloIndex++; - if(tremoloIndex >= OPL3DataStruct::tremoloTableLength) tremoloIndex = 0; - output += 2; - } -} - -void OPL3::write(int array, int address, int data) { - // The OPL3 has two registers arrays, each with adresses ranging - // from 0x00 to 0xF5. - // This emulator uses one array, with the two original register arrays - // starting at 0x00 and at 0x100. - int registerAddress = (array<<8) | address; - // If the address is out of the OPL3 memory map, returns. - if(registerAddress<0 || registerAddress>=0x200) return; - - registers[registerAddress] = data; - switch(address&0xE0) { - // The first 3 bits masking gives the type of the register by using its base address: - // 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 - // When it is needed, we further separate the register type inside each base address, - // which is the case of 0x00 and 0xA0. - - // Through out this emulator we will use the same name convention to - // reference a byte with several bit registers. - // The name of each bit register will be followed by the number of bits - // it occupies inside the byte. - // Numbers without accompanying names are unused bits. - case 0x00: - // Unique registers for the entire OPL3: - if(array==1) { - if(address==0x04) - update_2_CONNECTIONSEL6(); - else if(address==0x05) - update_7_NEW1(); - } - else if(address==0x08) update_1_NTS1_6(); - break; - - case 0xA0: - // 0xBD is a control register for the entire OPL3: - if(address==0xBD) { - if(array==0) - update_DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1(); - break; - } - // Registers for each channel are in A0-A8, B0-B8, C0-C8, in both register arrays. - // 0xB0...0xB8 keeps kon,block,fnum(h) for each channel. - if( (address&0xF0) == 0xB0 && address <= 0xB8) { - // If the address is in the second register array, adds 9 to the channel number. - // The channel number is given by the last four bits, like in A0,...,A8. - channels[array][address&0x0F]->update_2_KON1_BLOCK3_FNUMH2(this); - break; - } - // 0xA0...0xA8 keeps fnum(l) for each channel. - if( (address&0xF0) == 0xA0 && address <= 0xA8) - channels[array][address&0x0F]->update_FNUML8(this); - break; - // 0xC0...0xC8 keeps cha,chb,chc,chd,fb,cnt for each channel: - case 0xC0: - if(address <= 0xC8) - channels[array][address&0x0F]->update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(this); - break; - - // Registers for each of the 36 Operators: - default: - int operatorOffset = address&0x1F; - if(operators[array][operatorOffset] == NULL) break; - switch(address&0xE0) { - // 0x20...0x35 keeps am,vib,egt,ksr,mult for each operator: - case 0x20: - operators[array][operatorOffset]->update_AM1_VIB1_EGT1_KSR1_MULT4(this); - break; - // 0x40...0x55 keeps ksl,tl for each operator: - case 0x40: - operators[array][operatorOffset]->update_KSL2_TL6(this); - break; - // 0x60...0x75 keeps ar,dr for each operator: - case 0x60: - operators[array][operatorOffset]->update_AR4_DR4(this); - break; - // 0x80...0x95 keeps sl,rr for each operator: - case 0x80: - operators[array][operatorOffset]->update_SL4_RR4(this); - break; - // 0xE0...0xF5 keeps ws for each operator: - case 0xE0: - operators[array][operatorOffset]->update_5_WS3(this); - } - } -} - -OPL3::OPL3(bool fullpan) -: tomTomTopCymbalChannel(fullpan ? CENTER_PANNING_POWER : 1, &tomTomOperator, &topCymbalOperator), - bassDrumChannel(fullpan ? CENTER_PANNING_POWER : 1), - highHatSnareDrumChannel(fullpan ? CENTER_PANNING_POWER : 1, &highHatOperator, &snareDrumOperator) -{ - FullPan = fullpan; - nts = dam = dvb = ryt = bd = sd = tom = tc = hh = _new = connectionsel = 0; - vibratoIndex = tremoloIndex = 0; - - if (InstanceCount++ == 0) - { - OPL3Data = new struct OPL3DataStruct; - OperatorData = new struct OperatorDataStruct; - } - - initOperators(); - initChannels2op(); - initChannels4op(); - initRhythmChannels(); - initChannels(); -} - -OPL3::~OPL3() -{ - ryt = 0; - setRhythmMode(); // Make sure all operators point to the dynamically allocated ones. - for (int array = 0; array < 2; array++) - { - for (int operatorNumber = 0; operatorNumber < 0x20; operatorNumber++) - { - if (operators[array][operatorNumber] != NULL) - { - delete operators[array][operatorNumber]; - } - } - for (int channelNumber = 0; channelNumber < 9; channelNumber++) - { - delete channels2op[array][channelNumber]; - } - for (int channelNumber = 0; channelNumber < 3; channelNumber++) - { - delete channels4op[array][channelNumber]; - } - } - if (--InstanceCount == 0) - { - delete OPL3Data; - OPL3Data = NULL; - delete OperatorData; - OperatorData = NULL; - } -} - - -void OPL3::initOperators() { - int baseAddress; - // The YMF262 has 36 operators: - memset(operators, 0, sizeof(operators)); - for(int array=0; array<2; array++) - for(int group = 0; group<=0x10; group+=8) - for(int offset=0; offset<6; offset++) { - baseAddress = (array<<8) | (group+offset); - operators[array][group+offset] = new Operator(baseAddress); - } - - // Save operators when they are in non-rhythm mode: - // Channel 7: - highHatOperatorInNonRhythmMode = operators[0][0x11]; - snareDrumOperatorInNonRhythmMode = operators[0][0x14]; - // Channel 8: - tomTomOperatorInNonRhythmMode = operators[0][0x12]; - topCymbalOperatorInNonRhythmMode = operators[0][0x15]; - -} - -void OPL3::initChannels2op() { - // The YMF262 has 18 2-op channels. - // Each 2-op channel can be at a serial or parallel operator configuration: - memset(channels2op, 0, sizeof(channels2op)); - double startvol = FullPan ? CENTER_PANNING_POWER : 1; - for(int array=0; array<2; array++) - for(int channelNumber=0; channelNumber<3; channelNumber++) { - int baseAddress = (array<<8) | channelNumber; - // Channels 1, 2, 3 -> Operator offsets 0x0,0x3; 0x1,0x4; 0x2,0x5 - channels2op[array][channelNumber] = new Channel2op(baseAddress, startvol, operators[array][channelNumber], operators[array][channelNumber+0x3]); - // Channels 4, 5, 6 -> Operator offsets 0x8,0xB; 0x9,0xC; 0xA,0xD - channels2op[array][channelNumber+3] = new Channel2op(baseAddress+3, startvol, operators[array][channelNumber+0x8], operators[array][channelNumber+0xB]); - // Channels 7, 8, 9 -> Operators 0x10,0x13; 0x11,0x14; 0x12,0x15 - channels2op[array][channelNumber+6] = new Channel2op(baseAddress+6, startvol, operators[array][channelNumber+0x10], operators[array][channelNumber+0x13]); - } -} - -void OPL3::initChannels4op() { - // The YMF262 has 3 4-op channels in each array: - memset(channels4op, 0, sizeof(channels4op)); - double startvol = FullPan ? CENTER_PANNING_POWER : 1; - for(int array=0; array<2; array++) - for(int channelNumber=0; channelNumber<3; channelNumber++) { - int baseAddress = (array<<8) | channelNumber; - // Channels 1, 2, 3 -> Operators 0x0,0x3,0x8,0xB; 0x1,0x4,0x9,0xC; 0x2,0x5,0xA,0xD; - channels4op[array][channelNumber] = new Channel4op(baseAddress, startvol, operators[array][channelNumber], operators[array][channelNumber+0x3], operators[array][channelNumber+0x8], operators[array][channelNumber+0xB]); - } -} - -void OPL3::initRhythmChannels() { -} - -void OPL3::initChannels() { - // Channel is an abstract class that can be a 2-op, 4-op, rhythm or disabled channel, - // depending on the OPL3 configuration at the time. - // channels[] inits as a 2-op serial channel array: - for(int array=0; array<2; array++) - for(int i=0; i<9; i++) channels[array][i] = channels2op[array][i]; -} - -void OPL3::update_1_NTS1_6() { - int _1_nts1_6 = registers[OPL3DataStruct::_1_NTS1_6_Offset]; - // Note Selection. This register is used in Channel.updateOperators() implementations, - // to calculate the channel´s Key Scale Number. - // The value of the actual envelope rate follows the value of - // OPL3.nts,Operator.keyScaleNumber and Operator.ksr - nts = (_1_nts1_6 & 0x40) >> 6; -} - -void OPL3::update_DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1() { - int dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 = registers[OPL3DataStruct::DAM1_DVB1_RYT1_BD1_SD1_TOM1_TC1_HH1_Offset]; - // Depth of amplitude. This register is used in EnvelopeGenerator.getEnvelope(); - dam = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x80) >> 7; - - // Depth of vibrato. This register is used in PhaseGenerator.getPhase(); - dvb = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x40) >> 6; - - int new_ryt = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x20) >> 5; - if(new_ryt != ryt) { - ryt = new_ryt; - setRhythmMode(); - } - - int new_bd = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x10) >> 4; - if(new_bd != bd) { - bd = new_bd; - if(bd==1) { - bassDrumChannel.op1->keyOn(); - bassDrumChannel.op2->keyOn(); - } - } - - int new_sd = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x08) >> 3; - if(new_sd != sd) { - sd = new_sd; - if(sd==1) snareDrumOperator.keyOn(); - } - - int new_tom = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x04) >> 2; - if(new_tom != tom) { - tom = new_tom; - if(tom==1) tomTomOperator.keyOn(); - } - - int new_tc = (dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x02) >> 1; - if(new_tc != tc) { - tc = new_tc; - if(tc==1) topCymbalOperator.keyOn(); - } - - int new_hh = dam1_dvb1_ryt1_bd1_sd1_tom1_tc1_hh1 & 0x01; - if(new_hh != hh) { - hh = new_hh; - if(hh==1) highHatOperator.keyOn(); - } - -} - -void OPL3::update_7_NEW1() { - int _7_new1 = registers[OPL3DataStruct::_7_NEW1_Offset]; - // OPL2/OPL3 mode selection. This register is used in - // OPL3.read(), OPL3.write() and Operator.getOperatorOutput(); - _new = (_7_new1 & 0x01); - if(_new==1) setEnabledChannels(); - set4opConnections(); - updateChannelPans(); -} - -void OPL3::setEnabledChannels() { - for(int array=0; array<2; array++) - for(int i=0; i<9; i++) { - int baseAddress = channels[array][i]->channelBaseAddress; - registers[baseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset] |= 0xF0; - channels[array][i]->update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(this); - } -} - -void OPL3::updateChannelPans() { - for(int array=0; array<2; array++) - for(int i=0; i<9; i++) { - int baseAddress = channels[array][i]->channelBaseAddress; - registers[baseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset] |= 0xF0; - channels[array][i]->updatePan(this); - } - -} - -void OPL3::update_2_CONNECTIONSEL6() { - // This method is called only if _new is set. - int _2_connectionsel6 = registers[OPL3DataStruct::_2_CONNECTIONSEL6_Offset]; - // 2-op/4-op channel selection. This register is used here to configure the OPL3.channels[] array. - connectionsel = (_2_connectionsel6 & 0x3F); - set4opConnections(); -} - -void OPL3::set4opConnections() { - // bits 0, 1, 2 sets respectively 2-op channels (1,4), (2,5), (3,6) to 4-op operation. - // bits 3, 4, 5 sets respectively 2-op channels (10,13), (11,14), (12,15) to 4-op operation. - for(int array=0; array<2; array++) - for(int i=0; i<3; i++) { - if(_new == 1) { - int shift = array*3 + i; - int connectionBit = (connectionsel >> shift) & 0x01; - if(connectionBit == 1) { - channels[array][i] = channels4op[array][i]; - channels[array][i+3] = &disabledChannel; - channels[array][i]->updateChannel(this); - continue; - } - } - channels[array][i] = channels2op[array][i]; - channels[array][i+3] = channels2op[array][i+3]; - channels[array][i]->updateChannel(this); - channels[array][i+3]->updateChannel(this); - } -} - -void OPL3::setRhythmMode() { - if(ryt==1) { - channels[0][6] = &bassDrumChannel; - channels[0][7] = &highHatSnareDrumChannel; - channels[0][8] = &tomTomTopCymbalChannel; - operators[0][0x11] = &highHatOperator; - operators[0][0x14] = &snareDrumOperator; - operators[0][0x12] = &tomTomOperator; - operators[0][0x15] = &topCymbalOperator; - } - else { - for(int i=6; i<=8; i++) channels[0][i] = channels2op[0][i]; - operators[0][0x11] = highHatOperatorInNonRhythmMode; - operators[0][0x14] = snareDrumOperatorInNonRhythmMode; - operators[0][0x12] = tomTomOperatorInNonRhythmMode; - operators[0][0x15] = topCymbalOperatorInNonRhythmMode; - } - for(int i=6; i<=8; i++) channels[0][i]->updateChannel(this); -} - -static double EnvelopeFromDB(double db) -{ -#if 0 - return pow(10.0, db/10); -#else - if (db < MIN_DB) - return 0; - return OPL3::OperatorData->dbpow[xs_FloorToInt(-db * DB_TABLE_RES)]; -#endif -} - -Channel::Channel (int baseAddress, double startvol) { - channelBaseAddress = baseAddress; - fnuml = fnumh = kon = block = fb = cnt = 0; - feedback[0] = feedback[1] = 0; - leftPan = rightPan = startvol; -} - -void Channel::update_2_KON1_BLOCK3_FNUMH2(OPL3 *OPL3) { - - int _2_kon1_block3_fnumh2 = OPL3->registers[channelBaseAddress+ChannelData::_2_KON1_BLOCK3_FNUMH2_Offset]; - - // Frequency Number (hi-register) and Block. These two registers, together with fnuml, - // sets the Channel´s base frequency; - block = (_2_kon1_block3_fnumh2 & 0x1C) >> 2; - fnumh = _2_kon1_block3_fnumh2 & 0x03; - updateOperators(OPL3); - - // Key On. If changed, calls Channel.keyOn() / keyOff(). - int newKon = (_2_kon1_block3_fnumh2 & 0x20) >> 5; - if(newKon != kon) { - if(newKon == 1) keyOn(); - else keyOff(); - kon = newKon; - } -} - -void Channel::update_FNUML8(OPL3 *OPL3) { - int fnuml8 = OPL3->registers[channelBaseAddress+ChannelData::FNUML8_Offset]; - // Frequency Number, low register. - fnuml = fnuml8&0xFF; - updateOperators(OPL3); -} - -void Channel::update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(OPL3 *OPL3) { - int chd1_chc1_chb1_cha1_fb3_cnt1 = OPL3->registers[channelBaseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset]; -// chd = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x80) >> 7; -// chc = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x40) >> 6; - chb = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x20) >> 5; - cha = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x10) >> 4; - fb = (chd1_chc1_chb1_cha1_fb3_cnt1 & 0x0E) >> 1; - cnt = chd1_chc1_chb1_cha1_fb3_cnt1 & 0x01; - updatePan(OPL3); - updateOperators(OPL3); -} - -void Channel::updatePan(OPL3 *OPL3) { - if (!OPL3->FullPan) - { - if (OPL3->_new == 0) - { - leftPan = VOLUME_MUL; - rightPan = VOLUME_MUL; - } - else - { - leftPan = cha * VOLUME_MUL; - rightPan = chb * VOLUME_MUL; - } - } -} - -void Channel::updateChannel(OPL3 *OPL3) { - update_2_KON1_BLOCK3_FNUMH2(OPL3); - update_FNUML8(OPL3); - update_CHD1_CHC1_CHB1_CHA1_FB3_CNT1(OPL3); -} - -Channel2op::Channel2op (int baseAddress, double startvol, Operator *o1, Operator *o2) -: Channel(baseAddress, startvol) -{ - op1 = o1; - op2 = o2; -} - -double Channel2op::getChannelOutput(OPL3 *OPL3) { - double channelOutput = 0, op1Output = 0, op2Output = 0; - // The feedback uses the last two outputs from - // the first operator, instead of just the last one. - double feedbackOutput = (feedback[0] + feedback[1]) / 2; - - switch(cnt) { - // CNT = 0, the operators are in series, with the first in feedback. - case 0: - if(op2->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return 0; - op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); - channelOutput = op2->getOperatorOutput(OPL3, op1Output*toPhase); - break; - // CNT = 1, the operators are in parallel, with the first in feedback. - case 1: - if(op1->envelopeGenerator.stage==EnvelopeGenerator::OFF && - op2->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return 0; - op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); - op2Output = op2->getOperatorOutput(OPL3, Operator::noModulator); - channelOutput = (op1Output + op2Output) / 2; - } - - feedback[0] = feedback[1]; - feedback[1] = StripIntPart(op1Output * ChannelData::feedback[fb]); - return channelOutput; -} - -void Channel2op::keyOn() { - op1->keyOn(); - op2->keyOn(); - feedback[0] = feedback[1] = 0; -} - -void Channel2op::keyOff() { - op1->keyOff(); - op2->keyOff(); -} - -void Channel2op::updateOperators(OPL3 *OPL3) { - // Key Scale Number, used in EnvelopeGenerator.setActualRates(). - int keyScaleNumber = block*2 + ((fnumh>>OPL3->nts)&0x01); - int f_number = (fnumh<<8) | fnuml; - op1->updateOperator(OPL3, keyScaleNumber, f_number, block); - op2->updateOperator(OPL3, keyScaleNumber, f_number, block); -} - -Channel4op::Channel4op (int baseAddress, double startvol, Operator *o1, Operator *o2, Operator *o3, Operator *o4) -: Channel(baseAddress, startvol) -{ - op1 = o1; - op2 = o2; - op3 = o3; - op4 = o4; -} - -double Channel4op::getChannelOutput(OPL3 *OPL3) { - double channelOutput = 0, - op1Output = 0, op2Output = 0, op3Output = 0, op4Output = 0; - - int secondChannelBaseAddress = channelBaseAddress+3; - int secondCnt = OPL3->registers[secondChannelBaseAddress+ChannelData::CHD1_CHC1_CHB1_CHA1_FB3_CNT1_Offset] & 0x1; - int cnt4op = (cnt << 1) | secondCnt; - - double feedbackOutput = (feedback[0] + feedback[1]) / 2; - - switch(cnt4op) { - case 0: - if(op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return 0; - - op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); - op2Output = op2->getOperatorOutput(OPL3, op1Output*toPhase); - op3Output = op3->getOperatorOutput(OPL3, op2Output*toPhase); - channelOutput = op4->getOperatorOutput(OPL3, op3Output*toPhase); - - break; - case 1: - if(op2->envelopeGenerator.stage==EnvelopeGenerator::OFF && - op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return 0; - - op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); - op2Output = op2->getOperatorOutput(OPL3, op1Output*toPhase); - - op3Output = op3->getOperatorOutput(OPL3, Operator::noModulator); - op4Output = op4->getOperatorOutput(OPL3, op3Output*toPhase); - - channelOutput = (op2Output + op4Output) / 2; - break; - case 2: - if(op1->envelopeGenerator.stage==EnvelopeGenerator::OFF && - op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return 0; - - op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); - - op2Output = op2->getOperatorOutput(OPL3, Operator::noModulator); - op3Output = op3->getOperatorOutput(OPL3, op2Output*toPhase); - op4Output = op4->getOperatorOutput(OPL3, op3Output*toPhase); - - channelOutput = (op1Output + op4Output) / 2; - break; - case 3: - if(op1->envelopeGenerator.stage==EnvelopeGenerator::OFF && - op3->envelopeGenerator.stage==EnvelopeGenerator::OFF && - op4->envelopeGenerator.stage==EnvelopeGenerator::OFF) - return 0; - - op1Output = op1->getOperatorOutput(OPL3, feedbackOutput); - - op2Output = op2->getOperatorOutput(OPL3, Operator::noModulator); - op3Output = op3->getOperatorOutput(OPL3, op2Output*toPhase); - - op4Output = op4->getOperatorOutput(OPL3, Operator::noModulator); - - channelOutput = (op1Output + op3Output + op4Output) / 3; - } - - feedback[0] = feedback[1]; - feedback[1] = StripIntPart(op1Output * ChannelData::feedback[fb]); - - return channelOutput; -} - -void Channel4op::keyOn() { - op1->keyOn(); - op2->keyOn(); - op3->keyOn(); - op4->keyOn(); - feedback[0] = feedback[1] = 0; -} - -void Channel4op::keyOff() { - op1->keyOff(); - op2->keyOff(); - op3->keyOff(); - op4->keyOff(); -} - -void Channel4op::updateOperators(OPL3 *OPL3) { - // Key Scale Number, used in EnvelopeGenerator.setActualRates(). - int keyScaleNumber = block*2 + ((fnumh>>OPL3->nts)&0x01); - int f_number = (fnumh<<8) | fnuml; - op1->updateOperator(OPL3, keyScaleNumber, f_number, block); - op2->updateOperator(OPL3, keyScaleNumber, f_number, block); - op3->updateOperator(OPL3, keyScaleNumber, f_number, block); - op4->updateOperator(OPL3, keyScaleNumber, f_number, block); -} - -const double Operator::noModulator = 0; - -Operator::Operator(int baseAddress) { - operatorBaseAddress = baseAddress; - - envelope = 0; - am = vib = ksr = egt = mult = ksl = tl = ar = dr = sl = rr = ws = 0; - keyScaleNumber = f_number = block = 0; -} - -void Operator::update_AM1_VIB1_EGT1_KSR1_MULT4(OPL3 *OPL3) { - - int am1_vib1_egt1_ksr1_mult4 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::AM1_VIB1_EGT1_KSR1_MULT4_Offset]; - - // Amplitude Modulation. This register is used int EnvelopeGenerator.getEnvelope(); - am = (am1_vib1_egt1_ksr1_mult4 & 0x80) >> 7; - // Vibrato. This register is used in PhaseGenerator.getPhase(); - vib = (am1_vib1_egt1_ksr1_mult4 & 0x40) >> 6; - // Envelope Generator Type. This register is used in EnvelopeGenerator.getEnvelope(); - egt = (am1_vib1_egt1_ksr1_mult4 & 0x20) >> 5; - // Key Scale Rate. Sets the actual envelope rate together with rate and keyScaleNumber. - // This register os used in EnvelopeGenerator.setActualAttackRate(). - ksr = (am1_vib1_egt1_ksr1_mult4 & 0x10) >> 4; - // Multiple. Multiplies the Channel.baseFrequency to get the Operator.operatorFrequency. - // This register is used in PhaseGenerator.setFrequency(). - mult = am1_vib1_egt1_ksr1_mult4 & 0x0F; - - phaseGenerator.setFrequency(f_number, block, mult); - envelopeGenerator.setActualAttackRate(ar, ksr, keyScaleNumber); - envelopeGenerator.setActualDecayRate(dr, ksr, keyScaleNumber); - envelopeGenerator.setActualReleaseRate(rr, ksr, keyScaleNumber); -} - -void Operator::update_KSL2_TL6(OPL3 *OPL3) { - - int ksl2_tl6 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::KSL2_TL6_Offset]; - - // Key Scale Level. Sets the attenuation in accordance with the octave. - ksl = (ksl2_tl6 & 0xC0) >> 6; - // Total Level. Sets the overall damping for the envelope. - tl = ksl2_tl6 & 0x3F; - - envelopeGenerator.setAtennuation(f_number, block, ksl); - envelopeGenerator.setTotalLevel(tl); -} - -void Operator::update_AR4_DR4(OPL3 *OPL3) { - - int ar4_dr4 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::AR4_DR4_Offset]; - - // Attack Rate. - ar = (ar4_dr4 & 0xF0) >> 4; - // Decay Rate. - dr = ar4_dr4 & 0x0F; - - envelopeGenerator.setActualAttackRate(ar, ksr, keyScaleNumber); - envelopeGenerator.setActualDecayRate(dr, ksr, keyScaleNumber); -} - -void Operator::update_SL4_RR4(OPL3 *OPL3) { - - int sl4_rr4 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::SL4_RR4_Offset]; - - // Sustain Level. - sl = (sl4_rr4 & 0xF0) >> 4; - // Release Rate. - rr = sl4_rr4 & 0x0F; - - envelopeGenerator.setActualSustainLevel(sl); - envelopeGenerator.setActualReleaseRate(rr, ksr, keyScaleNumber); -} - -void Operator::update_5_WS3(OPL3 *OPL3) { - int _5_ws3 = OPL3->registers[operatorBaseAddress+OperatorDataStruct::_5_WS3_Offset]; - ws = _5_ws3 & 0x07; -} - -double Operator::getOperatorOutput(OPL3 *OPL3, double modulator) { - if(envelopeGenerator.stage == EnvelopeGenerator::OFF) return 0; - - double envelopeInDB = envelopeGenerator.getEnvelope(OPL3, egt, am); - envelope = EnvelopeFromDB(envelopeInDB); - - // If it is in OPL2 mode, use first four waveforms only: - ws &= ((OPL3->_new<<2) + 3); - double *waveform = OPL3::OperatorData->waveforms[ws]; - - phase = phaseGenerator.getPhase(OPL3, vib); - - double operatorOutput = getOutput(modulator, phase, waveform); - return operatorOutput; -} - -double Operator::getOutput(double modulator, double outputPhase, double *waveform) { - int sampleIndex = xs_FloorToInt((outputPhase + modulator) * OperatorDataStruct::waveLength) & (OperatorDataStruct::waveLength - 1); - return waveform[sampleIndex] * envelope; -} - -void Operator::keyOn() { - if(ar > 0) { - envelopeGenerator.keyOn(); - phaseGenerator.keyOn(); - } - else envelopeGenerator.stage = EnvelopeGenerator::OFF; -} - -void Operator::keyOff() { - envelopeGenerator.keyOff(); -} - -void Operator::updateOperator(OPL3 *OPL3, int ksn, int f_num, int blk) { - keyScaleNumber = ksn; - f_number = f_num; - block = blk; - update_AM1_VIB1_EGT1_KSR1_MULT4(OPL3); - update_KSL2_TL6(OPL3); - update_AR4_DR4(OPL3); - update_SL4_RR4(OPL3); - update_5_WS3(OPL3); -} - -EnvelopeGenerator::EnvelopeGenerator() { - stage = OFF; - actualAttackRate = actualDecayRate = actualReleaseRate = 0; - xAttackIncrement = xMinimumInAttack = 0; - dBdecayIncrement = 0; - dBreleaseIncrement = 0; - attenuation = totalLevel = sustainLevel = 0; - x = dBtoX(-96); - envelope = -96; -} - -void EnvelopeGenerator::setActualSustainLevel(int sl) { - // If all SL bits are 1, sustain level is set to -93 dB: - if(sl == 0x0F) { - sustainLevel = -93; - return; - } - // The datasheet states that the SL formula is - // sustainLevel = -24*d7 -12*d6 -6*d5 -3*d4, - // translated as: - sustainLevel = -3*sl; -} - -void EnvelopeGenerator::setTotalLevel(int tl) { - // The datasheet states that the TL formula is - // TL = -(24*d5 + 12*d4 + 6*d3 + 3*d2 + 1.5*d1 + 0.75*d0), - // translated as: - totalLevel = tl*-0.75; -} - -void EnvelopeGenerator::setAtennuation(int f_number, int block, int ksl) { - int hi4bits = (f_number>>6)&0x0F; - switch(ksl) { - case 0: - attenuation = 0; - break; - case 1: - // ~3 dB/Octave - attenuation = OperatorDataStruct::ksl3dBtable[hi4bits][block]; - break; - case 2: - // ~1.5 dB/Octave - attenuation = OperatorDataStruct::ksl3dBtable[hi4bits][block]/2; - break; - case 3: - // ~6 dB/Octave - attenuation = OperatorDataStruct::ksl3dBtable[hi4bits][block]*2; - } -} - -void EnvelopeGenerator::setActualAttackRate(int attackRate, int ksr, int keyScaleNumber) { - // According to the YMF278B manual's OPL3 section, the attack curve is exponential, - // with a dynamic range from -96 dB to 0 dB and a resolution of 0.1875 dB - // per level. - // - // This method sets an attack increment and attack minimum value - // that creates a exponential dB curve with 'period0to100' seconds in length - // and 'period10to90' seconds between 10% and 90% of the curve total level. - actualAttackRate = calculateActualRate(attackRate, ksr, keyScaleNumber); - double period0to100inSeconds = EnvelopeGeneratorData::attackTimeValuesTable[actualAttackRate][0]/1000.0; - int period0to100inSamples = (int)(period0to100inSeconds*OPL_SAMPLE_RATE); - double period10to90inSeconds = EnvelopeGeneratorData::attackTimeValuesTable[actualAttackRate][1]/1000.0; - int period10to90inSamples = (int)(period10to90inSeconds*OPL_SAMPLE_RATE); - // The x increment is dictated by the period between 10% and 90%: - xAttackIncrement = OPL3DataStruct::calculateIncrement(percentageToX(0.1), percentageToX(0.9), period10to90inSeconds); - // Discover how many samples are still from the top. - // It cannot reach 0 dB, since x is a logarithmic parameter and would be - // negative infinity. So we will use -0.1875 dB as the resolution - // maximum. - // - // percentageToX(0.9) + samplesToTheTop*xAttackIncrement = dBToX(-0.1875); -> - // samplesToTheTop = (dBtoX(-0.1875) - percentageToX(0.9)) / xAttackIncrement); -> - // period10to100InSamples = period10to90InSamples + samplesToTheTop; -> - int period10to100inSamples = (int) (period10to90inSamples + (dBtoX(-0.1875) - percentageToX(0.9)) / xAttackIncrement); - // Discover the minimum x that, through the attackIncrement value, keeps - // the 10%-90% period, and reaches 0 dB at the total period: - xMinimumInAttack = percentageToX(0.1) - (period0to100inSamples-period10to100inSamples)*xAttackIncrement; -} - - -void EnvelopeGenerator::setActualDecayRate(int decayRate, int ksr, int keyScaleNumber) { - actualDecayRate = calculateActualRate(decayRate, ksr, keyScaleNumber); - double period10to90inSeconds = EnvelopeGeneratorData::decayAndReleaseTimeValuesTable[actualDecayRate][1]/1000.0; - // Differently from the attack curve, the decay/release curve is linear. - // The dB increment is dictated by the period between 10% and 90%: - dBdecayIncrement = OPL3DataStruct::calculateIncrement(percentageToDB(0.1), percentageToDB(0.9), period10to90inSeconds); -} - -void EnvelopeGenerator::setActualReleaseRate(int releaseRate, int ksr, int keyScaleNumber) { - actualReleaseRate = calculateActualRate(releaseRate, ksr, keyScaleNumber); - double period10to90inSeconds = EnvelopeGeneratorData::decayAndReleaseTimeValuesTable[actualReleaseRate][1]/1000.0; - dBreleaseIncrement = OPL3DataStruct::calculateIncrement(percentageToDB(0.1), percentageToDB(0.9), period10to90inSeconds); -} - -int EnvelopeGenerator::calculateActualRate(int rate, int ksr, int keyScaleNumber) { - int rof = EnvelopeGeneratorData::rateOffset[ksr][keyScaleNumber]; - int actualRate = rate*4 + rof; - // If, as an example at the maximum, rate is 15 and the rate offset is 15, - // the value would - // be 75, but the maximum allowed is 63: - if(actualRate > 63) actualRate = 63; - return actualRate; -} - -double EnvelopeGenerator::getEnvelope(OPL3 *OPL3, int egt, int am) { - // The datasheets attenuation values - // must be halved to match the real OPL3 output. - double envelopeSustainLevel = sustainLevel / 2; - double envelopeTremolo = - OPL3::OPL3Data->tremoloTable[OPL3->dam][OPL3->tremoloIndex] / 2; - double envelopeAttenuation = attenuation / 2; - double envelopeTotalLevel = totalLevel / 2; - - double envelopeMinimum = -96; - double envelopeResolution = 0.1875; - - double outputEnvelope; - // - // Envelope Generation - // - switch(stage) { - case ATTACK: - // Since the attack is exponential, it will never reach 0 dB, so - // we´ll work with the next to maximum in the envelope resolution. - if(envelope<-envelopeResolution && xAttackIncrement != -EnvelopeGeneratorData::MUGEN) { - // The attack is exponential. -#if 0 - envelope = -pow(2.0,x); -#else - int index = xs_FloorToInt((x - ATTACK_MIN) / ATTACK_RES); - if (index < 0) - envelope = OPL3::OperatorData->attackTable[0]; - else if (index >= ATTACK_TABLE_SIZE) - envelope = OPL3::OperatorData->attackTable[ATTACK_TABLE_SIZE-1]; - else - envelope = OPL3::OperatorData->attackTable[index]; -#endif - x += xAttackIncrement; - break; - } - else { - // It is needed here to explicitly set envelope = 0, since - // only the attack can have a period of - // 0 seconds and produce an infinity envelope increment. - envelope = 0; - stage = DECAY; - } - case DECAY: - // The decay and release are linear. - if(envelope>envelopeSustainLevel) { - envelope -= dBdecayIncrement; - break; - } - else - stage = SUSTAIN; - case SUSTAIN: - // The Sustain stage is mantained all the time of the Key ON, - // even if we are in non-sustaining mode. - // This is necessary because, if the key is still pressed, we can - // change back and forth the state of EGT, and it will release and - // hold again accordingly. - if(egt==1) break; - else { - if(envelope > envelopeMinimum) - envelope -= dBreleaseIncrement; - else stage = OFF; - } - break; - case RELEASE: - // If we have Key OFF, only here we are in the Release stage. - // Now, we can turn EGT back and forth and it will have no effect,i.e., - // it will release inexorably to the Off stage. - if(envelope > envelopeMinimum) - envelope -= dBreleaseIncrement; - else stage = OFF; - case OFF: - break; - } - - // Ongoing original envelope - outputEnvelope = envelope; - - //Tremolo - if(am == 1) outputEnvelope += envelopeTremolo; - - //Attenuation - outputEnvelope += envelopeAttenuation; - - //Total Level - outputEnvelope += envelopeTotalLevel; - - return outputEnvelope; -} - -void EnvelopeGenerator::keyOn() { - // If we are taking it in the middle of a previous envelope, - // start to rise from the current level: - // envelope = - (2 ^ x); -> - // 2 ^ x = -envelope -> - // x = log2(-envelope); -> - double xCurrent = OperatorDataStruct::log2(-envelope); - x = xCurrent < xMinimumInAttack ? xCurrent : xMinimumInAttack; - stage = ATTACK; -} - -void EnvelopeGenerator::keyOff() { - if(stage != OFF) stage = RELEASE; -} - -double EnvelopeGenerator::dBtoX(double dB) { - return OperatorDataStruct::log2(-dB); -} - -double EnvelopeGenerator::percentageToDB(double percentage) { - return log10(percentage) * 10.0; -} - -double EnvelopeGenerator::percentageToX(double percentage) { - return dBtoX(percentageToDB(percentage)); -} - -PhaseGenerator::PhaseGenerator() { - phase = phaseIncrement = 0; -} - -void PhaseGenerator::setFrequency(int f_number, int block, int mult) { - // This frequency formula is derived from the following equation: - // f_number = baseFrequency * pow(2,19) / OPL_SAMPLE_RATE / pow(2,block-1); - double baseFrequency = - f_number * pow(2.0, block-1) * OPL_SAMPLE_RATE / pow(2.0,19); - double operatorFrequency = baseFrequency*OperatorDataStruct::multTable[mult]; - - // phase goes from 0 to 1 at - // period = (1/frequency) seconds -> - // Samples in each period is (1/frequency)*OPL_SAMPLE_RATE = - // = OPL_SAMPLE_RATE/frequency -> - // So the increment in each sample, to go from 0 to 1, is: - // increment = (1-0) / samples in the period -> - // increment = 1 / (OPL_SAMPLE_RATE/operatorFrequency) -> - phaseIncrement = operatorFrequency/OPL_SAMPLE_RATE; -} - -double PhaseGenerator::getPhase(OPL3 *OPL3, int vib) { - if(vib==1) - // phaseIncrement = (operatorFrequency * vibrato) / OPL_SAMPLE_RATE - phase += phaseIncrement*OPL3::OPL3Data->vibratoTable[OPL3->dvb][OPL3->vibratoIndex]; - else - // phaseIncrement = operatorFrequency / OPL_SAMPLE_RATE - phase += phaseIncrement; - // Originally clamped phase to [0,1), but that's not needed - return phase; -} - -void PhaseGenerator::keyOn() { - phase = 0; -} - -double RhythmChannel::getChannelOutput(OPL3 *OPL3) { - double channelOutput = 0, op1Output = 0, op2Output = 0; - - // Note that, different from the common channel, - // we do not check to see if the Operator's envelopes are Off. - // Instead, we always do the calculations, - // to update the publicly available phase. - op1Output = op1->getOperatorOutput(OPL3, Operator::noModulator); - op2Output = op2->getOperatorOutput(OPL3, Operator::noModulator); - channelOutput = (op1Output + op2Output) / 2; - - return channelOutput; -}; - -TopCymbalOperator::TopCymbalOperator(int baseAddress) -: Operator(baseAddress) -{ } - -TopCymbalOperator::TopCymbalOperator() -: Operator(topCymbalOperatorBaseAddress) -{ } - -double TopCymbalOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { - double highHatOperatorPhase = - OPL3->highHatOperator.phase * OperatorDataStruct::multTable[OPL3->highHatOperator.mult]; - // The Top Cymbal operator uses its own phase together with the High Hat phase. - return getOperatorOutput(OPL3, modulator, highHatOperatorPhase); -} - -// This method is used here with the HighHatOperator phase -// as the externalPhase. -// Conversely, this method is also used through inheritance by the HighHatOperator, -// now with the TopCymbalOperator phase as the externalPhase. -double TopCymbalOperator::getOperatorOutput(OPL3 *OPL3, double modulator, double externalPhase) { - double envelopeInDB = envelopeGenerator.getEnvelope(OPL3, egt, am); - envelope = EnvelopeFromDB(envelopeInDB); - - phase = phaseGenerator.getPhase(OPL3, vib); - - int waveIndex = ws & ((OPL3->_new<<2) + 3); - double *waveform = OPL3::OperatorData->waveforms[waveIndex]; - - // Empirically tested multiplied phase for the Top Cymbal: - double carrierPhase = 8 * phase; - double modulatorPhase = externalPhase; - double modulatorOutput = getOutput(Operator::noModulator, modulatorPhase, waveform); - double carrierOutput = getOutput(modulatorOutput, carrierPhase, waveform); - - int cycles = 4; - double chopped = (carrierPhase * cycles) /* %cycles */; - chopped = chopped - floor(chopped / cycles) * cycles; - if( chopped > 0.1) carrierOutput = 0; - - return carrierOutput*2; -} - -HighHatOperator::HighHatOperator() -: TopCymbalOperator(highHatOperatorBaseAddress) -{ } - -double HighHatOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { - double topCymbalOperatorPhase = - OPL3->topCymbalOperator.phase * OperatorDataStruct::multTable[OPL3->topCymbalOperator.mult]; - // The sound output from the High Hat resembles the one from - // Top Cymbal, so we use the parent method and modify its output - // accordingly afterwards. - double operatorOutput = TopCymbalOperator::getOperatorOutput(OPL3, modulator, topCymbalOperatorPhase); - double randval = rand() / (double)RAND_MAX; - if(operatorOutput == 0) operatorOutput = randval*envelope; - return operatorOutput; -} - -SnareDrumOperator::SnareDrumOperator() -: Operator(snareDrumOperatorBaseAddress) -{ } - -double SnareDrumOperator::getOperatorOutput(OPL3 *OPL3, double modulator) { - if(envelopeGenerator.stage == EnvelopeGenerator::OFF) return 0; - - double envelopeInDB = envelopeGenerator.getEnvelope(OPL3, egt, am); - envelope = EnvelopeFromDB(envelopeInDB); - - // If it is in OPL2 mode, use first four waveforms only: - int waveIndex = ws & ((OPL3->_new<<2) + 3); - double *waveform = OPL3::OperatorData->waveforms[waveIndex]; - - phase = OPL3->highHatOperator.phase * 2; - - double operatorOutput = getOutput(modulator, phase, waveform); - - double randval = rand() / (double)RAND_MAX; - double noise = randval * envelope; - - if(operatorOutput/envelope != 1 && operatorOutput/envelope != -1) { - if(operatorOutput > 0) operatorOutput = noise; - else if(operatorOutput < 0) operatorOutput = -noise; - else operatorOutput = 0; - } - - return operatorOutput*2; -} - -BassDrumChannel::BassDrumChannel(double startvol) -: Channel2op(bassDrumChannelBaseAddress, startvol, &my_op1, &my_op2), - my_op1(op1BaseAddress), my_op2(op2BaseAddress) -{ } - -double BassDrumChannel::getChannelOutput(OPL3 *OPL3) { - // Bass Drum ignores first operator, when it is in series. - if(cnt == 1) op1->ar=0; - return Channel2op::getChannelOutput(OPL3); -} - -void OPL3DataStruct::loadVibratoTable() { - - // According to the YMF262 datasheet, the OPL3 vibrato repetition rate is 6.1 Hz. - // According to the YMF278B manual, it is 6.0 Hz. - // The information that the vibrato table has 8 levels standing 1024 samples each - // was taken from the emulator by Jarek Burczynski and Tatsuyuki Satoh, - // with a frequency of 6,06689453125 Hz, what makes sense with the difference - // in the information on the datasheets. - - const double semitone = pow(2.0,1/12.0); - // A cent is 1/100 of a semitone: - const double cent = pow(semitone, 1/100.0); - - // When dvb=0, the depth is 7 cents, when it is 1, the depth is 14 cents. - const double DVB0 = pow(cent,7.0); - const double DVB1 = pow(cent,14.0); - int i; - for(i = 0; i<1024; i++) - vibratoTable[0][i] = vibratoTable[1][i] = 1; - for(;i<2048; i++) { - vibratoTable[0][i] = sqrt(DVB0); - vibratoTable[1][i] = sqrt(DVB1); - } - for(;i<3072; i++) { - vibratoTable[0][i] = DVB0; - vibratoTable[1][i] = DVB1; - } - for(;i<4096; i++) { - vibratoTable[0][i] = sqrt(DVB0); - vibratoTable[1][i] = sqrt(DVB1); - } - for(; i<5120; i++) - vibratoTable[0][i] = vibratoTable[1][i] = 1; - for(;i<6144; i++) { - vibratoTable[0][i] = 1/sqrt(DVB0); - vibratoTable[1][i] = 1/sqrt(DVB1); - } - for(;i<7168; i++) { - vibratoTable[0][i] = 1/DVB0; - vibratoTable[1][i] = 1/DVB1; - } - for(;i<8192; i++) { - vibratoTable[0][i] = 1/sqrt(DVB0); - vibratoTable[1][i] = 1/sqrt(DVB1); - } - -} - -void OPL3DataStruct::loadTremoloTable() -{ - // The tremolo depth is -1 dB when DAM = 0, and -4.8 dB when DAM = 1. - static const double tremoloDepth[] = {-1, -4.8}; - - // According to the YMF278B manual's OPL3 section graph, - // the tremolo waveform is not - // \ / a sine wave, but a single triangle waveform. - // \ / Thus, the period to achieve the tremolo depth is T/2, and - // \ / the increment in each T/2 section uses a frequency of 2*f. - // \/ Tremolo varies from 0 dB to depth, to 0 dB again, at frequency*2: - const double tremoloIncrement[] = { - calculateIncrement(tremoloDepth[0],0,1/(2*tremoloFrequency)), - calculateIncrement(tremoloDepth[1],0,1/(2*tremoloFrequency)) - }; - - int tremoloTableLength = (int)(OPL_SAMPLE_RATE/tremoloFrequency); - - // This is undocumented. The tremolo starts at the maximum attenuation, - // instead of at 0 dB: - tremoloTable[0][0] = tremoloDepth[0]; - tremoloTable[1][0] = tremoloDepth[1]; - int counter = 0; - // The first half of the triangle waveform: - while(tremoloTable[0][counter]<0) { - counter++; - tremoloTable[0][counter] = tremoloTable[0][counter-1] + tremoloIncrement[0]; - tremoloTable[1][counter] = tremoloTable[1][counter-1] + tremoloIncrement[1]; - } - // The second half of the triangle waveform: - while(tremoloTable[0][counter]>tremoloDepth[0] && counter> 8, reg & 0xFF, v); -} - -void OPL3::SetPanning(int c, float left, float right) -{ - if (FullPan) - { - Channel *channel; - - if (c < 9) - { - channel = channels[0][c]; - } - else - { - channel = channels[1][c - 9]; - } - channel->leftPan = left; - channel->rightPan = right; - } -} - -} // JavaOPL3 - -OPLEmul *JavaOPLCreate(bool stereo) -{ - return new JavaOPL3::OPL3(stereo); -} diff --git a/libraries/oplsynth/dosbox/opl.cpp b/libraries/oplsynth/dosbox/opl.cpp deleted file mode 100644 index ffd056f73..000000000 --- a/libraries/oplsynth/dosbox/opl.cpp +++ /dev/null @@ -1,1445 +0,0 @@ -/* - * Copyright (C) 2002-2011 The DOSBox Team - * OPL2/OPL3 emulation library - * - * 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 - */ - - -/* - * Originally based on ADLIBEMU.C, an AdLib/OPL2 emulation library by Ken Silverman - * Copyright (C) 1998-2001 Ken Silverman - * Ken Silverman's official web site: "http://www.advsys.net/ken" - */ - -#include "../oplsynth/opl.h" -#include -#include -#include -#include - -typedef uintptr_t Bitu; -typedef intptr_t Bits; -typedef uint32_t Bit32u; -typedef int32_t Bit32s; -typedef uint16_t Bit16u; -typedef int16_t Bit16s; -typedef uint8_t Bit8u; -typedef int8_t Bit8s; - -#define OPLTYPE_IS_OPL3 -#undef PI - -#include "opl.h" - -static Bit16s wavtable[WAVEPREC*3]; // wave form table - -// key scale levels -static Bit8u kslev[8][16]; - -// key scale level lookup table -static const fltype kslmul[4] = { - 0.0, 0.5, 0.25, 1.0 // -> 0, 3, 1.5, 6 dB/oct -}; - -// frequency multiplicator lookup table -static const fltype frqmul_tab[16] = { - 0.5,1,2,3,4,5,6,7,8,9,10,10,12,12,15,15 -}; - -// map a channel number to the register offset of the modulator (=register base) -static const Bit8u modulatorbase[9] = { - 0,1,2, - 8,9,10, - 16,17,18 -}; - -// map a register base to a modulator operator number or operator number -#if defined(OPLTYPE_IS_OPL3) -static const Bit8u regbase2modop[44] = { - 0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8, // first set - 18,19,20,18,19,20,0,0,21,22,23,21,22,23,0,0,24,25,26,24,25,26 // second set -}; -static const Bit8u regbase2op[44] = { - 0,1,2,9,10,11,0,0,3,4,5,12,13,14,0,0,6,7,8,15,16,17, // first set - 18,19,20,27,28,29,0,0,21,22,23,30,31,32,0,0,24,25,26,33,34,35 // second set -}; -#else -static const Bit8u regbase2modop[22] = { - 0,1,2,0,1,2,0,0,3,4,5,3,4,5,0,0,6,7,8,6,7,8 -}; -static const Bit8u regbase2op[22] = { - 0,1,2,9,10,11,0,0,3,4,5,12,13,14,0,0,6,7,8,15,16,17 -}; -#endif - - -// start of the waveform -static const Bit32u waveform[8] = { - WAVEPREC, - WAVEPREC>>1, - WAVEPREC, - (WAVEPREC*3)>>2, - 0, - 0, - (WAVEPREC*5)>>2, - WAVEPREC<<1 -}; - -// length of the waveform as mask -static const Bit32u wavemask[8] = { - WAVEPREC-1, - WAVEPREC-1, - (WAVEPREC>>1)-1, - (WAVEPREC>>1)-1, - WAVEPREC-1, - ((WAVEPREC*3)>>2)-1, - WAVEPREC>>1, - WAVEPREC-1 -}; - -// where the first entry resides -static const Bit32u wavestart[8] = { - 0, - WAVEPREC>>1, - 0, - WAVEPREC>>2, - 0, - 0, - 0, - WAVEPREC>>3 -}; - -// envelope generator function constants -static const fltype attackconst[4] = { - (fltype)(1/2.82624), - (fltype)(1/2.25280), - (fltype)(1/1.88416), - (fltype)(1/1.59744) -}; -static const fltype decrelconst[4] = { - (fltype)(1/39.28064), - (fltype)(1/31.41608), - (fltype)(1/26.17344), - (fltype)(1/22.44608) -}; - - -void operator_advance(op_type* op_pt, Bit32s vib) { - op_pt->wfpos = op_pt->tcount; // waveform position - - // advance waveform time - op_pt->tcount += op_pt->tinc; - op_pt->tcount += (Bit32s)(op_pt->tinc)*vib/FIXEDPT; - - op_pt->generator_pos += generator_add; -} - -void operator_advance_drums(op_type* op_pt1, Bit32s vib1, op_type* op_pt2, Bit32s vib2, op_type* op_pt3, Bit32s vib3) { - Bit32u c1 = op_pt1->tcount/FIXEDPT; - Bit32u c3 = op_pt3->tcount/FIXEDPT; - Bit32u phasebit = (((c1 & 0x88) ^ ((c1<<5) & 0x80)) | ((c3 ^ (c3<<2)) & 0x20)) ? 0x02 : 0x00; - - Bit32u noisebit = rand() & 1; - - Bit32u snare_phase_bit = (Bit32u)(((Bitu)((op_pt1->tcount/FIXEDPT) / 0x100))&1); - - //Hihat - Bit32u inttm = (phasebit<<8) | (0x34<<(phasebit ^ (noisebit<<1))); - op_pt1->wfpos = inttm*FIXEDPT; // waveform position - // advance waveform time - op_pt1->tcount += op_pt1->tinc; - op_pt1->tcount += (Bit32s)(op_pt1->tinc)*vib1/FIXEDPT; - op_pt1->generator_pos += generator_add; - - //Snare - inttm = ((1+snare_phase_bit) ^ noisebit)<<8; - op_pt2->wfpos = inttm*FIXEDPT; // waveform position - // advance waveform time - op_pt2->tcount += op_pt2->tinc; - op_pt2->tcount += (Bit32s)(op_pt2->tinc)*vib2/FIXEDPT; - op_pt2->generator_pos += generator_add; - - //Cymbal - inttm = (1+phasebit)<<8; - op_pt3->wfpos = inttm*FIXEDPT; // waveform position - // advance waveform time - op_pt3->tcount += op_pt3->tinc; - op_pt3->tcount += (Bit32s)(op_pt3->tinc)*vib3/FIXEDPT; - op_pt3->generator_pos += generator_add; -} - - -// output level is sustained, mode changes only when operator is turned off (->release) -// or when the keep-sustained bit is turned off (->sustain_nokeep) -void operator_output(op_type* op_pt, Bit32s modulator, Bit32s trem) { - if (op_pt->op_state != OF_TYPE_OFF) { - op_pt->lastcval = op_pt->cval; - Bit32u i = (Bit32u)((op_pt->wfpos+modulator)/FIXEDPT); - - // wform: -16384 to 16383 (0x4000) - // trem : 32768 to 65535 (0x10000) - // step_amp: 0.0 to 1.0 - // vol : 1/2^14 to 1/2^29 (/0x4000; /1../0x8000) - - op_pt->cval = (Bit32s)(op_pt->step_amp*op_pt->vol*op_pt->cur_wform[i&op_pt->cur_wmask]*trem/16.0); - } -} - - -// no action, operator is off -void operator_off(op_type* /*op_pt*/) { -} - -// output level is sustained, mode changes only when operator is turned off (->release) -// or when the keep-sustained bit is turned off (->sustain_nokeep) -void operator_sustain(op_type* op_pt) { - Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples - for (Bit32u ct=0; ctcur_env_step++; - } - op_pt->generator_pos -= num_steps_add*FIXEDPT; -} - -// operator in release mode, if output level reaches zero the operator is turned off -void operator_release(op_type* op_pt) { - // ??? boundary? - if (op_pt->amp > 0.00000001) { - // release phase - op_pt->amp *= op_pt->releasemul; - } - - Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples - for (Bit32u ct=0; ctcur_env_step++; // sample counter - if ((op_pt->cur_env_step & op_pt->env_step_r)==0) { - if (op_pt->amp <= 0.00000001) { - // release phase finished, turn off this operator - op_pt->amp = 0.0; - if (op_pt->op_state == OF_TYPE_REL) { - op_pt->op_state = OF_TYPE_OFF; - } - } - op_pt->step_amp = op_pt->amp; - } - } - op_pt->generator_pos -= num_steps_add*FIXEDPT; -} - -// operator in decay mode, if sustain level is reached the output level is either -// kept (sustain level keep enabled) or the operator is switched into release mode -void operator_decay(op_type* op_pt) { - if (op_pt->amp > op_pt->sustain_level) { - // decay phase - op_pt->amp *= op_pt->decaymul; - } - - Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples - for (Bit32u ct=0; ctcur_env_step++; - if ((op_pt->cur_env_step & op_pt->env_step_d)==0) { - if (op_pt->amp <= op_pt->sustain_level) { - // decay phase finished, sustain level reached - if (op_pt->sus_keep) { - // keep sustain level (until turned off) - op_pt->op_state = OF_TYPE_SUS; - op_pt->amp = op_pt->sustain_level; - } else { - // next: release phase - op_pt->op_state = OF_TYPE_SUS_NOKEEP; - } - } - op_pt->step_amp = op_pt->amp; - } - } - op_pt->generator_pos -= num_steps_add*FIXEDPT; -} - -// operator in attack mode, if full output level is reached, -// the operator is switched into decay mode -void operator_attack(op_type* op_pt) { - op_pt->amp = ((op_pt->a3*op_pt->amp + op_pt->a2)*op_pt->amp + op_pt->a1)*op_pt->amp + op_pt->a0; - - Bit32u num_steps_add = op_pt->generator_pos/FIXEDPT; // number of (standardized) samples - for (Bit32u ct=0; ctcur_env_step++; // next sample - if ((op_pt->cur_env_step & op_pt->env_step_a)==0) { // check if next step already reached - if (op_pt->amp > 1.0) { - // attack phase finished, next: decay - op_pt->op_state = OF_TYPE_DEC; - op_pt->amp = 1.0; - op_pt->step_amp = 1.0; - } - op_pt->step_skip_pos_a <<= 1; - if (op_pt->step_skip_pos_a==0) op_pt->step_skip_pos_a = 1; - if (op_pt->step_skip_pos_a & op_pt->env_step_skip_a) { // check if required to skip next step - op_pt->step_amp = op_pt->amp; - } - } - } - op_pt->generator_pos -= num_steps_add*FIXEDPT; -} - - -typedef void (*optype_fptr)(op_type*); - -optype_fptr opfuncs[6] = { - operator_attack, - operator_decay, - operator_release, - operator_sustain, // sustain phase (keeping level) - operator_release, // sustain_nokeep phase (release-style) - operator_off -}; - -void DBOPL::change_attackrate(Bitu regbase, op_type* op_pt) { - Bits attackrate = adlibreg[ARC_ATTR_DECR+regbase]>>4; - if (attackrate) { - fltype f = (fltype)(pow(FL2,(fltype)attackrate+(op_pt->toff>>2)-1)*attackconst[op_pt->toff&3]*recipsamp); - // attack rate coefficients - op_pt->a0 = (fltype)(0.0377*f); - op_pt->a1 = (fltype)(10.73*f+1); - op_pt->a2 = (fltype)(-17.57*f); - op_pt->a3 = (fltype)(7.42*f); - - Bits step_skip = attackrate*4 + op_pt->toff; - Bits steps = step_skip >> 2; - op_pt->env_step_a = (1<<(steps<=12?12-steps:0))-1; - - Bits step_num = (step_skip<=48)?(4-(step_skip&3)):0; - static Bit8u step_skip_mask[5] = {0xff, 0xfe, 0xee, 0xba, 0xaa}; - op_pt->env_step_skip_a = step_skip_mask[step_num]; - -#if defined(OPLTYPE_IS_OPL3) - if (step_skip>=60) { -#else - if (step_skip>=62) { -#endif - op_pt->a0 = (fltype)(2.0); // something that triggers an immediate transition to amp:=1.0 - op_pt->a1 = (fltype)(0.0); - op_pt->a2 = (fltype)(0.0); - op_pt->a3 = (fltype)(0.0); - } - } else { - // attack disabled - op_pt->a0 = 0.0; - op_pt->a1 = 1.0; - op_pt->a2 = 0.0; - op_pt->a3 = 0.0; - op_pt->env_step_a = 0; - op_pt->env_step_skip_a = 0; - } -} - -void DBOPL::change_decayrate(Bitu regbase, op_type* op_pt) { - Bits decayrate = adlibreg[ARC_ATTR_DECR+regbase]&15; - // decaymul should be 1.0 when decayrate==0 - if (decayrate) { - fltype f = (fltype)(-7.4493*decrelconst[op_pt->toff&3]*recipsamp); - op_pt->decaymul = (fltype)(pow(FL2,f*pow(FL2,(fltype)(decayrate+(op_pt->toff>>2))))); - Bits steps = (decayrate*4 + op_pt->toff) >> 2; - op_pt->env_step_d = (1<<(steps<=12?12-steps:0))-1; - } else { - op_pt->decaymul = 1.0; - op_pt->env_step_d = 0; - } -} - -void DBOPL::change_releaserate(Bitu regbase, op_type* op_pt) { - Bits releaserate = adlibreg[ARC_SUSL_RELR+regbase]&15; - // releasemul should be 1.0 when releaserate==0 - if (releaserate) { - fltype f = (fltype)(-7.4493*decrelconst[op_pt->toff&3]*recipsamp); - op_pt->releasemul = (fltype)(pow(FL2,f*pow(FL2,(fltype)(releaserate+(op_pt->toff>>2))))); - Bits steps = (releaserate*4 + op_pt->toff) >> 2; - op_pt->env_step_r = (1<<(steps<=12?12-steps:0))-1; - } else { - op_pt->releasemul = 1.0; - op_pt->env_step_r = 0; - } -} - -void DBOPL::change_sustainlevel(Bitu regbase, op_type* op_pt) { - Bits sustainlevel = adlibreg[ARC_SUSL_RELR+regbase]>>4; - // sustainlevel should be 0.0 when sustainlevel==15 (max) - if (sustainlevel<15) { - op_pt->sustain_level = (fltype)(pow(FL2,(fltype)sustainlevel * (-FL05))); - } else { - op_pt->sustain_level = 0.0; - } -} - -void DBOPL::change_waveform(Bitu regbase, op_type* op_pt) { -#if defined(OPLTYPE_IS_OPL3) - if (regbase>=ARC_SECONDSET) regbase -= (ARC_SECONDSET-22); // second set starts at 22 -#endif - // waveform selection - op_pt->cur_wmask = wavemask[wave_sel[regbase]]; - op_pt->cur_wform = &wavtable[waveform[wave_sel[regbase]]]; - // (might need to be adapted to waveform type here...) -} - -void DBOPL::change_keepsustain(Bitu regbase, op_type* op_pt) { - op_pt->sus_keep = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x20)>0; - if (op_pt->op_state==OF_TYPE_SUS) { - if (!op_pt->sus_keep) op_pt->op_state = OF_TYPE_SUS_NOKEEP; - } else if (op_pt->op_state==OF_TYPE_SUS_NOKEEP) { - if (op_pt->sus_keep) op_pt->op_state = OF_TYPE_SUS; - } -} - -// enable/disable vibrato/tremolo LFO effects -void DBOPL::change_vibrato(Bitu regbase, op_type* op_pt) { - op_pt->vibrato = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x40)!=0; - op_pt->tremolo = (adlibreg[ARC_TVS_KSR_MUL+regbase]&0x80)!=0; -} - -// change amount of self-feedback -void DBOPL::change_feedback(Bitu chanbase, op_type* op_pt) { - Bits feedback = adlibreg[ARC_FEEDBACK+chanbase]&14; - if (feedback) op_pt->mfbi = (Bit32s)(pow(FL2,(fltype)((feedback>>1)+8))); - else op_pt->mfbi = 0; -} - -void DBOPL::change_frequency(Bitu chanbase, Bitu regbase, op_type* op_pt) { - // frequency - Bit32u frn = ((((Bit32u)adlibreg[ARC_KON_BNUM+chanbase])&3)<<8) + (Bit32u)adlibreg[ARC_FREQ_NUM+chanbase]; - // block number/octave - Bit32u oct = ((((Bit32u)adlibreg[ARC_KON_BNUM+chanbase])>>2)&7); - op_pt->freq_high = (Bit32s)((frn>>7)&7); - - // keysplit - Bit32u note_sel = (adlibreg[8]>>6)&1; - op_pt->toff = ((frn>>9)&(note_sel^1)) | ((frn>>8)¬e_sel); - op_pt->toff += (oct<<1); - - // envelope scaling (KSR) - if (!(adlibreg[ARC_TVS_KSR_MUL+regbase]&0x10)) op_pt->toff >>= 2; - - // 20+a0+b0: - op_pt->tinc = (Bit32u)((((fltype)(frn<>6]*kslev[oct][frn>>6]); - op_pt->vol = (fltype)(pow(FL2,(fltype)(vol_in * -0.125 - 14))); - - // operator frequency changed, care about features that depend on it - change_attackrate(regbase,op_pt); - change_decayrate(regbase,op_pt); - change_releaserate(regbase,op_pt); -} - -void DBOPL::enable_operator(Bitu regbase, op_type* op_pt, Bit32u act_type) { - // check if this is really an off-on transition - if (op_pt->act_state == OP_ACT_OFF) { - Bits wselbase = regbase; - if (wselbase>=ARC_SECONDSET) wselbase -= (ARC_SECONDSET-22); // second set starts at 22 - - op_pt->tcount = wavestart[wave_sel[wselbase]]*FIXEDPT; - - // start with attack mode - op_pt->op_state = OF_TYPE_ATT; - op_pt->act_state |= act_type; - } -} - -void DBOPL::disable_operator(op_type* op_pt, Bit32u act_type) { - // check if this is really an on-off transition - if (op_pt->act_state != OP_ACT_OFF) { - op_pt->act_state &= (~act_type); - if (op_pt->act_state == OP_ACT_OFF) { - if (op_pt->op_state != OF_TYPE_OFF) op_pt->op_state = OF_TYPE_REL; - } - } -} - -void DBOPL::Reset() { - Bit32u samplerate = (Bit32u)OPL_SAMPLE_RATE; - Bits i, j, oct; - - int_samplerate = samplerate; - - generator_add = (Bit32u)(INTFREQU*FIXEDPT/int_samplerate); - - - memset((void *)adlibreg,0,sizeof(adlibreg)); - memset((void *)op,0,sizeof(op_type)*MAXOPERATORS); - memset((void *)wave_sel,0,sizeof(wave_sel)); - - for (i=0;i=0;i--) { - frqmul[i] = (fltype)(frqmul_tab[i]*INTFREQU/(fltype)WAVEPREC*(fltype)FIXEDPT*recipsamp); - } - - status = 0; - opl_index = 0; - - - // create vibrato table - vib_table[0] = 8; - vib_table[1] = 4; - vib_table[2] = 0; - vib_table[3] = -4; - for (i=4; i(VIBTAB_SIZE*FIXEDPT_LFO/8192*INTFREQU/int_samplerate); - vibtab_pos = 0; - - for (i=0; i -0.5/6 to 0) - for (i=14; i<41; i++) trem_table_int[i] = Bit32s(-i+14); // downwards (26 to 0 -> 0 to -1/6) - for (i=41; i<53; i++) trem_table_int[i] = Bit32s(i-40-26); // upwards (1 to 12 -> -1/6 to -0.5/6) - - for (i=0; i>1);i++) { - wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<1) )*PI*2/WAVEPREC)); - wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<1)+1)*PI*2/WAVEPREC)); - wavtable[i] = wavtable[(i<<1) +WAVEPREC]; - // alternative: (zero-less) -/* wavtable[(i<<1) +WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<2)+1)*PI/WAVEPREC)); - wavtable[(i<<1)+1+WAVEPREC] = (Bit16s)(16384*sin((fltype)((i<<2)+3)*PI/WAVEPREC)); - wavtable[i] = wavtable[(i<<1)-1+WAVEPREC]; */ - } - for (i=0;i<(WAVEPREC>>3);i++) { - wavtable[i+(WAVEPREC<<1)] = wavtable[i+(WAVEPREC>>3)]-16384; - wavtable[i+((WAVEPREC*17)>>3)] = wavtable[i+(WAVEPREC>>2)]+16384; - } - - // key scale level table verified ([table in book]*8/3) - kslev[7][0] = 0; kslev[7][1] = 24; kslev[7][2] = 32; kslev[7][3] = 37; - kslev[7][4] = 40; kslev[7][5] = 43; kslev[7][6] = 45; kslev[7][7] = 47; - kslev[7][8] = 48; - for (i=9;i<16;i++) kslev[7][i] = (Bit8u)(i+41); - for (j=6;j>=0;j--) { - for (i=0;i<16;i++) { - oct = (Bits)kslev[j+1][i]-8; - if (oct < 0) oct = 0; - kslev[j][i] = (Bit8u)oct; - } - } - } - -} - - - -void DBOPL::WriteReg(int idx, int val) { - Bit32u second_set = (Bit32u)idx&0x100; - adlibreg[idx] = val; - - switch (idx&0xf0) { - case ARC_CONTROL: - // here we check for the second set registers, too: - switch (idx) { - case 0x02: // timer1 counter - case 0x03: // timer2 counter - break; - case 0x04: - // IRQ reset, timer mask/start - if (val&0x80) { - // clear IRQ bits in status register - status &= ~0x60; - } else { - status = 0; - } - break; -#if defined(OPLTYPE_IS_OPL3) - case 0x04|ARC_SECONDSET: - // 4op enable/disable switches for each possible channel - op[0].is_4op = (val&1)>0; - op[3].is_4op_attached = op[0].is_4op; - op[1].is_4op = (val&2)>0; - op[4].is_4op_attached = op[1].is_4op; - op[2].is_4op = (val&4)>0; - op[5].is_4op_attached = op[2].is_4op; - op[18].is_4op = (val&8)>0; - op[21].is_4op_attached = op[18].is_4op; - op[19].is_4op = (val&16)>0; - op[22].is_4op_attached = op[19].is_4op; - op[20].is_4op = (val&32)>0; - op[23].is_4op_attached = op[20].is_4op; - break; - case 0x05|ARC_SECONDSET: - break; -#endif - case 0x08: - // CSW, note select - break; - default: - break; - } - break; - case ARC_TVS_KSR_MUL: - case ARC_TVS_KSR_MUL+0x10: { - // tremolo/vibrato/sustain keeping enabled; key scale rate; frequency multiplication - int num = (int)idx&7; - Bitu base = (idx-ARC_TVS_KSR_MUL)&0xff; - if ((num<6) && (base<22)) { - Bitu modop = regbase2modop[second_set?(base+22):base]; - Bitu regbase = base+second_set; - Bitu chanbase = second_set?(modop-18+ARC_SECONDSET):modop; - - // change tremolo/vibrato and sustain keeping of this operator - op_type* op_ptr = &op[modop+((num<3) ? 0 : 9)]; - change_keepsustain(regbase,op_ptr); - change_vibrato(regbase,op_ptr); - - // change frequency calculations of this operator as - // key scale rate and frequency multiplicator can be changed -#if defined(OPLTYPE_IS_OPL3) - if ((adlibreg[0x105]&1) && (op[modop].is_4op_attached)) { - // operator uses frequency of channel - change_frequency(chanbase-3,regbase,op_ptr); - } else { - change_frequency(chanbase,regbase,op_ptr); - } -#else - change_frequency(chanbase,base,op_ptr); -#endif - } - } - break; - case ARC_KSL_OUTLEV: - case ARC_KSL_OUTLEV+0x10: { - // key scale level; output rate - int num = (int)idx&7; - Bitu base = (idx-ARC_KSL_OUTLEV)&0xff; - if ((num<6) && (base<22)) { - Bitu modop = regbase2modop[second_set?(base+22):base]; - Bitu chanbase = second_set?(modop-18+ARC_SECONDSET):modop; - - // change frequency calculations of this operator as - // key scale level and output rate can be changed - op_type* op_ptr = &op[modop+((num<3) ? 0 : 9)]; -#if defined(OPLTYPE_IS_OPL3) - Bitu regbase = base+second_set; - if ((adlibreg[0x105]&1) && (op[modop].is_4op_attached)) { - // operator uses frequency of channel - change_frequency(chanbase-3,regbase,op_ptr); - } else { - change_frequency(chanbase,regbase,op_ptr); - } -#else - change_frequency(chanbase,base,op_ptr); -#endif - } - } - break; - case ARC_ATTR_DECR: - case ARC_ATTR_DECR+0x10: { - // attack/decay rates - int num = (int)idx&7; - Bitu base = (idx-ARC_ATTR_DECR)&0xff; - if ((num<6) && (base<22)) { - Bitu regbase = base+second_set; - - // change attack rate and decay rate of this operator - op_type* op_ptr = &op[regbase2op[second_set?(base+22):base]]; - change_attackrate(regbase,op_ptr); - change_decayrate(regbase,op_ptr); - } - } - break; - case ARC_SUSL_RELR: - case ARC_SUSL_RELR+0x10: { - // sustain level; release rate - int num = (int)idx&7; - Bitu base = (idx-ARC_SUSL_RELR)&0xff; - if ((num<6) && (base<22)) { - Bitu regbase = base+second_set; - - // change sustain level and release rate of this operator - op_type* op_ptr = &op[regbase2op[second_set?(base+22):base]]; - change_releaserate(regbase,op_ptr); - change_sustainlevel(regbase,op_ptr); - } - } - break; - case ARC_FREQ_NUM: { - // 0xa0-0xa8 low8 frequency - Bitu base = (idx-ARC_FREQ_NUM)&0xff; - if (base<9) { - Bits opbase = second_set?(base+18):base; -#if defined(OPLTYPE_IS_OPL3) - if ((adlibreg[0x105]&1) && op[opbase].is_4op_attached) break; -#endif - // regbase of modulator: - Bits modbase = modulatorbase[base]+second_set; - - Bitu chanbase = base+second_set; - - change_frequency(chanbase,modbase,&op[opbase]); - change_frequency(chanbase,modbase+3,&op[opbase+9]); -#if defined(OPLTYPE_IS_OPL3) - // for 4op channels all four operators are modified to the frequency of the channel - if ((adlibreg[0x105]&1) && op[second_set?(base+18):base].is_4op) { - change_frequency(chanbase,modbase+8,&op[opbase+3]); - change_frequency(chanbase,modbase+3+8,&op[opbase+3+9]); - } -#endif - } - } - break; - case ARC_KON_BNUM: { - if (idx == ARC_PERC_MODE) { -#if defined(OPLTYPE_IS_OPL3) - if (second_set) return; -#endif - - if ((val&0x30) == 0x30) { // BassDrum active - enable_operator(16,&op[6],OP_ACT_PERC); - change_frequency(6,16,&op[6]); - enable_operator(16+3,&op[6+9],OP_ACT_PERC); - change_frequency(6,16+3,&op[6+9]); - } else { - disable_operator(&op[6],OP_ACT_PERC); - disable_operator(&op[6+9],OP_ACT_PERC); - } - if ((val&0x28) == 0x28) { // Snare active - enable_operator(17+3,&op[16],OP_ACT_PERC); - change_frequency(7,17+3,&op[16]); - } else { - disable_operator(&op[16],OP_ACT_PERC); - } - if ((val&0x24) == 0x24) { // TomTom active - enable_operator(18,&op[8],OP_ACT_PERC); - change_frequency(8,18,&op[8]); - } else { - disable_operator(&op[8],OP_ACT_PERC); - } - if ((val&0x22) == 0x22) { // Cymbal active - enable_operator(18+3,&op[8+9],OP_ACT_PERC); - change_frequency(8,18+3,&op[8+9]); - } else { - disable_operator(&op[8+9],OP_ACT_PERC); - } - if ((val&0x21) == 0x21) { // Hihat active - enable_operator(17,&op[7],OP_ACT_PERC); - change_frequency(7,17,&op[7]); - } else { - disable_operator(&op[7],OP_ACT_PERC); - } - - break; - } - // regular 0xb0-0xb8 - Bitu base = (idx-ARC_KON_BNUM)&0xff; - if (base<9) { - Bits opbase = second_set?(base+18):base; -#if defined(OPLTYPE_IS_OPL3) - if ((adlibreg[0x105]&1) && op[opbase].is_4op_attached) break; -#endif - // regbase of modulator: - Bits modbase = modulatorbase[base]+second_set; - - if (val&32) { - // operator switched on - enable_operator(modbase,&op[opbase],OP_ACT_NORMAL); // modulator (if 2op) - enable_operator(modbase+3,&op[opbase+9],OP_ACT_NORMAL); // carrier (if 2op) -#if defined(OPLTYPE_IS_OPL3) - // for 4op channels all four operators are switched on - if ((adlibreg[0x105]&1) && op[opbase].is_4op) { - // turn on chan+3 operators as well - enable_operator(modbase+8,&op[opbase+3],OP_ACT_NORMAL); - enable_operator(modbase+3+8,&op[opbase+3+9],OP_ACT_NORMAL); - } -#endif - } else { - // operator switched off - disable_operator(&op[opbase],OP_ACT_NORMAL); - disable_operator(&op[opbase+9],OP_ACT_NORMAL); -#if defined(OPLTYPE_IS_OPL3) - // for 4op channels all four operators are switched off - if ((adlibreg[0x105]&1) && op[opbase].is_4op) { - // turn off chan+3 operators as well - disable_operator(&op[opbase+3],OP_ACT_NORMAL); - disable_operator(&op[opbase+3+9],OP_ACT_NORMAL); - } -#endif - } - - Bitu chanbase = base+second_set; - - // change frequency calculations of modulator and carrier (2op) as - // the frequency of the channel has changed - change_frequency(chanbase,modbase,&op[opbase]); - change_frequency(chanbase,modbase+3,&op[opbase+9]); -#if defined(OPLTYPE_IS_OPL3) - // for 4op channels all four operators are modified to the frequency of the channel - if ((adlibreg[0x105]&1) && op[second_set?(base+18):base].is_4op) { - // change frequency calculations of chan+3 operators as well - change_frequency(chanbase,modbase+8,&op[opbase+3]); - change_frequency(chanbase,modbase+3+8,&op[opbase+3+9]); - } -#endif - } - } - break; - case ARC_FEEDBACK: { - // 0xc0-0xc8 feedback/modulation type (AM/FM) - Bitu base = (idx-ARC_FEEDBACK)&0xff; - if (base<9) { - Bits opbase = second_set?(base+18):base; - Bitu chanbase = base+second_set; - change_feedback(chanbase,&op[opbase]); -#if defined(OPLTYPE_IS_OPL3) - // OPL3 panning - if (!FullPan) - { - op[opbase].left_pan = (float)((val&0x10)>>4); - op[opbase].right_pan = (float)((val&0x20)>>5); - } -#endif - } - } - break; - case ARC_WAVE_SEL: - case ARC_WAVE_SEL+0x10: { - int num = (int)idx&7; - Bitu base = (idx-ARC_WAVE_SEL)&0xff; - if ((num<6) && (base<22)) { -#if defined(OPLTYPE_IS_OPL3) - Bits wselbase = second_set?(base+22):base; // for easier mapping onto wave_sel[] - // change waveform - if (adlibreg[0x105]&1) wave_sel[wselbase] = val&7; // opl3 mode enabled, all waveforms accessible - else wave_sel[wselbase] = val&3; - op_type* op_ptr = &op[regbase2modop[wselbase]+((num<3) ? 0 : 9)]; - change_waveform(wselbase,op_ptr); -#else - if (adlibreg[0x01]&0x20) { - // wave selection enabled, change waveform - wave_sel[base] = val&3; - op_type* op_ptr = &op[regbase2modop[base]+((num<3) ? 0 : 9)]; - change_waveform(base,op_ptr); - } -#endif - } - } - break; - default: - break; - } -} - -static void OPL_INLINE clipit16(float ival, float* outval) { - *outval += ival / 10240.f; -} - - - -// be careful with this -// uses cptr and chanval, outputs into outbufl(/outbufr) -// for opl3 check if opl3-mode is enabled (which uses stereo panning) -#undef CHANVAL_OUT -#if defined(OPLTYPE_IS_OPL3) -#define CHANVAL_OUT \ - if (adlibreg[0x105]&1) { \ - outbufl[i] += chanval*cptr[0].left_pan; \ - outbufr[i] += chanval*cptr[0].right_pan; \ - } else { \ - outbufl[i] += chanval; \ - } -#else -#define CHANVAL_OUT \ - outbufl[i] += chanval; -#endif - -void DBOPL::Update(float* sndptr, int numsamples) { - Bits i, endsamples; - op_type* cptr; - - float outbufl[BLOCKBUF_SIZE]; -#if defined(OPLTYPE_IS_OPL3) - // second output buffer (right channel for opl3 stereo) - float outbufr[BLOCKBUF_SIZE]; -#endif - - // vibrato/tremolo lookup tables (global, to possibly be used by all operators) - Bit32s vib_lut[BLOCKBUF_SIZE]; - Bit32s trem_lut[BLOCKBUF_SIZE]; - - Bits samples_to_process = numsamples; - - for (Bits cursmp=0; cursmpBLOCKBUF_SIZE) endsamples = BLOCKBUF_SIZE; - - memset((void*)&outbufl,0,endsamples*sizeof(Bit32s)); -#if defined(OPLTYPE_IS_OPL3) - // clear second output buffer (opl3 stereo) - if (adlibreg[0x105]&1) memset((void*)&outbufr,0,endsamples*sizeof(Bit32s)); -#endif - - // calculate vibrato/tremolo lookup tables - Bit32s vib_tshift = ((adlibreg[ARC_PERC_MODE]&0x40)==0) ? 1 : 0; // 14cents/7cents switching - for (i=0;i=VIBTAB_SIZE) vibtab_pos-=VIBTAB_SIZE*FIXEDPT_LFO; - vib_lut[i] = vib_table[vibtab_pos/FIXEDPT_LFO]>>vib_tshift; // 14cents (14/100 of a semitone) or 7cents - - // cycle through tremolo table - tremtab_pos += tremtab_add; - if (tremtab_pos/FIXEDPT_LFO>=TREMTAB_SIZE) tremtab_pos-=TREMTAB_SIZE*FIXEDPT_LFO; - if (adlibreg[ARC_PERC_MODE]&0x80) trem_lut[i] = trem_table[tremtab_pos/FIXEDPT_LFO]; - else trem_lut[i] = trem_table[TREMTAB_SIZE+tremtab_pos/FIXEDPT_LFO]; - } - - if (adlibreg[ARC_PERC_MODE]&0x20) { - //BassDrum - cptr = &op[6]; - if (adlibreg[ARC_FEEDBACK+6]&1) { - // additive synthesis - if (cptr[9].op_state != OF_TYPE_OFF) { - if (cptr[9].vibrato) { - vibval1 = vibval_var1; - for (i=0;i=0; cur_ch--) { - // skip drum/percussion operators - if ((adlibreg[ARC_PERC_MODE]&0x20) && (cur_ch >= 6) && (cur_ch < 9)) continue; - - Bitu k = cur_ch; -#if defined(OPLTYPE_IS_OPL3) - if (cur_ch < 9) { - cptr = &op[cur_ch]; - } else { - cptr = &op[cur_ch+9]; // second set is operator18-operator35 - k += (-9+256); // second set uses registers 0x100 onwards - } - // check if this operator is part of a 4-op - if ((adlibreg[0x105]&1) && cptr->is_4op_attached) continue; -#else - cptr = &op[cur_ch]; -#endif - - // check for FM/AM - if (adlibreg[ARC_FEEDBACK+k]&1) { -#if defined(OPLTYPE_IS_OPL3) - if ((adlibreg[0x105]&1) && cptr->is_4op) { - if (adlibreg[ARC_FEEDBACK+k+3]&1) { - // AM-AM-style synthesis (op1[fb] + (op2 * op3) + op4) - if (cptr[0].op_state != OF_TYPE_OFF) { - if (cptr[0].vibrato) { - vibval1 = vibval_var1; - for (i=0;iis_4op) { - if (adlibreg[ARC_FEEDBACK+k+3]&1) { - // FM-AM-style synthesis ((op1[fb] * op2) + (op3 * op4)) - if ((cptr[0].op_state != OF_TYPE_OFF) || (cptr[9].op_state != OF_TYPE_OFF)) { - if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) { - vibval1 = vibval_var1; - for (i=0;istereo) - for (i=0;istereo) - for (i=0;i= 9) - { - c += 9; - } - op[c].left_pan = left; - op[c].right_pan = right; - } -} - -DBOPL::DBOPL(bool fullpan) -{ - FullPan = fullpan; - Reset(); -} - -OPLEmul *DBOPLCreate(bool fullpan) -{ - return new DBOPL(fullpan); -} diff --git a/libraries/oplsynth/dosbox/opl.h b/libraries/oplsynth/dosbox/opl.h deleted file mode 100644 index eba6ee6ee..000000000 --- a/libraries/oplsynth/dosbox/opl.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * Copyright (C) 2002-2011 The DOSBox Team - * OPL2/OPL3 emulation library - * - * 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 - */ - - -/* - * Originally based on ADLIBEMU.C, an AdLib/OPL2 emulation library by Ken Silverman - * Copyright (C) 1998-2001 Ken Silverman - * Ken Silverman's official web site: "http://www.advsys.net/ken" - */ - - -#define fltype double - -/* - define Bits, Bitu, Bit32s, Bit32u, Bit16s, Bit16u, Bit8s, Bit8u here -*/ -/* -#include -typedef uintptr_t Bitu; -typedef intptr_t Bits; -typedef uint32_t Bit32u; -typedef int32_t Bit32s; -typedef uint16_t Bit16u; -typedef int16_t Bit16s; -typedef uint8_t Bit8u; -typedef int8_t Bit8s; -*/ - - -/* - define attribution that inlines/forces inlining of a function (optional) -*/ -#define OPL_INLINE inline - - -#undef NUM_CHANNELS -#if defined(OPLTYPE_IS_OPL3) -#define NUM_CHANNELS 18 -#else -#define NUM_CHANNELS 9 -#endif - -#define MAXOPERATORS (NUM_CHANNELS*2) - - -#define FL05 ((fltype)0.5) -#define FL2 ((fltype)2.0) -#define PI ((fltype)3.1415926535897932384626433832795) - - -#define FIXEDPT 0x10000 // fixed-point calculations using 16+16 -#define FIXEDPT_LFO 0x1000000 // fixed-point calculations using 8+24 - -#define WAVEPREC 1024 // waveform precision (10 bits) - -#define INTFREQU ((fltype)(14318180.0 / 288.0)) // clocking of the chip - - -#define OF_TYPE_ATT 0 -#define OF_TYPE_DEC 1 -#define OF_TYPE_REL 2 -#define OF_TYPE_SUS 3 -#define OF_TYPE_SUS_NOKEEP 4 -#define OF_TYPE_OFF 5 - -#define ARC_CONTROL 0x00 -#define ARC_TVS_KSR_MUL 0x20 -#define ARC_KSL_OUTLEV 0x40 -#define ARC_ATTR_DECR 0x60 -#define ARC_SUSL_RELR 0x80 -#define ARC_FREQ_NUM 0xa0 -#define ARC_KON_BNUM 0xb0 -#define ARC_PERC_MODE 0xbd -#define ARC_FEEDBACK 0xc0 -#define ARC_WAVE_SEL 0xe0 - -#define ARC_SECONDSET 0x100 // second operator set for OPL3 - - -#define OP_ACT_OFF 0x00 -#define OP_ACT_NORMAL 0x01 // regular channel activated (bitmasked) -#define OP_ACT_PERC 0x02 // percussion channel activated (bitmasked) - -#define BLOCKBUF_SIZE 512 - - -// vibrato constants -#define VIBTAB_SIZE 8 -#define VIBFAC 70/50000 // no braces, integer mul/div - -// tremolo constants and table -#define TREMTAB_SIZE 53 -#define TREM_FREQ ((fltype)(3.7)) // tremolo at 3.7hz - - -/* operator struct definition - For OPL2 all 9 channels consist of two operators each, carrier and modulator. - Channel x has operators x as modulator and operators (9+x) as carrier. - For OPL3 all 18 channels consist either of two operators (2op mode) or four - operators (4op mode) which is determined through register4 of the second - adlib register set. - Only the channels 0,1,2 (first set) and 9,10,11 (second set) can act as - 4op channels. The two additional operators for a channel y come from the - 2op channel y+3 so the operatorss y, (9+y), y+3, (9+y)+3 make up a 4op - channel. -*/ -typedef struct operator_struct { - Bit32s cval, lastcval; // current output/last output (used for feedback) - Bit32u tcount, wfpos, tinc; // time (position in waveform) and time increment - fltype amp, step_amp; // and amplification (envelope) - fltype vol; // volume - fltype sustain_level; // sustain level - Bit32s mfbi; // feedback amount - fltype a0, a1, a2, a3; // attack rate function coefficients - fltype decaymul, releasemul; // decay/release rate functions - Bit32u op_state; // current state of operator (attack/decay/sustain/release/off) - Bit32u toff; - Bit32s freq_high; // highest three bits of the frequency, used for vibrato calculations - Bit16s* cur_wform; // start of selected waveform - Bit32u cur_wmask; // mask for selected waveform - Bit32u act_state; // activity state (regular, percussion) - bool sus_keep; // keep sustain level when decay finished - bool vibrato,tremolo; // vibrato/tremolo enable bits - - // variables used to provide non-continuous envelopes - Bit32u generator_pos; // for non-standard sample rates we need to determine how many samples have passed - Bits cur_env_step; // current (standardized) sample position - Bits env_step_a,env_step_d,env_step_r; // number of std samples of one step (for attack/decay/release mode) - Bit8u step_skip_pos_a; // position of 8-cyclic step skipping (always 2^x to check against mask) - Bits env_step_skip_a; // bitmask that determines if a step is skipped (respective bit is zero then) - -#if defined(OPLTYPE_IS_OPL3) - bool is_4op,is_4op_attached; // base of a 4op channel/part of a 4op channel - float left_pan,right_pan; // opl3 stereo panning amount -#endif -} op_type; - -// per-chip variables -class DBOPL : public OPLEmul -{ -private: - op_type op[MAXOPERATORS]; - - Bits int_samplerate; - - Bit8u status; - Bit32u opl_index; -#if defined(OPLTYPE_IS_OPL3) - Bit8u adlibreg[512]; // adlib register set (including second set) - Bit8u wave_sel[44]; // waveform selection -#else - Bit8u adlibreg[256]; // adlib register set - Bit8u wave_sel[22]; // waveform selection -#endif - - fltype recipsamp; // inverse of sampling rate - - // vibrato/tremolo tables - Bit32s vib_table[VIBTAB_SIZE]; - Bit32s trem_table[TREMTAB_SIZE*2]; - - Bit32s vibval_const[BLOCKBUF_SIZE]; - Bit32s tremval_const[BLOCKBUF_SIZE]; - - // vibrato value tables (used per-operator) - Bit32s vibval_var1[BLOCKBUF_SIZE]; - Bit32s vibval_var2[BLOCKBUF_SIZE]; - - // vibrato/trmolo value table pointers - Bit32s *vibval1, *vibval2, *vibval3, *vibval4; - Bit32s *tremval1, *tremval2, *tremval3, *tremval4; - - // calculated frequency multiplication values (depend on sampling rate) - fltype frqmul[16]; - - - // vibrato/tremolo increment/counter - Bit32u vibtab_pos; - Bit32u vibtab_add; - Bit32u tremtab_pos; - Bit32u tremtab_add; - - // Enable full MIDI panning; disable OPL3 panning - bool FullPan; - - - // enable an operator - void enable_operator(Bitu regbase, op_type* op_pt, Bit32u act_type); - - void disable_operator(op_type* op_pt, Bit32u act_type); - - // functions to change parameters of an operator - void change_frequency(Bitu chanbase, Bitu regbase, op_type* op_pt); - - void change_attackrate(Bitu regbase, op_type* op_pt); - void change_decayrate(Bitu regbase, op_type* op_pt); - void change_releaserate(Bitu regbase, op_type* op_pt); - void change_sustainlevel(Bitu regbase, op_type* op_pt); - void change_waveform(Bitu regbase, op_type* op_pt); - void change_keepsustain(Bitu regbase, op_type* op_pt); - void change_vibrato(Bitu regbase, op_type* op_pt); - void change_feedback(Bitu chanbase, op_type* op_pt); - - // general functions -public: - void Reset(); - void Update(float* sndptr, int numsamples); - void WriteReg(int idx, int val); - void SetPanning(int c, float left, float right); - - DBOPL(bool stereo); -}; - -static Bit32u generator_add; // should be a chip parameter diff --git a/libraries/oplsynth/fmopl.cpp b/libraries/oplsynth/fmopl.cpp deleted file mode 100644 index 353e31339..000000000 --- a/libraries/oplsynth/fmopl.cpp +++ /dev/null @@ -1,1711 +0,0 @@ -// license:GPL-2.0+ -// copyright-holders:Jarek Burczynski,Tatsuyuki Satoh -/* - -This file is based on fmopl.c from MAME. The non-YM3816 parts have been -ripped out in the interest of making this simpler, since Doom music doesn't -need them. I also made it render the sound a voice at a time instead of a -sample at a time, so unused voices don't waste time being calculated. If all -voices are playing, it's not much difference, but it does offer a big -improvement when only a few voices are playing. - - - -** -** File: fmopl.c - software implementation of FM sound generator -** types OPL and OPL2 -** -** Copyright Jarek Burczynski (bujar at mame dot net) -** Copyright Tatsuyuki Satoh , MultiArcadeMachineEmulator development -** -** Version 0.72 -** - -Revision History: - -04-08-2003 Jarek Burczynski: - - removed BFRDY hack. BFRDY is busy flag, and it should be 0 only when the chip - handles memory read/write or during the adpcm synthesis when the chip - requests another byte of ADPCM data. - -24-07-2003 Jarek Burczynski: - - added a small hack for Y8950 status BFRDY flag (bit 3 should be set after - some (unknown) delay). Right now it's always set. - -14-06-2003 Jarek Burczynski: - - implemented all of the status register flags in Y8950 emulation - - renamed y8950_set_delta_t_memory() parameters from _rom_ to _mem_ since - they can be either RAM or ROM - -08-10-2002 Jarek Burczynski (thanks to Dox for the YM3526 chip) - - corrected ym3526_read() to always set bit 2 and bit 1 - to HIGH state - identical to ym3812_read (verified on real YM3526) - -04-28-2002 Jarek Burczynski: - - binary exact Envelope Generator (verified on real YM3812); - compared to YM2151: the EG clock is equal to internal_clock, - rates are 2 times slower and volume resolution is one bit less - - modified interface functions (they no longer return pointer - - that's internal to the emulator now): - - new wrapper functions for OPLCreate: ym3526_init(), ym3812_init() and y8950_init() - - corrected 'off by one' error in feedback calculations (when feedback is off) - - enabled waveform usage (credit goes to Vlad Romascanu and zazzal22) - - speeded up noise generator calculations (Nicola Salmoria) - -03-24-2002 Jarek Burczynski (thanks to Dox for the YM3812 chip) - Complete rewrite (all verified on real YM3812): - - corrected sin_tab and tl_tab data - - corrected operator output calculations - - corrected waveform_select_enable register; - simply: ignore all writes to waveform_select register when - waveform_select_enable == 0 and do not change the waveform previously selected. - - corrected KSR handling - - corrected Envelope Generator: attack shape, Sustain mode and - Percussive/Non-percussive modes handling - - Envelope Generator rates are two times slower now - - LFO amplitude (tremolo) and phase modulation (vibrato) - - rhythm sounds phase generation - - white noise generator (big thanks to Olivier Galibert for mentioning Berlekamp-Massey algorithm) - - corrected key on/off handling (the 'key' signal is ORed from three sources: FM, rhythm and CSM) - - funky details (like ignoring output of operator 1 in BD rhythm sound when connect == 1) - -12-28-2001 Acho A. Tang - - reflected Delta-T EOS status on Y8950 status port. - - fixed subscription range of attack/decay tables - - - To do: - add delay before key off in CSM mode (see CSMKeyControll) - verify volume of the FM part on the Y8950 -*/ - -#include -#include -#include -#include -#include -#include -//#include "driver.h" /* use M.A.M.E. */ -#include "opl.h" - -/* compiler dependence */ -#ifndef OSD_CPU_H -#define OSD_CPU_H -#endif - -#ifndef PI -#define PI 3.14159265358979323846 -#endif - -#ifdef _MSC_VER -#pragma warning (disable: 4244) -#endif - - -#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ -#define EG_SH 16 /* 16.16 fixed point (EG timing) */ -#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ -#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ - -#define FREQ_MASK ((1<>KSR */ - uint8_t mul; /* multiple: mul_tab[ML] */ - - /* Phase Generator */ - uint32_t Cnt; /* frequency counter */ - uint32_t Incr; /* frequency counter step */ - uint8_t FB; /* feedback shift value */ - int32_t *connect1; /* slot1 output pointer */ - int32_t op1_out[2]; /* slot1 output for feedback */ - uint8_t CON; /* connection (algorithm) type */ - - /* Envelope Generator */ - uint8_t eg_type; /* percussive/non-percussive mode */ - uint8_t state; /* phase type */ - uint32_t TL; /* total level: TL << 2 */ - int32_t TLL; /* adjusted now TL */ - int32_t volume; /* envelope counter */ - uint32_t sl; /* sustain level: sl_tab[SL] */ - uint8_t eg_sh_ar; /* (attack state) */ - uint8_t eg_sel_ar; /* (attack state) */ - uint8_t eg_sh_dr; /* (decay state) */ - uint8_t eg_sel_dr; /* (decay state) */ - uint8_t eg_sh_rr; /* (release state) */ - uint8_t eg_sel_rr; /* (release state) */ - uint32_t key; /* 0 = KEY OFF, >0 = KEY ON */ - - /* LFO */ - uint32_t AMmask; /* LFO Amplitude Modulation enable mask */ - uint8_t vib; /* LFO Phase Modulation enable flag (active high)*/ - - /* waveform select */ - uint16_t wavetable; -}; - -struct OPL_CH -{ - OPL_SLOT SLOT[2]; - /* phase generator state */ - uint32_t block_fnum; /* block+fnum */ - uint32_t fc; /* Freq. Increment base */ - uint32_t ksl_base; /* KeyScaleLevel Base step */ - uint8_t kcode; /* key code (for key scaling) */ - float LeftVol; /* volumes for stereo panning */ - float RightVol; -}; - -/* OPL state */ -struct FM_OPL -{ - /* FM channel slots */ - OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/ - - uint32_t eg_cnt; /* global envelope generator counter */ - uint32_t eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */ - uint32_t eg_timer_add; /* step of eg_timer */ - uint32_t eg_timer_overflow; /* envelope generator timer overflows every 1 sample (on real chip) */ - - uint8_t rhythm; /* Rhythm mode */ - - uint32_t fn_tab[1024]; /* fnumber->increment counter */ - - /* LFO */ - - uint8_t lfo_am_depth; - uint8_t lfo_pm_depth_range; - uint32_t lfo_am_cnt; - uint32_t lfo_am_inc; - uint32_t lfo_pm_cnt; - uint32_t lfo_pm_inc; - - uint32_t noise_rng; /* 23 bit noise shift register */ - uint32_t noise_p; /* current noise 'phase' */ - uint32_t noise_f; /* current noise period */ - - uint8_t wavesel; /* waveform select enable flag */ - - int T[2]; /* timer counters */ - uint8_t st[2]; /* timer enable */ - - - uint8_t address; /* address register */ - uint8_t status; /* status flag */ - uint8_t statusmask; /* status mask */ - uint8_t mode; /* Reg.08 : CSM,notesel,etc. */ - - bool IsStereo; /* Write stereo output */ -}; - - - -/* mapping of register number (offset) to slot number used by the emulator */ -static const int slot_array[32]= -{ - 0, 2, 4, 1, 3, 5,-1,-1, - 6, 8,10, 7, 9,11,-1,-1, - 12,14,16,13,15,17,-1,-1, - -1,-1,-1,-1,-1,-1,-1,-1 -}; - -/* key scale level */ -/* table is 3dB/octave , DV converts this into 6dB/octave */ -/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ -#define DV (0.1875/2.0) -static const uint32_t ksl_tab[8*16]= -{ - /* OCT 0 */ - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), - /* OCT 1 */ - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), - uint32_t(0.000/DV), uint32_t(0.750/DV), uint32_t(1.125/DV), uint32_t(1.500/DV), - uint32_t(1.875/DV), uint32_t(2.250/DV), uint32_t(2.625/DV), uint32_t(3.000/DV), - /* OCT 2 */ - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), - uint32_t(0.000/DV), uint32_t(1.125/DV), uint32_t(1.875/DV), uint32_t(2.625/DV), - uint32_t(3.000/DV), uint32_t(3.750/DV), uint32_t(4.125/DV), uint32_t(4.500/DV), - uint32_t(4.875/DV), uint32_t(5.250/DV), uint32_t(5.625/DV), uint32_t(6.000/DV), - /* OCT 3 */ - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(1.875/DV), - uint32_t(3.000/DV), uint32_t(4.125/DV), uint32_t(4.875/DV), uint32_t(5.625/DV), - uint32_t(6.000/DV), uint32_t(6.750/DV), uint32_t(7.125/DV), uint32_t(7.500/DV), - uint32_t(7.875/DV), uint32_t(8.250/DV), uint32_t(8.625/DV), uint32_t(9.000/DV), - /* OCT 4 */ - uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(3.000/DV), uint32_t(4.875/DV), - uint32_t(6.000/DV), uint32_t(7.125/DV), uint32_t(7.875/DV), uint32_t(8.625/DV), - uint32_t(9.000/DV), uint32_t(9.750/DV),uint32_t(10.125/DV),uint32_t(10.500/DV), - uint32_t(10.875/DV),uint32_t(11.250/DV),uint32_t(11.625/DV),uint32_t(12.000/DV), - /* OCT 5 */ - uint32_t(0.000/DV), uint32_t(3.000/DV), uint32_t(6.000/DV), uint32_t(7.875/DV), - uint32_t(9.000/DV),uint32_t(10.125/DV),uint32_t(10.875/DV),uint32_t(11.625/DV), - uint32_t(12.000/DV),uint32_t(12.750/DV),uint32_t(13.125/DV),uint32_t(13.500/DV), - uint32_t(13.875/DV),uint32_t(14.250/DV),uint32_t(14.625/DV),uint32_t(15.000/DV), - /* OCT 6 */ - uint32_t(0.000/DV), uint32_t(6.000/DV), uint32_t(9.000/DV),uint32_t(10.875/DV), - uint32_t(12.000/DV),uint32_t(13.125/DV),uint32_t(13.875/DV),uint32_t(14.625/DV), - uint32_t(15.000/DV),uint32_t(15.750/DV),uint32_t(16.125/DV),uint32_t(16.500/DV), - uint32_t(16.875/DV),uint32_t(17.250/DV),uint32_t(17.625/DV),uint32_t(18.000/DV), - /* OCT 7 */ - uint32_t(0.000/DV), uint32_t(9.000/DV),uint32_t(12.000/DV),uint32_t(13.875/DV), - uint32_t(15.000/DV),uint32_t(16.125/DV),uint32_t(16.875/DV),uint32_t(17.625/DV), - uint32_t(18.000/DV),uint32_t(18.750/DV),uint32_t(19.125/DV),uint32_t(19.500/DV), - uint32_t(19.875/DV),uint32_t(20.250/DV),uint32_t(20.625/DV),uint32_t(21.000/DV) -}; -#undef DV - -/* 0 / 3.0 / 1.5 / 6.0 dB/OCT */ -static const uint32_t ksl_shift[4] = { 31, 1, 2, 0 }; - - -/* sustain level table (3dB per step) */ -/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ -#define SC(db) (uint32_t) ( db * (2.0/ENV_STEP) ) -static const uint32_t sl_tab[16]={ - SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), - SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) -}; -#undef SC - - -#define RATE_STEPS (8) -static const unsigned char eg_inc[15*RATE_STEPS]={ -/*cycle:0 1 2 3 4 5 6 7*/ - -/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ -/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */ -/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */ -/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */ - -/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */ -/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */ -/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */ -/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */ - -/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */ -/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */ -/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */ -/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */ - -/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */ -/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */ -/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ -}; - - -#define O(a) (a*RATE_STEPS) - -/*note that there is no O(13) in this table - it's directly in the code */ -static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ -/* 16 infinite time rates */ -O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), -O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), - -/* rates 00-12 */ -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), -O( 0),O( 1),O( 2),O( 3), - -/* rate 13 */ -O( 4),O( 5),O( 6),O( 7), - -/* rate 14 */ -O( 8),O( 9),O(10),O(11), - -/* rate 15 */ -O(12),O(12),O(12),O(12), - -/* 16 dummy rates (same as 15 3) */ -O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), -O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), - -}; -#undef O - -/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */ -/*shift 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 */ -/*mask 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0 */ - -#define O(a) (a*1) -static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ -/* 16 infinite time rates */ -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), -O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), - -/* rates 00-12 */ -O(12),O(12),O(12),O(12), -O(11),O(11),O(11),O(11), -O(10),O(10),O(10),O(10), -O( 9),O( 9),O( 9),O( 9), -O( 8),O( 8),O( 8),O( 8), -O( 7),O( 7),O( 7),O( 7), -O( 6),O( 6),O( 6),O( 6), -O( 5),O( 5),O( 5),O( 5), -O( 4),O( 4),O( 4),O( 4), -O( 3),O( 3),O( 3),O( 3), -O( 2),O( 2),O( 2),O( 2), -O( 1),O( 1),O( 1),O( 1), -O( 0),O( 0),O( 0),O( 0), - -/* rate 13 */ -O( 0),O( 0),O( 0),O( 0), - -/* rate 14 */ -O( 0),O( 0),O( 0),O( 0), - -/* rate 15 */ -O( 0),O( 0),O( 0),O( 0), - -/* 16 dummy rates (same as 15 3) */ -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), -O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), - -}; -#undef O - - -/* multiple table */ -#define ML 2 -static const uint8_t mul_tab[16]= { -/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ - uint8_t(0.50*ML), uint8_t(1.00*ML), uint8_t(2.00*ML), uint8_t(3.00*ML), uint8_t(4.00*ML), uint8_t(5.00*ML), uint8_t(6.00*ML), uint8_t(7.00*ML), - uint8_t(8.00*ML), uint8_t(9.00*ML),uint8_t(10.00*ML),uint8_t(10.00*ML),uint8_t(12.00*ML),uint8_t(12.00*ML),uint8_t(15.00*ML),uint8_t(15.00*ML) -}; -#undef ML - -/* TL_TAB_LEN is calculated as: -* 12 - sinus amplitude bits (Y axis) -* 2 - sinus sign bit (Y axis) -* TL_RES_LEN - sinus resolution (X axis) -*/ -#define TL_TAB_LEN (12*2*TL_RES_LEN) -static signed int tl_tab[TL_TAB_LEN]; - -#define ENV_QUIET (TL_TAB_LEN>>4) - -/* sin waveform table in 'decibel' scale */ -/* four waveforms on OPL2 type chips */ -static unsigned int sin_tab[SIN_LEN * 4]; - - -/* LFO Amplitude Modulation table (verified on real YM3812) - 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples - - Length: 210 elements. - - Each of the elements has to be repeated - exactly 64 times (on 64 consecutive samples). - The whole table takes: 64 * 210 = 13440 samples. - - When AM = 1 data is used directly - When AM = 0 data is divided by 4 before being used (losing precision is important) -*/ - -#define LFO_AM_TAB_ELEMENTS 210 - -static const uint8_t lfo_am_table[LFO_AM_TAB_ELEMENTS] = { -0,0,0,0,0,0,0, -1,1,1,1, -2,2,2,2, -3,3,3,3, -4,4,4,4, -5,5,5,5, -6,6,6,6, -7,7,7,7, -8,8,8,8, -9,9,9,9, -10,10,10,10, -11,11,11,11, -12,12,12,12, -13,13,13,13, -14,14,14,14, -15,15,15,15, -16,16,16,16, -17,17,17,17, -18,18,18,18, -19,19,19,19, -20,20,20,20, -21,21,21,21, -22,22,22,22, -23,23,23,23, -24,24,24,24, -25,25,25,25, -26,26,26, -25,25,25,25, -24,24,24,24, -23,23,23,23, -22,22,22,22, -21,21,21,21, -20,20,20,20, -19,19,19,19, -18,18,18,18, -17,17,17,17, -16,16,16,16, -15,15,15,15, -14,14,14,14, -13,13,13,13, -12,12,12,12, -11,11,11,11, -10,10,10,10, -9,9,9,9, -8,8,8,8, -7,7,7,7, -6,6,6,6, -5,5,5,5, -4,4,4,4, -3,3,3,3, -2,2,2,2, -1,1,1,1 -}; - -/* LFO Phase Modulation table (verified on real YM3812) */ -static const int8_t lfo_pm_table[8*8*2] = { -/* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */ -0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ -0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 00 1xxxxxxx (0x0080) */ -0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ -1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 01 0xxxxxxx (0x0100) */ -1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ -2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 01 1xxxxxxx (0x0180) */ -1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ -3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 10 0xxxxxxx (0x0200) */ -2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ -4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 10 1xxxxxxx (0x0280) */ -2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ -5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 11 0xxxxxxx (0x0300) */ -3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ -6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/ - -/* FNUM2/FNUM = 11 1xxxxxxx (0x0380) */ -3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ -7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/ -}; - - - -/* work table */ -static signed int phase_modulation; /* phase modulation input (SLOT 2) */ -static signed int output; - -static uint32_t LFO_AM; -static int32_t LFO_PM; - -static bool CalcVoice (FM_OPL *OPL, int voice, float *buffer, int length); -static bool CalcRhythm (FM_OPL *OPL, float *buffer, int length); - - - -/* status set and IRQ handling */ -static inline void OPL_STATUS_SET(FM_OPL *OPL,int flag) -{ - /* set status flag */ - OPL->status |= flag; - if(!(OPL->status & 0x80)) - { - if(OPL->status & OPL->statusmask) - { /* IRQ on */ - OPL->status |= 0x80; - } - } -} - -/* status reset and IRQ handling */ -static inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag) -{ - /* reset status flag */ - OPL->status &=~flag; - if((OPL->status & 0x80)) - { - if (!(OPL->status & OPL->statusmask) ) - { - OPL->status &= 0x7f; - } - } -} - -/* IRQ mask set */ -static inline void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) -{ - OPL->statusmask = flag; - /* IRQ handling check */ - OPL_STATUS_SET(OPL,0); - OPL_STATUS_RESET(OPL,0); -} - - -/* advance LFO to next sample */ -static inline void advance_lfo(FM_OPL *OPL) -{ - uint8_t tmp; - - /* LFO */ - OPL->lfo_am_cnt += OPL->lfo_am_inc; - if (OPL->lfo_am_cnt >= (uint32_t)(LFO_AM_TAB_ELEMENTS<lfo_am_cnt -= (LFO_AM_TAB_ELEMENTS<lfo_am_cnt >> LFO_SH ]; - - if (OPL->lfo_am_depth) - LFO_AM = tmp; - else - LFO_AM = tmp>>2; - - OPL->lfo_pm_cnt += OPL->lfo_pm_inc; - LFO_PM = ((OPL->lfo_pm_cnt>>LFO_SH) & 7) | OPL->lfo_pm_depth_range; -} - -/* advance to next sample */ -static inline void advance(FM_OPL *OPL, int loch, int hich) -{ - OPL_CH *CH; - OPL_SLOT *op; - int i; - - OPL->eg_timer += OPL->eg_timer_add; - loch *= 2; - hich *= 2; - - while (OPL->eg_timer >= OPL->eg_timer_overflow) - { - OPL->eg_timer -= OPL->eg_timer_overflow; - - OPL->eg_cnt++; - - for (i = loch; i <= hich + 1; i++) - { - CH = &OPL->P_CH[i/2]; - op = &CH->SLOT[i&1]; - - /* Envelope Generator */ - switch(op->state) - { - case EG_ATT: /* attack phase */ - if ( !(OPL->eg_cnt & ((1<eg_sh_ar)-1) ) ) - { - op->volume += (~op->volume * - (eg_inc[op->eg_sel_ar + ((OPL->eg_cnt>>op->eg_sh_ar)&7)]) - ) >>3; - - if (op->volume <= MIN_ATT_INDEX) - { - op->volume = MIN_ATT_INDEX; - op->state = EG_DEC; - } - - } - break; - - case EG_DEC: /* decay phase */ - if ( !(OPL->eg_cnt & ((1<eg_sh_dr)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)]; - - if ( op->volume >= (int32_t)op->sl ) - op->state = EG_SUS; - - } - break; - - case EG_SUS: /* sustain phase */ - - /* this is important behaviour: - one can change percusive/non-percussive modes on the fly and - the chip will remain in sustain phase - verified on real YM3812 */ - - if(op->eg_type) /* non-percussive mode */ - { - /* do nothing */ - } - else /* percussive mode */ - { - /* during sustain phase chip adds Release Rate (in percussive mode) */ - if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; - - if ( op->volume >= MAX_ATT_INDEX ) - op->volume = MAX_ATT_INDEX; - } - /* else do nothing in sustain phase */ - } - break; - - case EG_REL: /* release phase */ - if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) - { - op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; - - if ( op->volume >= MAX_ATT_INDEX ) - { - op->volume = MAX_ATT_INDEX; - op->state = EG_OFF; - } - - } - break; - - default: - break; - } - - /* Phase Generator */ - if(op->vib) - { - uint8_t block; - unsigned int block_fnum = CH->block_fnum; - - unsigned int fnum_lfo = (block_fnum&0x0380) >> 7; - - signed int lfo_fn_table_index_offset = lfo_pm_table[LFO_PM + 16*fnum_lfo ]; - - if (lfo_fn_table_index_offset) /* LFO phase modulation active */ - { - block_fnum += lfo_fn_table_index_offset; - block = (block_fnum&0x1c00) >> 10; - op->Cnt += (OPL->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul; - } - else /* LFO phase modulation = zero */ - { - op->Cnt += op->Incr; - } - } - else /* LFO phase modulation disabled for this operator */ - { - op->Cnt += op->Incr; - } - } - } -} - -static inline void advance_noise(FM_OPL *OPL) -{ - int i; - - /* The Noise Generator of the YM3812 is 23-bit shift register. - * Period is equal to 2^23-2 samples. - * Register works at sampling frequency of the chip, so output - * can change on every sample. - * - * Output of the register and input to the bit 22 is: - * bit0 XOR bit14 XOR bit15 XOR bit22 - * - * Simply use bit 22 as the noise output. - */ - - OPL->noise_p += OPL->noise_f; - i = OPL->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */ - OPL->noise_p &= FREQ_MASK; - while (i) - { - /* - uint32_t j; - j = ( (OPL->noise_rng) ^ (OPL->noise_rng>>14) ^ (OPL->noise_rng>>15) ^ (OPL->noise_rng>>22) ) & 1; - OPL->noise_rng = (j<<22) | (OPL->noise_rng>>1); - */ - - /* - Instead of doing all the logic operations above, we - use a trick here (and use bit 0 as the noise output). - The difference is only that the noise bit changes one - step ahead. This doesn't matter since we don't know - what is real state of the noise_rng after the reset. - */ - - if (OPL->noise_rng & 1) OPL->noise_rng ^= 0x800302; - OPL->noise_rng >>= 1; - - i--; - } -} - - -static inline signed int op_calc(uint32_t phase, unsigned int env, signed int pm, unsigned int wave_tab) -{ - uint32_t p; - - p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ]; - - if (p >= TL_TAB_LEN) - return 0; - return tl_tab[p]; -} - -static inline signed int op_calc1(uint32_t phase, unsigned int env, signed int pm, unsigned int wave_tab) -{ - uint32_t p; - - p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK) ]; - - if (p >= TL_TAB_LEN) - return 0; - return tl_tab[p]; -} - - -#define volume_calc(OP) ((OP)->TLL + ((uint32_t)(OP)->volume) + (LFO_AM & (OP)->AMmask)) - -/* calculate output */ -static inline float OPL_CALC_CH( OPL_CH *CH ) -{ - OPL_SLOT *SLOT; - unsigned int env; - signed int out; - - phase_modulation = 0; - - /* SLOT 1 */ - SLOT = &CH->SLOT[SLOT1]; - env = volume_calc(SLOT); - out = SLOT->op1_out[0] + SLOT->op1_out[1]; - SLOT->op1_out[0] = SLOT->op1_out[1]; - *SLOT->connect1 += SLOT->op1_out[0]; - SLOT->op1_out[1] = 0; - if( env < ENV_QUIET ) - { - if (!SLOT->FB) - out = 0; - SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); - } - - /* SLOT 2 */ - SLOT++; - env = volume_calc(SLOT); - if( env < ENV_QUIET ) - { - output += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable); - /* [RH] Convert to floating point. */ - return float(output) / 10240; - } - return 0; -} - -/* - operators used in the rhythm sounds generation process: - - Envelope Generator: - -channel operator register number Bass High Snare Tom Top -/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal - 6 / 0 12 50 70 90 f0 + - 6 / 1 15 53 73 93 f3 + - 7 / 0 13 51 71 91 f1 + - 7 / 1 16 54 74 94 f4 + - 8 / 0 14 52 72 92 f2 + - 8 / 1 17 55 75 95 f5 + - - Phase Generator: - -channel operator register number Bass High Snare Tom Top -/ slot number MULTIPLE Drum Hat Drum Tom Cymbal - 6 / 0 12 30 + - 6 / 1 15 33 + - 7 / 0 13 31 + + + - 7 / 1 16 34 ----- n o t u s e d ----- - 8 / 0 14 32 + - 8 / 1 17 35 + + - -channel operator register number Bass High Snare Tom Top -number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal - 6 12,15 B6 A6 + - - 7 13,16 B7 A7 + + + - - 8 14,17 B8 A8 + + + - -*/ - -/* calculate rhythm */ - -static inline void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) -{ - OPL_SLOT *SLOT; - signed int out; - unsigned int env; - - - /* Bass Drum (verified on real YM3812): - - depends on the channel 6 'connect' register: - when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out) - when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored - - output sample always is multiplied by 2 - */ - - phase_modulation = 0; - /* SLOT 1 */ - SLOT = &CH[6].SLOT[SLOT1]; - env = volume_calc(SLOT); - - out = SLOT->op1_out[0] + SLOT->op1_out[1]; - SLOT->op1_out[0] = SLOT->op1_out[1]; - - if (!SLOT->CON) - phase_modulation = SLOT->op1_out[0]; - /* else ignore output of operator 1 */ - - SLOT->op1_out[1] = 0; - if( env < ENV_QUIET ) - { - if (!SLOT->FB) - out = 0; - SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); - } - - /* SLOT 2 */ - SLOT++; - env = volume_calc(SLOT); - if( env < ENV_QUIET ) - output += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable) * 2; - - - /* Phase generation is based on: */ - /* HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases) */ - /* SD (16) channel 7->slot 1 */ - /* TOM (14) channel 8->slot 1 */ - /* TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases) */ - - /* Envelope generation based on: */ - /* HH channel 7->slot1 */ - /* SD channel 7->slot2 */ - /* TOM channel 8->slot1 */ - /* TOP channel 8->slot2 */ - - - /* The following formulas can be well optimized. - I leave them in direct form for now (in case I've missed something). - */ - - /* High Hat (verified on real YM3812) */ - env = volume_calc(&CH[7].SLOT[SLOT1]); - if( env < ENV_QUIET ) - { - - /* high hat phase generation: - phase = d0 or 234 (based on frequency only) - phase = 34 or 2d0 (based on noise) - */ - - /* base frequency derived from operator 1 in channel 7 */ - unsigned char bit7 = ((CH[7].SLOT[SLOT1].Cnt>>FREQ_SH)>>7)&1; - unsigned char bit3 = ((CH[7].SLOT[SLOT1].Cnt>>FREQ_SH)>>3)&1; - unsigned char bit2 = ((CH[7].SLOT[SLOT1].Cnt>>FREQ_SH)>>2)&1; - - unsigned char res1 = (bit2 ^ bit7) | bit3; - - /* when res1 = 0 phase = 0x000 | 0xd0; */ - /* when res1 = 1 phase = 0x200 | (0xd0>>2); */ - uint32_t phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; - - /* enable gate based on frequency of operator 2 in channel 8 */ - unsigned char bit5e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>5)&1; - unsigned char bit3e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>3)&1; - - unsigned char res2 = (bit3e ^ bit5e); - - /* when res2 = 0 pass the phase from calculation above (res1); */ - /* when res2 = 1 phase = 0x200 | (0xd0>>2); */ - if (res2) - phase = (0x200|(0xd0>>2)); - - - /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */ - /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */ - if (phase&0x200) - { - if (noise) - phase = 0x200|0xd0; - } - else - /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */ - /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */ - { - if (noise) - phase = 0xd0>>2; - } - - output += op_calc(phase<>FREQ_SH)>>8)&1; - - /* when bit8 = 0 phase = 0x100; */ - /* when bit8 = 1 phase = 0x200; */ - uint32_t phase = bit8 ? 0x200 : 0x100; - - /* Noise bit XOR'es phase by 0x100 */ - /* when noisebit = 0 pass the phase from calculation above */ - /* when noisebit = 1 phase ^= 0x100; */ - /* in other words: phase ^= (noisebit<<8); */ - if (noise) - phase ^= 0x100; - - output += op_calc(phase<>FREQ_SH)>>7)&1; - unsigned char bit3 = ((CH[7].SLOT[SLOT1].Cnt>>FREQ_SH)>>3)&1; - unsigned char bit2 = ((CH[7].SLOT[SLOT1].Cnt>>FREQ_SH)>>2)&1; - - unsigned char res1 = (bit2 ^ bit7) | bit3; - - /* when res1 = 0 phase = 0x000 | 0x100; */ - /* when res1 = 1 phase = 0x200 | 0x100; */ - uint32_t phase = res1 ? 0x300 : 0x100; - - /* enable gate based on frequency of operator 2 in channel 8 */ - unsigned char bit5e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>5)&1; - unsigned char bit3e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>3)&1; - - unsigned char res2 = (bit3e ^ bit5e); - /* when res2 = 0 pass the phase from calculation above (res1); */ - /* when res2 = 1 phase = 0x200 | 0x100; */ - if (res2) - phase = 0x300; - - output += op_calc(phase<>= 4; /* 12 bits here */ - n = (n+1)>>1; /* round to nearest */ - /* 11 bits here (rounded) */ - n <<= 1; /* 12 bits here (as in real chip) */ - tl_tab[ x*2 + 0 ] = n; - tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; - - for (i=1; i<12; i++) - { - tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; - tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 ]>>i; - } - } - - for (i=0; i0.0) - o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ - else - o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ - - o = o / (ENV_STEP/4); - - n = (int)(2.0*o); - if (n&1) /* round to nearest */ - n = (n>>1)+1; - else - n = n>>1; - - sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); - } - - for (i=0; i>1) ]; - - /* waveform 3: _ _ _ _ */ - /* / |_/ |_/ |_/ |_*/ - /* abs(output only first quarter of the sinus waveform) */ - - if (i & (1<<(SIN_BITS-2)) ) - sin_tab[3*SIN_LEN+i] = TL_TAB_LEN; - else - sin_tab[3*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>2)]; - } - - did_init = true; -} - -static void OPL_initalize(FM_OPL *OPL) -{ - int i; - - /* make fnumber -> increment counter table */ - for( i=0 ; i < 1024 ; i++ ) - { - /* opn phase increment counter = 20bit */ - OPL->fn_tab[i] = (uint32_t)( (double)i * 64 * OPL_FREQBASE * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ - } - - /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ - /* One entry from LFO_AM_TABLE lasts for 64 samples */ - OPL->lfo_am_inc = uint32_t((1.0 / 64.0 ) * (1<lfo_pm_inc = uint32_t((1.0 / 1024.0) * (1<eg_timer_add = uint32_t((1<eg_timer_overflow = uint32_t(( 1 ) * (1<IsStereo = false; - for (int i = 0; i < 9; ++i) - { - OPL->P_CH[i].LeftVol = (float)CENTER_PANNING_POWER; - OPL->P_CH[i].RightVol = (float)CENTER_PANNING_POWER; - } -} - -static inline void FM_KEYON(OPL_SLOT *SLOT, uint32_t key_set) -{ - if( !SLOT->key ) - { - /* restart Phase Generator */ - SLOT->Cnt = 0; - /* phase -> Attack */ - SLOT->state = EG_ATT; - } - SLOT->key |= key_set; -} - -static inline void FM_KEYOFF(OPL_SLOT *SLOT, uint32_t key_clr) -{ - if( SLOT->key ) - { - SLOT->key &= key_clr; - - if( !SLOT->key ) - { - /* phase -> Release */ - if (SLOT->state>EG_REL) - SLOT->state = EG_REL; - } - } -} - -/* update phase increment counter of operator (also update the EG rates if necessary) */ -static inline void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) -{ - int ksr; - - /* (frequency) phase increment counter */ - SLOT->Incr = CH->fc * SLOT->mul; - ksr = CH->kcode >> SLOT->KSR; - - if( SLOT->ksr != ksr ) - { - SLOT->ksr = ksr; - - /* calculate envelope generator rates */ - if ((SLOT->ar + SLOT->ksr) < 16+62) - { - SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; - SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; - } - else - { - SLOT->eg_sh_ar = 0; - SLOT->eg_sel_ar = 13*RATE_STEPS; - } - SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; - SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; - SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; - SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; - } -} - -/* set multi,am,vib,EG-TYP,KSR,mul */ -static inline void set_mul(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->mul = mul_tab[v&0x0f]; - SLOT->KSR = (v&0x10) ? 0 : 2; - SLOT->eg_type = (v&0x20); - SLOT->vib = (v&0x40); - SLOT->AMmask = (v&0x80) ? ~0 : 0; - CALC_FCSLOT(CH,SLOT); -} - -/* set ksl & tl */ -static inline void set_ksl_tl(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->ksl = ksl_shift[v >> 6]; - SLOT->TL = (v&0x3f)<<(ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */ - - SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); -} - -/* set attack rate & decay rate */ -static inline void set_ar_dr(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0; - - if ((SLOT->ar + SLOT->ksr) < 16+62) - { - SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; - SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; - } - else - { - SLOT->eg_sh_ar = 0; - SLOT->eg_sel_ar = 13*RATE_STEPS; - } - - SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; - SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; - SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; -} - -/* set sustain level & release rate */ -static inline void set_sl_rr(FM_OPL *OPL,int slot,int v) -{ - OPL_CH *CH = &OPL->P_CH[slot/2]; - OPL_SLOT *SLOT = &CH->SLOT[slot&1]; - - SLOT->sl = sl_tab[ v>>4 ]; - - SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; - SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; - SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; -} - - -/* write a value v to register r on OPL chip */ -static void WriteRegister(FM_OPL *OPL, int r, int v) -{ - OPL_CH *CH; - int slot; - int block_fnum; - - /* adjust bus to 8 bits */ - r &= 0xff; - v &= 0xff; - - switch(r&0xe0) - { - case 0x00: /* 00-1f:control */ - switch(r&0x1f) - { - case 0x01: /* waveform select enable */ - OPL->wavesel = v&0x20; - break; - case 0x02: /* Timer 1 */ - OPL->T[0] = (256-v)*4; - break; - case 0x03: /* Timer 2 */ - OPL->T[1] = (256-v)*16; - break; - case 0x04: /* IRQ clear / mask and Timer enable */ - if(v&0x80) - { /* IRQ flag clear */ - OPL_STATUS_RESET(OPL,0x7f-0x08); /* don't reset BFRDY flag or we will have to call deltat module to set the flag */ - } - else - { /* set IRQ mask ,timer enable*/ - uint8_t st1 = v&1; - uint8_t st2 = (v>>1)&1; - - /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ - OPL_STATUS_RESET(OPL, v & (0x78-0x08) ); - OPL_STATUSMASK_SET(OPL, (~v) & 0x78 ); - - /* timer 2 */ - if(OPL->st[1] != st2) - { - OPL->st[1] = st2; - } - /* timer 1 */ - if(OPL->st[0] != st1) - { - OPL->st[0] = st1; - } - } - break; - case 0x08: /* MODE,DELTA-T control 2 : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ - OPL->mode = v; - break; - } - break; - case 0x20: /* am ON, vib ON, ksr, eg_type, mul */ - slot = slot_array[r&0x1f]; - if(slot < 0) return; - set_mul(OPL,slot,v); - break; - case 0x40: - slot = slot_array[r&0x1f]; - if(slot < 0) return; - set_ksl_tl(OPL,slot,v); - break; - case 0x60: - slot = slot_array[r&0x1f]; - if(slot < 0) return; - set_ar_dr(OPL,slot,v); - break; - case 0x80: - slot = slot_array[r&0x1f]; - if(slot < 0) return; - set_sl_rr(OPL,slot,v); - break; - case 0xa0: - if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */ - { - OPL->lfo_am_depth = v & 0x80; - OPL->lfo_pm_depth_range = (v&0x40) ? 8 : 0; - - OPL->rhythm = v&0x3f; - - if(OPL->rhythm&0x20) - { - /* BD key on/off */ - if(v&0x10) - { - FM_KEYON (&OPL->P_CH[6].SLOT[SLOT1], 2); - FM_KEYON (&OPL->P_CH[6].SLOT[SLOT2], 2); - } - else - { - FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); - FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); - } - /* HH key on/off */ - if(v&0x01) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT1], 2); - else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); - /* SD key on/off */ - if(v&0x08) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT2], 2); - else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); - /* TOM key on/off */ - if(v&0x04) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT1], 2); - else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); - /* TOP-CY key on/off */ - if(v&0x02) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT2], 2); - else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); - } - else - { - /* BD key off */ - FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); - FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); - /* HH key off */ - FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); - /* SD key off */ - FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); - /* TOM key off */ - FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); - /* TOP-CY off */ - FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); - } - return; - } - /* keyon,block,fnum */ - if( (r&0x0f) > 8) return; - CH = &OPL->P_CH[r&0x0f]; - if(!(r&0x10)) - { /* a0-a8 */ - block_fnum = (CH->block_fnum&0x1f00) | v; - } - else - { /* b0-b8 */ - block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); - - if(v&0x20) - { - FM_KEYON (&CH->SLOT[SLOT1], 1); - FM_KEYON (&CH->SLOT[SLOT2], 1); - } - else - { - FM_KEYOFF(&CH->SLOT[SLOT1],~1); - FM_KEYOFF(&CH->SLOT[SLOT2],~1); - } - } - /* update */ - if(CH->block_fnum != (uint32_t)block_fnum) - { - uint8_t block = block_fnum >> 10; - - CH->block_fnum = block_fnum; - - CH->ksl_base = ksl_tab[block_fnum>>6]; - CH->fc = OPL->fn_tab[block_fnum&0x03ff] >> (7-block); - - /* BLK 2,1,0 bits -> bits 3,2,1 of kcode */ - CH->kcode = (CH->block_fnum&0x1c00)>>9; - - /* the info below is actually opposite to what is stated in the Manuals (verifed on real YM3812) */ - /* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum */ - /* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */ - if (OPL->mode&0x40) - CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */ - else - CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */ - - /* refresh Total Level in both SLOTs of this channel */ - CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); - CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); - - /* refresh frequency counter in both SLOTs of this channel */ - CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); - CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); - } - break; - case 0xc0: - /* FB,C */ - if( (r&0x0f) > 8) return; - CH = &OPL->P_CH[r&0x0f]; - CH->SLOT[SLOT1].FB = (v>>1)&7 ? ((v>>1)&7) + 7 : 0; - CH->SLOT[SLOT1].CON = v&1; - CH->SLOT[SLOT1].connect1 = CH->SLOT[SLOT1].CON ? &output : &phase_modulation; - break; - case 0xe0: /* waveform select */ - /* simply ignore write to the waveform select register if selecting not enabled in test register */ - if(OPL->wavesel) - { - slot = slot_array[r&0x1f]; - if(slot < 0) return; - CH = &OPL->P_CH[slot/2]; - - CH->SLOT[slot&1].wavetable = (v&0x03)*SIN_LEN; - } - break; - } -} - -static void OPLResetChip(FM_OPL *OPL) -{ - int c,s; - int i; - - OPL->eg_timer = 0; - OPL->eg_cnt = 0; - - OPL->noise_rng = 1; /* noise shift register */ - OPL->mode = 0; /* normal mode */ - OPL_STATUS_RESET(OPL,0x7f); - - /* reset with register write */ - WriteRegister(OPL,0x01,0); /* wavesel disable */ - WriteRegister(OPL,0x02,0); /* Timer1 */ - WriteRegister(OPL,0x03,0); /* Timer2 */ - WriteRegister(OPL,0x04,0); /* IRQ mask clear */ - for(i = 0xff ; i >= 0x20 ; i-- ) WriteRegister(OPL,i,0); - - /* reset operator parameters */ - for( c = 0 ; c < 9 ; c++ ) - { - OPL_CH *CH = &OPL->P_CH[c]; - for(s = 0 ; s < 2 ; s++ ) - { - /* wave table */ - CH->SLOT[s].wavetable = 0; - CH->SLOT[s].state = EG_OFF; - CH->SLOT[s].volume = MAX_ATT_INDEX; - } - } -} - - -class YM3812 : public OPLEmul -{ -private: - FM_OPL Chip; - -public: - /* Create one of virtual YM3812 */ - YM3812(bool stereo) - { - init_tables(); - - /* clear */ - memset(&Chip, 0, sizeof(Chip)); - - /* init global tables */ - OPL_initalize(&Chip); - - Chip.IsStereo = stereo; - - Reset(); - } - - /* YM3812 I/O interface */ - void WriteReg(int reg, int v) - { - WriteRegister(&Chip, reg & 0xff, v); - } - - void Reset() - { - OPLResetChip(&Chip); - } - - /* [RH] Full support for MIDI panning */ - void SetPanning(int c, float left, float right) - { - Chip.P_CH[c].LeftVol = left; - Chip.P_CH[c].RightVol = right; - } - - - /* - ** Generate samples for one of the YM3812's - ** - ** '*buffer' is the output buffer pointer - ** 'length' is the number of samples that should be generated - */ - void Update(float *buffer, int length) - { - int i; - - uint8_t rhythm = Chip.rhythm&0x20; - - uint32_t lfo_am_cnt_bak = Chip.lfo_am_cnt; - uint32_t eg_timer_bak = Chip.eg_timer; - uint32_t eg_cnt_bak = Chip.eg_cnt; - - uint32_t lfo_am_cnt_out = lfo_am_cnt_bak; - uint32_t eg_timer_out = eg_timer_bak; - uint32_t eg_cnt_out = eg_cnt_bak; - - for (i = 0; i <= (rhythm ? 5 : 8); ++i) - { - Chip.lfo_am_cnt = lfo_am_cnt_bak; - Chip.eg_timer = eg_timer_bak; - Chip.eg_cnt = eg_cnt_bak; - if (CalcVoice (&Chip, i, buffer, length)) - { - lfo_am_cnt_out = Chip.lfo_am_cnt; - eg_timer_out = Chip.eg_timer; - eg_cnt_out = Chip.eg_cnt; - } - } - - Chip.lfo_am_cnt = lfo_am_cnt_out; - Chip.eg_timer = eg_timer_out; - Chip.eg_cnt = eg_cnt_out; - - if (rhythm) /* Rhythm part */ - { - Chip.lfo_am_cnt = lfo_am_cnt_bak; - Chip.eg_timer = eg_timer_bak; - Chip.eg_cnt = eg_cnt_bak; - CalcRhythm (&Chip, buffer, length); - } - } - - std::string GetVoiceString(void *chip) - { - FM_OPL *OPL = (FM_OPL *)chip; - char out[9*3]; - - for (int i = 0; i <= 8; ++i) - { - int color; - - if (OPL != NULL && (OPL->P_CH[i].SLOT[0].state != EG_OFF || OPL->P_CH[i].SLOT[1].state != EG_OFF)) - { - color = 'D'; // Green means in use - } - else - { - color = 'A'; // Brick means free - } - out[i*3+0] = '\x1c'; - out[i*3+1] = color; - out[i*3+2] = '*'; - } - return std::string (out, 9*3); - } -}; - -OPLEmul *YM3812Create(bool stereo) -{ - /* emulator create */ - return new YM3812(stereo); -} - -// [RH] Render a whole voice at once. If nothing else, it lets us avoid -// wasting a lot of time on voices that aren't playing anything. - -static bool CalcVoice (FM_OPL *OPL, int voice, float *buffer, int length) -{ - OPL_CH *const CH = &OPL->P_CH[voice]; - int i; - - if (CH->SLOT[0].state == EG_OFF && CH->SLOT[1].state == EG_OFF) - { // Voice is not playing, so don't do anything for it - return false; - } - - for (i = 0; i < length; ++i) - { - advance_lfo(OPL); - - output = 0; - float sample = OPL_CALC_CH(CH); - if (!OPL->IsStereo) - { - buffer[i] += sample; - } - else - { - buffer[i*2] += sample * CH->LeftVol; - buffer[i*2+1] += sample * CH->RightVol; - } - - advance(OPL, voice, voice); - } - return true; -} - -static bool CalcRhythm (FM_OPL *OPL, float *buffer, int length) -{ - int i; - - for (i = 0; i < length; ++i) - { - advance_lfo(OPL); - - output = 0; - OPL_CALC_RH(&OPL->P_CH[0], OPL->noise_rng & 1); - /* [RH] Convert to floating point. */ - float sample = float(output) / 10240; - if (!OPL->IsStereo) - { - buffer[i] += sample; - } - else - { - // [RH] Always use center panning for rhythm. - // The MIDI player doesn't use the rhythm section anyway. - buffer[i*2] += sample * CENTER_PANNING_POWER; - buffer[i*2+1] += sample * CENTER_PANNING_POWER; - } - - advance(OPL, 6, 8); - advance_noise(OPL); - } - return true; -} diff --git a/libraries/oplsynth/musicblock.cpp b/libraries/oplsynth/musicblock.cpp deleted file mode 100644 index 4d0aeb249..000000000 --- a/libraries/oplsynth/musicblock.cpp +++ /dev/null @@ -1,498 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 2002-2016 Randy Heit -// Copyright 2005-2014 Simon Howard -// Copyright 2017 Christoph Oelckers -// -// 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/ -// -//----------------------------------------------------------------------------- -// -// This is mostly a reimplementation of the interface provided by -// MusLib based on Chocolate-Doom's OPL player, although the -// interface has been cleaned up a bit to be more consistent and readable. -// -// - -#include -#include -#include "musicblock.h" - -musicBlock::musicBlock () -{ - memset (this, 0, sizeof(*this)); - for(auto &oplchannel : oplchannels) oplchannel.Panning = 64; // default to center panning. - for(auto &voice : voices) voice.index = ~0u; // mark all free. -} - -musicBlock::~musicBlock () -{ -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -int musicBlock::releaseVoice(uint32_t slot, uint32_t killed) -{ - struct OPLVoice *ch = &voices[slot]; - io->WriteFrequency(slot, ch->note, ch->pitch, 0); - ch->index = ~0u; - ch->sustained = false; - if (!killed) ch->timestamp = ++timeCounter; - if (killed) io->MuteChannel(slot); - return slot; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -int musicBlock::findFreeVoice() -{ - // We want to prefer the least recently freed voice, as more recently - // freed voices can still play a tone from their release state. - // Sustained voices are replaced when there are no free voices. - uint32_t min_value = ~0u; - int result = -1; - for (uint32_t i = 0; i < io->NumChannels; ++i) - { - uint32_t voice_value = voices[i].timestamp + (voices[i].sustained ? (1 << 31) : 0); - if ((voices[i].index == ~0u || voices[i].sustained) && (voice_value < min_value)) - { - min_value = voice_value; - result = i; - } - } - if (result >= 0) - { - releaseVoice(result, 1); - } - return result; -} - -//---------------------------------------------------------------------------- -// -// When all voices are in use, we must discard an existing voice to -// play a new note. Find and free an existing voice. The channel -// passed to the function is the channel for the new note to be -// played. -// -//---------------------------------------------------------------------------- - -int musicBlock::replaceExistingVoice() -{ - // Check the allocated voices, if we find an instrument that is - // of a lower priority to the new instrument, discard it. - // If a voice is being used to play the second voice of an instrument, - // use that, as second voices are non-essential. - // Lower numbered MIDI channels implicitly have a higher priority - // than higher-numbered channels, eg. MIDI channel 1 is never - // discarded for MIDI channel 2. - int result = 0; - - for (uint32_t i = 0; i < io->NumChannels; ++i) - { - if (voices[i].current_instr_voice == &voices[i].current_instr->voices[1] || - voices[i].index >= voices[result].index) - { - result = i; - } - } - - releaseVoice(result, 1); - return result; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::voiceKeyOn(uint32_t slot, uint32_t channo, GenMidiInstrument *instrument, uint32_t instrument_voice, uint32_t key, uint32_t volume) -{ - struct OPLVoice *voice = &voices[slot]; - auto &channel = oplchannels[channo]; - GenMidiVoice *gmvoice; - - voice->index = channo; - voice->key = key; - - // Program the voice with the instrument data: - voice->current_instr = instrument; - gmvoice = voice->current_instr_voice = &instrument->voices[instrument_voice]; - io->WriteInstrument(slot,gmvoice, channel.Vibrato); - io->WritePan(slot, gmvoice, channel.Panning); - - // Set the volume level. - voice->note_volume = volume; - io->WriteVolume(slot, gmvoice, channel.Volume, channel.Expression, volume); - - // Write the frequency value to turn the note on. - - // Work out the note to use. This is normally the same as - // the key, unless it is a fixed pitch instrument. - int note; - if (instrument->flags & GENMIDI_FLAG_FIXED) note = instrument->fixed_note; - else if (channo == CHAN_PERCUSSION) note = 60; - else note = key; - - // If this is the second voice of a double voice instrument, the - // frequency index can be adjusted by the fine tuning field. - voice->fine_tuning = (instrument_voice != 0) ? (voice->current_instr->fine_tuning / 2) - 64 : 0; - voice->pitch = voice->fine_tuning + channel.Pitch; - - if (!(instrument->flags & GENMIDI_FLAG_FIXED) && channo != CHAN_PERCUSSION) - { - note += gmvoice->base_note_offset; - } - - // Avoid possible overflow due to base note offset: - - while (note < 0) - { - note += 12; - } - - while (note > HIGHEST_NOTE) - { - note -= 12; - } - voice->note = note; - io->WriteFrequency(slot, note, voice->pitch, 1); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -bool opl_singlevoice; - -void musicBlock::noteOn(uint32_t channel, uint8_t key, int volume) -{ - if (volume <= 0) - { - noteOff(channel, key); - return; - } - GenMidiInstrument *instrument; - - // Percussion channel is treated differently. - if (channel == CHAN_PERCUSSION) - { - if (key < GENMIDI_FIST_PERCUSSION || key >= GENMIDI_FIST_PERCUSSION + GENMIDI_NUM_PERCUSSION) - { - return; - } - - instrument = &OPLinstruments[key + (GENMIDI_NUM_INSTRS - GENMIDI_FIST_PERCUSSION)]; - } - else - { - auto inst = oplchannels[channel].Instrument; - if (inst >= GENMIDI_NUM_TOTAL) return; // better safe than sorry. - instrument = &OPLinstruments[inst]; - } - - bool double_voice = ((instrument->flags) & GENMIDI_FLAG_2VOICE) && !opl_singlevoice; - - int i = findFreeVoice(); - if (i < 0) i = replaceExistingVoice(); - - if (i >= 0) - { - voiceKeyOn(i, channel, instrument, 0, key, volume); - if (double_voice) - { - i = findFreeVoice(); - if (i >= 0) - { - voiceKeyOn(i, channel, instrument, 1, key, volume); - } - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::noteOff(uint32_t id, uint8_t note) -{ - uint32_t sustain = oplchannels[id].Sustain; - - for(uint32_t i = 0; i < io->NumChannels; i++) - { - if (voices[i].index == id && voices[i].key == note) - { - if (sustain >= MIN_SUSTAIN) - { - voices[i].sustained = true; - voices[i].timestamp = ++timeCounter; - } - else releaseVoice(i, 0); - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::changePitch(uint32_t id, int val1, int val2) -{ - // Convert pitch from 14-bit to 7-bit, then scale it, since the player - // code only understands sensitivities of 2 semitones. - int pitch = ((val1 | (val2 << 7)) - 8192) * oplchannels[id].PitchSensitivity / (200 * 128) + 64; - oplchannels[id].Pitch = pitch; - for(uint32_t i = 0; i < io->NumChannels; i++) - { - auto &ch = voices[i]; - if (ch.index == id) - { - ch.pitch = ch.fine_tuning + pitch; - io->WriteFrequency(i, ch.note, ch.pitch, 1); - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::changeModulation(uint32_t id, int value) -{ - bool vibrato = (value >= VIBRATO_THRESHOLD); - oplchannels[id].Vibrato = vibrato; - for (uint32_t i = 0; i < io->NumChannels; i++) - { - auto &ch = voices[i]; - if (ch.index == id) - { - io->WriteTremolo(i, ch.current_instr_voice, vibrato); - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::changeSustain(uint32_t id, int value) -{ - oplchannels[id].Sustain = value; - if (value < MIN_SUSTAIN) - { - for (uint32_t i = 0; i < io->NumChannels; i++) - { - if (voices[i].index == id && voices[i].sustained) - releaseVoice(i, 0); - } - } -} - -//---------------------------------------------------------------------------- -// -// Change volume or expression. -// Since both go to the same register, one function can handle both. -// -//---------------------------------------------------------------------------- - -void musicBlock::changeVolume(uint32_t id, int value, bool expression) -{ - auto &chan = oplchannels[id]; - if (!expression) chan.Volume = value; - else chan.Expression = value; - for (uint32_t i = 0; i < io->NumChannels; i++) - { - auto &ch = voices[i]; - if (ch.index == id) - { - io->WriteVolume(i, ch.current_instr_voice, chan.Volume, chan.Expression, ch.note_volume); - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::changePanning(uint32_t id, int value) -{ - oplchannels[id].Panning = value; - for(uint32_t i = 0; i < io->NumChannels; i++) - { - auto &ch = voices[i]; - if (ch.index == id) - { - io->WritePan(i, ch.current_instr_voice, value); - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::notesOff(uint32_t id, int value) -{ - for (uint32_t i = 0; i < io->NumChannels; ++i) - { - if (voices[i].index == id) - { - if (oplchannels[id].Sustain >= MIN_SUSTAIN) - { - voices[i].sustained = true; - voices[i].timestamp = ++timeCounter; - } - else releaseVoice(i, 0); - } - } -} - -//---------------------------------------------------------------------------- -// -// release all notes for this channel -// -//---------------------------------------------------------------------------- - -void musicBlock::allNotesOff(uint32_t id, int value) -{ - for (uint32_t i = 0; i < io->NumChannels; ++i) - { - if (voices[i].index == id) - { - releaseVoice(i, 0); - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::changeExtended(uint32_t id, uint8_t controller, int value) -{ - switch (controller) - { - case ctrlRPNHi: - oplchannels[id].RPN = (oplchannels[id].RPN & 0x007F) | (value << 7); - break; - - case ctrlRPNLo: - oplchannels[id].RPN = (oplchannels[id].RPN & 0x3F80) | value; - break; - - case ctrlNRPNLo: - case ctrlNRPNHi: - oplchannels[id].RPN = 0x3FFF; - break; - - case ctrlDataEntryHi: - if (oplchannels[id].RPN == 0) - { - oplchannels[id].PitchSensitivity = value * 100 + (oplchannels[id].PitchSensitivity % 100); - } - break; - - case ctrlDataEntryLo: - if (oplchannels[id].RPN == 0) - { - oplchannels[id].PitchSensitivity = value + (oplchannels[id].PitchSensitivity / 100) * 100; - } - break; - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::resetControllers(uint32_t chan, int vol) -{ - auto &channel = oplchannels[chan]; - - channel.Volume = vol; - channel.Expression = 127; - channel.Sustain = 0; - channel.Pitch = 64; - channel.RPN = 0x3fff; - channel.PitchSensitivity = 200; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::programChange(uint32_t channel, int value) -{ - oplchannels[channel].Instrument = value; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::resetAllControllers(int vol) -{ - uint32_t i; - - for (i = 0; i < NUM_CHANNELS; i++) - { - resetControllers(i, vol); - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void musicBlock::stopAllVoices() -{ - for (uint32_t i = 0; i < io->NumChannels; i++) - { - if (voices[i].index != ~0u) releaseVoice(i, 1); - voices[i].timestamp = 0; - } - timeCounter = 0; -} diff --git a/libraries/oplsynth/nukedopl3.cpp b/libraries/oplsynth/nukedopl3.cpp deleted file mode 100644 index 4bc3aa4ed..000000000 --- a/libraries/oplsynth/nukedopl3.cpp +++ /dev/null @@ -1,1027 +0,0 @@ -/* -* 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 - -/* Changelog: - v1.1: - Vibrato's sign fix. - v1.2: - Operator key fix. - Corrected 4-operator mode. - Corrected rhythm mode. - Some small fixes. - v1.2.1: - Small envelope generator fix. - v1.3: - Complete rewrite. - v1.4: - New envelope and waveform generator. - Some small fixes. - v1.4.1: - Envelope generator rate calculation fix. - v1.4.2: - Version for ZDoom. - v1.5: - Optimizations. - v1.6: - Improved emulation output. -*/ - -#include -#include -#include "nukedopl3.h" - -// -// Envelope generator -// - -namespace NukedOPL3 -{ - -typedef Bit16s(*envelope_sinfunc)(Bit16u phase, Bit16u envelope); -typedef void(*envelope_genfunc)(opl_slot *slott); - -Bit16s envelope_calcexp(Bit32u level) { - if (level > 0x1fff) { - level = 0x1fff; - } - return ((exprom[(level & 0xff) ^ 0xff] | 0x400) << 1) >> (level >> 8); -} - -Bit16s envelope_calcsin0(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u out = 0; - Bit16u neg = 0; - if (phase & 0x200) { - neg = ~0; - } - if (phase & 0x100) { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else { - out = logsinrom[phase & 0xff]; - } - return envelope_calcexp(out + (envelope << 3)) ^ neg; -} - -Bit16s envelope_calcsin1(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u out = 0; - if (phase & 0x200) { - out = 0x1000; - } - else if (phase & 0x100) { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else { - out = logsinrom[phase & 0xff]; - } - return envelope_calcexp(out + (envelope << 3)); -} - -Bit16s envelope_calcsin2(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u out = 0; - if (phase & 0x100) { - out = logsinrom[(phase & 0xff) ^ 0xff]; - } - else { - out = logsinrom[phase & 0xff]; - } - return envelope_calcexp(out + (envelope << 3)); -} - -Bit16s envelope_calcsin3(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u out = 0; - if (phase & 0x100) { - out = 0x1000; - } - else { - out = logsinrom[phase & 0xff]; - } - return envelope_calcexp(out + (envelope << 3)); -} - -Bit16s envelope_calcsin4(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u out = 0; - Bit16u neg = 0; - if ((phase & 0x300) == 0x100) { - neg = ~0; - } - if (phase & 0x200) { - out = 0x1000; - } - else if (phase & 0x80) { - out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; - } - else { - out = logsinrom[(phase << 1) & 0xff]; - } - return envelope_calcexp(out + (envelope << 3)) ^ neg; -} - -Bit16s envelope_calcsin5(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u out = 0; - if (phase & 0x200) { - out = 0x1000; - } - else if (phase & 0x80) { - out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; - } - else { - out = logsinrom[(phase << 1) & 0xff]; - } - return envelope_calcexp(out + (envelope << 3)); -} - -Bit16s envelope_calcsin6(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u neg = 0; - if (phase & 0x200) { - neg = ~0; - } - return envelope_calcexp(envelope << 3) ^ neg; -} - -Bit16s envelope_calcsin7(Bit16u phase, Bit16u envelope) { - phase &= 0x3ff; - Bit16u out = 0; - Bit16u neg = 0; - if (phase & 0x200) { - neg = ~0; - phase = (phase & 0x1ff) ^ 0x1ff; - } - out = phase << 3; - return envelope_calcexp(out + (envelope << 3)) ^ neg; -} - -envelope_sinfunc envelope_sin[8] = { - envelope_calcsin0, - envelope_calcsin1, - envelope_calcsin2, - envelope_calcsin3, - envelope_calcsin4, - envelope_calcsin5, - envelope_calcsin6, - envelope_calcsin7 -}; - -void envelope_gen_off(opl_slot *slott); -void envelope_gen_attack(opl_slot *slott); -void envelope_gen_decay(opl_slot *slott); -void envelope_gen_sustain(opl_slot *slott); -void envelope_gen_release(opl_slot *slott); - -envelope_genfunc envelope_gen[5] = { - envelope_gen_off, - envelope_gen_attack, - envelope_gen_decay, - envelope_gen_sustain, - envelope_gen_release -}; - -enum envelope_gen_num { - envelope_gen_num_off = 0, - envelope_gen_num_attack = 1, - envelope_gen_num_decay = 2, - envelope_gen_num_sustain = 3, - envelope_gen_num_release = 4, - envelope_gen_num_change = 5 -}; - -Bit8u envelope_calc_rate(opl_slot *slot, Bit8u reg_rate) { - if (reg_rate == 0x00) { - return 0x00; - } - Bit8u rate = (reg_rate << 2) + (slot->reg_ksr ? slot->channel->ksv : (slot->channel->ksv >> 2)); - if (rate > 0x3c) { - rate = 0x3c; - } - return rate; -} - -void envelope_update_ksl(opl_slot *slot) { - Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) - ((0x08 - slot->channel->block) << 5); - if (ksl < 0) { - ksl = 0; - } - slot->eg_ksl = (Bit8u)ksl; -} - -void envelope_update_rate(opl_slot *slot) { - switch (slot->eg_gen) { - case envelope_gen_num_off: - slot->eg_rate = 0; - break; - case envelope_gen_num_attack: - slot->eg_rate = envelope_calc_rate(slot, slot->reg_ar); - break; - case envelope_gen_num_decay: - slot->eg_rate = envelope_calc_rate(slot, slot->reg_dr); - break; - case envelope_gen_num_sustain: - case envelope_gen_num_release: - slot->eg_rate = envelope_calc_rate(slot, slot->reg_rr); - break; - } -} - -void envelope_gen_off(opl_slot *slot) { - slot->eg_rout = 0x1ff; -} - -void envelope_gen_attack(opl_slot *slot) { - if (slot->eg_rout == 0x00) { - slot->eg_gen = envelope_gen_num_decay; - envelope_update_rate(slot); - return; - } - slot->eg_rout += ((~slot->eg_rout) *slot->eg_inc) >> 3; - if (slot->eg_rout < 0x00) { - slot->eg_rout = 0x00; - } -} - -void envelope_gen_decay(opl_slot *slot) { - if (slot->eg_rout >= slot->reg_sl << 4) { - slot->eg_gen = envelope_gen_num_sustain; - envelope_update_rate(slot); - return; - } - slot->eg_rout += slot->eg_inc; -} - -void envelope_gen_sustain(opl_slot *slot) { - if (!slot->reg_type) { - envelope_gen_release(slot); - } -} - -void envelope_gen_release(opl_slot *slot) { - if (slot->eg_rout >= 0x1ff) { - slot->eg_gen = envelope_gen_num_off; - slot->eg_rout = 0x1ff; - envelope_update_rate(slot); - return; - } - slot->eg_rout += slot->eg_inc; -} - -void envelope_calc(opl_slot *slot) { - Bit8u rate_h, rate_l; - rate_h = slot->eg_rate >> 2; - rate_l = slot->eg_rate & 3; - Bit8u inc = 0; - if (eg_incsh[rate_h] > 0) { - if ((slot->chip->timer & ((1 << eg_incsh[rate_h]) - 1)) == 0) { - inc = eg_incstep[eg_incdesc[rate_h]][rate_l][((slot->chip->timer) >> eg_incsh[rate_h]) & 0x07]; - } - } - else { - inc = eg_incstep[eg_incdesc[rate_h]][rate_l][slot->chip->timer & 0x07] << (-eg_incsh[rate_h]); - } - slot->eg_inc = inc; - slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; - envelope_gen[slot->eg_gen](slot); -} - -void eg_keyon(opl_slot *slot, Bit8u type) { - if (!slot->key) { - slot->eg_gen = envelope_gen_num_attack; - envelope_update_rate(slot); - if ((slot->eg_rate >> 2) == 0x0f) { - slot->eg_gen = envelope_gen_num_decay; - envelope_update_rate(slot); - slot->eg_rout = 0x00; - } - slot->pg_phase = 0x00; - } - slot->key |= type; -} - -void eg_keyoff(opl_slot *slot, Bit8u type) { - if (slot->key) { - slot->key &= (~type); - if (!slot->key) { - slot->eg_gen = envelope_gen_num_release; - envelope_update_rate(slot); - } - } -} - -// -// Phase Generator -// - -void pg_generate(opl_slot *slot) { - Bit16u f_num = slot->channel->f_num; - if (slot->reg_vib) { - Bit8u f_num_high = f_num >> (7 + vib_table[(slot->chip->timer >> 10) & 0x07] + (0x01 - slot->chip->dvb)); - f_num += f_num_high * vibsgn_table[(slot->chip->timer >> 10) & 0x07]; - } - slot->pg_phase += (((f_num << slot->channel->block) >> 1) * mt[slot->reg_mult]) >> 1; -} - -// -// Noise Generator -// - -void n_generate(opl_chip *chip) { - if (chip->noise & 0x01) { - chip->noise ^= 0x800302; - } - chip->noise >>= 1; -} - -// -// Slot -// - -void slot_write20(opl_slot *slot, Bit8u data) { - if ((data >> 7) & 0x01) { - slot->trem = &slot->chip->tremval; - } - else { - slot->trem = (Bit8u*)&slot->chip->zeromod; - } - slot->reg_vib = (data >> 6) & 0x01; - slot->reg_type = (data >> 5) & 0x01; - slot->reg_ksr = (data >> 4) & 0x01; - slot->reg_mult = data & 0x0f; - envelope_update_rate(slot); -} - -void slot_write40(opl_slot *slot, Bit8u data) { - slot->reg_ksl = (data >> 6) & 0x03; - slot->reg_tl = data & 0x3f; - envelope_update_ksl(slot); -} - -void slot_write60(opl_slot *slot, Bit8u data) { - slot->reg_ar = (data >> 4) & 0x0f; - slot->reg_dr = data & 0x0f; - envelope_update_rate(slot); -} - -void slot_write80(opl_slot *slot, Bit8u data) { - slot->reg_sl = (data >> 4) & 0x0f; - if (slot->reg_sl == 0x0f) { - slot->reg_sl = 0x1f; - } - slot->reg_rr = data & 0x0f; - envelope_update_rate(slot); -} - -void slot_writee0(opl_slot *slot, Bit8u data) { - slot->reg_wf = data & 0x07; - if (slot->chip->newm == 0x00) { - slot->reg_wf &= 0x03; - } -} - -void slot_generatephase(opl_slot *slot, Bit16u phase) { - slot->out = envelope_sin[slot->reg_wf](phase, slot->eg_out); -} - -void slot_generate(opl_slot *slot) { - slot->out = envelope_sin[slot->reg_wf]((Bit16u)(slot->pg_phase >> 9) + (*slot->mod), slot->eg_out); -} - -void slot_generatezm(opl_slot *slot) { - slot->out = envelope_sin[slot->reg_wf]((Bit16u)(slot->pg_phase >> 9), slot->eg_out); -} - -void slot_calcfb(opl_slot *slot) { - slot->prout[1] = slot->prout[0]; - slot->prout[0] = slot->out; - if (slot->channel->fb != 0x00) { - slot->fbmod = (slot->prout[0] + slot->prout[1]) >> (0x09 - slot->channel->fb); - } - else { - slot->fbmod = 0; - } -} - -// -// Channel -// - -void chan_setupalg(opl_channel *channel); - -void chan_updaterhythm(opl_chip *chip, Bit8u data) { - chip->rhy = data & 0x3f; - if (chip->rhy & 0x20) { - opl_channel *channel6 = &chip->channel[6]; - opl_channel *channel7 = &chip->channel[7]; - opl_channel *channel8 = &chip->channel[8]; - channel6->out[0] = &channel6->slots[1]->out; - channel6->out[1] = &channel6->slots[1]->out; - channel6->out[2] = &chip->zeromod; - channel6->out[3] = &chip->zeromod; - channel7->out[0] = &channel7->slots[0]->out; - channel7->out[1] = &channel7->slots[0]->out; - channel7->out[2] = &channel7->slots[1]->out; - channel7->out[3] = &channel7->slots[1]->out; - channel8->out[0] = &channel8->slots[0]->out; - channel8->out[1] = &channel8->slots[0]->out; - channel8->out[2] = &channel8->slots[1]->out; - channel8->out[3] = &channel8->slots[1]->out; - for (Bit8u chnum = 6; chnum < 9; chnum++) { - chip->channel[chnum].chtype = ch_drum; - } - chan_setupalg(channel6); - //hh - if (chip->rhy & 0x01) { - eg_keyon(channel7->slots[0], egk_drum); - } - else { - eg_keyoff(channel7->slots[0], egk_drum); - } - //tc - if (chip->rhy & 0x02) { - eg_keyon(channel8->slots[1], egk_drum); - } - else { - eg_keyoff(channel8->slots[1], egk_drum); - } - //tom - if (chip->rhy & 0x04) { - eg_keyon(channel8->slots[0], egk_drum); - } - else { - eg_keyoff(channel8->slots[0], egk_drum); - } - //sd - if (chip->rhy & 0x08) { - eg_keyon(channel7->slots[1], egk_drum); - } - else { - eg_keyoff(channel7->slots[1], egk_drum); - } - //bd - if (chip->rhy & 0x10) { - eg_keyon(channel6->slots[0], egk_drum); - eg_keyon(channel6->slots[1], egk_drum); - } - else { - eg_keyoff(channel6->slots[0], egk_drum); - eg_keyoff(channel6->slots[1], egk_drum); - } - } - else { - for (Bit8u chnum = 6; chnum < 9; chnum++) { - chip->channel[chnum].chtype = ch_2op; - chan_setupalg(&chip->channel[chnum]); - } - } -} - -void chan_writea0(opl_channel *channel, Bit8u data) { - if (channel->chip->newm && channel->chtype == ch_4op2) { - return; - } - channel->f_num = (channel->f_num & 0x300) | data; - channel->ksv = (channel->block << 1) | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); - envelope_update_ksl(channel->slots[0]); - envelope_update_ksl(channel->slots[1]); - envelope_update_rate(channel->slots[0]); - envelope_update_rate(channel->slots[1]); - if (channel->chip->newm && channel->chtype == ch_4op) { - channel->pair->f_num = channel->f_num; - channel->pair->ksv = channel->ksv; - envelope_update_ksl(channel->pair->slots[0]); - envelope_update_ksl(channel->pair->slots[1]); - envelope_update_rate(channel->pair->slots[0]); - envelope_update_rate(channel->pair->slots[1]); - } -} - -void chan_writeb0(opl_channel *channel, Bit8u data) { - if (channel->chip->newm && channel->chtype == ch_4op2) { - return; - } - channel->f_num = (channel->f_num & 0xff) | ((data & 0x03) << 8); - channel->block = (data >> 2) & 0x07; - channel->ksv = (channel->block << 1) | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); - envelope_update_ksl(channel->slots[0]); - envelope_update_ksl(channel->slots[1]); - envelope_update_rate(channel->slots[0]); - envelope_update_rate(channel->slots[1]); - if (channel->chip->newm && channel->chtype == ch_4op) { - channel->pair->f_num = channel->f_num; - channel->pair->block = channel->block; - channel->pair->ksv = channel->ksv; - envelope_update_ksl(channel->pair->slots[0]); - envelope_update_ksl(channel->pair->slots[1]); - envelope_update_rate(channel->pair->slots[0]); - envelope_update_rate(channel->pair->slots[1]); - } -} - -void chan_setupalg(opl_channel *channel) { - if (channel->chtype == ch_drum) { - switch (channel->alg & 0x01) { - case 0x00: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->slots[0]->out; - break; - case 0x01: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->chip->zeromod; - break; - } - return; - } - if (channel->alg & 0x08) { - return; - } - if (channel->alg & 0x04) { - channel->pair->out[0] = &channel->chip->zeromod; - channel->pair->out[1] = &channel->chip->zeromod; - channel->pair->out[2] = &channel->chip->zeromod; - channel->pair->out[3] = &channel->chip->zeromod; - switch (channel->alg & 0x03) { - case 0x00: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; - channel->slots[0]->mod = &channel->pair->slots[1]->out; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->slots[1]->out; - channel->out[1] = &channel->chip->zeromod; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x01: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; - channel->slots[0]->mod = &channel->chip->zeromod; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->pair->slots[1]->out; - channel->out[1] = &channel->slots[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x02: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->chip->zeromod; - channel->slots[0]->mod = &channel->pair->slots[1]->out; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->pair->slots[0]->out; - channel->out[1] = &channel->slots[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x03: - channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; - channel->pair->slots[1]->mod = &channel->chip->zeromod; - channel->slots[0]->mod = &channel->pair->slots[1]->out; - channel->slots[1]->mod = &channel->chip->zeromod; - channel->out[0] = &channel->pair->slots[0]->out; - channel->out[1] = &channel->slots[0]->out; - channel->out[2] = &channel->slots[1]->out; - channel->out[3] = &channel->chip->zeromod; - break; - } - } - else { - switch (channel->alg & 0x01) { - case 0x00: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->slots[0]->out; - channel->out[0] = &channel->slots[1]->out; - channel->out[1] = &channel->chip->zeromod; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - case 0x01: - channel->slots[0]->mod = &channel->slots[0]->fbmod; - channel->slots[1]->mod = &channel->chip->zeromod; - channel->out[0] = &channel->slots[0]->out; - channel->out[1] = &channel->slots[1]->out; - channel->out[2] = &channel->chip->zeromod; - channel->out[3] = &channel->chip->zeromod; - break; - } - } -} - -void chan_writec0(opl_channel *channel, Bit8u data) { - channel->fb = (data & 0x0e) >> 1; - channel->con = data & 0x01; - channel->alg = channel->con; - if (channel->chip->newm) { - if (channel->chtype == ch_4op) { - channel->pair->alg = 0x04 | (channel->con << 1) | (channel->pair->con); - channel->alg = 0x08; - chan_setupalg(channel->pair); - } - else if (channel->chtype == ch_4op2) { - channel->alg = 0x04 | (channel->pair->con << 1) | (channel->con); - channel->pair->alg = 0x08; - chan_setupalg(channel); - } - else { - chan_setupalg(channel); - } - } - else { - chan_setupalg(channel); - } - if (channel->chip->newm) { - channel->cha = ((data >> 4) & 0x01) ? ~0 : 0; - channel->chb = ((data >> 5) & 0x01) ? ~0 : 0; - } - else { - channel->cha = channel->chb = ~0; - } -} - -void chan_generaterhythm1(opl_chip *chip) { - opl_channel *channel6 = &chip->channel[6]; - opl_channel *channel7 = &chip->channel[7]; - opl_channel *channel8 = &chip->channel[8]; - slot_generate(channel6->slots[0]); - Bit16u phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; - Bit16u phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; - Bit16u phase = 0x00; - //hh tc phase bit - Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; - //hh - phase = (phasebit << 9) | (0x34 << ((phasebit ^ (chip->noise & 0x01) << 1))); - slot_generatephase(channel7->slots[0], phase); - //tt - slot_generatezm(channel8->slots[0]); -} - -void chan_generaterhythm2(opl_chip *chip) { - opl_channel *channel6 = &chip->channel[6]; - opl_channel *channel7 = &chip->channel[7]; - opl_channel *channel8 = &chip->channel[8]; - slot_generate(channel6->slots[1]); - Bit16u phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; - Bit16u phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; - Bit16u phase = 0x00; - //hh tc phase bit - Bit16u phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; - //sd - phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); - slot_generatephase(channel7->slots[1], phase); - //tc - phase = 0x100 | (phasebit << 9); - slot_generatephase(channel8->slots[1], phase); -} - -void chan_enable(opl_channel *channel) { - if (channel->chip->newm) { - if (channel->chtype == ch_4op) { - eg_keyon(channel->slots[0], egk_norm); - eg_keyon(channel->slots[1], egk_norm); - eg_keyon(channel->pair->slots[0], egk_norm); - eg_keyon(channel->pair->slots[1], egk_norm); - } - else if (channel->chtype == ch_2op || channel->chtype == ch_drum) { - eg_keyon(channel->slots[0], egk_norm); - eg_keyon(channel->slots[1], egk_norm); - } - } - else { - eg_keyon(channel->slots[0], egk_norm); - eg_keyon(channel->slots[1], egk_norm); - } -} - -void chan_disable(opl_channel *channel) { - if (channel->chip->newm) { - if (channel->chtype == ch_4op) { - eg_keyoff(channel->slots[0], egk_norm); - eg_keyoff(channel->slots[1], egk_norm); - eg_keyoff(channel->pair->slots[0], egk_norm); - eg_keyoff(channel->pair->slots[1], egk_norm); - } - else if (channel->chtype == ch_2op || channel->chtype == ch_drum) { - eg_keyoff(channel->slots[0], egk_norm); - eg_keyoff(channel->slots[1], egk_norm); - } - } - else { - eg_keyoff(channel->slots[0], egk_norm); - eg_keyoff(channel->slots[1], egk_norm); - } -} - -void chan_set4op(opl_chip *chip, Bit8u data) { - for (Bit8u bit = 0; bit < 6; bit++) { - Bit8u chnum = bit; - if (bit >= 3) { - chnum += 9 - 3; - } - if ((data >> bit) & 0x01) { - chip->channel[chnum].chtype = ch_4op; - chip->channel[chnum + 3].chtype = ch_4op2; - } - else { - chip->channel[chnum].chtype = ch_2op; - chip->channel[chnum + 3].chtype = ch_2op; - } - } -} - -Bit16s limshort(Bit32s a) { - if (a > 32767) { - a = 32767; - } - else if (a < -32768) { - a = -32768; - } - return (Bit16s)a; -} - -void chip_generate(opl_chip *chip, Bit16s *buff) { - buff[1] = limshort(chip->mixbuff[1]); - - for (Bit8u ii = 0; ii < 12; ii++) { - slot_calcfb(&chip->slot[ii]); - pg_generate(&chip->slot[ii]); - envelope_calc(&chip->slot[ii]); - slot_generate(&chip->slot[ii]); - } - - for (Bit8u ii = 12; ii < 15; ii++) { - slot_calcfb(&chip->slot[ii]); - pg_generate(&chip->slot[ii]); - envelope_calc(&chip->slot[ii]); - } - - if (chip->rhy & 0x20) { - chan_generaterhythm1(chip); - } - else { - slot_generate(&chip->slot[12]); - slot_generate(&chip->slot[13]); - slot_generate(&chip->slot[14]); - } - - chip->mixbuff[0] = 0; - for (Bit8u ii = 0; ii < 18; ii++) { - Bit16s accm = 0; - for (Bit8u jj = 0; jj < 4; jj++) { - accm += *chip->channel[ii].out[jj]; - } - if (chip->FullPan) { - chip->mixbuff[0] += (Bit16s)(accm * chip->channel[ii].fcha); - } - else { - chip->mixbuff[0] += (Bit16s)(accm & chip->channel[ii].cha); - } - } - - for (Bit8u ii = 15; ii < 18; ii++) { - slot_calcfb(&chip->slot[ii]); - pg_generate(&chip->slot[ii]); - envelope_calc(&chip->slot[ii]); - } - - if (chip->rhy & 0x20) { - chan_generaterhythm2(chip); - } - else { - slot_generate(&chip->slot[15]); - slot_generate(&chip->slot[16]); - slot_generate(&chip->slot[17]); - } - - buff[0] = limshort(chip->mixbuff[0]); - - for (Bit8u ii = 18; ii < 33; ii++) { - slot_calcfb(&chip->slot[ii]); - pg_generate(&chip->slot[ii]); - envelope_calc(&chip->slot[ii]); - slot_generate(&chip->slot[ii]); - } - - chip->mixbuff[1] = 0; - for (Bit8u ii = 0; ii < 18; ii++) { - Bit16s accm = 0; - for (Bit8u jj = 0; jj < 4; jj++) { - accm += *chip->channel[ii].out[jj]; - } - if (chip->FullPan) { - chip->mixbuff[1] += (Bit16s)(accm * chip->channel[ii].fchb); - } - else { - chip->mixbuff[1] += (Bit16s)(accm & chip->channel[ii].chb); - } - } - - for (Bit8u ii = 33; ii < 36; ii++) { - slot_calcfb(&chip->slot[ii]); - pg_generate(&chip->slot[ii]); - envelope_calc(&chip->slot[ii]); - slot_generate(&chip->slot[ii]); - } - - n_generate(chip); - - if ((chip->timer & 0x3f) == 0x3f) { - if (!chip->tremdir) { - if (chip->tremtval == 105) { - chip->tremtval--; - chip->tremdir = 1; - } - else { - chip->tremtval++; - } - } - else { - if (chip->tremtval == 0) { - chip->tremtval++; - chip->tremdir = 0; - } - else { - chip->tremtval--; - } - } - chip->tremval = (chip->tremtval >> 2) >> ((1 - chip->dam) << 1); - } - - chip->timer++; -} - -void NukedOPL3::Reset() { - memset(&opl3, 0, sizeof(opl_chip)); - for (Bit8u slotnum = 0; slotnum < 36; slotnum++) { - opl3.slot[slotnum].chip = &opl3; - opl3.slot[slotnum].mod = &opl3.zeromod; - opl3.slot[slotnum].eg_rout = 0x1ff; - opl3.slot[slotnum].eg_out = 0x1ff; - opl3.slot[slotnum].eg_gen = envelope_gen_num_off; - opl3.slot[slotnum].trem = (Bit8u*)&opl3.zeromod; - } - for (Bit8u channum = 0; channum < 18; channum++) { - opl3.channel[channum].slots[0] = &opl3.slot[ch_slot[channum]]; - opl3.channel[channum].slots[1] = &opl3.slot[ch_slot[channum] + 3]; - opl3.slot[ch_slot[channum]].channel = &opl3.channel[channum]; - opl3.slot[ch_slot[channum] + 3].channel = &opl3.channel[channum]; - if ((channum % 9) < 3) { - opl3.channel[channum].pair = &opl3.channel[channum + 3]; - } - else if ((channum % 9) < 6) { - opl3.channel[channum].pair = &opl3.channel[channum - 3]; - } - opl3.channel[channum].chip = &opl3; - opl3.channel[channum].out[0] = &opl3.zeromod; - opl3.channel[channum].out[1] = &opl3.zeromod; - opl3.channel[channum].out[2] = &opl3.zeromod; - opl3.channel[channum].out[3] = &opl3.zeromod; - opl3.channel[channum].chtype = ch_2op; - opl3.channel[channum].cha = ~0; - opl3.channel[channum].chb = ~0; - opl3.channel[channum].fcha = 1.0; - opl3.channel[channum].fchb = 1.0; - chan_setupalg(&opl3.channel[channum]); - } - opl3.noise = 0x306600; - opl3.timer = 0; - opl3.FullPan = FullPan; -} - -void NukedOPL3::WriteReg(int reg, int v) { - v &= 0xff; - reg &= 0x1ff; - Bit8u high = (reg >> 8) & 0x01; - Bit8u regm = reg & 0xff; - switch (regm & 0xf0) { - case 0x00: - if (high) { - switch (regm & 0x0f) { - case 0x04: - chan_set4op(&opl3, v); - break; - case 0x05: - opl3.newm = v & 0x01; - break; - } - } - else { - switch (regm & 0x0f) { - case 0x08: - opl3.nts = (v >> 6) & 0x01; - break; - } - } - break; - case 0x20: - case 0x30: - if (ad_slot[regm & 0x1f] >= 0) { - slot_write20(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x40: - case 0x50: - if (ad_slot[regm & 0x1f] >= 0) { - slot_write40(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x60: - case 0x70: - if (ad_slot[regm & 0x1f] >= 0) { - slot_write60(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0x80: - case 0x90: - if (ad_slot[regm & 0x1f] >= 0) { - slot_write80(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v);; - } - break; - case 0xe0: - case 0xf0: - if (ad_slot[regm & 0x1f] >= 0) { - slot_writee0(&opl3.slot[18 * high + ad_slot[regm & 0x1f]], v); - } - break; - case 0xa0: - if ((regm & 0x0f) < 9) { - chan_writea0(&opl3.channel[9 * high + (regm & 0x0f)], v); - } - break; - case 0xb0: - if (regm == 0xbd && !high) { - opl3.dam = v >> 7; - opl3.dvb = (v >> 6) & 0x01; - chan_updaterhythm(&opl3, v); - } - else if ((regm & 0x0f) < 9) { - chan_writeb0(&opl3.channel[9 * high + (regm & 0x0f)], v); - if (v & 0x20) { - chan_enable(&opl3.channel[9 * high + (regm & 0x0f)]); - } - else { - chan_disable(&opl3.channel[9 * high + (regm & 0x0f)]); - } - } - break; - case 0xc0: - if ((regm & 0x0f) < 9) { - chan_writec0(&opl3.channel[9 * high + (regm & 0x0f)], v); - } - break; - } -} - -void NukedOPL3::Update(float* sndptr, int numsamples) { - Bit16s buffer[2]; - for (Bit32u i = 0; i < (Bit32u)numsamples; i++) { - chip_generate(&opl3, buffer); - *sndptr++ += (float)(buffer[0] / 10240.0); - *sndptr++ += (float)(buffer[1] / 10240.0); - } -} - -void NukedOPL3::SetPanning(int c, float left, float right) { - if (FullPan) { - opl3.channel[c].fcha = left; - opl3.channel[c].fchb = right; - } -} - -NukedOPL3::NukedOPL3(bool stereo) { - FullPan = stereo; - Reset(); -} - -} // namespace NukedOPL3 - -OPLEmul *NukedOPL3Create(bool stereo) { - return new NukedOPL3::NukedOPL3(stereo); -} diff --git a/libraries/oplsynth/opl_mus_player.cpp b/libraries/oplsynth/opl_mus_player.cpp deleted file mode 100644 index 9f88538af..000000000 --- a/libraries/oplsynth/opl_mus_player.cpp +++ /dev/null @@ -1,527 +0,0 @@ -/* -** opl_mus_player.cpp -** -**--------------------------------------------------------------------------- -** Copyright 1999-2016 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -*/ - -#ifdef _WIN32 -#include -#endif -#include -#include -#include -#include - -#include "opl_mus_player.h" -#include "opl.h" -#include "o_swap.h" - - -#define IMF_RATE 700.0 - -OPLmusicBlock::OPLmusicBlock(int core, int numchips) -{ - currentCore = core; - scoredata = NULL; - NextTickIn = 0; - LastOffset = 0; - NumChips = std::min(numchips, 2); - Looping = false; - FullPan = false; - io = NULL; - io = new OPLio; -} - -OPLmusicBlock::~OPLmusicBlock() -{ - delete io; -} - -void OPLmusicBlock::ResetChips (int numchips) -{ - io->Reset (); - NumChips = io->Init(currentCore, std::min(numchips, 2), FullPan, false); -} - -void OPLmusicBlock::Restart() -{ - stopAllVoices (); - resetAllControllers (127); - playingcount = 0; - LastOffset = 0; -} - -OPLmusicFile::OPLmusicFile (const void *data, size_t length, int core, int numchips, const char *&errormessage) - : OPLmusicBlock(core, numchips), ScoreLen ((int)length) -{ - static char errorbuffer[80]; - errormessage = nullptr; - if (io == nullptr) - { - return; - } - - scoredata = new uint8_t[ScoreLen]; - memcpy(scoredata, data, length); - - if (0 == (NumChips = io->Init(core, NumChips, false, false))) - { - goto fail; - } - - // Check for RDosPlay raw OPL format - if (!memcmp(scoredata, "RAWADATA", 8)) - { - RawPlayer = RDosPlay; - if (*(uint16_t *)(scoredata + 8) == 0) - { // A clock speed of 0 is bad - *(uint16_t *)(scoredata + 8) = 0xFFFF; - } - SamplesPerTick = LittleShort(*(uint16_t *)(scoredata + 8)) / ADLIB_CLOCK_MUL; - } - // Check for DosBox OPL dump - else if (!memcmp(scoredata, "DBRAWOPL", 8)) - { - if (LittleShort(((uint16_t *)scoredata)[5]) == 1) - { - RawPlayer = DosBox1; - SamplesPerTick = OPL_SAMPLE_RATE / 1000; - ScoreLen = std::min(ScoreLen - 24, LittleLong(((uint32_t *)scoredata)[4])) + 24; - } - else if (LittleLong(((uint32_t *)scoredata)[2]) == 2) - { - bool okay = true; - if (scoredata[21] != 0) - { - snprintf(errorbuffer, 80, "Unsupported DOSBox Raw OPL format %d\n", scoredata[20]); - errormessage = errorbuffer; - okay = false; - } - if (scoredata[22] != 0) - { - snprintf(errorbuffer, 80, "Unsupported DOSBox Raw OPL compression %d\n", scoredata[21]); - errormessage = errorbuffer; - okay = false; - } - if (!okay) - goto fail; - RawPlayer = DosBox2; - SamplesPerTick = OPL_SAMPLE_RATE / 1000; - int headersize = 0x1A + scoredata[0x19]; - ScoreLen = std::min(ScoreLen - headersize, LittleLong(((uint32_t *)scoredata)[3]) * 2) + headersize; - } - else - { - snprintf(errorbuffer, 80, "Unsupported DOSBox Raw OPL version %d.%d\n", LittleShort(((uint16_t *)scoredata)[4]), LittleShort(((uint16_t *)scoredata)[5])); - errormessage = errorbuffer; - goto fail; - } - } - // Check for modified IMF format (includes a header) - else if (!memcmp(scoredata, "ADLIB\1", 6)) - { - int songlen; - uint8_t *max = scoredata + ScoreLen; - RawPlayer = IMF; - SamplesPerTick = OPL_SAMPLE_RATE / IMF_RATE; - - score = scoredata + 6; - // Skip track and game name - for (int i = 2; i != 0; --i) - { - while (score < max && *score++ != '\0') {} - } - if (score < max) score++; // Skip unknown byte - if (score + 8 > max) - { // Not enough room left for song data - goto fail; - } - songlen = LittleLong(*(uint32_t *)score); - if (songlen != 0 && (songlen +=4) < ScoreLen - (score - scoredata)) - { - ScoreLen = songlen + int(score - scoredata); - } - } - else - { - errormessage = "Unknown OPL format"; - goto fail; - } - - Restart (); - return; - -fail: - delete[] scoredata; - scoredata = nullptr; - return; - -} - -OPLmusicFile::~OPLmusicFile () -{ - if (scoredata != NULL) - { - io->Reset (); - delete[] scoredata; - scoredata = NULL; - } -} - -bool OPLmusicFile::IsValid () const -{ - return scoredata != NULL; -} - -void OPLmusicFile::SetLooping (bool loop) -{ - Looping = loop; -} - -void OPLmusicFile::Restart () -{ - OPLmusicBlock::Restart(); - WhichChip = 0; - switch (RawPlayer) - { - case RDosPlay: - score = scoredata + 10; - SamplesPerTick = LittleShort(*(uint16_t *)(scoredata + 8)) / ADLIB_CLOCK_MUL; - break; - - case DosBox1: - score = scoredata + 24; - SamplesPerTick = OPL_SAMPLE_RATE / 1000; - break; - - case DosBox2: - score = scoredata + 0x1A + scoredata[0x19]; - SamplesPerTick = OPL_SAMPLE_RATE / 1000; - break; - - case IMF: - score = scoredata + 6; - - // Skip track and game name - for (int i = 2; i != 0; --i) - { - while (*score++ != '\0') {} - } - score++; // Skip unknown byte - if (*(uint32_t *)score != 0) - { - score += 4; // Skip song length - } - break; - } - io->SetClockRate(SamplesPerTick); -} - -bool OPLmusicBlock::ServiceStream (void *buff, int numbytes) -{ - float *samples1 = (float *)buff; - int stereoshift = (int)(FullPan | io->IsOPL3); - int numsamples = numbytes / (sizeof(float) << stereoshift); - bool prevEnded = false; - bool res = true; - - memset(buff, 0, numbytes); - - while (numsamples > 0) - { - int tick_in = int(NextTickIn); - int samplesleft = std::min(numsamples, tick_in); - size_t i; - - if (samplesleft > 0) - { - for (i = 0; i < io->NumChips; ++i) - { - io->chips[i]->Update(samples1, samplesleft); - } - OffsetSamples(samples1, samplesleft << stereoshift); - NextTickIn -= samplesleft; - assert (NextTickIn >= 0); - numsamples -= samplesleft; - samples1 += samplesleft << stereoshift; - } - - if (NextTickIn < 1) - { - int next = PlayTick(); - assert(next >= 0); - if (next == 0) - { // end of song - if (!Looping || prevEnded) - { - if (numsamples > 0) - { - for (i = 0; i < io->NumChips; ++i) - { - io->chips[i]->Update(samples1, numsamples); - } - OffsetSamples(samples1, numsamples << stereoshift); - } - res = false; - break; - } - else - { - // Avoid infinite loops from songs that do nothing but end - prevEnded = true; - Restart (); - } - } - else - { - prevEnded = false; - io->WriteDelay(next); - NextTickIn += SamplesPerTick * next; - assert (NextTickIn >= 0); - } - } - } - return res; -} - -void OPLmusicBlock::OffsetSamples(float *buff, int count) -{ - // Three out of four of the OPL waveforms are non-negative. Depending on - // timbre selection, this can cause the output waveform to tend toward - // very large positive values. Heretic's music is particularly bad for - // this. This function attempts to compensate by offseting the sample - // data back to around the [-1.0, 1.0] range. - - double max = -1e10, min = 1e10, offset, step; - int i, ramp, largest_at = 0; - - // Find max and min values for this segment of the waveform. - for (i = 0; i < count; ++i) - { - if (buff[i] > max) - { - max = buff[i]; - largest_at = i; - } - if (buff[i] < min) - { - min = buff[i]; - largest_at = i; - } - } - // Prefer to keep the offset at 0, even if it means a little clipping. - if (LastOffset == 0 && min >= -1.1 && max <= 1.1) - { - offset = 0; - } - else - { - offset = (max + min) / 2; - // If the new offset is close to 0, make it 0 to avoid making another - // full loop through the sample data. - if (fabs(offset) < 1/256.0) - { - offset = 0; - } - } - // Ramp the offset change so there aren't any abrupt clicks in the output. - // If the ramp is too short, it can sound scratchy. cblood2.mid is - // particularly unforgiving of short ramps. - if (count >= 512) - { - ramp = 512; - step = (offset - LastOffset) / 512; - } - else - { - ramp = std::min(count, std::max(196, largest_at)); - step = (offset - LastOffset) / ramp; - } - offset = LastOffset; - i = 0; - if (step != 0) - { - for (; i < ramp; ++i) - { - buff[i] = float(buff[i] - offset); - offset += step; - } - } - if (offset != 0) - { - for (; i < count; ++i) - { - buff[i] = float(buff[i] - offset); - } - } - LastOffset = float(offset); -} - -int OPLmusicFile::PlayTick () -{ - uint8_t reg, data; - uint16_t delay; - - switch (RawPlayer) - { - case RDosPlay: - while (score < scoredata + ScoreLen) - { - data = *score++; - reg = *score++; - switch (reg) - { - case 0: // Delay - if (data != 0) - { - return data; - } - break; - - case 2: // Speed change or OPL3 switch - if (data == 0) - { - SamplesPerTick = LittleShort(*(uint16_t *)(score)) / ADLIB_CLOCK_MUL; - io->SetClockRate(SamplesPerTick); - score += 2; - } - else if (data == 1) - { - WhichChip = 0; - } - else if (data == 2) - { - WhichChip = 1; - } - break; - - case 0xFF: // End of song - if (data == 0xFF) - { - return 0; - } - break; - - default: // It's something to stuff into the OPL chip - io->WriteRegister(WhichChip, reg, data); - break; - } - } - break; - - case DosBox1: - while (score < scoredata + ScoreLen) - { - reg = *score++; - - if (reg == 4) - { - reg = *score++; - data = *score++; - } - else if (reg == 0) - { // One-byte delay - return *score++ + 1; - } - else if (reg == 1) - { // Two-byte delay - int delay = score[0] + (score[1] << 8) + 1; - score += 2; - return delay; - } - else if (reg == 2) - { // Select OPL chip 0 - WhichChip = 0; - continue; - } - else if (reg == 3) - { // Select OPL chip 1 - WhichChip = 1; - continue; - } - else - { - data = *score++; - } - io->WriteRegister(WhichChip, reg, data); - } - break; - - case DosBox2: - { - uint8_t *to_reg = scoredata + 0x1A; - uint8_t to_reg_size = scoredata[0x19]; - uint8_t short_delay_code = scoredata[0x17]; - uint8_t long_delay_code = scoredata[0x18]; - - while (score < scoredata + ScoreLen) - { - uint8_t code = *score++; - data = *score++; - - // Which OPL chip to write to is encoded in the high bit of the code value. - int which = !!(code & 0x80); - code &= 0x7F; - - if (code == short_delay_code) - { - return data + 1; - } - else if (code == long_delay_code) - { - return (data + 1) << 8; - } - else if (code < to_reg_size) - { - io->WriteRegister(which, to_reg[code], data); - } - } - } - break; - - case IMF: - delay = 0; - while (delay == 0 && score + 4 - scoredata <= ScoreLen) - { - if (*(uint32_t *)score == 0xFFFFFFFF) - { // This is a special value that means to end the song. - return 0; - } - reg = score[0]; - data = score[1]; - delay = LittleShort(((uint16_t *)score)[1]); - score += 4; - io->WriteRegister (0, reg, data); - } - return delay; - } - return 0; -} - diff --git a/libraries/oplsynth/oplio.cpp b/libraries/oplsynth/oplio.cpp deleted file mode 100644 index e1b6e8644..000000000 --- a/libraries/oplsynth/oplio.cpp +++ /dev/null @@ -1,485 +0,0 @@ -//----------------------------------------------------------------------------- -// -// Copyright 2002-2016 Randy Heit -// Copyright 2005-2014 Simon Howard -// Copyright 2017 Christoph Oelckers -// -// 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/ -// -//----------------------------------------------------------------------------- -// -// OPL IO interface. Partly built from the non-MusLib code in the old version -// plus some additions from Chocolate Doom. -// - -#include -#include -#include -#include - -#include "genmidi.h" -#include "oplio.h" -#include "opl.h" - -const double HALF_PI = (3.14159265358979323846 * 0.5); - -OPLio::~OPLio() -{ -} - -void OPLio::SetClockRate(double samples_per_tick) -{ -} - -void OPLio::WriteDelay(int ticks) -{ -} - -//---------------------------------------------------------------------------- -// -// Initialize OPL emulator -// -//---------------------------------------------------------------------------- - -int OPLio::Init(int core, uint32_t numchips, bool stereo, bool initopl3) -{ - assert(numchips >= 1 && numchips <= OPL_NUM_VOICES); - uint32_t i; - IsOPL3 = (core == 1 || core == 2 || core == 3); - - memset(chips, 0, sizeof(chips)); - if (IsOPL3) - { - numchips = (numchips + 1) >> 1; - } - for (i = 0; i < numchips; ++i) - { - OPLEmul *chip = IsOPL3 ? (core == 1 ? DBOPLCreate(stereo) : (core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo); - if (chip == NULL) - { - break; - } - chips[i] = chip; - } - NumChips = i; - NumChannels = i * (IsOPL3 ? OPL3_NUM_VOICES : OPL_NUM_VOICES); - WriteInitState(initopl3); - return i; -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::WriteInitState(bool initopl3) -{ - for (uint32_t k = 0; k < NumChips; ++k) - { - int chip = k << (int)IsOPL3; - if (IsOPL3 && initopl3) - { - WriteRegister(chip, OPL_REG_OPL3_ENABLE, 1); - WriteRegister(chip, OPL_REG_4OPMODE_ENABLE, 0); - } - WriteRegister(chip, OPL_REG_WAVEFORM_ENABLE, WAVEFORM_ENABLED); - WriteRegister(chip, OPL_REG_PERCUSSION_MODE, 0); // should be the default, but cannot verify for some of the cores. - } - - // Reset all channels. - for (uint32_t k = 0; k < NumChannels; k++) - { - MuteChannel(k); - WriteValue(OPL_REGS_FREQ_2, k, 0); - } -} - - -//---------------------------------------------------------------------------- -// -// Deinitialize emulator before shutdown -// -//---------------------------------------------------------------------------- - -void OPLio::Reset(void) -{ - for (auto &c : chips) - { - if (c != nullptr) - { - delete c; - c = nullptr; - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::WriteRegister(int chipnum, uint32_t reg, uint8_t data) -{ - if (IsOPL3) - { - reg |= (chipnum & 1) << 8; - chipnum >>= 1; - } - if (chips[chipnum] != nullptr) - { - chips[chipnum]->WriteReg(reg, data); - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::WriteValue(uint32_t regbase, uint32_t channel, uint8_t value) -{ - WriteRegister (channel / OPL_NUM_VOICES, regbase + (channel % OPL_NUM_VOICES), value); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -static const int voice_operators[OPL_NUM_VOICES] = { 0x00, 0x01, 0x02, 0x08, 0x09, 0x0a, 0x10, 0x11, 0x12 }; - -void OPLio::WriteOperator(uint32_t regbase, uint32_t channel, int index, uint8_t data2) -{ - WriteRegister(channel / OPL_NUM_VOICES, regbase + voice_operators[channel % OPL_NUM_VOICES] + 3*index, data2); -} - -//---------------------------------------------------------------------------- -// -// Write frequency/octave/keyon data to a channel -// -// [RH] This is totally different from the original MUS library code -// but matches exactly what DMX does. I haven't a clue why there are 284 -// special bytes at the beginning of the table for the first few notes. -// That last byte in the table doesn't look right, either, but that's what -// it really is. -// -//---------------------------------------------------------------------------- - -static const uint16_t frequencies[] = { // (this is the table from Chocolate Doom, which contains the same values as ZDoom's original one but is better formatted. - - 0x133, 0x133, 0x134, 0x134, 0x135, 0x136, 0x136, 0x137, // -1 - 0x137, 0x138, 0x138, 0x139, 0x139, 0x13a, 0x13b, 0x13b, - 0x13c, 0x13c, 0x13d, 0x13d, 0x13e, 0x13f, 0x13f, 0x140, - 0x140, 0x141, 0x142, 0x142, 0x143, 0x143, 0x144, 0x144, - - 0x145, 0x146, 0x146, 0x147, 0x147, 0x148, 0x149, 0x149, // -2 - 0x14a, 0x14a, 0x14b, 0x14c, 0x14c, 0x14d, 0x14d, 0x14e, - 0x14f, 0x14f, 0x150, 0x150, 0x151, 0x152, 0x152, 0x153, - 0x153, 0x154, 0x155, 0x155, 0x156, 0x157, 0x157, 0x158, - - // These are used for the first seven MIDI note values: - - 0x158, 0x159, 0x15a, 0x15a, 0x15b, 0x15b, 0x15c, 0x15d, // 0 - 0x15d, 0x15e, 0x15f, 0x15f, 0x160, 0x161, 0x161, 0x162, - 0x162, 0x163, 0x164, 0x164, 0x165, 0x166, 0x166, 0x167, - 0x168, 0x168, 0x169, 0x16a, 0x16a, 0x16b, 0x16c, 0x16c, - - 0x16d, 0x16e, 0x16e, 0x16f, 0x170, 0x170, 0x171, 0x172, // 1 - 0x172, 0x173, 0x174, 0x174, 0x175, 0x176, 0x176, 0x177, - 0x178, 0x178, 0x179, 0x17a, 0x17a, 0x17b, 0x17c, 0x17c, - 0x17d, 0x17e, 0x17e, 0x17f, 0x180, 0x181, 0x181, 0x182, - - 0x183, 0x183, 0x184, 0x185, 0x185, 0x186, 0x187, 0x188, // 2 - 0x188, 0x189, 0x18a, 0x18a, 0x18b, 0x18c, 0x18d, 0x18d, - 0x18e, 0x18f, 0x18f, 0x190, 0x191, 0x192, 0x192, 0x193, - 0x194, 0x194, 0x195, 0x196, 0x197, 0x197, 0x198, 0x199, - - 0x19a, 0x19a, 0x19b, 0x19c, 0x19d, 0x19d, 0x19e, 0x19f, // 3 - 0x1a0, 0x1a0, 0x1a1, 0x1a2, 0x1a3, 0x1a3, 0x1a4, 0x1a5, - 0x1a6, 0x1a6, 0x1a7, 0x1a8, 0x1a9, 0x1a9, 0x1aa, 0x1ab, - 0x1ac, 0x1ad, 0x1ad, 0x1ae, 0x1af, 0x1b0, 0x1b0, 0x1b1, - - 0x1b2, 0x1b3, 0x1b4, 0x1b4, 0x1b5, 0x1b6, 0x1b7, 0x1b8, // 4 - 0x1b8, 0x1b9, 0x1ba, 0x1bb, 0x1bc, 0x1bc, 0x1bd, 0x1be, - 0x1bf, 0x1c0, 0x1c0, 0x1c1, 0x1c2, 0x1c3, 0x1c4, 0x1c4, - 0x1c5, 0x1c6, 0x1c7, 0x1c8, 0x1c9, 0x1c9, 0x1ca, 0x1cb, - - 0x1cc, 0x1cd, 0x1ce, 0x1ce, 0x1cf, 0x1d0, 0x1d1, 0x1d2, // 5 - 0x1d3, 0x1d3, 0x1d4, 0x1d5, 0x1d6, 0x1d7, 0x1d8, 0x1d8, - 0x1d9, 0x1da, 0x1db, 0x1dc, 0x1dd, 0x1de, 0x1de, 0x1df, - 0x1e0, 0x1e1, 0x1e2, 0x1e3, 0x1e4, 0x1e5, 0x1e5, 0x1e6, - - 0x1e7, 0x1e8, 0x1e9, 0x1ea, 0x1eb, 0x1ec, 0x1ed, 0x1ed, // 6 - 0x1ee, 0x1ef, 0x1f0, 0x1f1, 0x1f2, 0x1f3, 0x1f4, 0x1f5, - 0x1f6, 0x1f6, 0x1f7, 0x1f8, 0x1f9, 0x1fa, 0x1fb, 0x1fc, - 0x1fd, 0x1fe, 0x1ff, 0x200, 0x201, 0x201, 0x202, 0x203, - - // First note of looped range used for all octaves: - - 0x204, 0x205, 0x206, 0x207, 0x208, 0x209, 0x20a, 0x20b, // 7 - 0x20c, 0x20d, 0x20e, 0x20f, 0x210, 0x210, 0x211, 0x212, - 0x213, 0x214, 0x215, 0x216, 0x217, 0x218, 0x219, 0x21a, - 0x21b, 0x21c, 0x21d, 0x21e, 0x21f, 0x220, 0x221, 0x222, - - 0x223, 0x224, 0x225, 0x226, 0x227, 0x228, 0x229, 0x22a, // 8 - 0x22b, 0x22c, 0x22d, 0x22e, 0x22f, 0x230, 0x231, 0x232, - 0x233, 0x234, 0x235, 0x236, 0x237, 0x238, 0x239, 0x23a, - 0x23b, 0x23c, 0x23d, 0x23e, 0x23f, 0x240, 0x241, 0x242, - - 0x244, 0x245, 0x246, 0x247, 0x248, 0x249, 0x24a, 0x24b, // 9 - 0x24c, 0x24d, 0x24e, 0x24f, 0x250, 0x251, 0x252, 0x253, - 0x254, 0x256, 0x257, 0x258, 0x259, 0x25a, 0x25b, 0x25c, - 0x25d, 0x25e, 0x25f, 0x260, 0x262, 0x263, 0x264, 0x265, - - 0x266, 0x267, 0x268, 0x269, 0x26a, 0x26c, 0x26d, 0x26e, // 10 - 0x26f, 0x270, 0x271, 0x272, 0x273, 0x275, 0x276, 0x277, - 0x278, 0x279, 0x27a, 0x27b, 0x27d, 0x27e, 0x27f, 0x280, - 0x281, 0x282, 0x284, 0x285, 0x286, 0x287, 0x288, 0x289, - - 0x28b, 0x28c, 0x28d, 0x28e, 0x28f, 0x290, 0x292, 0x293, // 11 - 0x294, 0x295, 0x296, 0x298, 0x299, 0x29a, 0x29b, 0x29c, - 0x29e, 0x29f, 0x2a0, 0x2a1, 0x2a2, 0x2a4, 0x2a5, 0x2a6, - 0x2a7, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ae, 0x2af, 0x2b0, - - 0x2b1, 0x2b2, 0x2b4, 0x2b5, 0x2b6, 0x2b7, 0x2b9, 0x2ba, // 12 - 0x2bb, 0x2bd, 0x2be, 0x2bf, 0x2c0, 0x2c2, 0x2c3, 0x2c4, - 0x2c5, 0x2c7, 0x2c8, 0x2c9, 0x2cb, 0x2cc, 0x2cd, 0x2ce, - 0x2d0, 0x2d1, 0x2d2, 0x2d4, 0x2d5, 0x2d6, 0x2d8, 0x2d9, - - 0x2da, 0x2dc, 0x2dd, 0x2de, 0x2e0, 0x2e1, 0x2e2, 0x2e4, // 13 - 0x2e5, 0x2e6, 0x2e8, 0x2e9, 0x2ea, 0x2ec, 0x2ed, 0x2ee, - 0x2f0, 0x2f1, 0x2f2, 0x2f4, 0x2f5, 0x2f6, 0x2f8, 0x2f9, - 0x2fb, 0x2fc, 0x2fd, 0x2ff, 0x300, 0x302, 0x303, 0x304, - - 0x306, 0x307, 0x309, 0x30a, 0x30b, 0x30d, 0x30e, 0x310, // 14 - 0x311, 0x312, 0x314, 0x315, 0x317, 0x318, 0x31a, 0x31b, - 0x31c, 0x31e, 0x31f, 0x321, 0x322, 0x324, 0x325, 0x327, - 0x328, 0x329, 0x32b, 0x32c, 0x32e, 0x32f, 0x331, 0x332, - - 0x334, 0x335, 0x337, 0x338, 0x33a, 0x33b, 0x33d, 0x33e, // 15 - 0x340, 0x341, 0x343, 0x344, 0x346, 0x347, 0x349, 0x34a, - 0x34c, 0x34d, 0x34f, 0x350, 0x352, 0x353, 0x355, 0x357, - 0x358, 0x35a, 0x35b, 0x35d, 0x35e, 0x360, 0x361, 0x363, - - 0x365, 0x366, 0x368, 0x369, 0x36b, 0x36c, 0x36e, 0x370, // 16 - 0x371, 0x373, 0x374, 0x376, 0x378, 0x379, 0x37b, 0x37c, - 0x37e, 0x380, 0x381, 0x383, 0x384, 0x386, 0x388, 0x389, - 0x38b, 0x38d, 0x38e, 0x390, 0x392, 0x393, 0x395, 0x397, - - 0x398, 0x39a, 0x39c, 0x39d, 0x39f, 0x3a1, 0x3a2, 0x3a4, // 17 - 0x3a6, 0x3a7, 0x3a9, 0x3ab, 0x3ac, 0x3ae, 0x3b0, 0x3b1, - 0x3b3, 0x3b5, 0x3b7, 0x3b8, 0x3ba, 0x3bc, 0x3bd, 0x3bf, - 0x3c1, 0x3c3, 0x3c4, 0x3c6, 0x3c8, 0x3ca, 0x3cb, 0x3cd, - - // The last note has an incomplete range, and loops round back to - // the start. Note that the last value is actually a buffer overrun - // and does not fit with the other values. - - 0x3cf, 0x3d1, 0x3d2, 0x3d4, 0x3d6, 0x3d8, 0x3da, 0x3db, // 18 - 0x3dd, 0x3df, 0x3e1, 0x3e3, 0x3e4, 0x3e6, 0x3e8, 0x3ea, - 0x3ec, 0x3ed, 0x3ef, 0x3f1, 0x3f3, 0x3f5, 0x3f6, 0x3f8, - 0x3fa, 0x3fc, 0x3fe, 0x36c, -}; - -void OPLio::WriteFrequency(uint32_t channel, uint32_t note, uint32_t pitch, uint32_t keyon) -{ - int octave = 0; - int j = (note << 5) + pitch; - - if (j < 0) - { - j = 0; - } - else if (j >= 284) - { - j -= 284; - octave = j / (32*12); - if (octave > 7) - { - octave = 7; - } - j = (j % (32*12)) + 284; - } - int i = frequencies[j] | (octave << 10); - - WriteValue (OPL_REGS_FREQ_1, channel, (uint8_t)i); - WriteValue (OPL_REGS_FREQ_2, channel, (uint8_t)(i>>8)|(keyon<<5)); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -static uint8_t volumetable[128] = { - 0, 1, 3, 5, 6, 8, 10, 11, - 13, 14, 16, 17, 19, 20, 22, 23, - 25, 26, 27, 29, 30, 32, 33, 34, - 36, 37, 39, 41, 43, 45, 47, 49, - 50, 52, 54, 55, 57, 59, 60, 61, - 63, 64, 66, 67, 68, 69, 71, 72, - 73, 74, 75, 76, 77, 79, 80, 81, - 82, 83, 84, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 92, 93, 94, 95, - 96, 96, 97, 98, 99, 99, 100, 101, - 101, 102, 103, 103, 104, 105, 105, 106, - 107, 107, 108, 109, 109, 110, 110, 111, - 112, 112, 113, 113, 114, 114, 115, 115, - 116, 117, 117, 118, 118, 119, 119, 120, - 120, 121, 121, 122, 122, 123, 123, 123, - 124, 124, 125, 125, 126, 126, 127, 127}; - -void OPLio::WriteVolume(uint32_t channel, struct GenMidiVoice *voice, uint32_t vol1, uint32_t vol2, uint32_t vol3) -{ - if (voice != nullptr) - { - uint32_t full_volume = volumetable[std::min(127, (uint32_t)((uint64_t)vol1*vol2*vol3) / (127 * 127))]; - int reg_volume2 = ((0x3f - voice->carrier.level) * full_volume) / 128; - reg_volume2 = (0x3f - reg_volume2) | voice->carrier.scale; - WriteOperator(OPL_REGS_LEVEL, channel, 1, reg_volume2); - - int reg_volume1; - if (voice->feedback & 0x01) - { - // Chocolate Doom says: - // If we are using non-modulated feedback mode, we must set the - // volume for both voices. - // Note that the same register volume value is written for - // both voices, always calculated from the carrier's level - // value. - - // But Muslib does it differently than the comment above states. Which one is correct? - - reg_volume1 = ((0x3f - voice->modulator.level) * full_volume) / 128; - reg_volume1 = (0x3f - reg_volume1) | voice->modulator.scale; - } - else - { - reg_volume1 = voice->modulator.level | voice->modulator.scale; - } - WriteOperator(OPL_REGS_LEVEL, channel, 0,reg_volume1); - } -} - - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::WritePan(uint32_t channel, struct GenMidiVoice *voice, int pan) -{ - if (voice != 0) - { - WriteValue(OPL_REGS_FEEDBACK, channel, voice->feedback | (pan >= 28 ? 0x20 : 0) | (pan <= 100 ? 0x10 : 0)); - - // Set real panning if we're using emulated chips. - int chanper = IsOPL3 ? OPL3_NUM_VOICES : OPL_NUM_VOICES; - int which = channel / chanper; - if (chips[which] != NULL) - { - // This is the MIDI-recommended pan formula. 0 and 1 are - // both hard left so that 64 can be perfectly center. - double level = (pan <= 1) ? 0 : (pan - 1) / 126.0; - chips[which]->SetPanning(channel % chanper, - (float)cos(HALF_PI * level), (float)sin(HALF_PI * level)); - } - } -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::WriteTremolo(uint32_t channel, struct GenMidiVoice *voice, bool vibrato) -{ - int val1 = voice->modulator.tremolo, val2 = voice->carrier.tremolo; - if (vibrato) - { - if (voice->feedback & 1) val1 |= 0x40; - val2 |= 0x40; - } - WriteOperator(OPL_REGS_TREMOLO, channel, 1, val2); - WriteOperator(OPL_REGS_TREMOLO, channel, 0, val1); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::MuteChannel(uint32_t channel) -{ - WriteOperator(OPL_REGS_LEVEL, channel, 1, NO_VOLUME); - WriteOperator(OPL_REGS_ATTACK, channel, 1, MAX_ATTACK_DECAY); - WriteOperator(OPL_REGS_SUSTAIN, channel, 1, NO_SUSTAIN_MAX_RELEASE); - - WriteOperator(OPL_REGS_LEVEL, channel, 0, NO_VOLUME); - WriteOperator(OPL_REGS_ATTACK, channel, 0, MAX_ATTACK_DECAY); - WriteOperator(OPL_REGS_SUSTAIN, channel, 0, NO_SUSTAIN_MAX_RELEASE); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::LoadOperatorData(uint32_t channel, int op_index, genmidi_op_t *data, bool max_level, bool vibrato) -{ - // The scale and level fields must be combined for the level register. - // For the carrier wave we always set the maximum level. - - int level = data->scale; - if (max_level) level |= 0x3f; - else level |= data->level; - - int tremolo = data->tremolo; - if (vibrato) tremolo |= 0x40; - - WriteOperator(OPL_REGS_LEVEL, channel, op_index, level); - WriteOperator(OPL_REGS_TREMOLO, channel, op_index, tremolo); - WriteOperator(OPL_REGS_ATTACK, channel, op_index, data->attack); - WriteOperator(OPL_REGS_SUSTAIN, channel, op_index, data->sustain); - WriteOperator(OPL_REGS_WAVEFORM, channel, op_index, data->waveform); -} - -//---------------------------------------------------------------------------- -// -// -// -//---------------------------------------------------------------------------- - -void OPLio::WriteInstrument(uint32_t channel, struct GenMidiVoice *voice, bool vibrato) -{ - bool modulating = (voice->feedback & 0x01) == 0; - - // Doom loads the second operator first, then the first. - // The carrier is set to minimum volume until the voice volume - // is set later. If we are not using modulating mode, we must set both to minimum volume. - - LoadOperatorData(channel, 1, &voice->carrier, true, vibrato); - LoadOperatorData(channel, 0, &voice->modulator, !modulating, vibrato && modulating); - - // The feedback register is written by the calling code. -} diff --git a/libraries/oplsynth/oplsynth/genmidi.h b/libraries/oplsynth/oplsynth/genmidi.h deleted file mode 100644 index 6d8cd68a9..000000000 --- a/libraries/oplsynth/oplsynth/genmidi.h +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once -#include - -#if defined(__GNUC__) -// With versions of GCC newer than 4.2, it appears it was determined that the -// cost of an unaligned pointer on PPC was high enough to add padding to the -// end of packed structs. For whatever reason __packed__ and pragma pack are -// handled differently in this regard. Note that this only needs to be applied -// to types which are used in arrays or sizeof is needed. This also prevents -// code from taking references to the struct members. -#define FORCE_PACKED __attribute__((__packed__)) -#else -#define FORCE_PACKED -#endif - -#pragma pack(push, 1) -struct genmidi_op_t -{ - uint8_t tremolo; - uint8_t attack; - uint8_t sustain; - uint8_t waveform; - uint8_t scale; - uint8_t level; -} FORCE_PACKED; - -struct GenMidiVoice -{ - genmidi_op_t modulator; - uint8_t feedback; - genmidi_op_t carrier; - uint8_t unused; - int16_t base_note_offset; -} FORCE_PACKED; - - -struct GenMidiInstrument -{ - uint16_t flags; - uint8_t fine_tuning; - uint8_t fixed_note; - GenMidiVoice voices[2]; -} FORCE_PACKED; - -#pragma pack(pop) - -enum -{ - GENMIDI_FLAG_FIXED = 0x0001, /* fixed pitch */ - GENMIDI_FLAG_2VOICE = 0x0004 /* double voice (OPL3) */ -}; - -enum -{ - GENMIDI_NUM_INSTRS = 128, - GENMIDI_FIST_PERCUSSION = 35, - GENMIDI_NUM_PERCUSSION = 47, - GENMIDI_NUM_TOTAL = GENMIDI_NUM_INSTRS + GENMIDI_NUM_PERCUSSION -}; - diff --git a/libraries/oplsynth/oplsynth/musicblock.h b/libraries/oplsynth/oplsynth/musicblock.h deleted file mode 100644 index cc2612b8b..000000000 --- a/libraries/oplsynth/oplsynth/musicblock.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once -#include -#include "genmidi.h" -#include "oplio.h" - - -struct OPLVoice -{ - unsigned int index; // Index of this voice, or -1 if not in use. - unsigned int key; // The midi key that this voice is playing. - unsigned int note; // The note being played. This is normally the same as the key, but if the instrument is a fixed pitch instrument, it is different. - unsigned int note_volume; // The volume of the note being played on this channel. - GenMidiInstrument *current_instr; // Currently-loaded instrument data - GenMidiVoice *current_instr_voice;// The voice number in the instrument to use. This is normally set to the instrument's first voice; if this is a double voice instrument, it may be the second one - bool sustained; - int8_t fine_tuning; - int pitch; - uint32_t timestamp; -}; - -struct musicBlock { - musicBlock(); - ~musicBlock(); - - OPLChannel oplchannels[NUM_CHANNELS]; - OPLio *io; - uint32_t timeCounter; - - struct GenMidiInstrument OPLinstruments[GENMIDI_NUM_TOTAL]; - - void changeModulation(uint32_t id, int value); - void changeSustain(uint32_t id, int value); - void changeVolume(uint32_t id, int value, bool expression); - void changePanning(uint32_t id, int value); - void notesOff(uint32_t id, int value); - void allNotesOff(uint32_t id, int value); - void changeExtended(uint32_t channel, uint8_t controller, int value); - void resetControllers(uint32_t channel, int vol); - void programChange(uint32_t channel, int value); - void resetAllControllers(int vol); - void changePitch(uint32_t channel, int val1, int val2); - - void noteOn(uint32_t channel, uint8_t note, int volume); - void noteOff(uint32_t channel, uint8_t note); - void stopAllVoices(); - -protected: - OPLVoice voices[NUM_VOICES]; - - int findFreeVoice(); - int replaceExistingVoice(); - void voiceKeyOn(uint32_t slot, uint32_t channo, GenMidiInstrument *instrument, uint32_t instrument_voice, uint32_t, uint32_t volume); - int releaseVoice(uint32_t slot, uint32_t killed); - - friend class Stat_opl; - -}; - -enum ExtCtrl { - ctrlRPNHi, - ctrlRPNLo, - ctrlNRPNHi, - ctrlNRPNLo, - ctrlDataEntryHi, - ctrlDataEntryLo, -}; diff --git a/libraries/oplsynth/oplsynth/nukedopl3.h b/libraries/oplsynth/oplsynth/nukedopl3.h deleted file mode 100644 index 423fbf668..000000000 --- a/libraries/oplsynth/oplsynth/nukedopl3.h +++ /dev/null @@ -1,240 +0,0 @@ -/* -* 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" -#include "musicblock.h" - -namespace NukedOPL3 -{ - -typedef uintptr_t Bitu; -typedef intptr_t Bits; -typedef uint32_t Bit32u; -typedef int32_t Bit32s; -typedef uint16_t Bit16u; -typedef int16_t Bit16s; -typedef uint8_t Bit8u; -typedef int8_t 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 : public OPLEmul { -private: - opl_chip opl3; - bool FullPan; -public: - void Reset(); - void Update(float* sndptr, int numsamples); - void WriteReg(int reg, int v); - void SetPanning(int c, float left, float right); - - NukedOPL3(bool stereo); -}; - -} // namespace NukedOPL3 diff --git a/libraries/oplsynth/oplsynth/o_swap.h b/libraries/oplsynth/oplsynth/o_swap.h deleted file mode 100644 index de9b7780a..000000000 --- a/libraries/oplsynth/oplsynth/o_swap.h +++ /dev/null @@ -1,255 +0,0 @@ -// -// DESCRIPTION: -// Endianess handling, swapping 16bit and 32bit. -// -//----------------------------------------------------------------------------- - - -#ifndef __M_SWAP_H__ -#define __M_SWAP_H__ - -#include - -// Endianess handling. -// WAD files are stored little endian. - -#ifdef __APPLE__ -#include - -inline short LittleShort(short x) -{ - return (short)OSSwapLittleToHostInt16((uint16_t)x); -} - -inline unsigned short LittleShort(unsigned short x) -{ - return OSSwapLittleToHostInt16(x); -} - -inline short LittleShort(int x) -{ - return OSSwapLittleToHostInt16((uint16_t)x); -} - -inline unsigned short LittleShort(unsigned int x) -{ - return OSSwapLittleToHostInt16((uint16_t)x); -} - -inline int LittleLong(int x) -{ - return OSSwapLittleToHostInt32((uint32_t)x); -} - -inline unsigned int LittleLong(unsigned int x) -{ - return OSSwapLittleToHostInt32(x); -} - -inline short BigShort(short x) -{ - return (short)OSSwapBigToHostInt16((uint16_t)x); -} - -inline unsigned short BigShort(unsigned short x) -{ - return OSSwapBigToHostInt16(x); -} - -inline int BigLong(int x) -{ - return OSSwapBigToHostInt32((uint32_t)x); -} - -inline unsigned int BigLong(unsigned int x) -{ - return OSSwapBigToHostInt32(x); -} - -#elif defined __BIG_ENDIAN__ - -// Swap 16bit, that is, MSB and LSB byte. -// No masking with 0xFF should be necessary. -inline short LittleShort (short x) -{ - return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8)); -} - -inline unsigned short LittleShort (unsigned short x) -{ - return (unsigned short)((x>>8) | (x<<8)); -} - -inline short LittleShort (int x) -{ - return LittleShort((short)x); -} - -inline unsigned short LittleShort (unsigned int x) -{ - return LittleShort((unsigned short)x); -} - -// Swapping 32bit. -inline unsigned int LittleLong (unsigned int x) -{ - return (unsigned int)( - (x>>24) - | ((x>>8) & 0xff00) - | ((x<<8) & 0xff0000) - | (x<<24)); -} - -inline int LittleLong (int x) -{ - return (int)( - (((unsigned int)x)>>24) - | ((((unsigned int)x)>>8) & 0xff00) - | ((((unsigned int)x)<<8) & 0xff0000) - | (((unsigned int)x)<<24)); -} - -inline short BigShort(short x) -{ - return x; -} - -inline unsigned short BigShort(unsigned short x) -{ - return x; -} - -inline unsigned int BigLong(unsigned int x) -{ - return x; -} - -inline int BigLong(int x) -{ - return x; -} - -#else - -inline short LittleShort(short x) -{ - return x; -} - -inline unsigned short LittleShort(unsigned short x) -{ - return x; -} - -inline unsigned int LittleLong(unsigned int x) -{ - return x; -} - -inline int LittleLong(int x) -{ - return x; -} - -#ifdef _MSC_VER - -inline short BigShort(short x) -{ - return (short)_byteswap_ushort((unsigned short)x); -} - -inline unsigned short BigShort(unsigned short x) -{ - return _byteswap_ushort(x); -} - -inline int BigLong(int x) -{ - return (int)_byteswap_ulong((unsigned long)x); -} - -inline unsigned int BigLong(unsigned int x) -{ - return (unsigned int)_byteswap_ulong((unsigned long)x); -} -#pragma warning (default: 4035) - -#else - -inline short BigShort (short x) -{ - return (short)((((unsigned short)x)>>8) | (((unsigned short)x)<<8)); -} - -inline unsigned short BigShort (unsigned short x) -{ - return (unsigned short)((x>>8) | (x<<8)); -} - -inline unsigned int BigLong (unsigned int x) -{ - return (unsigned int)( - (x>>24) - | ((x>>8) & 0xff00) - | ((x<<8) & 0xff0000) - | (x<<24)); -} - -inline int BigLong (int x) -{ - return (int)( - (((unsigned int)x)>>24) - | ((((unsigned int)x)>>8) & 0xff00) - | ((((unsigned int)x)<<8) & 0xff0000) - | (((unsigned int)x)<<24)); -} - -#endif - -#endif // __BIG_ENDIAN__ - -// These may be destructive so they should create errors -unsigned long BigLong(unsigned long) = delete; -long BigLong(long) = delete; -unsigned long LittleLong(unsigned long) = delete; -long LittleLong(long) = delete; - - -// Data accessors, since some data is highly likely to be unaligned. -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) -inline int GetShort(const unsigned char *foo) -{ - return *(const short *)foo; -} -inline int GetInt(const unsigned char *foo) -{ - return *(const int *)foo; -} -#else -inline int GetShort(const unsigned char *foo) -{ - return short(foo[0] | (foo[1] << 8)); -} -inline int GetInt(const unsigned char *foo) -{ - return int(foo[0] | (foo[1] << 8) | (foo[2] << 16) | (foo[3] << 24)); -} -#endif -inline int GetBigInt(const unsigned char *foo) -{ - return int((foo[0] << 24) | (foo[1] << 16) | (foo[2] << 8) | foo[3]); -} - -#ifdef __BIG_ENDIAN__ -inline int GetNativeInt(const unsigned char *foo) -{ - return GetBigInt(foo); -} -#else -inline int GetNativeInt(const unsigned char *foo) -{ - return GetInt(foo); -} -#endif - -#endif // __M_SWAP_H__ diff --git a/libraries/oplsynth/oplsynth/opl.h b/libraries/oplsynth/oplsynth/opl.h deleted file mode 100644 index 57c394f26..000000000 --- a/libraries/oplsynth/oplsynth/opl.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef OPL_H -#define OPL_H - -// Abstract base class for OPL emulators - -class OPLEmul -{ -public: - OPLEmul() {} - virtual ~OPLEmul() {} - - virtual void Reset() = 0; - virtual void WriteReg(int reg, int v) = 0; - virtual void Update(float *buffer, int length) = 0; - virtual void SetPanning(int c, float left, float right) = 0; -}; - -OPLEmul *YM3812Create(bool stereo); -OPLEmul *DBOPLCreate(bool stereo); -OPLEmul *JavaOPLCreate(bool stereo); -OPLEmul *NukedOPL3Create(bool stereo); - -#define OPL_SAMPLE_RATE 49716.0 -#define CENTER_PANNING_POWER 0.70710678118 /* [RH] volume at center for EQP */ -#define ADLIB_CLOCK_MUL 24.0 - - - -#endif \ No newline at end of file diff --git a/libraries/oplsynth/oplsynth/opl3_Float.h b/libraries/oplsynth/oplsynth/opl3_Float.h deleted file mode 100644 index 6c676ee3a..000000000 --- a/libraries/oplsynth/oplsynth/opl3_Float.h +++ /dev/null @@ -1,238 +0,0 @@ -// ==================================================================================================================== -// ==================================================================================================================== -// xs_Float.h -// -// Source: "Know Your FPU: Fixing Floating Fast" -// http://www.stereopsis.com/sree/fpu2006.html -// -// xs_CRoundToInt: Round toward nearest, but ties round toward even (just like FISTP) -// xs_ToInt: Round toward zero, just like the C (int) cast -// xs_FloorToInt: Round down -// xs_CeilToInt: Round up -// xs_RoundToInt: Round toward nearest, but ties round up -// ==================================================================================================================== -// ==================================================================================================================== -#ifndef _xs_FLOAT_H_ -#define _xs_FLOAT_H_ - -#include - -// ==================================================================================================================== -// Defines -// ==================================================================================================================== -#ifndef _xs_DEFAULT_CONVERSION -#define _xs_DEFAULT_CONVERSION 0 -#endif //_xs_DEFAULT_CONVERSION - - -#if __BIG_ENDIAN__ - #define _xs_iexp_ 0 - #define _xs_iman_ 1 -#else - #define _xs_iexp_ 1 //intel is little endian - #define _xs_iman_ 0 -#endif //BigEndian_ - -#ifdef __GNUC__ -#define finline inline -#else -#define finline __forceinline -#endif - -typedef double real64; - - -union _xs_doubleints -{ - real64 val; - uint32_t ival[2]; -}; - -#if 0 -#define _xs_doublecopysgn(a,b) ((int32_t*)&a)[_xs_iexp_]&=~(((int32_t*)&b)[_xs_iexp_]&0x80000000) -#define _xs_doubleisnegative(a) ((((int32_t*)&a)[_xs_iexp_])|0x80000000) -#endif - -// ==================================================================================================================== -// Constants -// ==================================================================================================================== -const real64 _xs_doublemagic = real64 (6755399441055744.0); //2^52 * 1.5, uses limited precisicion to floor -const real64 _xs_doublemagicdelta = (1.5e-8); //almost .5f = .5f + 1e^(number of exp bit) -const real64 _xs_doublemagicroundeps = (.5f-_xs_doublemagicdelta); //almost .5f = .5f - 1e^(number of exp bit) - - -// ==================================================================================================================== -// Prototypes -// ==================================================================================================================== -static int32_t xs_CRoundToInt (real64 val, real64 dmr = _xs_doublemagic); -static int32_t xs_ToInt (real64 val, real64 dme = -_xs_doublemagicroundeps); -static int32_t xs_FloorToInt (real64 val, real64 dme = _xs_doublemagicroundeps); -static int32_t xs_CeilToInt (real64 val, real64 dme = _xs_doublemagicroundeps); -static int32_t xs_RoundToInt (real64 val); - -//int32_t versions -finline static int32_t xs_CRoundToInt (int32_t val) {return val;} -finline static int32_t xs_ToInt (int32_t val) {return val;} - - - -// ==================================================================================================================== -// Fix Class -// ==================================================================================================================== -template class xs_Fix -{ -public: - typedef int32_t Fix; - - // ==================================================================================================================== - // Basic Conversion from Numbers - // ==================================================================================================================== - finline static Fix ToFix (int32_t val) {return val<>N;} - - - -protected: - // ==================================================================================================================== - // Helper function - mainly to preserve _xs_DEFAULT_CONVERSION - // ==================================================================================================================== - finline static int32_t xs_ConvertToFixed (real64 val) - { - #if _xs_DEFAULT_CONVERSION==0 - return xs_CRoundToInt(val, _xs_doublemagic/(1<= 1400 - // VC++ 2005's standard cast is a little bit faster than this - // magic number code. (Which is pretty amazing!) SSE has the - // fastest C-style float->int conversion, but unfortunately, - // checking for SSE support every time you need to do a - // conversion completely negates its performance advantage. - return int32_t(val); -#else -#if _xs_DEFAULT_CONVERSION==0 - return (val<0) ? xs_CRoundToInt(val-dme) : - xs_CRoundToInt(val+dme); -#else - return int32_t(val); -#endif -#endif -} - - -// ==================================================================================================================== -finline static int32_t xs_FloorToInt(real64 val, real64 dme) -{ -#if _xs_DEFAULT_CONVERSION==0 - return xs_CRoundToInt (val - dme); -#else - return floor(val); -#endif -} - - -// ==================================================================================================================== -finline static int32_t xs_CeilToInt(real64 val, real64 dme) -{ -#if _xs_DEFAULT_CONVERSION==0 - return xs_CRoundToInt (val + dme); -#else - return ceil(val); -#endif -} - - -// ==================================================================================================================== -finline static int32_t xs_RoundToInt(real64 val) -{ -#if _xs_DEFAULT_CONVERSION==0 - // Yes, it is important that two fadds be generated, so you cannot override the dmr - // passed to xs_CRoundToInt with _xs_doublemagic + _xs_doublemagicdelta. If you do, - // you'll end up with Banker's Rounding again. - return xs_CRoundToInt (val + _xs_doublemagicdelta); -#else - return floor(val+.5); -#endif -} - - - -// ==================================================================================================================== -// ==================================================================================================================== -// Unsigned variants -// ==================================================================================================================== -// ==================================================================================================================== -finline static uint32_t xs_CRoundToUInt(real64 val) -{ - return (uint32_t)xs_CRoundToInt(val); -} - -finline static uint32_t xs_FloorToUInt(real64 val) -{ - return (uint32_t)xs_FloorToInt(val); -} - -finline static uint32_t xs_CeilToUInt(real64 val) -{ - return (uint32_t)xs_CeilToInt(val); -} - -finline static uint32_t xs_RoundToUInt(real64 val) -{ - return (uint32_t)xs_RoundToInt(val); -} - - - -// ==================================================================================================================== -// ==================================================================================================================== -#endif // _xs_FLOAT_H_ \ No newline at end of file diff --git a/libraries/oplsynth/oplsynth/opl_mus_player.h b/libraries/oplsynth/oplsynth/opl_mus_player.h deleted file mode 100644 index bc0620f88..000000000 --- a/libraries/oplsynth/oplsynth/opl_mus_player.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once -#include -#include -#include -#include "musicblock.h" - -class OPLmusicBlock : public musicBlock -{ -public: - OPLmusicBlock(int core, int numchips); - virtual ~OPLmusicBlock(); - - bool ServiceStream(void *buff, int numbytes); - void ResetChips(int numchips); - - virtual void Restart(); - -protected: - virtual int PlayTick() = 0; - void OffsetSamples(float *buff, int count); - - uint8_t *score; - uint8_t *scoredata; - double NextTickIn; - double SamplesPerTick; - double LastOffset; - int playingcount; - int NumChips; - int currentCore; - bool Looping; - bool FullPan; -}; - -class OPLmusicFile : public OPLmusicBlock -{ -public: - OPLmusicFile(const void *data, size_t length, int core, int numchips, const char *&errormessage); - virtual ~OPLmusicFile(); - - bool IsValid() const; - void SetLooping(bool loop); - void Restart(); - -protected: - OPLmusicFile(int core, int numchips) : OPLmusicBlock(core, numchips) {} - int PlayTick(); - - enum { RDosPlay, IMF, DosBox1, DosBox2 } RawPlayer; - int ScoreLen; - int WhichChip; -}; diff --git a/libraries/oplsynth/oplsynth/oplio.h b/libraries/oplsynth/oplsynth/oplio.h deleted file mode 100644 index 92be980cb..000000000 --- a/libraries/oplsynth/oplsynth/oplio.h +++ /dev/null @@ -1,99 +0,0 @@ -#pragma once - - -enum -{ - // Operator registers (21 of each): - OPL_REGS_TREMOLO = 0x20, - OPL_REGS_LEVEL = 0x40, - OPL_REGS_ATTACK = 0x60, - OPL_REGS_SUSTAIN = 0x80, - OPL_REGS_WAVEFORM = 0xE0, - - // Voice registers (9 of each): - OPL_REGS_FREQ_1 = 0xA0, - OPL_REGS_FREQ_2 = 0xB0, - OPL_REGS_FEEDBACK = 0xC0, -}; - -enum -{ - OPL_REG_WAVEFORM_ENABLE = 0x01, - OPL_REG_TIMER1 = 0x02, - OPL_REG_TIMER2 = 0x03, - OPL_REG_TIMER_CTRL = 0x04, - OPL_REG_FM_MODE = 0x08, - OPL_REG_PERCUSSION_MODE = 0xBD, - - OPL_REG_OPL3_ENABLE = 0x105, - OPL_REG_4OPMODE_ENABLE = 0x104, - -}; - -enum -{ - NO_VOLUME = 0x3f, - MAX_ATTACK_DECAY = 0xff, - NO_SUSTAIN_MAX_RELEASE = 0xf, - WAVEFORM_ENABLED = 0x20 -}; - -enum -{ - OPL_NUM_VOICES = 9, - OPL3_NUM_VOICES = 18, - MAXOPL2CHIPS = 8, - NUM_VOICES = (OPL_NUM_VOICES * MAXOPL2CHIPS), - - NUM_CHANNELS = 16, - CHAN_PERCUSSION = 15, - - VIBRATO_THRESHOLD = 40, - MIN_SUSTAIN = 0x40, - HIGHEST_NOTE = 127, - -}; - -struct GenMidiVoice; -struct genmidi_op_t; - -struct OPLio -{ - virtual ~OPLio(); - - void WriteOperator(uint32_t regbase, uint32_t channel, int index, uint8_t data2); - void LoadOperatorData(uint32_t channel, int op_index, genmidi_op_t *op_data, bool maxlevel, bool vibrato); - void WriteValue(uint32_t regbase, uint32_t channel, uint8_t value); - void WriteFrequency(uint32_t channel, uint32_t freq, uint32_t octave, uint32_t keyon); - void WriteVolume(uint32_t channel, GenMidiVoice *voice, uint32_t v1, uint32_t v2, uint32_t v3); - void WritePan(uint32_t channel, GenMidiVoice *voice, int pan); - void WriteTremolo(uint32_t channel, GenMidiVoice *voice, bool vibrato); - void WriteInstrument(uint32_t channel, GenMidiVoice *voice, bool vibrato); - void WriteInitState(bool opl3); - void MuteChannel(uint32_t chan); - void StopPlayback(); - - virtual int Init(int core, uint32_t numchips, bool stereo, bool initopl3); - virtual void Reset(); - virtual void WriteRegister(int which, uint32_t reg, uint8_t data); - virtual void SetClockRate(double samples_per_tick); - virtual void WriteDelay(int ticks); - - class OPLEmul *chips[OPL_NUM_VOICES]; - uint32_t NumChannels; - uint32_t NumChips; - bool IsOPL3; -}; - -struct OPLChannel -{ - uint32_t Instrument; - uint8_t Volume; - uint8_t Panning; - int8_t Pitch; - uint8_t Sustain; - bool Vibrato; - uint8_t Expression; - uint16_t PitchSensitivity; - uint16_t RPN; -}; diff --git a/libraries/zmusic/CMakeLists.txt b/libraries/zmusic/CMakeLists.txt index 11ba6c881..24c9498ab 100644 --- a/libraries/zmusic/CMakeLists.txt +++ b/libraries/zmusic/CMakeLists.txt @@ -41,7 +41,7 @@ else() endif() -include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../libraries/dumb/include" "${ZLIB_INCLUDE_DIR}" "${TIMIDITYPP_INCLUDE_DIR}" "${OPLSYNTH_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" ) +include_directories( "${CMAKE_CURRENT_SOURCE_DIR}/../libraries/dumb/include" "${ZLIB_INCLUDE_DIR}" "${TIMIDITYPP_INCLUDE_DIR}" "${GME_INCLUDE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}" ) if (WIN32) set( PLAT_SOURCES @@ -65,7 +65,6 @@ add_library( zmusic STATIC ${HEADER_FILES} i_module.cpp mididevices/music_base_mididevice.cpp - mididevices/music_opl_mididevice.cpp mididevices/music_timiditypp_mididevice.cpp mididevices/music_fluidsynth_mididevice.cpp mididevices/music_softsynth_mididevice.cpp @@ -78,7 +77,6 @@ add_library( zmusic STATIC streamsources/music_dumb.cpp streamsources/music_gme.cpp streamsources/music_libsndfile.cpp - streamsources/music_opl.cpp streamsources/music_xa.cpp musicformats/music_stream.cpp musicformats/music_midi.cpp @@ -90,7 +88,7 @@ add_library( zmusic STATIC zmusic/zmusic.cpp ${PLAT_SOURCES} ) -target_link_libraries( zmusic dumb gme oplsynth timidityplus) +target_link_libraries( zmusic dumb gme timidityplus) if( NOT DYN_SNDFILE AND SNDFILE_FOUND ) include_directories( "${SNDFILE_INCLUDE_DIRS}" ) diff --git a/libraries/zmusic/mididevices/music_opl_mididevice.cpp b/libraries/zmusic/mididevices/music_opl_mididevice.cpp deleted file mode 100644 index f7503f689..000000000 --- a/libraries/zmusic/mididevices/music_opl_mididevice.cpp +++ /dev/null @@ -1,326 +0,0 @@ -/* -** music_opl_mididevice.cpp -** Provides an emulated OPL implementation of a MIDI output device. -** -**--------------------------------------------------------------------------- -** Copyright 2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -** -*/ - -// HEADER FILES ------------------------------------------------------------ - -#include "mididevice.h" -#include "zmusic/mus2midi.h" -#include "oplsynth/opl.h" -#include "oplsynth/opl_mus_player.h" - -// MACROS ------------------------------------------------------------------ - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -OPLConfig oplConfig; - -// OPL implementation of a MIDI output device ------------------------------- - -class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock -{ -public: - OPLMIDIDevice(int core); - int OpenRenderer() override; - void Close() override; - int GetTechnology() const override; - std::string GetStats() override; - -protected: - void CalcTickRate() override; - int PlayTick() override; - void HandleEvent(int status, int parm1, int parm2) override; - void HandleLongEvent(const uint8_t *data, int len) override; - void ComputeOutput(float *buffer, int len) override; - bool ServiceStream(void *buff, int numbytes) override; - int GetDeviceType() const override { return MDEV_OPL; } -}; - - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -// CODE -------------------------------------------------------------------- - -//========================================================================== -// -// OPLMIDIDevice Contructor -// -//========================================================================== - -OPLMIDIDevice::OPLMIDIDevice(int core) - : SoftSynthMIDIDevice((int)OPL_SAMPLE_RATE), OPLmusicBlock(core, oplConfig.numchips) -{ - FullPan = oplConfig.fullpan; - memcpy(OPLinstruments, oplConfig.OPLinstruments, sizeof(OPLinstruments)); - StreamBlockSize = 14; -} - -//========================================================================== -// -// OPLMIDIDevice :: Open -// -// Returns 0 on success. -// -//========================================================================== - -int OPLMIDIDevice::OpenRenderer() -{ - if (io == NULL || 0 == (NumChips = io->Init(currentCore, NumChips, FullPan, true))) - { - return 1; - } - isMono = !FullPan && !io->IsOPL3; - stopAllVoices(); - resetAllControllers(100); - return 0; -} - -//========================================================================== -// -// OPLMIDIDevice :: Close -// -//========================================================================== - -void OPLMIDIDevice::Close() -{ - SoftSynthMIDIDevice::Close(); - io->Reset(); -} - -//========================================================================== -// -// OPLMIDIDevice :: GetTechnology -// -//========================================================================== - -int OPLMIDIDevice::GetTechnology() const -{ - return MIDIDEV_FMSYNTH; -} - -//========================================================================== -// -// OPLMIDIDevice :: CalcTickRate -// -// Tempo is the number of microseconds per quarter note. -// Division is the number of ticks per quarter note. -// -//========================================================================== - -void OPLMIDIDevice::CalcTickRate() -{ - SoftSynthMIDIDevice::CalcTickRate(); - io->SetClockRate(OPLmusicBlock::SamplesPerTick = SoftSynthMIDIDevice::SamplesPerTick); -} - -//========================================================================== -// -// OPLMIDIDevice :: PlayTick -// -// We derive from two base classes that both define PlayTick(), so we need -// to be unambiguous about which one to use. -// -//========================================================================== - -int OPLMIDIDevice::PlayTick() -{ - return SoftSynthMIDIDevice::PlayTick(); -} - -//========================================================================== -// -// OPLMIDIDevice :: HandleEvent -// -// Processes a normal MIDI event. -// -//========================================================================== - -void OPLMIDIDevice::HandleEvent(int status, int parm1, int parm2) -{ - int command = status & 0xF0; - int channel = status & 0x0F; - - // Swap voices 9 and 15, because their roles are reversed - // in MUS and MIDI formats. - if (channel == 9) - { - channel = 15; - } - else if (channel == 15) - { - channel = 9; - } - - switch (command) - { - case MIDI_NOTEOFF: - playingcount--; - noteOff(channel, parm1); - break; - - case MIDI_NOTEON: - playingcount++; - noteOn(channel, parm1, parm2); - break; - - case MIDI_POLYPRESS: - //DEBUGOUT("Unhandled note aftertouch: Channel %d, note %d, value %d\n", channel, parm1, parm2); - break; - - case MIDI_CTRLCHANGE: - switch (parm1) - { - // some controllers here get passed on but are not handled by the player. - //case 0: changeBank(channel, parm2); break; - case 1: changeModulation(channel, parm2); break; - case 6: changeExtended(channel, ctrlDataEntryHi, parm2); break; - case 7: changeVolume(channel, parm2, false); break; - case 10: changePanning(channel, parm2); break; - case 11: changeVolume(channel, parm2, true); break; - case 38: changeExtended(channel, ctrlDataEntryLo, parm2); break; - case 64: changeSustain(channel, parm2); break; - //case 67: changeSoftPedal(channel, parm2); break; - //case 91: changeReverb(channel, parm2); break; - //case 93: changeChorus(channel, parm2); break; - case 98: changeExtended(channel, ctrlNRPNLo, parm2); break; - case 99: changeExtended(channel, ctrlNRPNHi, parm2); break; - case 100: changeExtended(channel, ctrlRPNLo, parm2); break; - case 101: changeExtended(channel, ctrlRPNHi, parm2); break; - case 120: allNotesOff(channel, parm2); break; - case 121: resetControllers(channel, 100); break; - case 123: notesOff(channel, parm2); break; - //case 126: changeMono(channel, parm2); break; - //case 127: changePoly(channel, parm2); break; - default: - //DEBUGOUT("Unhandled controller: Channel %d, controller %d, value %d\n", channel, parm1, parm2); - break; - } - break; - - case MIDI_PRGMCHANGE: - programChange(channel, parm1); - break; - - case MIDI_CHANPRESS: - //DEBUGOUT("Unhandled channel aftertouch: Channel %d, value %d\n", channel, parm1, 0); - break; - - case MIDI_PITCHBEND: - changePitch(channel, parm1, parm2); - break; - } -} - -//========================================================================== -// -// OPLMIDIDevice :: HandleLongEvent -// -//========================================================================== - -void OPLMIDIDevice::HandleLongEvent(const uint8_t *data, int len) -{ -} - -//========================================================================== -// -// OPLMIDIDevice :: ComputeOutput -// -// We override ServiceStream, so this function is never actually called. -// -//========================================================================== - -void OPLMIDIDevice::ComputeOutput(float *buffer, int len) -{ -} - -//========================================================================== -// -// OPLMIDIDevice :: ServiceStream -// -//========================================================================== - -bool OPLMIDIDevice::ServiceStream(void *buff, int numbytes) -{ - return OPLmusicBlock::ServiceStream(buff, numbytes); -} - -//========================================================================== -// -// OPLMIDIDevice :: GetStats -// -//========================================================================== - -std::string OPLMIDIDevice::GetStats() -{ - std::string out; - for (uint32_t i = 0; i < io->NumChannels; ++i) - { - char star = '*'; - if (voices[i].index == ~0u) - { - star = '/'; - } - else if (voices[i].sustained) - { - star = '-'; - } - else if (voices[i].current_instr_voice == &voices[i].current_instr->voices[1]) - { - star = '\\'; - } - else - { - star = '+'; - } - out += star; - } - return out; -} - - -MIDIDevice* CreateOplMIDIDevice(const char *Args) -{ - if (!oplConfig.genmidiset) throw std::runtime_error("Cannot play OPL without GENMIDI data"); - int core = oplConfig.core; - if (Args != NULL && *Args >= '0' && *Args < '4') core = *Args - '0'; - return new OPLMIDIDevice(core); -} diff --git a/libraries/zmusic/musicformats/music_midi.cpp b/libraries/zmusic/musicformats/music_midi.cpp index 9e080a5d0..ada4b9189 100644 --- a/libraries/zmusic/musicformats/music_midi.cpp +++ b/libraries/zmusic/musicformats/music_midi.cpp @@ -195,21 +195,6 @@ bool MIDIStreamer::IsValid() const EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device) { - /* MIDI are played as: - - OPL: - - if explicitly selected by $mididevice - - when snd_mididevice is -3 and no midi device is set for the song - - - Timidity: - - if explicitly selected by $mididevice - - when snd_mididevice is -2 and no midi device is set for the song - - - MMAPI (Win32 only): - - if explicitly selected by $mididevice (non-Win32 redirects this to Sound System) - - when snd_mididevice is >= 0 and no midi device is set for the song - - as fallback when both OPL and Timidity failed and snd_mididevice is >= 0 - */ - // Choose the type of MIDI device we want. if (device != MDEV_DEFAULT) { @@ -220,7 +205,6 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device) case -1: return MDEV_SNDSYS; case -4: case -2: return MDEV_TIMIDITY; - case -3: return MDEV_OPL; case -5: return MDEV_FLUIDSYNTH; default: #ifdef _WIN32 @@ -267,10 +251,6 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate) break; #endif // HAVE_FLUIDSYNTH - case MDEV_OPL: - dev = CreateOplMIDIDevice(Args.c_str()); - break; - case MDEV_TIMIDITY: dev = CreateTimidityPPMIDIDevice(Args.c_str(), samplerate); break; @@ -291,7 +271,6 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate) #ifdef _WIN32 else if (!checked[MDEV_MMAPI]) devtype = MDEV_MMAPI; #endif - else if (!checked[MDEV_OPL]) devtype = MDEV_OPL; if (devtype == MDEV_DEFAULT) { @@ -304,7 +283,7 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype, int samplerate) { static const char *devnames[] = { "Windows Default", - "OPL", + "", "", "Timidity++", "FluidSynth", diff --git a/libraries/zmusic/streamsources/music_opl.cpp b/libraries/zmusic/streamsources/music_opl.cpp deleted file mode 100644 index 856c16bf1..000000000 --- a/libraries/zmusic/streamsources/music_opl.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* -** music_opl.cpp -** Plays raw OPL formats -** -**--------------------------------------------------------------------------- -** Copyright 1998-2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -*/ - -#include "streamsource.h" -#include "oplsynth/opl.h" -#include "oplsynth/opl_mus_player.h" -#include "../../libraries/music_common/fileio.h" -#include "zmusic/midiconfig.h" - - -//========================================================================== -// -// OPL file played by a software OPL2 synth and streamed through the sound system -// -//========================================================================== - -class OPLMUSSong : public StreamSource -{ -public: - OPLMUSSong (MusicIO::FileInterface *reader, OPLConfig *config); - ~OPLMUSSong (); - bool Start() override; - void ChangeSettingInt(const char *name, int value) override; - SoundStreamInfo GetFormat() override; - -protected: - bool GetData(void *buffer, size_t len) override; - - OPLmusicFile *Music; - int current_opl_core; -}; - - -//========================================================================== -// -// -// -//========================================================================== - -OPLMUSSong::OPLMUSSong(MusicIO::FileInterface* reader, OPLConfig* config) -{ - const char* error = nullptr; - reader->seek(0, SEEK_END); - auto fs = reader->tell(); - reader->seek(0, SEEK_SET); - std::vector data(fs); - reader->read(data.data(), (int)data.size()); - Music = new OPLmusicFile(data.data(), data.size(), config->core, config->numchips, error); - if (error) - { - delete Music; - throw std::runtime_error(error); - } -} - -//========================================================================== -// -// -// -//========================================================================== - -SoundStreamInfo OPLMUSSong::GetFormat() -{ - int samples = int(OPL_SAMPLE_RATE / 14); - return { samples * 4, int(OPL_SAMPLE_RATE), current_opl_core == 0? 1:2 }; -} - -//========================================================================== -// -// -// -//========================================================================== - -OPLMUSSong::~OPLMUSSong () -{ - if (Music != NULL) - { - delete Music; - } -} - -//========================================================================== -// -// -// -//========================================================================== - -void OPLMUSSong::ChangeSettingInt(const char * name, int val) -{ - if (!strcmp(name, "opl.numchips")) - Music->ResetChips (val); -} - -//========================================================================== -// -// -// -//========================================================================== - -bool OPLMUSSong::Start() -{ - Music->SetLooping (m_Looping); - Music->Restart (); - return true; -} - -//========================================================================== -// -// -// -//========================================================================== - -bool OPLMUSSong::GetData(void *buffer, size_t len) -{ - return Music->ServiceStream(buffer, int(len)) ? len : 0; -} - -StreamSource *OPL_OpenSong(MusicIO::FileInterface* reader, OPLConfig *config) -{ - return new OPLMUSSong(reader, config); -} diff --git a/libraries/zmusic/zmusic/configuration.cpp b/libraries/zmusic/zmusic/configuration.cpp index 76f30d8fa..5f456d4cc 100644 --- a/libraries/zmusic/zmusic/configuration.cpp +++ b/libraries/zmusic/zmusic/configuration.cpp @@ -33,7 +33,6 @@ */ #include #include "timiditypp/timidity.h" -#include "oplsynth/oplio.h" #include "../../libraries/dumb/include/dumb.h" #include "zmusic.h" @@ -61,8 +60,6 @@ void ZMusic_SetCallbacks(const Callbacks* cb) void ZMusic_SetGenMidi(const uint8_t* data) { - memcpy(oplConfig.OPLinstruments, data, 175 * 36); - oplConfig.genmidiset = true; } template @@ -224,28 +221,6 @@ bool ChangeMusicSetting(ZMusic::EIntConfigKey key, MusInfo *currSong, int value, ChangeAndReturn(fluidConfig.fluid_chorus_type, value, pRealValue); return false; - case opl_numchips: - if (value <= 0) - value = 1; - else if (value > MAXOPL2CHIPS) - value = MAXOPL2CHIPS; - - if (currSong != NULL) - currSong->ChangeSettingInt("opl.numchips", value); - - ChangeAndReturn(oplConfig.numchips, value, pRealValue); - return false; - - case opl_core: - if (value < 0) value = 0; - else if (value > 3) value = 3; - ChangeAndReturn(oplConfig.core, value, pRealValue); - return devType() == MDEV_OPL; - - case opl_fullpan: - ChangeAndReturn(oplConfig.fullpan, value, pRealValue); - return false; - case timidity_modulation_wheel: ChangeVarSync(TimidityPlus::timidity_modulation_wheel, value); if (pRealValue) *pRealValue = value; diff --git a/libraries/zmusic/zmusic/zmusic.cpp b/libraries/zmusic/zmusic/zmusic.cpp index 7d6b18f8a..c042a294a 100644 --- a/libraries/zmusic/zmusic/zmusic.cpp +++ b/libraries/zmusic/zmusic/zmusic.cpp @@ -56,7 +56,6 @@ #define GZIP_FCOMMENT 16 class MIDIDevice; -class OPLmusicFile; class StreamSource; class MusInfo; @@ -230,14 +229,7 @@ MusInfo *ZMusic_OpenSong (MusicIO::FileInterface *reader, EMidiDevice device, co // Check for various raw OPL formats else { - if ( - (id[0] == MAKE_ID('R', 'A', 'W', 'A') && id[1] == MAKE_ID('D', 'A', 'T', 'A')) || // Rdos Raw OPL - (id[0] == MAKE_ID('D', 'B', 'R', 'A') && id[1] == MAKE_ID('W', 'O', 'P', 'L')) || // DosBox Raw OPL - (id[0] == MAKE_ID('A', 'D', 'L', 'I') && *((uint8_t*)id + 4) == 'B')) // Martin Fernandez's modified IMF - { - streamsource = OPL_OpenSong(reader, &oplConfig); - } - else if ((id[0] == MAKE_ID('R', 'I', 'F', 'F') && id[2] == MAKE_ID('C', 'D', 'X', 'A'))) + if ((id[0] == MAKE_ID('R', 'I', 'F', 'F') && id[2] == MAKE_ID('C', 'D', 'X', 'A'))) { streamsource = XA_OpenSong(reader); // this takes over the reader. reader = nullptr; // We do not own this anymore. diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index ac691ec95..6c9c19762 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -961,7 +961,6 @@ endif() if( CMAKE_COMPILER_IS_GNUCXX ) # GCC misoptimizes this file - #set_source_files_properties( oplsynth/fmopl.cpp PROPERTIES COMPILE_FLAGS "-fno-tree-dominator-opts -fno-tree-fre" ) endif() if( APPLE ) diff --git a/source/common/music/i_music.cpp b/source/common/music/i_music.cpp index 638b3a99c..eeead2fc9 100644 --- a/source/common/music/i_music.cpp +++ b/source/common/music/i_music.cpp @@ -215,29 +215,6 @@ static MusicIO::SoundFontReaderInterface* mus_openSoundFont(const char* sfname, } -//========================================================================== -// -// Pass some basic working data to the music backend -// We do this once at startup for everything available. -// -//========================================================================== - -static void SetupGenMidi() -{ - // The OPL renderer should not care about where this comes from. - // Note: No I_Error here - this needs to be consistent with the rest of the music code. - auto lump = fileSystem.FindFile("engine/genmidi.op2"); - if (lump < 0) - { - Printf("No GENMIDI lump found. OPL playback not available."); - return; - } - auto data = fileSystem.OpenFileReader(lump); - - auto genmidi = data.Read(); - if (genmidi.Size() < 8 + 175 * 36 || memcmp(genmidi.Data(), "#OPL_II#", 8)) return; - ZMusic_SetGenMidi(genmidi.Data()+8); -} //========================================================================== // @@ -268,7 +245,6 @@ void Mus_Init(void) //callbacks.DumbVorbisDecode = dumb_decode_vorbis_; ZMusic_SetCallbacks(&callbacks); - SetupGenMidi(); timerSetCallback(S_UpdateMusic); } diff --git a/wadsrc/static/engine/GENMIDI.op2 b/wadsrc/static/engine/GENMIDI.op2 deleted file mode 100644 index 5c86b7787..000000000 Binary files a/wadsrc/static/engine/GENMIDI.op2 and /dev/null differ