/* 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. See the License for the specific language governing permissions and limitations under the License. */ //using namespace std; #include #include "synth.h" #include "env.h" uint32_t Env::sr_multiplier = (1 << 24); 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], 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() { #ifdef ACCURATE_ENVELOPE if (staticcount_) { staticcount_ -= _N_; if (staticcount_ <= 0) { staticcount_ = 0; advance(ix_ + 1); } } #endif if (ix_ < 3 || ((ix_ < 4) && !down_)) { if (staticcount_) { ; } else 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); } } } // 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); } } int Env::scaleoutlevel(int 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); #ifdef ACCURATE_ENVELOPE if (targetlevel_ == level_ || (ix_ == 0 && newlevel == 0)) { // 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); if (staticrate < 77 && (ix_ == 0 && newlevel == 0)) { staticcount_ /= 20; // attack is scaled faster } 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], 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 ourselves 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) { *step = ix_; } void Env::transfer(Env &src) { for (int i = 0; i < 4; i++) { rates_[i] = src.rates_[i]; levels_[i] = src.levels_[i]; } outlevel_ = src.outlevel_; rate_scaling_ = src.rate_scaling_; level_ = src.level_; targetlevel_ = src.targetlevel_; rising_ = src.rising_; ix_ = src.ix_; down_ = src.down_; #ifdef ACCURATE_ENVELOPE staticcount_ = src.staticcount_; #endif inc_ = src.inc_; }