Replacing env.cpp and env.h with the newest msfa version with some fixespull/37/head
parent
b5f75705bf
commit
48710fa0a3
@ -1,188 +0,0 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
#include <math.h> |
||||
|
||||
#include "synth.h" |
||||
#include "env.h" |
||||
|
||||
//using namespace std;
|
||||
|
||||
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 FRAC_NUM-checked anyway)
|
||||
}; |
||||
#endif |
||||
|
||||
void Env::init_sr(FRAC_NUM 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 (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); |
||||
} |
||||
} |
||||
|
||||
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_) { |
||||
// approximate number of samples at 44.100 kHz to achieve the time
|
||||
// empirically gathered using 2 TF1s, could probably use some FRAC_NUM-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], 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) { |
||||
*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_; |
||||
} |
||||
|
@ -1,283 +0,0 @@ |
||||
/*
|
||||
* 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. |
||||
*/ |
||||
|
||||
#include <math.h> |
||||
|
||||
#include <cstdlib> |
||||
|
||||
#ifdef HAVE_NEON |
||||
#include <cpu-features.h> |
||||
#endif |
||||
|
||||
#include "synth.h" |
||||
#include "sin.h" |
||||
#include "fm_op_kernel.h" |
||||
|
||||
#ifdef HAVE_NEONx |
||||
static bool hasNeon() { |
||||
return true; |
||||
return (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0; |
||||
} |
||||
|
||||
extern "C" |
||||
void neon_fm_kernel(const int *in, const int *busin, int *out, int count, |
||||
int32_t phase0, int32_t freq, int32_t gain1, int32_t dgain); |
||||
|
||||
const int32_t __attribute__ ((aligned(16))) zeros[N] = {0}; |
||||
|
||||
#else |
||||
static bool hasNeon() { |
||||
return false; |
||||
} |
||||
#endif |
||||
|
||||
void FmOpKernel::compute(int32_t *output, const int32_t *input, |
||||
int32_t phase0, int32_t freq, |
||||
int32_t gain1, int32_t gain2, bool add) { |
||||
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
||||
int32_t gain = gain1; |
||||
int32_t phase = phase0; |
||||
if (hasNeon()) { |
||||
#ifdef HAVE_NEON |
||||
neon_fm_kernel(input, add ? output : zeros, output, _N_, |
||||
phase0, freq, gain, dgain); |
||||
#endif |
||||
} else { |
||||
if (add) { |
||||
for (int i = 0; i < _N_; i++) { |
||||
gain += dgain; |
||||
int32_t y = Sin::lookup(phase + input[i]); |
||||
int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24; |
||||
output[i] += y1; |
||||
phase += freq; |
||||
} |
||||
} else { |
||||
for (int i = 0; i < _N_; i++) { |
||||
gain += dgain; |
||||
int32_t y = Sin::lookup(phase + input[i]); |
||||
int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24; |
||||
output[i] = y1; |
||||
phase += freq; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
||||
int32_t gain1, int32_t gain2, bool add) { |
||||
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
||||
int32_t gain = gain1; |
||||
int32_t phase = phase0; |
||||
if (hasNeon()) { |
||||
#ifdef HAVE_NEON |
||||
neon_fm_kernel(zeros, add ? output : zeros, output, _N_, |
||||
phase0, freq, gain, dgain); |
||||
#endif |
||||
} else { |
||||
if (add) { |
||||
for (int i = 0; i < _N_; i++) { |
||||
gain += dgain; |
||||
int32_t y = Sin::lookup(phase); |
||||
int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24; |
||||
output[i] += y1; |
||||
phase += freq; |
||||
} |
||||
} else { |
||||
for (int i = 0; i < _N_; i++) { |
||||
gain += dgain; |
||||
int32_t y = Sin::lookup(phase); |
||||
int32_t y1 = ((int64_t)y * (int64_t)gain) >> 24;
|
||||
output[i] = y1; |
||||
phase += freq; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
#define noDOUBLE_ACCURACY |
||||
#define HIGH_ACCURACY |
||||
|
||||
void FmOpKernel::compute_fb(int32_t *output, int32_t phase0, int32_t freq, |
||||
int32_t gain1, int32_t gain2, |
||||
int32_t *fb_buf, int fb_shift, bool add) { |
||||
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
||||
int32_t gain = gain1; |
||||
int32_t phase = phase0; |
||||
int32_t y0 = fb_buf[0]; |
||||
int32_t y = fb_buf[1]; |
||||
if (add) { |
||||
for (int i = 0; i < _N_; i++) { |
||||
gain += dgain; |
||||
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); |
||||
y0 = y; |
||||
y = Sin::lookup(phase + scaled_fb); |
||||
y = ((int64_t)y * (int64_t)gain) >> 24; |
||||
output[i] += y; |
||||
phase += freq; |
||||
} |
||||
} else { |
||||
for (int i = 0; i < _N_; i++) { |
||||
gain += dgain; |
||||
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); |
||||
y0 = y; |
||||
y = Sin::lookup(phase + scaled_fb); |
||||
y = ((int64_t)y * (int64_t)gain) >> 24; |
||||
output[i] = y; |
||||
phase += freq; |
||||
} |
||||
} |
||||
fb_buf[0] = y0; |
||||
fb_buf[1] = y; |
||||
} |
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Experimental sine wave generators below
|
||||
#if 0 |
||||
// Results: accuracy 64.3 mean, 170 worst case
|
||||
// high accuracy: 5.0 mean, 49 worst case
|
||||
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
||||
int32_t gain1, int32_t gain2, bool add) { |
||||
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
||||
int32_t gain = gain1; |
||||
int32_t phase = phase0; |
||||
#ifdef HIGH_ACCURACY |
||||
int32_t u = Sin::compute10(phase << 6); |
||||
u = ((int64_t)u * gain) >> 30; |
||||
int32_t v = Sin::compute10((phase << 6) + (1 << 28)); // quarter cycle
|
||||
v = ((int64_t)v * gain) >> 30; |
||||
int32_t s = Sin::compute10(freq << 6); |
||||
int32_t c = Sin::compute10((freq << 6) + (1 << 28)); |
||||
#else |
||||
int32_t u = Sin::compute(phase); |
||||
u = ((int64_t)u * gain) >> 24; |
||||
int32_t v = Sin::compute(phase + (1 << 22)); // quarter cycle
|
||||
v = ((int64_t)v * gain) >> 24; |
||||
int32_t s = Sin::compute(freq) << 6; |
||||
int32_t c = Sin::compute(freq + (1 << 22)) << 6; |
||||
#endif |
||||
for (int i = 0; i < _N_; i++) { |
||||
output[i] = u; |
||||
int32_t t = ((int64_t)v * (int64_t)c - (int64_t)u * (int64_t)s) >> 30; |
||||
u = ((int64_t)u * (int64_t)c + (int64_t)v * (int64_t)s) >> 30; |
||||
v = t; |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
#if 0 |
||||
// Results: accuracy 392.3 mean, 15190 worst case (near freq = 0.5)
|
||||
// for freq < 0.25, 275.2 mean, 716 worst
|
||||
// high accuracy: 57.4 mean, 7559 worst
|
||||
// freq < 0.25: 17.9 mean, 78 worst
|
||||
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
||||
int32_t gain1, int32_t gain2, bool add) { |
||||
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
||||
int32_t gain = gain1; |
||||
int32_t phase = phase0; |
||||
#ifdef HIGH_ACCURACY |
||||
int32_t u = floor(gain * sin(phase * (M_PI / (1 << 23))) + 0.5); |
||||
int32_t v = floor(gain * cos((phase - freq * 0.5) * (M_PI / (1 << 23))) + 0.5); |
||||
int32_t a = floor((1 << 25) * sin(freq * (M_PI / (1 << 24))) + 0.5); |
||||
#else |
||||
int32_t u = Sin::compute(phase); |
||||
u = ((int64_t)u * gain) >> 24; |
||||
int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1)); |
||||
v = ((int64_t)v * gain) >> 24; |
||||
int32_t a = Sin::compute(freq >> 1) << 1; |
||||
#endif |
||||
for (int i = 0; i < _N_; i++) { |
||||
output[i] = u; |
||||
v -= ((int64_t)a * (int64_t)u) >> 24; |
||||
u += ((int64_t)a * (int64_t)v) >> 24; |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
#if 0 |
||||
// Results: accuracy 370.0 mean, 15480 worst case (near freq = 0.5)
|
||||
// with FRAC_NUM accuracy initialization: mean 1.55, worst 58 (near freq = 0)
|
||||
// with high accuracy: mean 4.2, worst 292 (near freq = 0.5)
|
||||
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
||||
int32_t gain1, int32_t gain2, bool add) { |
||||
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
||||
int32_t gain = gain1; |
||||
int32_t phase = phase0; |
||||
#ifdef DOUBLE_ACCURACY |
||||
int32_t u = floor((1 << 30) * sin(phase * (M_PI / (1 << 23))) + 0.5); |
||||
FRAC_NUM a_d = sin(freq * (M_PI / (1 << 24))); |
||||
int32_t v = floor((1LL << 31) * a_d * cos((phase - freq * 0.5) * |
||||
(M_PI / (1 << 23))) + 0.5); |
||||
int32_t aa = floor((1LL << 31) * a_d * a_d + 0.5); |
||||
#else |
||||
#ifdef HIGH_ACCURACY |
||||
int32_t u = Sin::compute10(phase << 6); |
||||
int32_t v = Sin::compute10((phase << 6) + (1 << 28) - (freq << 5)); |
||||
int32_t a = Sin::compute10(freq << 5); |
||||
v = ((int64_t)v * (int64_t)a) >> 29; |
||||
int32_t aa = ((int64_t)a * (int64_t)a) >> 29; |
||||
#else |
||||
int32_t u = Sin::compute(phase) << 6; |
||||
int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1)); |
||||
int32_t a = Sin::compute(freq >> 1); |
||||
v = ((int64_t)v * (int64_t)a) >> 17; |
||||
int32_t aa = ((int64_t)a * (int64_t)a) >> 17; |
||||
#endif |
||||
#endif |
||||
|
||||
if (aa < 0) aa = (1 << 31) - 1; |
||||
for (int i = 0; i < _N_; i++) { |
||||
gain += dgain; |
||||
output[i] = ((int64_t)u * (int64_t)gain) >> 30; |
||||
v -= ((int64_t)aa * (int64_t)u) >> 29; |
||||
u += v; |
||||
} |
||||
} |
||||
#endif |
||||
|
||||
#if 0 |
||||
// Results:: accuracy 112.3 mean, 4262 worst (near freq = 0.5)
|
||||
// high accuracy 2.9 mean, 143 worst
|
||||
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, |
||||
int32_t gain1, int32_t gain2, bool add) { |
||||
int32_t dgain = (gain2 - gain1 + (N >> 1)) >> LG_N; |
||||
int32_t gain = gain1; |
||||
int32_t phase = phase0; |
||||
#ifdef HIGH_ACCURACY |
||||
int32_t u = Sin::compute10(phase << 6); |
||||
int32_t lastu = Sin::compute10((phase - freq) << 6); |
||||
int32_t a = Sin::compute10((freq << 6) + (1 << 28)) << 1; |
||||
#else |
||||
int32_t u = Sin::compute(phase) << 6; |
||||
int32_t lastu = Sin::compute(phase - freq) << 6; |
||||
int32_t a = Sin::compute(freq + (1 << 22)) << 7; |
||||
#endif |
||||
if (a < 0 && freq < 256) a = (1 << 31) - 1; |
||||
if (a > 0 && freq > 0x7fff00) a = -(1 << 31); |
||||
for (int i = 0; i < _N_; i++) { |
||||
gain += dgain; |
||||
output[i] = ((int64_t)u * (int64_t)gain) >> 30; |
||||
//output[i] = u;
|
||||
int32_t newu = (((int64_t)u * (int64_t)a) >> 30) - lastu; |
||||
lastu = u; |
||||
u = newu; |
||||
} |
||||
} |
||||
#endif |
||||
|
Loading…
Reference in new issue