From c395d44728c0397ccd28dc169f1810f14b577daf Mon Sep 17 00:00:00 2001 From: bruce Date: Sun, 20 Oct 2013 00:28:53 +0800 Subject: [PATCH] Start porting DBOPL to Javascript --- js/dbopl.js | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) create mode 100644 js/dbopl.js diff --git a/js/dbopl.js b/js/dbopl.js new file mode 100644 index 0000000..a6ff076 --- /dev/null +++ b/js/dbopl.js @@ -0,0 +1,177 @@ +var DBOPL = new function() { // DBOPL namespace + +// dbopl.h + +this.WAVE_HANDLER = 10; +this.WAVE_TABLELOG = 11; +this.WAVE_TABLEMUL = 12; +this.DBOPL_WAVE = this.WAVE_TABLEMUL; + +this.SynthMode = { + sm2AM:0, + sm2FM:1, + sm3AM:2, + sm3FM:3, + sm4Start:4, + sm3FMFM:5, + sm3AMFM:6, + sm3FMAM:7, + sm3AMAM:8, + sm6Start:9, + sm2Percussion:10, + sm3Percussion:11, +}; + +this.SHIFT_KSLBASE = 16; +this.SHIFT_KEYCODE = 24; + +this.Operator = function() { + // public: + + // enum + this.MASK_KSR = 0x10; + this.MASK_SUSTAIN = 0x20; + this.MASK_VIBRATO = 0x40; + this.MASK_TREMOLO = 0x80; + this.State = { // typedef enum + OFF:0, + RELEASE:1, + SUSTAIN:2, + DECAY:3, + ATTACK:4, + }; + this.volHandler=0; + this.waveBase=0; + this.waveMask=0; + this.waveStart=0; + + this.waveIndex=0; //WAVE_BITS shifted counter of the frequency index + this.waveAdd=0; //The base frequency without vibrato + this.waveCurrent=0; //waveAdd + vibratao + + this.chanData=0; //Frequency/octave and derived data coming from whatever channel controls this + this.freqMul=0; //Scale channel frequency with this, TODO maybe remove? + this.vibrato=0; //Scaled up vibrato strength + this.sustainLevel=0; //When stopping at sustain level stop here + this.totalLevel=0; //totalLevel is added to every generated volume + this.currentLevel=0; //totalLevel + tremolo + this.volume=0; //The currently active volume + + this.attackAdd=0; //Timers for the different states of the envelope + this.decayAdd=0; + this.releaseAdd=0; + this.rateIndex=0; //Current position of the evenlope + + this.rateZero=0; //Bits for the different states of the envelope having no changes + this.keyOn=0; //Bitmask of different values that can generate keyon + //Registers, also used to check for changes + this.reg20=0; + this.reg40=0; + this.reg60=0; + this.reg80=0; + this.regE0=0; + //Active part of the envelope we're in + this.state=0; + //0xff when tremolo is enabled + this.tremoloMask=0; + //Strength of the vibrato + this.vibStrength=0; + //Keep track of the calculated KSR so we can check for changes + this.ksr=0; + + return this; +}; + +// dbopl.cpp (private stuff) +var ZeroArray = function(size) { + // http://stackoverflow.com/questions/1295584/most-efficient-way-to-create-a-zero-filled-javascript-array + return Array.apply(null, new Array(size)).map(Number.prototype.valueOf,0); +}; + +var PI = 3.14159265358979323846; +var OPLRATE = 14318180.0 / 288.0; +var TREMOLO_TABLE = 52; +var WAVE_BITS = 10; +var WAVE_SH = 32 - WAVE_BITS; +var WAVE_MASK = (1 << WAVE_SH) - 1; +var LFO_SH = WAVE_SH - 10; +var LFO_MAX = 256 << LFO_SH; +var ENV_BITS = 9; +var ENV_MIN = 0; +var ENV_EXTRA = ENV_BITS - 9; +var ENV_MAX = 511 << ENV_EXTRA; +var ENV_LIMIT = (12 * 256) >> (3 - ENV_EXTRA); +var ENV_SILENT = function(_X_) { return _X_ >= ENV_LIMIT; } +var RATE_SH = 24; +var RATE_MASK = (1 << RATE_SH ) - 1; +var MUL_SH = 16; + +var KslCreateTable = [ + 64, 32, 24, 19, + 16, 12, 11, 10, + 8, 6, 5, 4, + 3, 2, 1, 0, +]; +var M = function(_X_) {return _X_ * 2}; +var FreqCreateTable = [ + M(0.5), M(1), M(2), M(3), M(4), M(5), M(6), M(7), + M(8), M(9), M(10), M(10), M(12), M(12), M(15), M(15), +]; + +var AttackSamplesTable = [ + 69, 55, 46, 40, + 35, 29, 23, 20, + 19, 15, 11, 10, + 9 +]; +var EnvelopeIncreaseTable = [ + 4, 5, 6, 7, + 8, 10, 12, 14, + 16, 20, 24, 28, + 32, +]; + +var WaveTable = ZeroArray(8 * 512); + +var WaveBaseTable = [ + 0x000, 0x200, 0x200, 0x800, + 0xa00, 0xc00, 0x100, 0x400, +]; + +var WaveMaskTable = [ + 1023, 1023, 511, 511, + 1023, 1023, 512, 1023, +]; + +var WaveStartTable = [ + 512, 0, 0, 0, + 0, 512, 512, 256, +]; + +var MulTable = ZeroArray(384); +var KslTable = ZeroArray(8 * 16); +var TremoloTable = ZeroArray(TREMOLO_TABLE); +var ChanOffsetTable = ZeroArray(32); +var OpOffsetTable = ZeroArray(64); +var VibratoTable = [ + 1 - 0x00, 0 - 0x00, 1 - 0x00, 30 - 0x00, + 1 - 0x80, 0 - 0x80, 1 - 0x80, 30 - 0x80 +]; + +// Note: the original used reference parameters to return index and shift.. +function EnvelopeSelect(val) { + var shift, index; + if ( val < 13 * 4 ) { //Rate 0 - 12 + shift = 12 - ( val >> 2 ); + index = val & 3; + } else if ( val < 15 * 4 ) { //rate 13 - 14 + shift = 0; + index = val - 12 * 4; + } else { //rate 15 and up + shift = 0; + index = 12; + } + return [index, shift]; +} + +}; // end of DBOPL namespace