diff --git a/src/EngineMkI.cpp b/src/EngineMkI.cpp index df66a47..6f8f200 100644 --- a/src/EngineMkI.cpp +++ b/src/EngineMkI.cpp @@ -35,12 +35,14 @@ #endif #ifdef _WIN32 +#if _MSC_VER < 1800 double log2(double n) { return log(n) / log(2.0); } double round(double n) { return n < 0.0 ? ceil(n - 0.5) : floor(n + 0.5); } +#endif __declspec(align(16)) const int zeros[N] = {0}; #else const int32_t __attribute__ ((aligned(16))) zeros[N] = {0}; @@ -76,7 +78,6 @@ static inline uint16_t sinLog(uint16_t phi) { } EngineMkI::EngineMkI() { - TRACE("Hi"); float bitReso = SINLOG_TABLESIZE; for(int i=0;i> (22 - SINLOG_BITDEPTH)) + (env); -#ifdef MKIDEBUG - int16_t expValShow = expVal; -#endif - + //int16_t expValShow = expVal; + const bool isSigned = expVal & NEGATIVE_BIT; expVal &= ~NEGATIVE_BIT; @@ -295,7 +292,7 @@ void EngineMkI::compute_fb3(int32_t *output, FmOpParams *parms, int32_t gain01, fb_buf[1] = y; } -void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int feedback_shift) { +void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int32_t feedback_shift) { const int kLevelThresh = ENV_MAX-100; FmAlgorithm alg = algorithms[algorithm]; bool has_contents[3] = { true, false, false }; @@ -330,14 +327,14 @@ void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm, int32 switch ( algorithm ) { // three operator feedback, process exception for ALGO 4 case 3 : - compute_fb3(outptr, params, gain1, gain2, fb_buf, min((feedback_shift+2),16)); + compute_fb3(outptr, params, gain1, gain2, fb_buf, min((feedback_shift+2), 16)); params[1].phase += params[1].freq << LG_N; // hack, we already processed op-5 - op-4 params[2].phase += params[2].freq << LG_N; // yuk yuk op += 2; // ignore the 2 other operators break; // two operator feedback, process exception for ALGO 6 case 5 : - compute_fb2(outptr, params, gain1, gain2, fb_buf, min((feedback_shift+2),16)); + compute_fb2(outptr, params, gain1, gain2, fb_buf, min((feedback_shift+2), 16)); params[1].phase += params[1].freq << LG_N; // yuk, hack, we already processed op-5 op++; // ignore next operator; break; diff --git a/src/EngineMkI.h b/src/EngineMkI.h index 18cd715..ed9c7f5 100644 --- a/src/EngineMkI.h +++ b/src/EngineMkI.h @@ -29,7 +29,7 @@ class EngineMkI : public FmCore { public: EngineMkI(); - void render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int feedback_shift) override; + void render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int32_t feedback_shift) override; void compute(int32_t *output, const int32_t *input, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, bool add); diff --git a/src/EngineOpl.cpp b/src/EngineOpl.cpp index 073881e..5c39167 100644 --- a/src/EngineOpl.cpp +++ b/src/EngineOpl.cpp @@ -169,7 +169,7 @@ void EngineOpl::compute_fb(int32_t *output, int32_t phase0, int32_t freq, void EngineOpl::render(int32_t *output, FmOpParams *params, int algorithm, - int32_t *fb_buf, int feedback_shift) { + int32_t *fb_buf, int32_t feedback_shift) { const int kLevelThresh = 507; // really ???? const FmAlgorithm alg = algorithms[algorithm]; bool has_contents[3] = { true, false, false }; diff --git a/src/msfa/.gitignore b/src/msfa/.gitignore deleted file mode 100644 index a62c258..0000000 --- a/src/msfa/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.o -*.gch diff --git a/src/msfa/aligned_buf.h b/src/msfa/aligned_buf.h old mode 100755 new mode 100644 diff --git a/src/msfa/controllers.h b/src/msfa/controllers.h old mode 100755 new mode 100644 diff --git a/src/msfa/dx7note.cc b/src/msfa/dx7note.cc index 8c689ca..ce34341 100644 --- a/src/msfa/dx7note.cc +++ b/src/msfa/dx7note.cc @@ -44,14 +44,20 @@ int32_t osc_freq(int midinote, int mode, int coarse, int fine, int detune) { int32_t logfreq; if (mode == 0) { logfreq = midinote_to_logfreq(midinote); + + // could use more precision, closer enough for now. those numbers comes from my DX7 + double detuneRatio = 0.0209 * exp(-0.396 * (((float)logfreq)/(1<<24))) / 7; + logfreq += detuneRatio * logfreq * (detune - 7); + logfreq += coarsemul[coarse & 31]; if (fine) { // (1 << 24) / log(2) logfreq += (int32_t)floor(24204406.323123 * log(1 + 0.01 * fine) + 0.5); } - // This was measured at 7.213Hz per count at 9600Hz, but the exact - // value is somewhat dependent on midinote. Close enough for now. - logfreq += 12606 * (detune - 7); + + // // This was measured at 7.213Hz per count at 9600Hz, but the exact + // // value is somewhat dependent on midinote. Close enough for now. + // //logfreq += 12606 * (detune -7); } else { // ((1 << 24) * log(10) / log(2) * .01) << 3 logfreq = (4458616 * ((coarse & 3) * 100 + fine)) >> 3; @@ -138,7 +144,7 @@ Dx7Note::Dx7Note() { } } -void Dx7Note::init(const uint8_t patch[167], int midinote, int velocity) { +void Dx7Note::init(const uint8_t patch[156], int midinote, int velocity) { int rates[4]; int levels[4]; for (int op = 0; op < 6; op++) { @@ -164,6 +170,7 @@ void Dx7Note::init(const uint8_t patch[167], int midinote, int velocity) { int fine = patch[off + 19]; int detune = patch[off + 20]; int32_t freq = osc_freq(midinote, mode, coarse, fine, detune); + opMode[op] = mode; basepitch_[op] = freq; ampmodsens_[op] = ampmodsenstab[patch[off + 14] & 3]; } @@ -186,30 +193,31 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Co int32_t senslfo = pitchmodsens_ * (lfo_val - (1 << 23)); int32_t pmod_1 = (((int64_t) pmd) * (int64_t) senslfo) >> 39; pmod_1 = abs(pmod_1); - int32_t pmod_2 = ((int64_t)ctrls->pitch_mod * (int64_t)senslfo) >> 14; + int32_t pmod_2 = (int32_t)(((int64_t)ctrls->pitch_mod * (int64_t)senslfo) >> 14); pmod_2 = abs(pmod_2); int32_t pitch_mod = max(pmod_1, pmod_2); pitch_mod = pitchenv_.getsample() + (pitch_mod * (senslfo < 0 ? -1 : 1)); - + // ---- PITCH BEND ---- int pitchbend = ctrls->values_[kControllerPitch]; int32_t pb = (pitchbend - 0x2000); if (pb != 0) { if (ctrls->values_[kControllerPitchStep] == 0) { - pb = ((float) (pb << 11)) * ((float)ctrls->values_[kControllerPitchRange]) / 12.0; + pb = ((float) (pb << 11)) * ((float) ctrls->values_[kControllerPitchRange]) / 12.0; } else { int stp = 12 / ctrls->values_[kControllerPitchStep]; pb = pb * stp / 8191; pb = (pb * (8191 / stp)) << 11; } } - pitch_mod += pb; - pitch_mod += ctrls->masterTune; - + int32_t pitch_base = pb + ctrls->masterTune; + pitch_mod += pitch_base; + // ==== AMP MOD ==== - uint32_t amod_1 = ((int64_t) ampmoddepth_ * (int64_t) lfo_delay) >> 8; // Q24 :D - amod_1 = ((int64_t) amod_1 * (int64_t) lfo_val) >> 24; - uint32_t amod_2 = ((int64_t) ctrls->amp_mod * (int64_t) lfo_val) >> 7; // Q?? :| + lfo_val = (1<<24) - lfo_val; + uint32_t amod_1 = (uint32_t)(((int64_t) ampmoddepth_ * (int64_t) lfo_delay) >> 8); // Q24 :D + amod_1 = (uint32_t)(((int64_t) amod_1 * (int64_t) lfo_val) >> 24); + uint32_t amod_2 = (uint32_t)(((int64_t) ctrls->amp_mod * (int64_t) lfo_val) >> 7); // Q?? :| uint32_t amd_mod = max(amod_1, amod_2); // ==== EG AMP MOD ==== @@ -218,21 +226,25 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Co // ==== OP RENDER ==== for (int op = 0; op < 6; op++) { - //if ( ctrls->opSwitch[op] == '0' ) { - if (!(ctrls->opSwitch & (1<opSwitch[op] == '0' ) { + if (!(ctrls->opSwitch & (1<> 24; + uint32_t sensamp = (uint32_t)(((uint64_t) amd_mod) * ((uint64_t) ampmodsens_[op]) >> 24); // TODO: mehhh.. this needs some real tuning. uint32_t pt = exp(((float)sensamp)/262144 * 0.07 + 12.2); - uint32_t ldiff = ((uint64_t)level) * (((uint64_t)pt<<4)) >> 28; + uint32_t ldiff = (uint32_t)(((uint64_t)level) * (((uint64_t)pt<<4)) >> 28); level -= ldiff; } params_[op].level_in = level; @@ -259,10 +271,11 @@ void Dx7Note::update(const uint8_t patch[156], int midinote, int velocity) { int detune = patch[off + 20]; basepitch_[op] = osc_freq(midinote, mode, coarse, fine, detune); ampmodsens_[op] = ampmodsenstab[patch[off + 14] & 3]; + opMode[op] = mode; for (int i = 0; i < 4; i++) { rates[i] = patch[off + i]; - levels[i] = patch[off + 4 + i]; + levels[i] = patch[off + 4 + i]; } int outlevel = patch[off + 16]; outlevel = Env::scaleoutlevel(outlevel); @@ -316,4 +329,3 @@ void Dx7Note::oscSync() { params_[i].phase = 0; } } - diff --git a/src/msfa/dx7note.h b/src/msfa/dx7note.h index 3636797..da0120e 100644 --- a/src/msfa/dx7note.h +++ b/src/msfa/dx7note.h @@ -37,8 +37,7 @@ struct VoiceStatus { class Dx7Note { public: Dx7Note(); - //void init(const uint8_t patch[156], int midinote, int velocity, int fb_depth); - void init(const uint8_t patch[160], int midinote, int velocity); + void init(const uint8_t patch[156], int midinote, int velocity); // Note: this _adds_ to the buffer. Interesting question whether it's // worth it... @@ -67,6 +66,7 @@ private: int32_t fb_buf_[2]; int32_t fb_shift_; int32_t ampmodsens_[6]; + int32_t opMode[6]; int ampmoddepth_; int algorithm_; diff --git a/src/msfa/env.cc b/src/msfa/env.cc index b6b98de..58478a3 100644 --- a/src/msfa/env.cc +++ b/src/msfa/env.cc @@ -1,13 +1,13 @@ /* * Copyright 2017 Pascal Gauthier. * Copyright 2012 Google Inc. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,96 +28,140 @@ const int levellut[] = { 0, 5, 9, 13, 17, 20, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 42, 43, 45, 46 }; +#ifdef ACCURATE_ENVELOPE +const int statics[] = { + 1764000, 1764000, 1411200, 1411200, 1190700, 1014300, 992250, + 882000, 705600, 705600, 584325, 507150, 502740, 441000, 418950, + 352800, 308700, 286650, 253575, 220500, 220500, 176400, 145530, + 145530, 125685, 110250, 110250, 88200, 88200, 74970, 61740, + 61740, 55125, 48510, 44100, 37485, 31311, 30870, 27562, 27562, + 22050, 18522, 17640, 15435, 14112, 13230, 11025, 9261, 9261, 7717, + 6615, 6615, 5512, 5512, 4410, 3969, 3969, 3439, 2866, 2690, 2249, + 1984, 1896, 1808, 1411, 1367, 1234, 1146, 926, 837, 837, 705, + 573, 573, 529, 441, 441 + // and so on, I stopped measuring after R=76 (needs to be double-checked anyway) +}; +#endif + void Env::init_sr(double sampleRate) { sr_multiplier = (44100.0 / sampleRate) * (1<<24); } -void Env::init(const int r[4], const int l[4], int32_t ol, int rate_scaling) { - for (int i = 0; i < 4; i++) { - rates_[i] = r[i]; - levels_[i] = l[i]; - } - outlevel_ = ol; - rate_scaling_ = rate_scaling; - level_ = 0; - down_ = true; - advance(0); +void Env::init(const int r[4], const int l[4], int ol, int rate_scaling) { + for (int i = 0; i < 4; i++) { + rates_[i] = r[i]; + levels_[i] = l[i]; + } + outlevel_ = ol; + rate_scaling_ = rate_scaling; + level_ = 0; + down_ = true; + advance(0); } int32_t Env::getsample() { - if (ix_ < 3 || ((ix_ < 4) && !down_)) { - if (rising_) { - const int jumptarget = 1716; - if (level_ < (jumptarget << 16)) { - level_ = jumptarget << 16; - } - level_ += (((17 << 24) - level_) >> 24) * inc_; - // TODO: should probably be more accurate when inc is large - if (level_ >= targetlevel_) { - level_ = targetlevel_; - advance(ix_ + 1); - } - } else { // !rising - level_ -= inc_; - if (level_ <= targetlevel_) { - level_ = targetlevel_; - advance(ix_ + 1); - } +#ifdef ACCURATE_ENVELOPE + if (staticcount_) { + staticcount_ -= N; + if (staticcount_ <= 0) { + staticcount_ = 0; + advance(ix_ + 1); + } } - } - // TODO: this would be a good place to set level to 0 when under threshold - return level_; +#endif + + if (ix_ < 3 || ((ix_ < 4) && !down_)) { + if (rising_) { + const int jumptarget = 1716; + if (level_ < (jumptarget << 16)) { + level_ = jumptarget << 16; + } + level_ += (((17 << 24) - level_) >> 24) * inc_; + // TODO: should probably be more accurate when inc is large + if (level_ >= targetlevel_) { + level_ = targetlevel_; + advance(ix_ + 1); + } + } + else if (staticcount_) { + ; + } + else { // !rising + level_ -= inc_; + if (level_ <= targetlevel_) { + level_ = targetlevel_; + advance(ix_ + 1); + } + } + } + // TODO: this would be a good place to set level to 0 when under threshold + return level_; } void Env::keydown(bool d) { - if (down_ != d) { - down_ = d; - advance(d ? 0 : 3); - } + if (down_ != d) { + down_ = d; + advance(d ? 0 : 3); + } } int Env::scaleoutlevel(int outlevel) { - return outlevel >= 20 ? 28 + outlevel : levellut[outlevel]; + return outlevel >= 20 ? 28 + outlevel : levellut[outlevel]; } void Env::advance(int newix) { - ix_ = newix; - if (ix_ < 4) { - int newlevel = levels_[ix_]; - int actuallevel = scaleoutlevel(newlevel) >> 1; - actuallevel = (actuallevel << 6) + outlevel_ - 4256; - actuallevel = actuallevel < 16 ? 16 : actuallevel; - // level here is same as Java impl - targetlevel_ = actuallevel << 16; - rising_ = (targetlevel_ > level_); - - // rate - int qrate = (rates_[ix_] * 41) >> 6; - qrate += rate_scaling_; - qrate = min(qrate, 63); - inc_ = (4 + (qrate & 3)) << (2 + LG_N + (qrate >> 2)); - - // meh, this should be fixed elsewhere - inc_ = ((int64_t)inc_ * (int64_t)sr_multiplier) >> 24; - } + ix_ = newix; + if (ix_ < 4) { + int newlevel = levels_[ix_]; + int actuallevel = scaleoutlevel(newlevel) >> 1; + actuallevel = (actuallevel << 6) + outlevel_ - 4256; + actuallevel = actuallevel < 16 ? 16 : actuallevel; + // level here is same as Java impl + targetlevel_ = actuallevel << 16; + rising_ = (targetlevel_ > level_); + + // rate + int qrate = (rates_[ix_] * 41) >> 6; + qrate += rate_scaling_; + qrate = min(qrate, 63); + +#ifdef ACCURATE_ENVELOPE + if (targetlevel_ == level_) { + // approximate number of samples at 44.100 kHz to achieve the time + // empirically gathered using 2 TF1s, could probably use some double-checking + // and cleanup, but it's pretty close for now. + int staticrate = rates_[ix_]; + staticrate += rate_scaling_; // needs to be checked, as well, but seems correct + staticrate = min(staticrate, 99); + staticcount_ = staticrate < 77 ? statics[staticrate] : 20 * (99 - staticrate); + staticcount_ = (int)(((int64_t)staticcount_ * (int64_t)sr_multiplier) >> 24); + } + else { + staticcount_ = 0; + } +#endif + inc_ = (4 + (qrate & 3)) << (2 + LG_N + (qrate >> 2)); + // meh, this should be fixed elsewhere + inc_ = (int)(((int64_t)inc_ * (int64_t)sr_multiplier) >> 24); + } } -void Env::update(const int r[4], const int l[4], int32_t ol, int rate_scaling) { - for (int i = 0; i < 4; i++) { - rates_[i] = r[i]; - levels_[i] = l[i]; - } - outlevel_ = ol; - rate_scaling_ = rate_scaling; - if ( down_ ) { - // for now we simply reset ourselve at level 3 - int newlevel = levels_[2]; - int actuallevel = scaleoutlevel(newlevel) >> 1; - actuallevel = (actuallevel << 6) - 4256; - actuallevel = actuallevel < 16 ? 16 : actuallevel; - targetlevel_ = actuallevel << 16; - advance(2); - } +void Env::update(const int r[4], const int l[4], int ol, int rate_scaling) { + for (int i = 0; i < 4; i++) { + rates_[i] = r[i]; + levels_[i] = l[i]; + } + outlevel_ = ol; + rate_scaling_ = rate_scaling; + if ( down_ ) { + // for now we simply reset ourselve at level 3 + int newlevel = levels_[2]; + int actuallevel = scaleoutlevel(newlevel) >> 1; + actuallevel = (actuallevel << 6) - 4256; + actuallevel = actuallevel < 16 ? 16 : actuallevel; + targetlevel_ = actuallevel << 16; + advance(2); + } } void Env::getPosition(char *step) { @@ -135,7 +179,10 @@ void Env::transfer(Env &src) { targetlevel_ = src.targetlevel_; rising_= src.rising_; ix_ = src.ix_; - inc_ = src.inc_; down_ = src.down_; +#ifdef ACCURATE_ENVELOPE + staticcount_ = src.staticcount_; +#endif + inc_ = src.inc_; } diff --git a/src/msfa/env.h b/src/msfa/env.h old mode 100755 new mode 100644 index cb5daa6..9aaf7ec --- a/src/msfa/env.h +++ b/src/msfa/env.h @@ -1,4 +1,5 @@ /* + * Copyright 2017 Pascal Gauthier. * Copyright 2012 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +22,8 @@ // DX7 envelope generation +#define ACCURATE_ENVELOPE + class Env { public: @@ -33,7 +36,6 @@ class Env { void update(const int rates[4], const int levels[4], int outlevel, int rate_scaling); - // Result is in Q24/doubling log format. Also, result is subsampled // for every N samples. // A couple more things need to happen for this to be used as a gain @@ -50,10 +52,11 @@ class Env { void transfer(Env &src); private: + // PG: This code is normalized to 44100, need to put a multiplier // if we are not using 44100. static uint32_t sr_multiplier; - + int rates_[4]; int levels_[4]; int outlevel_; @@ -66,6 +69,9 @@ class Env { bool rising_; int ix_; int inc_; +#ifdef ACCURATE_ENVELOPE + int staticcount_; +#endif bool down_; diff --git a/src/msfa/exp2.cc b/src/msfa/exp2.cc old mode 100755 new mode 100644 diff --git a/src/msfa/exp2.h b/src/msfa/exp2.h old mode 100755 new mode 100644 diff --git a/src/msfa/fm_core.cc b/src/msfa/fm_core.cc index c2fb911..102e52d 100644 --- a/src/msfa/fm_core.cc +++ b/src/msfa/fm_core.cc @@ -23,6 +23,7 @@ #include "fm_op_kernel.h" #include "fm_core.h" + //using namespace std; const FmAlgorithm FmCore::algorithms[32] = { diff --git a/src/msfa/freqlut.cc b/src/msfa/freqlut.cc old mode 100755 new mode 100644 diff --git a/src/msfa/freqlut.h b/src/msfa/freqlut.h old mode 100755 new mode 100644 diff --git a/src/msfa/lfo.cc b/src/msfa/lfo.cc index e3ffddd..bdff062 100644 --- a/src/msfa/lfo.cc +++ b/src/msfa/lfo.cc @@ -95,4 +95,3 @@ void Lfo::keydown() { } delaystate_ = 0; } - diff --git a/src/msfa/module.h b/src/msfa/module.h old mode 100755 new mode 100644 diff --git a/src/msfa/pitchenv.h b/src/msfa/pitchenv.h old mode 100755 new mode 100644 diff --git a/src/msfa/synth.h b/src/msfa/synth.h index fe0e349..eb896da 100644 --- a/src/msfa/synth.h +++ b/src/msfa/synth.h @@ -57,7 +57,6 @@ inline static T max(const T& a, const T& b) { return a > b ? a : b; } - #define QER(n,b) ( ((float)n)/(1<