Code cleanup: formatiing of all files with the internal Arduino-IDE code formatter.

Replacing env.cpp and env.h with the newest msfa version with some fixes
pull/37/head
Holger Wirtz 4 years ago
parent b5f75705bf
commit 48710fa0a3
  1. 531
      EngineMkI.cpp
  2. 40
      EngineMkI.h
  3. 364
      EngineOpl.cpp
  4. 40
      EngineOpl.h
  5. 3
      MicroDexed.ino
  6. 40
      aligned_buf.h
  7. 2
      config.h
  8. 2
      dexed.cpp
  9. 881
      effect_freeverbf.cpp
  10. 344
      effect_freeverbf.h
  11. 188
      env.cc
  12. 137
      env.cpp
  13. 125
      env.h
  14. 48
      exp2.h
  15. 114
      fm_core.cpp
  16. 50
      fm_core.h
  17. 283
      fm_op_kernel.cc
  18. 197
      fm_op_kernel.cpp
  19. 70
      fm_op_kernel.h
  20. 28
      freqlut.cpp
  21. 34
      freqlut.h
  22. 144
      lfo.cpp
  23. 64
      lfo.h
  24. 2
      midinotes.h
  25. 39
      module.h
  26. 855
      my_effect_freeverb.cpp
  27. 332
      my_effect_freeverb.h
  28. 6
      name.c
  29. 30
      pitchenv.cpp
  30. 79
      pitchenv.h
  31. 42
      sin.h
  32. 2
      source_microdexed.h

@ -1,25 +1,25 @@
/* /*
* Copyright (C) 2015-2017 Pascal Gauthier. Copyright (C) 2015-2017 Pascal Gauthier.
*
* This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version. (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* The code is based on ppplay https://github.com/stohrendorf/ppplay and opl3 The code is based on ppplay https://github.com/stohrendorf/ppplay and opl3
* math documentation : math documentation :
* https://github.com/gtaylormb/opl3_fpga/blob/master/docs/opl3math/opl3math.pdf https://github.com/gtaylormb/opl3_fpga/blob/master/docs/opl3math/opl3math.pdf
*
*/ */
#include "EngineMkI.h" #include "EngineMkI.h"
#define _USE_MATH_DEFINES #define _USE_MATH_DEFINES
@ -30,325 +30,324 @@
#include "exp2.h" #include "exp2.h"
#ifdef DEBUG #ifdef DEBUG
#include "time.h" #include "time.h"
//#define MKIDEBUG //#define MKIDEBUG
#endif #endif
#ifdef _WIN32 #ifdef _WIN32
#if _MSC_VER < 1800 #if _MSC_VER < 1800
FRAC_NUM log2(FRAC_NUM n) { FRAC_NUM log2(FRAC_NUM n) {
//return log(n) / log(2.0); //return log(n) / log(2.0);
return LOG_FUNC(n) / LOG_FUNC(2.0); return LOG_FUNC(n) / LOG_FUNC(2.0);
} }
FRAC_NUM round(FRAC_NUM n) { FRAC_NUM round(FRAC_NUM n) {
return n < 0.0 ? ceil(n - 0.5) : floor(n + 0.5); return n < 0.0 ? ceil(n - 0.5) : floor(n + 0.5);
} }
#endif #endif
__declspec(align(16)) const int zeros[N] = {0}; __declspec(align(16)) const int zeros[N] = {0};
#else #else
const int32_t __attribute__ ((aligned(16))) zeros[_N_] = {0}; const int32_t __attribute__ ((aligned(16))) zeros[_N_] = {0};
#endif #endif
static const uint16_t NEGATIVE_BIT = 0x8000; static const uint16_t NEGATIVE_BIT = 0x8000;
static const uint16_t ENV_BITDEPTH = 14; static const uint16_t ENV_BITDEPTH = 14;
static const uint16_t SINLOG_BITDEPTH = 10; static const uint16_t SINLOG_BITDEPTH = 10;
static const uint16_t SINLOG_TABLESIZE = 1<<SINLOG_BITDEPTH; static const uint16_t SINLOG_TABLESIZE = 1 << SINLOG_BITDEPTH;
static uint16_t sinLogTable[SINLOG_TABLESIZE]; static uint16_t sinLogTable[SINLOG_TABLESIZE];
static const uint16_t SINEXP_BITDEPTH = 10; static const uint16_t SINEXP_BITDEPTH = 10;
static const uint16_t SINEXP_TABLESIZE = 1<<SINEXP_BITDEPTH; static const uint16_t SINEXP_TABLESIZE = 1 << SINEXP_BITDEPTH;
static uint16_t sinExpTable[SINEXP_TABLESIZE]; static uint16_t sinExpTable[SINEXP_TABLESIZE];
const uint16_t ENV_MAX = 1<<ENV_BITDEPTH; const uint16_t ENV_MAX = 1 << ENV_BITDEPTH;
static inline uint16_t sinLog(uint16_t phi) { static inline uint16_t sinLog(uint16_t phi) {
const uint16_t SINLOG_TABLEFILTER = SINLOG_TABLESIZE-1; const uint16_t SINLOG_TABLEFILTER = SINLOG_TABLESIZE - 1;
const uint16_t index = (phi & SINLOG_TABLEFILTER); const uint16_t index = (phi & SINLOG_TABLEFILTER);
switch( ( phi & (SINLOG_TABLESIZE * 3) ) ) { switch ( ( phi & (SINLOG_TABLESIZE * 3) ) ) {
case 0: case 0:
return sinLogTable[index]; return sinLogTable[index];
case SINLOG_TABLESIZE: case SINLOG_TABLESIZE:
return sinLogTable[index ^ SINLOG_TABLEFILTER]; return sinLogTable[index ^ SINLOG_TABLEFILTER];
case SINLOG_TABLESIZE * 2 : case SINLOG_TABLESIZE * 2 :
return sinLogTable[index] | NEGATIVE_BIT; return sinLogTable[index] | NEGATIVE_BIT;
default: default:
return sinLogTable[index ^ SINLOG_TABLEFILTER] | NEGATIVE_BIT; return sinLogTable[index ^ SINLOG_TABLEFILTER] | NEGATIVE_BIT;
} }
} }
EngineMkI::EngineMkI() { EngineMkI::EngineMkI() {
float bitReso = SINLOG_TABLESIZE; float bitReso = SINLOG_TABLESIZE;
for(int i=0;i<SINLOG_TABLESIZE;i++) { for (int i = 0; i < SINLOG_TABLESIZE; i++) {
//float x1 = sin(((0.5+i)/bitReso) * M_PI/2.0); //float x1 = sin(((0.5+i)/bitReso) * M_PI/2.0);
float x1 = SIN_FUNC(((0.5+i)/bitReso) * M_PI/2.0); float x1 = SIN_FUNC(((0.5 + i) / bitReso) * M_PI / 2.0);
sinLogTable[i] = round(-1024 * log2(x1)); sinLogTable[i] = round(-1024 * log2(x1));
} }
bitReso = SINEXP_TABLESIZE; bitReso = SINEXP_TABLESIZE;
for(int i=0;i<SINEXP_TABLESIZE;i++) { for (int i = 0; i < SINEXP_TABLESIZE; i++) {
float x1 = (pow(2, float(i)/bitReso)-1) * 4096; float x1 = (pow(2, float(i) / bitReso) - 1) * 4096;
sinExpTable[i] = round(x1); sinExpTable[i] = round(x1);
} }
#ifdef MKIDEBUG #ifdef MKIDEBUG
char buffer[4096]; char buffer[4096];
int pos = 0; int pos = 0;
for(int i=0;i<SINLOG_TABLESIZE;i++) { for (int i = 0; i < SINLOG_TABLESIZE; i++) {
pos += sprintf(buffer+pos, "%d ", sinLogTable[i]); pos += sprintf(buffer + pos, "%d ", sinLogTable[i]);
if ( pos > 90 ) { if ( pos > 90 ) {
buffer[0] = 0; buffer[0] = 0;
pos = 0; pos = 0;
}
} }
buffer[0] = 0; }
pos = 0; buffer[0] = 0;
for(int i=0;i<SINEXP_TABLESIZE;i++) { pos = 0;
pos += sprintf(buffer+pos, "%d ", sinExpTable[i]); for (int i = 0; i < SINEXP_TABLESIZE; i++) {
if ( pos > 90 ) { pos += sprintf(buffer + pos, "%d ", sinExpTable[i]);
buffer[0] = 0; if ( pos > 90 ) {
pos = 0; buffer[0] = 0;
} pos = 0;
} }
}
#endif #endif
} }
inline int32_t mkiSin(int32_t phase, uint16_t env) { inline int32_t mkiSin(int32_t phase, uint16_t env) {
uint16_t expVal = sinLog(phase >> (22 - SINLOG_BITDEPTH)) + (env); uint16_t expVal = sinLog(phase >> (22 - SINLOG_BITDEPTH)) + (env);
//int16_t expValShow = expVal; //int16_t expValShow = expVal;
const bool isSigned = expVal & NEGATIVE_BIT; const bool isSigned = expVal & NEGATIVE_BIT;
expVal &= ~NEGATIVE_BIT; expVal &= ~NEGATIVE_BIT;
const uint16_t SINEXP_FILTER = 0x3FF; const uint16_t SINEXP_FILTER = 0x3FF;
uint16_t result = 4096 + sinExpTable[( expVal & SINEXP_FILTER ) ^ SINEXP_FILTER]; uint16_t result = 4096 + sinExpTable[( expVal & SINEXP_FILTER ) ^ SINEXP_FILTER];
//uint16_t resultB4 = result; //uint16_t resultB4 = result;
result >>= ( expVal >> 10 ); // exp result >>= ( expVal >> 10 ); // exp
#ifdef MKIDEBUG #ifdef MKIDEBUG
if ( ( time(NULL) % 5 ) == 0 ) { if ( ( time(NULL) % 5 ) == 0 ) {
if ( expValShow < 0 ) { if ( expValShow < 0 ) {
expValShow = (expValShow + 0x7FFF) * -1; expValShow = (expValShow + 0x7FFF) * -1;
}
} }
}
#endif #endif
if( isSigned ) if ( isSigned )
return (-result - 1) << 13; return (-result - 1) << 13;
else else
return result << 13; return result << 13;
} }
void EngineMkI::compute(int32_t *output, const int32_t *input, void EngineMkI::compute(int32_t *output, const int32_t *input,
int32_t phase0, int32_t freq, int32_t phase0, int32_t freq,
int32_t gain1, int32_t gain2, bool add) { int32_t gain1, int32_t gain2, bool add) {
int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N; int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N;
int32_t gain = gain1; int32_t gain = gain1;
int32_t phase = phase0; int32_t phase = phase0;
const int32_t *adder = add ? output : zeros; const int32_t *adder = add ? output : zeros;
for (int i = 0; i < _N_; i++) { for (int i = 0; i < _N_; i++) {
gain += dgain; gain += dgain;
int32_t y = mkiSin((phase+input[i]), gain); int32_t y = mkiSin((phase + input[i]), gain);
output[i] = y + adder[i]; output[i] = y + adder[i];
phase += freq; phase += freq;
} }
} }
void EngineMkI::compute_pure(int32_t *output, int32_t phase0, int32_t freq, void EngineMkI::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
int32_t gain1, int32_t gain2, bool add) { int32_t gain1, int32_t gain2, bool add) {
int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N; int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N;
int32_t gain = gain1; int32_t gain = gain1;
int32_t phase = phase0; int32_t phase = phase0;
const int32_t *adder = add ? output : zeros; const int32_t *adder = add ? output : zeros;
for (int i = 0; i < _N_; i++) { for (int i = 0; i < _N_; i++) {
gain += dgain; gain += dgain;
int32_t y = mkiSin(phase , gain); int32_t y = mkiSin(phase , gain);
output[i] = y + adder[i]; output[i] = y + adder[i];
phase += freq; phase += freq;
} }
} }
void EngineMkI::compute_fb(int32_t *output, int32_t phase0, int32_t freq, void EngineMkI::compute_fb(int32_t *output, int32_t phase0, int32_t freq,
int32_t gain1, int32_t gain2, int32_t gain1, int32_t gain2,
int32_t *fb_buf, int fb_shift, bool add) { int32_t *fb_buf, int fb_shift, bool add) {
int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N; int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N;
int32_t gain = gain1; int32_t gain = gain1;
int32_t phase = phase0; int32_t phase = phase0;
const int32_t *adder = add ? output : zeros; const int32_t *adder = add ? output : zeros;
int32_t y0 = fb_buf[0]; int32_t y0 = fb_buf[0];
int32_t y = fb_buf[1]; int32_t y = fb_buf[1];
for (int i = 0; i < _N_; i++) { for (int i = 0; i < _N_; i++) {
gain += dgain; gain += dgain;
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); int32_t scaled_fb = (y0 + y) >> (fb_shift + 1);
y0 = y; y0 = y;
y = mkiSin((phase+scaled_fb), gain); y = mkiSin((phase + scaled_fb), gain);
output[i] = y + adder[i]; output[i] = y + adder[i];
phase += freq; phase += freq;
} }
fb_buf[0] = y0; fb_buf[0] = y0;
fb_buf[1] = y; fb_buf[1] = y;
} }
// exclusively used for ALGO 6 with feedback // exclusively used for ALGO 6 with feedback
void EngineMkI::compute_fb2(int32_t *output, FmOpParams *parms, int32_t gain01, int32_t gain02, int32_t *fb_buf, int fb_shift) { void EngineMkI::compute_fb2(int32_t *output, FmOpParams *parms, int32_t gain01, int32_t gain02, int32_t *fb_buf, int fb_shift) {
int32_t dgain[2]; int32_t dgain[2];
int32_t gain[2]; int32_t gain[2];
int32_t phase[2]; int32_t phase[2];
int32_t y0 = fb_buf[0]; int32_t y0 = fb_buf[0];
int32_t y = fb_buf[1]; int32_t y = fb_buf[1];
phase[0] = parms[0].phase; phase[0] = parms[0].phase;
phase[1] = parms[1].phase; phase[1] = parms[1].phase;
parms[1].gain_out = (ENV_MAX-(parms[1].level_in >> (28-ENV_BITDEPTH))); parms[1].gain_out = (ENV_MAX - (parms[1].level_in >> (28 - ENV_BITDEPTH)));
gain[0] = gain01; gain[0] = gain01;
gain[1] = parms[1].gain_out == 0 ? (ENV_MAX-1) : parms[1].gain_out; gain[1] = parms[1].gain_out == 0 ? (ENV_MAX - 1) : parms[1].gain_out;
dgain[0] = (gain02 - gain01 + (_N_ >> 1)) >> LG_N; dgain[0] = (gain02 - gain01 + (_N_ >> 1)) >> LG_N;
dgain[1] = (parms[1].gain_out - (parms[1].gain_out == 0 ? (ENV_MAX-1) : parms[1].gain_out)); dgain[1] = (parms[1].gain_out - (parms[1].gain_out == 0 ? (ENV_MAX - 1) : parms[1].gain_out));
for (int i = 0; i < _N_; i++) { for (int i = 0; i < _N_; i++) {
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); int32_t scaled_fb = (y0 + y) >> (fb_shift + 1);
// op 0 // op 0
gain[0] += dgain[0]; gain[0] += dgain[0];
y0 = y; y0 = y;
y = mkiSin(phase[0]+scaled_fb, gain[0]); y = mkiSin(phase[0] + scaled_fb, gain[0]);
phase[0] += parms[0].freq; phase[0] += parms[0].freq;
// op 1 // op 1
gain[1] += dgain[1]; gain[1] += dgain[1];
y = mkiSin(phase[1]+y, gain[1]); y = mkiSin(phase[1] + y, gain[1]);
phase[1] += parms[1].freq; phase[1] += parms[1].freq;
output[i] = y; output[i] = y;
} }
fb_buf[0] = y0; fb_buf[0] = y0;
fb_buf[1] = y; fb_buf[1] = y;
} }
// exclusively used for ALGO 4 with feedback // exclusively used for ALGO 4 with feedback
void EngineMkI::compute_fb3(int32_t *output, FmOpParams *parms, int32_t gain01, int32_t gain02, int32_t *fb_buf, int fb_shift) { void EngineMkI::compute_fb3(int32_t *output, FmOpParams *parms, int32_t gain01, int32_t gain02, int32_t *fb_buf, int fb_shift) {
int32_t dgain[3]; int32_t dgain[3];
int32_t gain[3]; int32_t gain[3];
int32_t phase[3]; int32_t phase[3];
int32_t y0 = fb_buf[0]; int32_t y0 = fb_buf[0];
int32_t y = fb_buf[1]; int32_t y = fb_buf[1];
phase[0] = parms[0].phase; phase[0] = parms[0].phase;
phase[1] = parms[1].phase; phase[1] = parms[1].phase;
phase[2] = parms[2].phase; phase[2] = parms[2].phase;
parms[1].gain_out = (ENV_MAX-(parms[1].level_in >> (28-ENV_BITDEPTH))); parms[1].gain_out = (ENV_MAX - (parms[1].level_in >> (28 - ENV_BITDEPTH)));
parms[2].gain_out = (ENV_MAX-(parms[2].level_in >> (28-ENV_BITDEPTH))); parms[2].gain_out = (ENV_MAX - (parms[2].level_in >> (28 - ENV_BITDEPTH)));
gain[0] = gain01; gain[0] = gain01;
gain[1] = parms[1].gain_out == 0 ? (ENV_MAX-1) : parms[1].gain_out; gain[1] = parms[1].gain_out == 0 ? (ENV_MAX - 1) : parms[1].gain_out;
gain[2] = parms[2].gain_out == 0 ? (ENV_MAX-1) : parms[2].gain_out; gain[2] = parms[2].gain_out == 0 ? (ENV_MAX - 1) : parms[2].gain_out;
dgain[0] = (gain02 - gain01 + (_N_ >> 1)) >> LG_N; dgain[0] = (gain02 - gain01 + (_N_ >> 1)) >> LG_N;
dgain[1] = (parms[1].gain_out - (parms[1].gain_out == 0 ? (ENV_MAX-1) : parms[1].gain_out)); dgain[1] = (parms[1].gain_out - (parms[1].gain_out == 0 ? (ENV_MAX - 1) : parms[1].gain_out));
dgain[2] = (parms[2].gain_out - (parms[2].gain_out == 0 ? (ENV_MAX-1) : parms[2].gain_out)); dgain[2] = (parms[2].gain_out - (parms[2].gain_out == 0 ? (ENV_MAX - 1) : parms[2].gain_out));
for (int i = 0; i < _N_; i++) { for (int i = 0; i < _N_; i++) {
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); int32_t scaled_fb = (y0 + y) >> (fb_shift + 1);
// op 0 // op 0
gain[0] += dgain[0]; gain[0] += dgain[0];
y0 = y; y0 = y;
y = mkiSin(phase[0]+scaled_fb, gain[0]); y = mkiSin(phase[0] + scaled_fb, gain[0]);
phase[0] += parms[0].freq; phase[0] += parms[0].freq;
// op 1 // op 1
gain[1] += dgain[1]; gain[1] += dgain[1];
y = mkiSin(phase[1]+y, gain[1]); y = mkiSin(phase[1] + y, gain[1]);
phase[1] += parms[1].freq; phase[1] += parms[1].freq;
// op 2 // op 2
gain[2] += dgain[2]; gain[2] += dgain[2];
y = mkiSin(phase[2]+y, gain[2]); y = mkiSin(phase[2] + y, gain[2]);
phase[2] += parms[2].freq; phase[2] += parms[2].freq;
output[i] = y; output[i] = y;
} }
fb_buf[0] = y0; fb_buf[0] = y0;
fb_buf[1] = y; fb_buf[1] = y;
} }
void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int32_t 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; const int kLevelThresh = ENV_MAX - 100;
FmAlgorithm alg = algorithms[algorithm]; FmAlgorithm alg = algorithms[algorithm];
bool has_contents[3] = { true, false, false }; bool has_contents[3] = { true, false, false };
bool fb_on = feedback_shift < 16; bool fb_on = feedback_shift < 16;
switch(algorithm) { switch (algorithm) {
case 3 : case 5 : case 3 : case 5 :
if ( fb_on ) if ( fb_on )
alg.ops[0] = 0xc4; alg.ops[0] = 0xc4;
} }
for (int op = 0; op < 6; op++) { for (int op = 0; op < 6; op++) {
int flags = alg.ops[op]; int flags = alg.ops[op];
bool add = (flags & OUT_BUS_ADD) != 0; bool add = (flags & OUT_BUS_ADD) != 0;
FmOpParams &param = params[op]; FmOpParams &param = params[op];
int inbus = (flags >> 4) & 3; int inbus = (flags >> 4) & 3;
int outbus = flags & 3; int outbus = flags & 3;
int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get(); int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get();
int32_t gain1 = param.gain_out == 0 ? (ENV_MAX-1) : param.gain_out; int32_t gain1 = param.gain_out == 0 ? (ENV_MAX - 1) : param.gain_out;
int32_t gain2 = ENV_MAX-(param.level_in >> (28-ENV_BITDEPTH)); int32_t gain2 = ENV_MAX - (param.level_in >> (28 - ENV_BITDEPTH));
param.gain_out = gain2; param.gain_out = gain2;
if (gain1 <= kLevelThresh || gain2 <= kLevelThresh) { if (gain1 <= kLevelThresh || gain2 <= kLevelThresh) {
if (!has_contents[outbus]) { if (!has_contents[outbus]) {
add = false; add = false;
} }
if (inbus == 0 || !has_contents[inbus]) { if (inbus == 0 || !has_contents[inbus]) {
// PG: this is my 'dirty' implementation of FB for 2 and 3 operators... // PG: this is my 'dirty' implementation of FB for 2 and 3 operators...
if ((flags & 0xc0) == 0xc0 && fb_on) { if ((flags & 0xc0) == 0xc0 && fb_on) {
switch ( algorithm ) { switch ( algorithm ) {
// three operator feedback, process exception for ALGO 4 // three operator feedback, process exception for ALGO 4
case 3 : 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[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 params[2].phase += params[2].freq << LG_N; // yuk yuk
op += 2; // ignore the 2 other operators op += 2; // ignore the 2 other operators
break; break;
// two operator feedback, process exception for ALGO 6 // two operator feedback, process exception for ALGO 6
case 5 : 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 params[1].phase += params[1].freq << LG_N; // yuk, hack, we already processed op-5
op++; // ignore next operator; op++; // ignore next operator;
break; break;
default: default:
// one operator feedback, normal proces // one operator feedback, normal proces
compute_fb(outptr, param.phase, param.freq, gain1, gain2, fb_buf, feedback_shift, add); compute_fb(outptr, param.phase, param.freq, gain1, gain2, fb_buf, feedback_shift, add);
break; break;
} }
} else { } else {
compute_pure(outptr, param.phase, param.freq, gain1, gain2, add); compute_pure(outptr, param.phase, param.freq, gain1, gain2, add);
}
} else {
compute(outptr, buf_[inbus - 1].get(), param.phase, param.freq, gain1, gain2, add);
}
has_contents[outbus] = true;
} else if (!add) {
has_contents[outbus] = false;
} }
param.phase += param.freq << LG_N; } else {
compute(outptr, buf_[inbus - 1].get(), param.phase, param.freq, gain1, gain2, add);
}
has_contents[outbus] = true;
} else if (!add) {
has_contents[outbus] = false;
} }
param.phase += param.freq << LG_N;
}
} }

@ -1,19 +1,19 @@
/* /*
* Copyright 2014 Pascal Gauthier. Copyright 2014 Pascal Gauthier.
* Copyright 2012 Google Inc. Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
#ifndef ENGINEMKI_H_INCLUDED #ifndef ENGINEMKI_H_INCLUDED
#define ENGINEMKI_H_INCLUDED #define ENGINEMKI_H_INCLUDED
@ -27,19 +27,19 @@
class EngineMkI : public FmCore { class EngineMkI : public FmCore {
public: public:
EngineMkI(); EngineMkI();
void render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int32_t feedback_shift); void render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int32_t feedback_shift);
void compute(int32_t *output, const int32_t *input, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, void compute(int32_t *output, const int32_t *input, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2,
bool add); bool add);
void compute_pure(int32_t *output, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, void compute_pure(int32_t *output, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2,
bool add); bool add);
void compute_fb(int32_t *output, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, void compute_fb(int32_t *output, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2,
int32_t *fb_buf, int fb_gain, bool add); int32_t *fb_buf, int fb_gain, bool add);
void compute_fb2(int32_t *output, FmOpParams *params, int32_t gain01, int32_t gain02, int32_t *fb_buf, int fb_shift); void compute_fb2(int32_t *output, FmOpParams *params, int32_t gain01, int32_t gain02, int32_t *fb_buf, int fb_shift);

@ -1,225 +1,213 @@
/* /*
* Copyright (C) 2014 Pascal Gauthier. Copyright (C) 2014 Pascal Gauthier.
* Copyright (C) 2012 Steffen Ohrendorf <steffen.ohrendorf@gmx.de> Copyright (C) 2012 Steffen Ohrendorf <steffen.ohrendorf@gmx.de>
*
* This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version. (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Original Java Code: Copyright (C) 2008 Robson Cozendey <robson@cozendey.com> Original Java Code: Copyright (C) 2008 Robson Cozendey <robson@cozendey.com>
*
* Some code based on forum posts in: http://forums.submarine.org.uk/phpBB/viewforum.php?f=9, Some code based on forum posts in: http://forums.submarine.org.uk/phpBB/viewforum.php?f=9,
* Copyright (C) 2010-2013 by carbon14 and opl3 Copyright (C) 2010-2013 by carbon14 and opl3
*
*/ */
#include "EngineOpl.h" #include "EngineOpl.h"
#ifdef _WIN32 #ifdef _WIN32
__declspec(align(16)) const int zeros[N] = {0}; __declspec(align(16)) const int zeros[N] = {0};
#else #else
const int32_t __attribute__ ((aligned(16))) zeros[_N_] = {0}; const int32_t __attribute__ ((aligned(16))) zeros[_N_] = {0};
#endif #endif
uint16_t SignBit = 0x8000; uint16_t SignBit = 0x8000;
uint16_t sinLogTable[256] = { uint16_t sinLogTable[256] = {
2137, 1731, 1543, 1419, 1326, 1252, 1190, 1137, 1091, 1050, 1013, 979, 949, 920, 894, 869, 2137, 1731, 1543, 1419, 1326, 1252, 1190, 1137, 1091, 1050, 1013, 979, 949, 920, 894, 869,
846, 825, 804, 785, 767, 749, 732, 717, 701, 687, 672, 659, 646, 633, 621, 609, 846, 825, 804, 785, 767, 749, 732, 717, 701, 687, 672, 659, 646, 633, 621, 609,
598, 587, 576, 566, 556, 546, 536, 527, 518, 509, 501, 492, 484, 476, 468, 461, 598, 587, 576, 566, 556, 546, 536, 527, 518, 509, 501, 492, 484, 476, 468, 461,
453, 446, 439, 432, 425, 418, 411, 405, 399, 392, 386, 380, 375, 369, 363, 358, 453, 446, 439, 432, 425, 418, 411, 405, 399, 392, 386, 380, 375, 369, 363, 358,
352, 347, 341, 336, 331, 326, 321, 316, 311, 307, 302, 297, 293, 289, 284, 280, 352, 347, 341, 336, 331, 326, 321, 316, 311, 307, 302, 297, 293, 289, 284, 280,
276, 271, 267, 263, 259, 255, 251, 248, 244, 240, 236, 233, 229, 226, 222, 219, 276, 271, 267, 263, 259, 255, 251, 248, 244, 240, 236, 233, 229, 226, 222, 219,
215, 212, 209, 205, 202, 199, 196, 193, 190, 187, 184, 181, 178, 175, 172, 169, 215, 212, 209, 205, 202, 199, 196, 193, 190, 187, 184, 181, 178, 175, 172, 169,
167, 164, 161, 159, 156, 153, 151, 148, 146, 143, 141, 138, 136, 134, 131, 129, 167, 164, 161, 159, 156, 153, 151, 148, 146, 143, 141, 138, 136, 134, 131, 129,
127, 125, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, 102, 100, 98, 96, 127, 125, 122, 120, 118, 116, 114, 112, 110, 108, 106, 104, 102, 100, 98, 96,
94, 92, 91, 89, 87, 85, 83, 82, 80, 78, 77, 75, 74, 72, 70, 69, 94, 92, 91, 89, 87, 85, 83, 82, 80, 78, 77, 75, 74, 72, 70, 69,
67, 66, 64, 63, 62, 60, 59, 57, 56, 55, 53, 52, 51, 49, 48, 47, 67, 66, 64, 63, 62, 60, 59, 57, 56, 55, 53, 52, 51, 49, 48, 47,
46, 45, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 46, 45, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30,
29, 28, 27, 26, 25, 24, 23, 23, 22, 21, 20, 20, 19, 18, 17, 17, 29, 28, 27, 26, 25, 24, 23, 23, 22, 21, 20, 20, 19, 18, 17, 17,
16, 15, 15, 14, 13, 13, 12, 12, 11, 10, 10, 9, 9, 8, 8, 7, 16, 15, 15, 14, 13, 13, 12, 12, 11, 10, 10, 9, 9, 8, 8, 7,
7, 7, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 7, 7, 6, 6, 5, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2,
2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 2, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0
}; };
uint16_t sinExpTable[256] = { uint16_t sinExpTable[256] = {
0, 3, 6, 8, 11, 14, 17, 20, 22, 25, 28, 31, 34, 37, 40, 42, 0, 3, 6, 8, 11, 14, 17, 20, 22, 25, 28, 31, 34, 37, 40, 42,
45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75, 78, 81, 84, 87, 90,
93, 96, 99, 102, 105, 108, 111, 114, 117, 120, 123, 126, 130, 133, 136, 139, 93, 96, 99, 102, 105, 108, 111, 114, 117, 120, 123, 126, 130, 133, 136, 139,
142, 145, 148, 152, 155, 158, 161, 164, 168, 171, 174, 177, 181, 184, 187, 190, 142, 145, 148, 152, 155, 158, 161, 164, 168, 171, 174, 177, 181, 184, 187, 190,
194, 197, 200, 204, 207, 210, 214, 217, 220, 224, 227, 231, 234, 237, 241, 244, 194, 197, 200, 204, 207, 210, 214, 217, 220, 224, 227, 231, 234, 237, 241, 244,
248, 251, 255, 258, 262, 265, 268, 272, 276, 279, 283, 286, 290, 293, 297, 300, 248, 251, 255, 258, 262, 265, 268, 272, 276, 279, 283, 286, 290, 293, 297, 300,
304, 308, 311, 315, 318, 322, 326, 329, 333, 337, 340, 344, 348, 352, 355, 359, 304, 308, 311, 315, 318, 322, 326, 329, 333, 337, 340, 344, 348, 352, 355, 359,
363, 367, 370, 374, 378, 382, 385, 389, 393, 397, 401, 405, 409, 412, 416, 420, 363, 367, 370, 374, 378, 382, 385, 389, 393, 397, 401, 405, 409, 412, 416, 420,
424, 428, 432, 436, 440, 444, 448, 452, 456, 460, 464, 468, 472, 476, 480, 484, 424, 428, 432, 436, 440, 444, 448, 452, 456, 460, 464, 468, 472, 476, 480, 484,
488, 492, 496, 501, 505, 509, 513, 517, 521, 526, 530, 534, 538, 542, 547, 551, 488, 492, 496, 501, 505, 509, 513, 517, 521, 526, 530, 534, 538, 542, 547, 551,
555, 560, 564, 568, 572, 577, 581, 585, 590, 594, 599, 603, 607, 612, 616, 621, 555, 560, 564, 568, 572, 577, 581, 585, 590, 594, 599, 603, 607, 612, 616, 621,
625, 630, 634, 639, 643, 648, 652, 657, 661, 666, 670, 675, 680, 684, 689, 693, 625, 630, 634, 639, 643, 648, 652, 657, 661, 666, 670, 675, 680, 684, 689, 693,
698, 703, 708, 712, 717, 722, 726, 731, 736, 741, 745, 750, 755, 760, 765, 770, 698, 703, 708, 712, 717, 722, 726, 731, 736, 741, 745, 750, 755, 760, 765, 770,
774, 779, 784, 789, 794, 799, 804, 809, 814, 819, 824, 829, 834, 839, 844, 849, 774, 779, 784, 789, 794, 799, 804, 809, 814, 819, 824, 829, 834, 839, 844, 849,
854, 859, 864, 869, 874, 880, 885, 890, 895, 900, 906, 911, 916, 921, 927, 932, 854, 859, 864, 869, 874, 880, 885, 890, 895, 900, 906, 911, 916, 921, 927, 932,
937, 942, 948, 953, 959, 964, 969, 975, 980, 986, 991, 996, 1002, 1007, 1013, 1018 937, 942, 948, 953, 959, 964, 969, 975, 980, 986, 991, 996, 1002, 1007, 1013, 1018
}; };
inline uint16_t sinLog(uint16_t phi) { inline uint16_t sinLog(uint16_t phi) {
const uint8_t index = (phi & 0xff); const uint8_t index = (phi & 0xff);
switch( ( phi & 0x0300 ) ) { switch ( ( phi & 0x0300 ) ) {
case 0x0000: case 0x0000:
// rising quarter wave Shape A // rising quarter wave Shape A
return sinLogTable[index]; return sinLogTable[index];
case 0x0100: case 0x0100:
// falling quarter wave Shape B // falling quarter wave Shape B
return sinLogTable[index ^ 0xFF]; return sinLogTable[index ^ 0xFF];
case 0x0200: case 0x0200:
// rising quarter wave -ve Shape C // rising quarter wave -ve Shape C
return sinLogTable[index] | SignBit; return sinLogTable[index] | SignBit;
default: default:
// falling quarter wave -ve Shape D // falling quarter wave -ve Shape D
return sinLogTable[index ^ 0xFF] | SignBit; return sinLogTable[index ^ 0xFF] | SignBit;
} }
} }
// 16 env units are ~3dB and halve the output // 16 env units are ~3dB and halve the output
/** /**
* @brief OPL Sine Wave calculation @brief OPL Sine Wave calculation
* @param[in] phase Wave phase (0..1023) @param[in] phase Wave phase (0..1023)
* @param[in] env Envelope value (0..511) @param[in] env Envelope value (0..511)
* @warning @a env will not be checked for correct values. @warning @a env will not be checked for correct values.
*/ */
inline int16_t oplSin( uint16_t phase, uint16_t env ) { inline int16_t oplSin( uint16_t phase, uint16_t env ) {
uint16_t expVal = sinLog(phase) + (env << 3); uint16_t expVal = sinLog(phase) + (env << 3);
const bool isSigned = expVal & SignBit; const bool isSigned = expVal & SignBit;
expVal &= ~SignBit; expVal &= ~SignBit;
// expVal: 0..2137+511*8 = 0..6225 // expVal: 0..2137+511*8 = 0..6225
// result: 0..1018+1024 // result: 0..1018+1024
uint32_t result = 0x0400 + sinExpTable[( expVal & 0xff ) ^ 0xFF]; uint32_t result = 0x0400 + sinExpTable[( expVal & 0xff ) ^ 0xFF];
result <<= 1; result <<= 1;
result >>= ( expVal >> 8 ); // exp result >>= ( expVal >> 8 ); // exp
if( isSigned ) { if ( isSigned ) {
// -1 for one's complement // -1 for one's complement
return -result - 1; return -result - 1;
} else { } else {
return result; return result;
} }
} }
void EngineOpl::compute(int32_t *output, const int32_t *input, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, bool add) { void EngineOpl::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 dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N;
int32_t gain = gain1; int32_t gain = gain1;
int32_t phase = phase0; int32_t phase = phase0;
const int32_t *adder = add ? output : zeros; const int32_t *adder = add ? output : zeros;
for (int i = 0; i < _N_; i++) { for (int i = 0; i < _N_; i++) {
gain += dgain; gain += dgain;
int32_t y = oplSin((phase+input[i]) >> 14, gain); int32_t y = oplSin((phase + input[i]) >> 14, gain);
output[i] = (y << 14) + adder[i]; output[i] = (y << 14) + adder[i];
phase += freq; phase += freq;
} }
} }
void EngineOpl::compute_pure(int32_t *output, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, bool add) { void EngineOpl::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 dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N;
int32_t gain = gain1; int32_t gain = gain1;
int32_t phase = phase0; int32_t phase = phase0;
const int32_t *adder = add ? output : zeros; const int32_t *adder = add ? output : zeros;
for (int i = 0; i < _N_; i++) { for (int i = 0; i < _N_; i++) {
gain += dgain; gain += dgain;
int32_t y = oplSin(phase >> 14, gain); int32_t y = oplSin(phase >> 14, gain);
output[i] = (y << 14) + adder[i]; output[i] = (y << 14) + adder[i];
phase += freq; phase += freq;
} }
} }
void EngineOpl::compute_fb(int32_t *output, int32_t phase0, int32_t freq, void EngineOpl::compute_fb(int32_t *output, int32_t phase0, int32_t freq,
int32_t gain1, int32_t gain2, int32_t gain1, int32_t gain2,
int32_t *fb_buf, int fb_shift, bool add) { int32_t *fb_buf, int fb_shift, bool add) {
int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N; int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N;
int32_t gain = gain1; int32_t gain = gain1;
int32_t phase = phase0; int32_t phase = phase0;
const int32_t *adder = add ? output : zeros; const int32_t *adder = add ? output : zeros;
int32_t y0 = fb_buf[0]; int32_t y0 = fb_buf[0];
int32_t y = fb_buf[1]; int32_t y = fb_buf[1];
for (int i = 0; i < _N_; i++) { for (int i = 0; i < _N_; i++) {
gain += dgain; gain += dgain;
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); int32_t scaled_fb = (y0 + y) >> (fb_shift + 1);
y0 = y; y0 = y;
y = oplSin((phase+scaled_fb) >> 14, gain) << 14; y = oplSin((phase + scaled_fb) >> 14, gain) << 14;
output[i] = y + adder[i]; output[i] = y + adder[i];
phase += freq; phase += freq;
} }
fb_buf[0] = y0; fb_buf[0] = y0;
fb_buf[1] = y; fb_buf[1] = y;
} }
void EngineOpl::render(int32_t *output, FmOpParams *params, int algorithm,int32_t *fb_buf, int32_t feedback_shift) { void EngineOpl::render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int32_t feedback_shift) {
const int kLevelThresh = 507; // really ???? const int kLevelThresh = 507; // really ????
const FmAlgorithm alg = algorithms[algorithm]; const FmAlgorithm alg = algorithms[algorithm];
bool has_contents[3] = { true, false, false }; bool has_contents[3] = { true, false, false };
for (int op = 0; op < 6; op++) { for (int op = 0; op < 6; op++) {
int flags = alg.ops[op]; int flags = alg.ops[op];
bool add = (flags & OUT_BUS_ADD) != 0; bool add = (flags & OUT_BUS_ADD) != 0;
FmOpParams &param = params[op]; FmOpParams &param = params[op];
int inbus = (flags >> 4) & 3; int inbus = (flags >> 4) & 3;
int outbus = flags & 3; int outbus = flags & 3;
int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get(); int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get();
int32_t gain1 = param.gain_out == 0 ? 511 : param.gain_out; int32_t gain1 = param.gain_out == 0 ? 511 : param.gain_out;
int32_t gain2 = 512-(param.level_in >> 19); int32_t gain2 = 512 - (param.level_in >> 19);
param.gain_out = gain2; param.gain_out = gain2;
if (gain1 <= kLevelThresh || gain2 <= kLevelThresh) { if (gain1 <= kLevelThresh || gain2 <= kLevelThresh) {
if (!has_contents[outbus]) { if (!has_contents[outbus]) {
add = false; add = false;
} }
if (inbus == 0 || !has_contents[inbus]) { if (inbus == 0 || !has_contents[inbus]) {
// todo: more than one op in a feedback loop // todo: more than one op in a feedback loop
if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) { if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) {
// cout << op << " fb " << inbus << outbus << add << endl; // cout << op << " fb " << inbus << outbus << add << endl;
compute_fb(outptr, param.phase, param.freq, compute_fb(outptr, param.phase, param.freq,
gain1, gain2, gain1, gain2,
fb_buf, feedback_shift, add); fb_buf, feedback_shift, add);
} else { } else {
// cout << op << " pure " << inbus << outbus << add << endl; // cout << op << " pure " << inbus << outbus << add << endl;
compute_pure(outptr, param.phase, param.freq, compute_pure(outptr, param.phase, param.freq,
gain1, gain2, add); gain1, gain2, add);
}
} else {
// cout << op << " normal " << inbus << outbus << " " << param.freq << add << endl;
compute(outptr, buf_[inbus - 1].get(),
param.phase, param.freq, gain1, gain2, add);
}
has_contents[outbus] = true;
} else if (!add) {
has_contents[outbus] = false;
} }
param.phase += param.freq << LG_N; } else {
// cout << op << " normal " << inbus << outbus << " " << param.freq << add << endl;
compute(outptr, buf_[inbus - 1].get(),
param.phase, param.freq, gain1, gain2, add);
}
has_contents[outbus] = true;
} else if (!add) {
has_contents[outbus] = false;
} }
param.phase += param.freq << LG_N;
}
} }

@ -1,22 +1,22 @@
/** /**
*
* Copyright (c) 2014 Pascal Gauthier. Copyright (c) 2014 Pascal Gauthier.
*
* This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version. (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/ */
#ifndef ENGINEOPL_H_INCLUDED #ifndef ENGINEOPL_H_INCLUDED
#define ENGINEOPL_H_INCLUDED #define ENGINEOPL_H_INCLUDED
@ -29,11 +29,11 @@
class EngineOpl : public FmCore { class EngineOpl : public FmCore {
public: public:
virtual void render(int32_t *output, FmOpParams *params, int algorithm, virtual void render(int32_t *output, FmOpParams *params, int algorithm,
int32_t *fb_buf, int32_t feedback_shift); int32_t *fb_buf, int32_t feedback_shift);
void compute(int32_t *output, const int32_t *input, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, bool add); void compute(int32_t *output, const int32_t *input, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, bool add);
void compute_pure(int32_t *output, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, bool add); void compute_pure(int32_t *output, int32_t phase0, int32_t freq, int32_t gain1, int32_t gain2, bool add);
void compute_fb(int32_t *output, int32_t phase0, int32_t freq, void compute_fb(int32_t *output, int32_t phase0, int32_t freq,
int32_t gain1, int32_t gain2, int32_t gain1, int32_t gain2,
int32_t *fb_buf, int fb_gain, bool add); int32_t *fb_buf, int fb_gain, bool add);

@ -1864,9 +1864,6 @@ void set_fx_params(void)
modchorus_filter[instance_id]->setLowpass(2, MOD_FILTER_CUTOFF_HZ, 0.54); modchorus_filter[instance_id]->setLowpass(2, MOD_FILTER_CUTOFF_HZ, 0.54);
modchorus_filter[instance_id]->setLowpass(3, MOD_FILTER_CUTOFF_HZ, 1.3); modchorus_filter[instance_id]->setLowpass(3, MOD_FILTER_CUTOFF_HZ, 1.3);
#endif #endif
//chorus_mixer[instance_id]->gain(0, 1.0 - pseudo_log_curve(mapfloat(configuration.fx.chorus_level[instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 0.5)));
//chorus_mixer[instance_id]->gain(1, pseudo_log_curve(mapfloat(configuration.fx.chorus_level[instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 0.5)));
//chorus_mixer[instance_id]->gain(0, 1.0 - mapfloat(configuration.fx.chorus_level[instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 0.5));
chorus_mixer[instance_id]->gain(0, 1.0); chorus_mixer[instance_id]->gain(0, 1.0);
chorus_mixer[instance_id]->gain(1, mapfloat(configuration.fx.chorus_level[instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 0.5)); chorus_mixer[instance_id]->gain(1, mapfloat(configuration.fx.chorus_level[instance_id], CHORUS_LEVEL_MIN, CHORUS_LEVEL_MAX, 0.0, 0.5));

@ -1,18 +1,18 @@
/* /*
* Copyright 2013 Google Inc. Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
// A convenient wrapper for buffers with alignment constraints // A convenient wrapper for buffers with alignment constraints
@ -25,12 +25,12 @@
template<typename T, size_t size, size_t alignment = 16> template<typename T, size_t size, size_t alignment = 16>
class AlignedBuf { class AlignedBuf {
public: public:
T *get() { T *get() {
return (T *)((((intptr_t)storage_) + alignment - 1) & -alignment); return (T *)((((intptr_t)storage_) + alignment - 1) & -alignment);
} }
private: private:
unsigned char storage_[size * sizeof(T) + alignment]; unsigned char storage_[size * sizeof(T) + alignment];
}; };
#endif // __ALIGNED_BUF_H #endif // __ALIGNED_BUF_H

@ -114,7 +114,7 @@
#define MOD_FILTER_OUTPUT MOD_BUTTERWORTH_FILTER_OUTPUT // MOD_LINKWITZ_RILEY_FILTER_OUTPUT MOD_BUTTERWORTH_FILTER_OUTPUT MOD_NO_FILTER_OUTPUT #define MOD_FILTER_OUTPUT MOD_BUTTERWORTH_FILTER_OUTPUT // MOD_LINKWITZ_RILEY_FILTER_OUTPUT MOD_BUTTERWORTH_FILTER_OUTPUT MOD_NO_FILTER_OUTPUT
#define MOD_FILTER_CUTOFF_HZ 2000 #define MOD_FILTER_CUTOFF_HZ 2000
// REVERB parameters // REVERB parameters
#define REVERB_ANTIALIAS_FRQ 7500 //#define REVERB_ANTIALIAS_FRQ 7500
//#define PATCHED_FREEVERB 1 //#define PATCHED_FREEVERB 1
#define FREEVERB_FLOAT 1 #define FREEVERB_FLOAT 1
// ANTIALIAS frequency // ANTIALIAS frequency

@ -753,7 +753,7 @@ void Dexed::setATController(uint8_t at_range, uint8_t at_assign, uint8_t at_mode
void Dexed::setPortamentoMode(uint8_t portamento_mode, uint8_t portamento_glissando, uint8_t portamento_time) void Dexed::setPortamentoMode(uint8_t portamento_mode, uint8_t portamento_glissando, uint8_t portamento_time)
{ {
controllers.portamento_cc = portamento_time; controllers.portamento_cc = portamento_time;
controllers.portamento_enable_cc=portamento_mode>63; controllers.portamento_enable_cc = portamento_mode > 63;
if (portamento_time > 0) if (portamento_time > 0)
controllers.portamento_enable_cc = true; controllers.portamento_enable_cc = true;

@ -1,28 +1,28 @@
/* Audio Library for Teensy 3.X /* Audio Library for Teensy 3.X
* Copyright (c) 2018, Paul Stoffregen, paul@pjrc.com Copyright (c) 2018, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products. open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software. notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. THE SOFTWARE.
*/ */
// A Floating point implementation of Freeverb by Jezar at Dreampoint // A Floating point implementation of Freeverb by Jezar at Dreampoint
// http://blog.bjornroche.com/2012/06/freeverb-original-public-domain-code-by.html // http://blog.bjornroche.com/2012/06/freeverb-original-public-domain-code-by.html
@ -34,41 +34,41 @@
AudioEffectFreeverbFloat::AudioEffectFreeverbFloat() : AudioStream(1, inputQueueArray) AudioEffectFreeverbFloat::AudioEffectFreeverbFloat() : AudioStream(1, inputQueueArray)
{ {
for(unsigned int i = 0; i < sizeof(comb1buf)/sizeof(float); i++) comb1buf[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb1buf) / sizeof(float); i++) comb1buf[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb2buf)/sizeof(float); i++) comb2buf[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb2buf) / sizeof(float); i++) comb2buf[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb3buf)/sizeof(float); i++) comb3buf[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb3buf) / sizeof(float); i++) comb3buf[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb4buf)/sizeof(float); i++) comb4buf[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb4buf) / sizeof(float); i++) comb4buf[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb5buf)/sizeof(float); i++) comb5buf[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb5buf) / sizeof(float); i++) comb5buf[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb6buf)/sizeof(float); i++) comb6buf[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb6buf) / sizeof(float); i++) comb6buf[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb7buf)/sizeof(float); i++) comb7buf[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb7buf) / sizeof(float); i++) comb7buf[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb8buf)/sizeof(float); i++) comb8buf[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb8buf) / sizeof(float); i++) comb8buf[i] = 0.0;
comb1index = 0; comb1index = 0;
comb2index = 0; comb2index = 0;
comb3index = 0; comb3index = 0;
comb4index = 0; comb4index = 0;
comb5index = 0; comb5index = 0;
comb6index = 0; comb6index = 0;
comb7index = 0; comb7index = 0;
comb8index = 0; comb8index = 0;
comb1filter = 0.0; comb1filter = 0.0;
comb2filter = 0.0; comb2filter = 0.0;
comb3filter = 0.0; comb3filter = 0.0;
comb4filter = 0.0; comb4filter = 0.0;
comb5filter = 0.0; comb5filter = 0.0;
comb6filter = 0.0; comb6filter = 0.0;
comb7filter = 0.0; comb7filter = 0.0;
comb8filter = 0.0; comb8filter = 0.0;
combdamp1 = 6553.0; combdamp1 = 6553.0;
combdamp2 = 26215.0; combdamp2 = 26215.0;
combfeeback = 27524.0; combfeeback = 27524.0;
for(unsigned int i = 0; i < sizeof(allpass1buf)/sizeof(float); i++) allpass1buf[i] = 0.0; for (unsigned int i = 0; i < sizeof(allpass1buf) / sizeof(float); i++) allpass1buf[i] = 0.0;
for(unsigned int i = 0; i < sizeof(allpass2buf)/sizeof(float); i++) allpass2buf[i] = 0.0; for (unsigned int i = 0; i < sizeof(allpass2buf) / sizeof(float); i++) allpass2buf[i] = 0.0;
for(unsigned int i = 0; i < sizeof(allpass3buf)/sizeof(float); i++) allpass3buf[i] = 0.0; for (unsigned int i = 0; i < sizeof(allpass3buf) / sizeof(float); i++) allpass3buf[i] = 0.0;
for(unsigned int i = 0; i < sizeof(allpass4buf)/sizeof(float); i++) allpass4buf[i] = 0.0; for (unsigned int i = 0; i < sizeof(allpass4buf) / sizeof(float); i++) allpass4buf[i] = 0.0;
allpass1index = 0; allpass1index = 0;
allpass2index = 0; allpass2index = 0;
allpass3index = 0; allpass3index = 0;
allpass4index = 0; allpass4index = 0;
} }
#if 0 #if 0
@ -76,23 +76,23 @@ AudioEffectFreeverbFloat::AudioEffectFreeverbFloat() : AudioStream(1, inputQueue
#else #else
// cleaner sat16 by http://www.moseleyinstruments.com/ // cleaner sat16 by http://www.moseleyinstruments.com/
static int16_t sat16i(int32_t n, int rshift) { static int16_t sat16i(int32_t n, int rshift) {
// we should always round towards 0 // we should always round towards 0
// to avoid recirculating round-off noise // to avoid recirculating round-off noise
// //
// a 2s complement positive number is always // a 2s complement positive number is always
// rounded down, so we only need to take // rounded down, so we only need to take
// care of negative numbers // care of negative numbers
if (n < 0) { if (n < 0) {
n = n + (~(0xFFFFFFFFUL << rshift)); n = n + (~(0xFFFFFFFFUL << rshift));
} }
n = n >> rshift; n = n >> rshift;
if (n > 32767) { if (n > 32767) {
return 32767; return 32767;
} }
if (n < -32768) { if (n < -32768) {
return -32768; return -32768;
} }
return n; return n;
} }
#endif #endif
@ -105,405 +105,406 @@ static int16_t sat16i(int32_t n, int rshift) {
// care of negative numbers // care of negative numbers
n = n / (float) (1<<rshift); n = n / (float) (1<<rshift);
return n; return n;
} */ } */
// TODO: move this to one of the data files, use in output_adat.cpp, output_tdm.cpp, etc // TODO: move this to one of the data files, use in output_adat.cpp, output_tdm.cpp, etc
static const audio_block_t zeroblock = { static const audio_block_t zeroblock = {
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, 0, 0, 0, 0, 0,
#if AUDIO_BLOCK_SAMPLES > 16 #if AUDIO_BLOCK_SAMPLES > 16
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,
#endif #endif
#if AUDIO_BLOCK_SAMPLES > 32 #if AUDIO_BLOCK_SAMPLES > 32
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,
#endif #endif
#if AUDIO_BLOCK_SAMPLES > 48 #if AUDIO_BLOCK_SAMPLES > 48
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,
#endif #endif
#if AUDIO_BLOCK_SAMPLES > 64 #if AUDIO_BLOCK_SAMPLES > 64
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,
#endif #endif
#if AUDIO_BLOCK_SAMPLES > 80 #if AUDIO_BLOCK_SAMPLES > 80
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,
#endif #endif
#if AUDIO_BLOCK_SAMPLES > 96 #if AUDIO_BLOCK_SAMPLES > 96
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,
#endif #endif
#if AUDIO_BLOCK_SAMPLES > 112 #if AUDIO_BLOCK_SAMPLES > 112
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,
#endif #endif
} }; }
};
void AudioEffectFreeverbFloat::update() void AudioEffectFreeverbFloat::update()
{ {
#if defined(__ARM_ARCH_7EM__) #if defined(__ARM_ARCH_7EM__)
const audio_block_t *block; const audio_block_t *block;
audio_block_t *outblock; audio_block_t *outblock;
int i; int i;
float input, bufout, output; float input, bufout, output;
float sum; float sum;
outblock = allocate(); outblock = allocate();
if (!outblock) { if (!outblock) {
audio_block_t *tmp = receiveReadOnly(0); audio_block_t *tmp = receiveReadOnly(0);
if (tmp) release(tmp); if (tmp) release(tmp);
return; return;
} }
block = receiveReadOnly(0); block = receiveReadOnly(0);
if (!block) block = &zeroblock; if (!block) block = &zeroblock;
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
// TODO: scale numerical range depending on roomsize & damping // TODO: scale numerical range depending on roomsize & damping
//input = sat16(block->data[i] * 8738, 17); // for numerical headroom //input = sat16(block->data[i] * 8738, 17); // for numerical headroom
input = (float)block->data[i] / 32768.0f; input = (float)block->data[i] / 32768.0f;
sum = 0; sum = 0;
bufout = comb1buf[comb1index]; bufout = comb1buf[comb1index];
sum += bufout; sum += bufout;
comb1filter = bufout * combdamp2 + comb1filter * combdamp1; comb1filter = bufout * combdamp2 + comb1filter * combdamp1;
comb1buf[comb1index] = input + comb1filter * combfeeback; comb1buf[comb1index] = input + comb1filter * combfeeback;
if (++comb1index >= sizeof(comb1buf)/sizeof(float)) comb1index = 0; if (++comb1index >= sizeof(comb1buf) / sizeof(float)) comb1index = 0;
bufout = comb2buf[comb2index]; bufout = comb2buf[comb2index];
sum += bufout; sum += bufout;
comb2filter = bufout * combdamp2 + comb2filter * combdamp1; comb2filter = bufout * combdamp2 + comb2filter * combdamp1;
comb2buf[comb2index] = input + comb2filter * combfeeback; comb2buf[comb2index] = input + comb2filter * combfeeback;
if (++comb2index >= sizeof(comb2buf)/sizeof(float)) comb2index = 0; if (++comb2index >= sizeof(comb2buf) / sizeof(float)) comb2index = 0;
bufout = comb3buf[comb3index]; bufout = comb3buf[comb3index];
sum += bufout; sum += bufout;
comb3filter = bufout * combdamp2 + comb3filter * combdamp1; comb3filter = bufout * combdamp2 + comb3filter * combdamp1;
comb3buf[comb3index] = input + comb3filter * combfeeback; comb3buf[comb3index] = input + comb3filter * combfeeback;
if (++comb3index >= sizeof(comb3buf)/sizeof(float)) comb3index = 0; if (++comb3index >= sizeof(comb3buf) / sizeof(float)) comb3index = 0;
bufout = comb4buf[comb4index]; bufout = comb4buf[comb4index];
sum += bufout; sum += bufout;
comb4filter = bufout * combdamp2 + comb4filter * combdamp1; comb4filter = bufout * combdamp2 + comb4filter * combdamp1;
comb4buf[comb4index] = input + comb4filter * combfeeback; comb4buf[comb4index] = input + comb4filter * combfeeback;
if (++comb4index >= sizeof(comb4buf)/sizeof(float)) comb4index = 0; if (++comb4index >= sizeof(comb4buf) / sizeof(float)) comb4index = 0;
bufout = comb5buf[comb5index]; bufout = comb5buf[comb5index];
sum += bufout; sum += bufout;
comb5filter = bufout * combdamp2 + comb5filter * combdamp1; comb5filter = bufout * combdamp2 + comb5filter * combdamp1;
comb5buf[comb5index] = input + comb5filter * combfeeback; comb5buf[comb5index] = input + comb5filter * combfeeback;
if (++comb5index >= sizeof(comb5buf)/sizeof(float)) comb5index = 0; if (++comb5index >= sizeof(comb5buf) / sizeof(float)) comb5index = 0;
bufout = comb6buf[comb6index]; bufout = comb6buf[comb6index];
sum += bufout; sum += bufout;
comb6filter = bufout * combdamp2 + comb6filter * combdamp1; comb6filter = bufout * combdamp2 + comb6filter * combdamp1;
comb6buf[comb6index] = input + comb6filter * combfeeback; comb6buf[comb6index] = input + comb6filter * combfeeback;
if (++comb6index >= sizeof(comb6buf)/sizeof(float)) comb6index = 0; if (++comb6index >= sizeof(comb6buf) / sizeof(float)) comb6index = 0;
bufout = comb7buf[comb7index]; bufout = comb7buf[comb7index];
sum += bufout; sum += bufout;
comb7filter = bufout * combdamp2 + comb7filter * combdamp1; comb7filter = bufout * combdamp2 + comb7filter * combdamp1;
comb7buf[comb7index] = input + comb7filter * combfeeback; comb7buf[comb7index] = input + comb7filter * combfeeback;
if (++comb7index >= sizeof(comb7buf)/sizeof(float)) comb7index = 0; if (++comb7index >= sizeof(comb7buf) / sizeof(float)) comb7index = 0;
bufout = comb8buf[comb8index]; bufout = comb8buf[comb8index];
sum += bufout; sum += bufout;
comb8filter = bufout * combdamp2 + comb8filter * combdamp1; comb8filter = bufout * combdamp2 + comb8filter * combdamp1;
comb8buf[comb8index] = input + comb8filter * combfeeback; comb8buf[comb8index] = input + comb8filter * combfeeback;
if (++comb8index >= sizeof(comb8buf)/sizeof(float)) comb8index = 0; if (++comb8index >= sizeof(comb8buf) / sizeof(float)) comb8index = 0;
//output = sat16(sum * 31457.0, 17); //output = sat16(sum * 31457.0, 17);
//output = sum * 31457.0/131072.0f; //output = sum * 31457.0/131072.0f;
output = sum; output = sum;
bufout = allpass1buf[allpass1index]; bufout = allpass1buf[allpass1index];
allpass1buf[allpass1index] = output + (bufout / 2.0); allpass1buf[allpass1index] = output + (bufout / 2.0);
output = (bufout - output) /2.0; output = (bufout - output) / 2.0;
if (++allpass1index >= sizeof(allpass1buf)/sizeof(float)) allpass1index = 0; if (++allpass1index >= sizeof(allpass1buf) / sizeof(float)) allpass1index = 0;
bufout = allpass2buf[allpass2index]; bufout = allpass2buf[allpass2index];
allpass2buf[allpass2index] = output + (bufout / 2.0); allpass2buf[allpass2index] = output + (bufout / 2.0);
output = (bufout - output) /2.0; output = (bufout - output) / 2.0;
if (++allpass2index >= sizeof(allpass2buf)/sizeof(float)) allpass2index = 0; if (++allpass2index >= sizeof(allpass2buf) / sizeof(float)) allpass2index = 0;
bufout = allpass3buf[allpass3index]; bufout = allpass3buf[allpass3index];
allpass3buf[allpass3index] = output + (bufout / 2.0); allpass3buf[allpass3index] = output + (bufout / 2.0);
output = (bufout - output) /2.0; output = (bufout - output) / 2.0;
if (++allpass3index >= sizeof(allpass3buf)/sizeof(float)) allpass3index = 0; if (++allpass3index >= sizeof(allpass3buf) / sizeof(float)) allpass3index = 0;
bufout = allpass4buf[allpass4index]; bufout = allpass4buf[allpass4index];
allpass4buf[allpass4index] = output + (bufout / 2.0); allpass4buf[allpass4index] = output + (bufout / 2.0);
output = (bufout - output) /2.0; output = (bufout - output) / 2.0;
if (++allpass4index >= sizeof(allpass4buf)/sizeof(float)) allpass4index = 0; if (++allpass4index >= sizeof(allpass4buf) / sizeof(float)) allpass4index = 0;
//outblock->data[i] = sat16i(output * 30.0, 0); //outblock->data[i] = sat16i(output * 30.0, 0);
outblock->data[i] = sat16i(output * 32768.0, 0); outblock->data[i] = sat16i(output * 32768.0, 0);
} }
transmit(outblock); transmit(outblock);
release(outblock); release(outblock);
if (block != &zeroblock) release((audio_block_t *)block); if (block != &zeroblock) release((audio_block_t *)block);
#elif defined(KINETISL) #elif defined(KINETISL)
audio_block_t *block; audio_block_t *block;
block = receiveReadOnly(0); block = receiveReadOnly(0);
if (block) release(block); if (block) release(block);
#endif #endif
} }
AudioEffectFreeverbStereoFloat::AudioEffectFreeverbStereoFloat() : AudioStream(1, inputQueueArray) AudioEffectFreeverbStereoFloat::AudioEffectFreeverbStereoFloat() : AudioStream(1, inputQueueArray)
{ {
for(unsigned int i = 0; i < sizeof(comb1bufL)/sizeof(float); i++) comb1bufL[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb1bufL) / sizeof(float); i++) comb1bufL[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb2bufL)/sizeof(float); i++) comb2bufL[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb2bufL) / sizeof(float); i++) comb2bufL[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb3bufL)/sizeof(float); i++) comb3bufL[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb3bufL) / sizeof(float); i++) comb3bufL[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb4bufL)/sizeof(float); i++) comb4bufL[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb4bufL) / sizeof(float); i++) comb4bufL[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb5bufL)/sizeof(float); i++) comb5bufL[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb5bufL) / sizeof(float); i++) comb5bufL[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb6bufL)/sizeof(float); i++) comb6bufL[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb6bufL) / sizeof(float); i++) comb6bufL[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb7bufL)/sizeof(float); i++) comb7bufL[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb7bufL) / sizeof(float); i++) comb7bufL[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb8bufL)/sizeof(float); i++) comb8bufL[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb8bufL) / sizeof(float); i++) comb8bufL[i] = 0.0;
comb1indexL = 0; comb1indexL = 0;
comb2indexL = 0; comb2indexL = 0;
comb3indexL = 0; comb3indexL = 0;
comb4indexL = 0; comb4indexL = 0;
comb5indexL = 0; comb5indexL = 0;
comb6indexL = 0; comb6indexL = 0;
comb7indexL = 0; comb7indexL = 0;
comb8indexL = 0; comb8indexL = 0;
comb1filterL = 0.0; comb1filterL = 0.0;
comb2filterL = 0.0; comb2filterL = 0.0;
comb3filterL = 0.0; comb3filterL = 0.0;
comb4filterL = 0.0; comb4filterL = 0.0;
comb5filterL = 0.0; comb5filterL = 0.0;
comb6filterL = 0.0; comb6filterL = 0.0;
comb7filterL = 0.0; comb7filterL = 0.0;
comb8filterL = 0.0; comb8filterL = 0.0;
for(unsigned int i = 0; i < sizeof(comb1bufR)/sizeof(float); i++) comb1bufR[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb1bufR) / sizeof(float); i++) comb1bufR[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb2bufR)/sizeof(float); i++) comb2bufR[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb2bufR) / sizeof(float); i++) comb2bufR[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb3bufR)/sizeof(float); i++) comb3bufR[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb3bufR) / sizeof(float); i++) comb3bufR[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb4bufR)/sizeof(float); i++) comb4bufR[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb4bufR) / sizeof(float); i++) comb4bufR[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb5bufR)/sizeof(float); i++) comb5bufR[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb5bufR) / sizeof(float); i++) comb5bufR[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb6bufR)/sizeof(float); i++) comb6bufR[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb6bufR) / sizeof(float); i++) comb6bufR[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb7bufR)/sizeof(float); i++) comb7bufR[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb7bufR) / sizeof(float); i++) comb7bufR[i] = 0.0;
for(unsigned int i = 0; i < sizeof(comb8bufR)/sizeof(float); i++) comb8bufR[i] = 0.0; for (unsigned int i = 0; i < sizeof(comb8bufR) / sizeof(float); i++) comb8bufR[i] = 0.0;
comb1indexR = 0; comb1indexR = 0;
comb2indexR = 0; comb2indexR = 0;
comb3indexR = 0; comb3indexR = 0;
comb4indexR = 0; comb4indexR = 0;
comb5indexR = 0; comb5indexR = 0;
comb6indexR = 0; comb6indexR = 0;
comb7indexR = 0; comb7indexR = 0;
comb8indexR = 0; comb8indexR = 0;
comb1filterR = 0.0; comb1filterR = 0.0;
comb2filterR = 0.0; comb2filterR = 0.0;
comb3filterR = 0.0; comb3filterR = 0.0;
comb4filterR = 0.0; comb4filterR = 0.0;
comb5filterR = 0.0; comb5filterR = 0.0;
comb6filterR = 0.0; comb6filterR = 0.0;
comb7filterR = 0.0; comb7filterR = 0.0;
comb8filterR = 0.0; comb8filterR = 0.0;
combdamp1 = 6553.0; combdamp1 = 6553.0;
combdamp2 = 26215.0; combdamp2 = 26215.0;
combfeeback = 27524.0; combfeeback = 27524.0;
for(unsigned int i = 0; i < sizeof(allpass1bufL)/sizeof(float); i++) allpass1bufL[i] = 0.0; for (unsigned int i = 0; i < sizeof(allpass1bufL) / sizeof(float); i++) allpass1bufL[i] = 0.0;
for(unsigned int i = 0; i < sizeof(allpass2bufL)/sizeof(float); i++) allpass2bufL[i] = 0.0; for (unsigned int i = 0; i < sizeof(allpass2bufL) / sizeof(float); i++) allpass2bufL[i] = 0.0;
for(unsigned int i = 0; i < sizeof(allpass3bufL)/sizeof(float); i++) allpass3bufL[i] = 0.0; for (unsigned int i = 0; i < sizeof(allpass3bufL) / sizeof(float); i++) allpass3bufL[i] = 0.0;
for(unsigned int i = 0; i < sizeof(allpass4bufL)/sizeof(float); i++) allpass4bufL[i] = 0.0; for (unsigned int i = 0; i < sizeof(allpass4bufL) / sizeof(float); i++) allpass4bufL[i] = 0.0;
allpass1indexL = 0; allpass1indexL = 0;
allpass2indexL = 0; allpass2indexL = 0;
allpass3indexL = 0; allpass3indexL = 0;
allpass4indexL = 0; allpass4indexL = 0;
for(unsigned int i = 0; i < sizeof(allpass1bufR)/sizeof(float); i++) allpass1bufR[i] = 0.0; for (unsigned int i = 0; i < sizeof(allpass1bufR) / sizeof(float); i++) allpass1bufR[i] = 0.0;
for(unsigned int i = 0; i < sizeof(allpass2bufR)/sizeof(float); i++) allpass2bufR[i] = 0.0; for (unsigned int i = 0; i < sizeof(allpass2bufR) / sizeof(float); i++) allpass2bufR[i] = 0.0;
for(unsigned int i = 0; i < sizeof(allpass3bufR)/sizeof(float); i++) allpass3bufR[i] = 0.0; for (unsigned int i = 0; i < sizeof(allpass3bufR) / sizeof(float); i++) allpass3bufR[i] = 0.0;
for(unsigned int i = 0; i < sizeof(allpass4bufR)/sizeof(float); i++) allpass4bufR[i] = 0.0; for (unsigned int i = 0; i < sizeof(allpass4bufR) / sizeof(float); i++) allpass4bufR[i] = 0.0;
allpass1indexR = 0; allpass1indexR = 0;
allpass2indexR = 0; allpass2indexR = 0;
allpass3indexR = 0; allpass3indexR = 0;
allpass4indexR = 0; allpass4indexR = 0;
} }
void AudioEffectFreeverbStereoFloat::update() void AudioEffectFreeverbStereoFloat::update()
{ {
#if defined(__ARM_ARCH_7EM__) #if defined(__ARM_ARCH_7EM__)
const audio_block_t *block; const audio_block_t *block;
audio_block_t *outblockL; audio_block_t *outblockL;
audio_block_t *outblockR; audio_block_t *outblockR;
int i; int i;
float input, bufout, outputL, outputR; float input, bufout, outputL, outputR;
float sum; float sum;
block = receiveReadOnly(0); block = receiveReadOnly(0);
outblockL = allocate(); outblockL = allocate();
outblockR = allocate(); outblockR = allocate();
if (!outblockL || !outblockR) { if (!outblockL || !outblockR) {
if (outblockL) release(outblockL); if (outblockL) release(outblockL);
if (outblockR) release(outblockR); if (outblockR) release(outblockR);
if (block) release((audio_block_t *)block); if (block) release((audio_block_t *)block);
return; return;
} }
if (!block) block = &zeroblock; if (!block) block = &zeroblock;
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
// TODO: scale numerical range depending on roomsize & damping // TODO: scale numerical range depending on roomsize & damping
//input = sat16(block->data[i] * 8738.0, 17); // for numerical headroom //input = sat16(block->data[i] * 8738.0, 17); // for numerical headroom
input = block->data[i] / 32768.0; input = block->data[i] / 32768.0;
sum = 0; sum = 0;
bufout = comb1bufL[comb1indexL]; bufout = comb1bufL[comb1indexL];
sum += bufout; sum += bufout;
comb1filterL = bufout * combdamp2 + comb1filterL * combdamp1; comb1filterL = bufout * combdamp2 + comb1filterL * combdamp1;
comb1bufL[comb1indexL] = input + comb1filterL * combfeeback; comb1bufL[comb1indexL] = input + comb1filterL * combfeeback;
if (++comb1indexL >= sizeof(comb1bufL)/sizeof(float)) comb1indexL = 0; if (++comb1indexL >= sizeof(comb1bufL) / sizeof(float)) comb1indexL = 0;
bufout = comb2bufL[comb2indexL]; bufout = comb2bufL[comb2indexL];
sum += bufout; sum += bufout;
comb2filterL = bufout * combdamp2 + comb2filterL * combdamp1; comb2filterL = bufout * combdamp2 + comb2filterL * combdamp1;
comb2bufL[comb2indexL] = input + comb2filterL * combfeeback; comb2bufL[comb2indexL] = input + comb2filterL * combfeeback;
if (++comb2indexL >= sizeof(comb2bufL)/sizeof(float)) comb2indexL = 0; if (++comb2indexL >= sizeof(comb2bufL) / sizeof(float)) comb2indexL = 0;
bufout = comb3bufL[comb3indexL]; bufout = comb3bufL[comb3indexL];
sum += bufout; sum += bufout;
comb3filterL = bufout * combdamp2 + comb3filterL * combdamp1; comb3filterL = bufout * combdamp2 + comb3filterL * combdamp1;
comb3bufL[comb3indexL] = input + comb3filterL * combfeeback; comb3bufL[comb3indexL] = input + comb3filterL * combfeeback;
if (++comb3indexL >= sizeof(comb3bufL)/sizeof(float)) comb3indexL = 0; if (++comb3indexL >= sizeof(comb3bufL) / sizeof(float)) comb3indexL = 0;
bufout = comb4bufL[comb4indexL]; bufout = comb4bufL[comb4indexL];
sum += bufout; sum += bufout;
comb4filterL = bufout * combdamp2 + comb4filterL * combdamp1; comb4filterL = bufout * combdamp2 + comb4filterL * combdamp1;
comb4bufL[comb4indexL] = input +comb4filterL * combfeeback; comb4bufL[comb4indexL] = input + comb4filterL * combfeeback;
if (++comb4indexL >= sizeof(comb4bufL)/sizeof(float)) comb4indexL = 0; if (++comb4indexL >= sizeof(comb4bufL) / sizeof(float)) comb4indexL = 0;
bufout = comb5bufL[comb5indexL]; bufout = comb5bufL[comb5indexL];
sum += bufout; sum += bufout;
comb5filterL = bufout * combdamp2 + comb5filterL * combdamp1; comb5filterL = bufout * combdamp2 + comb5filterL * combdamp1;
comb5bufL[comb5indexL] = input + comb5filterL * combfeeback; comb5bufL[comb5indexL] = input + comb5filterL * combfeeback;
if (++comb5indexL >= sizeof(comb5bufL)/sizeof(float)) comb5indexL = 0; if (++comb5indexL >= sizeof(comb5bufL) / sizeof(float)) comb5indexL = 0;
bufout = comb6bufL[comb6indexL]; bufout = comb6bufL[comb6indexL];
sum += bufout; sum += bufout;
comb6filterL = bufout * combdamp2 + comb6filterL * combdamp1; comb6filterL = bufout * combdamp2 + comb6filterL * combdamp1;
comb6bufL[comb6indexL] = input + comb6filterL * combfeeback; comb6bufL[comb6indexL] = input + comb6filterL * combfeeback;
if (++comb6indexL >= sizeof(comb6bufL)/sizeof(float)) comb6indexL = 0; if (++comb6indexL >= sizeof(comb6bufL) / sizeof(float)) comb6indexL = 0;
bufout = comb7bufL[comb7indexL]; bufout = comb7bufL[comb7indexL];
sum += bufout; sum += bufout;
comb7filterL = bufout * combdamp2 + comb7filterL * combdamp1; comb7filterL = bufout * combdamp2 + comb7filterL * combdamp1;
comb7bufL[comb7indexL] = input + comb7filterL * combfeeback; comb7bufL[comb7indexL] = input + comb7filterL * combfeeback;
if (++comb7indexL >= sizeof(comb7bufL)/sizeof(float)) comb7indexL = 0; if (++comb7indexL >= sizeof(comb7bufL) / sizeof(float)) comb7indexL = 0;
bufout = comb8bufL[comb8indexL]; bufout = comb8bufL[comb8indexL];
sum += bufout; sum += bufout;
comb8filterL = bufout * combdamp2 + comb8filterL * combdamp1; comb8filterL = bufout * combdamp2 + comb8filterL * combdamp1;
comb8bufL[comb8indexL] = input + comb8filterL * combfeeback; comb8bufL[comb8indexL] = input + comb8filterL * combfeeback;
if (++comb8indexL >= sizeof(comb8bufL)/sizeof(float)) comb8indexL = 0; if (++comb8indexL >= sizeof(comb8bufL) / sizeof(float)) comb8indexL = 0;
//outputL = sat16(sum * 31457, 17); //outputL = sat16(sum * 31457, 17);
//outputL = sum * 31457.0/131072.0f; //outputL = sum * 31457.0/131072.0f;
outputL = sum; outputL = sum;
sum = 0.0; sum = 0.0;
bufout = comb1bufR[comb1indexR]; bufout = comb1bufR[comb1indexR];
sum += bufout; sum += bufout;
comb1filterR = bufout * combdamp2 + comb1filterR * combdamp1; comb1filterR = bufout * combdamp2 + comb1filterR * combdamp1;
comb1bufR[comb1indexR] = input + comb1filterR * combfeeback; comb1bufR[comb1indexR] = input + comb1filterR * combfeeback;
if (++comb1indexR >= sizeof(comb1bufR)/sizeof(float)) comb1indexR = 0; if (++comb1indexR >= sizeof(comb1bufR) / sizeof(float)) comb1indexR = 0;
bufout = comb2bufR[comb2indexR]; bufout = comb2bufR[comb2indexR];
sum += bufout; sum += bufout;
comb2filterR = bufout * combdamp2 + comb2filterR * combdamp1; comb2filterR = bufout * combdamp2 + comb2filterR * combdamp1;
comb2bufR[comb2indexR] = input + comb2filterR * combfeeback; comb2bufR[comb2indexR] = input + comb2filterR * combfeeback;
if (++comb2indexR >= sizeof(comb2bufR)/sizeof(float)) comb2indexR = 0; if (++comb2indexR >= sizeof(comb2bufR) / sizeof(float)) comb2indexR = 0;
bufout = comb3bufR[comb3indexR]; bufout = comb3bufR[comb3indexR];
sum += bufout; sum += bufout;
comb3filterR = bufout * combdamp2 + comb3filterR * combdamp1; comb3filterR = bufout * combdamp2 + comb3filterR * combdamp1;
comb3bufR[comb3indexR] = input + comb3filterR * combfeeback; comb3bufR[comb3indexR] = input + comb3filterR * combfeeback;
if (++comb3indexR >= sizeof(comb3bufR)/sizeof(float)) comb3indexR = 0; if (++comb3indexR >= sizeof(comb3bufR) / sizeof(float)) comb3indexR = 0;
bufout = comb4bufR[comb4indexR]; bufout = comb4bufR[comb4indexR];
sum += bufout; sum += bufout;
comb4filterR = bufout * combdamp2 + comb4filterR * combdamp1; comb4filterR = bufout * combdamp2 + comb4filterR * combdamp1;
comb4bufR[comb4indexR] = input + comb4filterR * combfeeback; comb4bufR[comb4indexR] = input + comb4filterR * combfeeback;
if (++comb4indexR >= sizeof(comb4bufR)/sizeof(float)) comb4indexR = 0; if (++comb4indexR >= sizeof(comb4bufR) / sizeof(float)) comb4indexR = 0;
bufout = comb5bufR[comb5indexR]; bufout = comb5bufR[comb5indexR];
sum += bufout; sum += bufout;
comb5filterR = bufout * combdamp2 + comb5filterR * combdamp1; comb5filterR = bufout * combdamp2 + comb5filterR * combdamp1;
comb5bufR[comb5indexR] = input + comb5filterR * combfeeback; comb5bufR[comb5indexR] = input + comb5filterR * combfeeback;
if (++comb5indexR >= sizeof(comb5bufR)/sizeof(float)) comb5indexR = 0; if (++comb5indexR >= sizeof(comb5bufR) / sizeof(float)) comb5indexR = 0;
bufout = comb6bufR[comb6indexR]; bufout = comb6bufR[comb6indexR];
sum += bufout; sum += bufout;
comb6filterR = bufout * combdamp2 + comb6filterR * combdamp1; comb6filterR = bufout * combdamp2 + comb6filterR * combdamp1;
comb6bufR[comb6indexR] = input + comb6filterR * combfeeback; comb6bufR[comb6indexR] = input + comb6filterR * combfeeback;
if (++comb6indexR >= sizeof(comb6bufR)/sizeof(float)) comb6indexR = 0; if (++comb6indexR >= sizeof(comb6bufR) / sizeof(float)) comb6indexR = 0;
bufout = comb7bufR[comb7indexR]; bufout = comb7bufR[comb7indexR];
sum += bufout; sum += bufout;
comb7filterR = bufout * combdamp2 + comb7filterR * combdamp1; comb7filterR = bufout * combdamp2 + comb7filterR * combdamp1;
comb7bufR[comb7indexR] = input + comb7filterR * combfeeback; comb7bufR[comb7indexR] = input + comb7filterR * combfeeback;
if (++comb7indexR >= sizeof(comb7bufR)/sizeof(float)) comb7indexR = 0; if (++comb7indexR >= sizeof(comb7bufR) / sizeof(float)) comb7indexR = 0;
bufout = comb8bufR[comb8indexR]; bufout = comb8bufR[comb8indexR];
sum += bufout; sum += bufout;
comb8filterR = bufout * combdamp2 + comb8filterR * combdamp1; comb8filterR = bufout * combdamp2 + comb8filterR * combdamp1;
comb8bufR[comb8indexR] = input + comb8filterR * combfeeback; comb8bufR[comb8indexR] = input + comb8filterR * combfeeback;
if (++comb8indexR >= sizeof(comb8bufR)/sizeof(float)) comb8indexR = 0; if (++comb8indexR >= sizeof(comb8bufR) / sizeof(float)) comb8indexR = 0;
//outputR = sat16(sum * 31457, 17); //outputR = sat16(sum * 31457, 17);
//outputR = sum * 31457.0/131072.0f; //outputR = sum * 31457.0/131072.0f;
outputR = sum; outputR = sum;
bufout = allpass1bufL[allpass1indexL]; bufout = allpass1bufL[allpass1indexL];
allpass1bufL[allpass1indexL] = outputL + (bufout / 2.0); allpass1bufL[allpass1indexL] = outputL + (bufout / 2.0);
outputL = (bufout - outputL)/2.0; outputL = (bufout - outputL) / 2.0;
if (++allpass1indexL >= sizeof(allpass1bufL)/sizeof(float)) allpass1indexL = 0; if (++allpass1indexL >= sizeof(allpass1bufL) / sizeof(float)) allpass1indexL = 0;
bufout = allpass2bufL[allpass2indexL]; bufout = allpass2bufL[allpass2indexL];
allpass2bufL[allpass2indexL] = outputL + (bufout / 2.0); allpass2bufL[allpass2indexL] = outputL + (bufout / 2.0);
outputL = (bufout - outputL)/2.0; outputL = (bufout - outputL) / 2.0;
if (++allpass2indexL >= sizeof(allpass2bufL)/sizeof(float)) allpass2indexL = 0; if (++allpass2indexL >= sizeof(allpass2bufL) / sizeof(float)) allpass2indexL = 0;
bufout = allpass3bufL[allpass3indexL]; bufout = allpass3bufL[allpass3indexL];
allpass3bufL[allpass3indexL] = outputL + (bufout / 2.0); allpass3bufL[allpass3indexL] = outputL + (bufout / 2.0);
outputL = (bufout - outputL)/2.0; outputL = (bufout - outputL) / 2.0;
if (++allpass3indexL >= sizeof(allpass3bufL)/sizeof(float)) allpass3indexL = 0; if (++allpass3indexL >= sizeof(allpass3bufL) / sizeof(float)) allpass3indexL = 0;
bufout = allpass4bufL[allpass4indexL]; bufout = allpass4bufL[allpass4indexL];
allpass4bufL[allpass4indexL] = outputL + (bufout / 2.0); allpass4bufL[allpass4indexL] = outputL + (bufout / 2.0);
outputL = (bufout - outputL)/2.0; outputL = (bufout - outputL) / 2.0;
if (++allpass4indexL >= sizeof(allpass4bufL)/sizeof(float)) allpass4indexL = 0; if (++allpass4indexL >= sizeof(allpass4bufL) / sizeof(float)) allpass4indexL = 0;
//outblockL->data[i] = sat16i(outputL * 30.0, 0); //outblockL->data[i] = sat16i(outputL * 30.0, 0);
outblockL->data[i] = sat16i(outputL * 32768.0, 0); outblockL->data[i] = sat16i(outputL * 32768.0, 0);
bufout = allpass1bufR[allpass1indexR]; bufout = allpass1bufR[allpass1indexR];
allpass1bufR[allpass1indexR] = outputR + (bufout / 2.0); allpass1bufR[allpass1indexR] = outputR + (bufout / 2.0);
//outputR = sat16(bufout - outputR, 1); //outputR = sat16(bufout - outputR, 1);
outputR = (bufout - outputR)/2.0; outputR = (bufout - outputR) / 2.0;
if (++allpass1indexR >= sizeof(allpass1bufR)/sizeof(float)) allpass1indexR = 0; if (++allpass1indexR >= sizeof(allpass1bufR) / sizeof(float)) allpass1indexR = 0;
bufout = allpass2bufR[allpass2indexR]; bufout = allpass2bufR[allpass2indexR];
allpass2bufR[allpass2indexR] = outputR + (bufout / 2.0); allpass2bufR[allpass2indexR] = outputR + (bufout / 2.0);
outputR = (bufout - outputR)/2.0; outputR = (bufout - outputR) / 2.0;
if (++allpass2indexR >= sizeof(allpass2bufR)/sizeof(float)) allpass2indexR = 0; if (++allpass2indexR >= sizeof(allpass2bufR) / sizeof(float)) allpass2indexR = 0;
bufout = allpass3bufR[allpass3indexR]; bufout = allpass3bufR[allpass3indexR];
allpass3bufR[allpass3indexR] = outputR + (bufout / 2.0); allpass3bufR[allpass3indexR] = outputR + (bufout / 2.0);
outputR = (bufout - outputR)/2.0; outputR = (bufout - outputR) / 2.0;
if (++allpass3indexR >= sizeof(allpass3bufR)/sizeof(float)) allpass3indexR = 0; if (++allpass3indexR >= sizeof(allpass3bufR) / sizeof(float)) allpass3indexR = 0;
bufout = allpass4bufR[allpass4indexR]; bufout = allpass4bufR[allpass4indexR];
allpass4bufR[allpass4indexR] = outputR + (bufout / 2.0); allpass4bufR[allpass4indexR] = outputR + (bufout / 2.0);
outputR = (bufout - outputR)/2.0; outputR = (bufout - outputR) / 2.0;
if (++allpass4indexR >= sizeof(allpass4bufR)/sizeof(float)) allpass4indexR = 0; if (++allpass4indexR >= sizeof(allpass4bufR) / sizeof(float)) allpass4indexR = 0;
//outblockR->data[i] = sat16i(outputR * 30.0, 0); //outblockR->data[i] = sat16i(outputR * 30.0, 0);
outblockR->data[i] = sat16i(outputR * 32768.0, 0); outblockR->data[i] = sat16i(outputR * 32768.0, 0);
} }
transmit(outblockL, 0); transmit(outblockL, 0);
transmit(outblockR, 1); transmit(outblockR, 1);
release(outblockL); release(outblockL);
release(outblockR); release(outblockR);
if (block != &zeroblock) release((audio_block_t *)block); if (block != &zeroblock) release((audio_block_t *)block);
#elif defined(KINETISL) #elif defined(KINETISL)
audio_block_t *block; audio_block_t *block;
block = receiveReadOnly(0); block = receiveReadOnly(0);
if (block) release(block); if (block) release(block);
#endif #endif
} }

@ -1,28 +1,28 @@
/* Audio Library for Teensy 3.X /* Audio Library for Teensy 3.X
* Copyright (c) 2018, Paul Stoffregen, paul@pjrc.com Copyright (c) 2018, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products. open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software. notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. THE SOFTWARE.
*/ */
#ifndef effect_freeverb_f_h_ #ifndef effect_freeverb_f_h_
#define effect_freeverb_f_h_ #define effect_freeverb_f_h_
@ -31,159 +31,159 @@
class AudioEffectFreeverbFloat : public AudioStream class AudioEffectFreeverbFloat : public AudioStream
{ {
public: public:
AudioEffectFreeverbFloat(); AudioEffectFreeverbFloat();
virtual void update(); virtual void update();
void roomsize(float n) { void roomsize(float n) {
if (n > 1.0f) n = 1.0f; if (n > 1.0f) n = 1.0f;
else if (n < 0.0) n = 0.0f; else if (n < 0.0) n = 0.0f;
//combfeeback = (n * 9175.04f) + 22937.0; //combfeeback = (n * 9175.04f) + 22937.0;
combfeeback = (n * 9175.04f/32768.0f) + 22937.0/32768.0f; combfeeback = (n * 9175.04f / 32768.0f) + 22937.0 / 32768.0f;
} }
void damping(float n) { void damping(float n) {
if (n > 1.0f) n = 1.0f; if (n > 1.0f) n = 1.0f;
else if (n < 0.0) n = 0.0f; else if (n < 0.0) n = 0.0f;
//float x1 = (n * 13107.2f); //float x1 = (n * 13107.2f);
//float x2 = 32768.0 - x1; //float x2 = 32768.0 - x1;
float x1 = (n * 13107.2f/ 32768.0f); float x1 = (n * 13107.2f / 32768.0f);
float x2 = 1.0 - x1; float x2 = 1.0 - x1;
__disable_irq(); __disable_irq();
combdamp1 = x1; combdamp1 = x1;
combdamp2 = x2; combdamp2 = x2;
__enable_irq(); __enable_irq();
} }
private: private:
audio_block_t *inputQueueArray[1]; audio_block_t *inputQueueArray[1];
float comb1buf[1116]; float comb1buf[1116];
float comb2buf[1188]; float comb2buf[1188];
float comb3buf[1277]; float comb3buf[1277];
float comb4buf[1356]; float comb4buf[1356];
float comb5buf[1422]; float comb5buf[1422];
float comb6buf[1491]; float comb6buf[1491];
float comb7buf[1557]; float comb7buf[1557];
float comb8buf[1617]; float comb8buf[1617];
uint16_t comb1index; uint16_t comb1index;
uint16_t comb2index; uint16_t comb2index;
uint16_t comb3index; uint16_t comb3index;
uint16_t comb4index; uint16_t comb4index;
uint16_t comb5index; uint16_t comb5index;
uint16_t comb6index; uint16_t comb6index;
uint16_t comb7index; uint16_t comb7index;
uint16_t comb8index; uint16_t comb8index;
float comb1filter; float comb1filter;
float comb2filter; float comb2filter;
float comb3filter; float comb3filter;
float comb4filter; float comb4filter;
float comb5filter; float comb5filter;
float comb6filter; float comb6filter;
float comb7filter; float comb7filter;
float comb8filter; float comb8filter;
float combdamp1; float combdamp1;
float combdamp2; float combdamp2;
float combfeeback; float combfeeback;
float allpass1buf[556]; float allpass1buf[556];
float allpass2buf[441]; float allpass2buf[441];
float allpass3buf[341]; float allpass3buf[341];
float allpass4buf[225]; float allpass4buf[225];
uint16_t allpass1index; uint16_t allpass1index;
uint16_t allpass2index; uint16_t allpass2index;
uint16_t allpass3index; uint16_t allpass3index;
uint16_t allpass4index; uint16_t allpass4index;
}; };
class AudioEffectFreeverbStereoFloat : public AudioStream class AudioEffectFreeverbStereoFloat : public AudioStream
{ {
public: public:
AudioEffectFreeverbStereoFloat(); AudioEffectFreeverbStereoFloat();
virtual void update(); virtual void update();
void roomsize(float n) { void roomsize(float n) {
if (n > 1.0f) n = 1.0f; if (n > 1.0f) n = 1.0f;
else if (n < 0.0) n = 0.0f; else if (n < 0.0) n = 0.0f;
//combfeeback = (n * 9175.04f) + 22937.0; //combfeeback = (n * 9175.04f) + 22937.0;
combfeeback = (n * 9175.04f/32768.0f) + 22937.0/32768.0f; combfeeback = (n * 9175.04f / 32768.0f) + 22937.0 / 32768.0f;
} }
void damping(float n) { void damping(float n) {
if (n > 1.0f) n = 1.0f; if (n > 1.0f) n = 1.0f;
else if (n < 0.0) n = 0.0f; else if (n < 0.0) n = 0.0f;
//float x1 = (n * 13107.2f); //float x1 = (n * 13107.2f);
//float x2 = 32768.0 - x1; //float x2 = 32768.0 - x1;
float x1 = (n * 13107.2f/ 32768.0f); float x1 = (n * 13107.2f / 32768.0f);
float x2 = 1.0 - x1; float x2 = 1.0 - x1;
__disable_irq(); __disable_irq();
combdamp1 = x1; combdamp1 = x1;
combdamp2 = x2; combdamp2 = x2;
__enable_irq(); __enable_irq();
} }
private: private:
audio_block_t *inputQueueArray[1]; audio_block_t *inputQueueArray[1];
float comb1bufL[1116]; float comb1bufL[1116];
float comb2bufL[1188]; float comb2bufL[1188];
float comb3bufL[1277]; float comb3bufL[1277];
float comb4bufL[1356]; float comb4bufL[1356];
float comb5bufL[1422]; float comb5bufL[1422];
float comb6bufL[1491]; float comb6bufL[1491];
float comb7bufL[1557]; float comb7bufL[1557];
float comb8bufL[1617]; float comb8bufL[1617];
uint16_t comb1indexL; uint16_t comb1indexL;
uint16_t comb2indexL; uint16_t comb2indexL;
uint16_t comb3indexL; uint16_t comb3indexL;
uint16_t comb4indexL; uint16_t comb4indexL;
uint16_t comb5indexL; uint16_t comb5indexL;
uint16_t comb6indexL; uint16_t comb6indexL;
uint16_t comb7indexL; uint16_t comb7indexL;
uint16_t comb8indexL; uint16_t comb8indexL;
float comb1filterL; float comb1filterL;
float comb2filterL; float comb2filterL;
float comb3filterL; float comb3filterL;
float comb4filterL; float comb4filterL;
float comb5filterL; float comb5filterL;
float comb6filterL; float comb6filterL;
float comb7filterL; float comb7filterL;
float comb8filterL; float comb8filterL;
float comb1bufR[1139]; float comb1bufR[1139];
float comb2bufR[1211]; float comb2bufR[1211];
float comb3bufR[1300]; float comb3bufR[1300];
float comb4bufR[1379]; float comb4bufR[1379];
float comb5bufR[1445]; float comb5bufR[1445];
float comb6bufR[1514]; float comb6bufR[1514];
float comb7bufR[1580]; float comb7bufR[1580];
float comb8bufR[1640]; float comb8bufR[1640];
uint16_t comb1indexR; uint16_t comb1indexR;
uint16_t comb2indexR; uint16_t comb2indexR;
uint16_t comb3indexR; uint16_t comb3indexR;
uint16_t comb4indexR; uint16_t comb4indexR;
uint16_t comb5indexR; uint16_t comb5indexR;
uint16_t comb6indexR; uint16_t comb6indexR;
uint16_t comb7indexR; uint16_t comb7indexR;
uint16_t comb8indexR; uint16_t comb8indexR;
float comb1filterR; float comb1filterR;
float comb2filterR; float comb2filterR;
float comb3filterR; float comb3filterR;
float comb4filterR; float comb4filterR;
float comb5filterR; float comb5filterR;
float comb6filterR; float comb6filterR;
float comb7filterR; float comb7filterR;
float comb8filterR; float comb8filterR;
float combdamp1; float combdamp1;
float combdamp2; float combdamp2;
float combfeeback; float combfeeback;
float allpass1bufL[556]; float allpass1bufL[556];
float allpass2bufL[441]; float allpass2bufL[441];
float allpass3bufL[341]; float allpass3bufL[341];
float allpass4bufL[225]; float allpass4bufL[225];
uint16_t allpass1indexL; uint16_t allpass1indexL;
uint16_t allpass2indexL; uint16_t allpass2indexL;
uint16_t allpass3indexL; uint16_t allpass3indexL;
uint16_t allpass4indexL; uint16_t allpass4indexL;
float allpass1bufR[579]; float allpass1bufR[579];
float allpass2bufR[464]; float allpass2bufR[464];
float allpass3bufR[364]; float allpass3bufR[364];
float allpass4bufR[248]; float allpass4bufR[248];
uint16_t allpass1indexR; uint16_t allpass1indexR;
uint16_t allpass2indexR; uint16_t allpass2indexR;
uint16_t allpass3indexR; uint16_t allpass3indexR;
uint16_t allpass4indexR; uint16_t allpass4indexR;
}; };

188
env.cc

@ -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,19 +1,19 @@
/* /*
* Copyright 2017 Pascal Gauthier. Copyright 2017 Pascal Gauthier.
* Copyright 2012 Google Inc. Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
#include <math.h> #include <math.h>
@ -22,17 +22,32 @@
//using namespace std; //using namespace std;
uint32_t Env::sr_multiplier = (1<<24); uint32_t Env::sr_multiplier = (1 << 24);
const int levellut[] = { const int levellut[] = {
0, 5, 9, 13, 17, 20, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 42, 43, 45, 46 0, 5, 9, 13, 17, 20, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 42, 43, 45, 46
}; };
void Env::init_sr(FRAC_NUM sampleRate) { #ifdef ACCURATE_ENVELOPE
sr_multiplier = (44100.0 / sampleRate) * (1<<24); 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) { void Env::init(const int r[4], const int l[4], int ol, int rate_scaling) {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
rates_[i] = r[i]; rates_[i] = r[i];
levels_[i] = l[i]; levels_[i] = l[i];
@ -45,8 +60,21 @@ void Env::init(const int r[4], const int l[4], int32_t ol, int rate_scaling) {
} }
int32_t Env::getsample() { 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 (ix_ < 3 || ((ix_ < 4) && !down_)) {
if (rising_) { if (staticcount_) {
;
}
else if (rising_) {
const int jumptarget = 1716; const int jumptarget = 1716;
if (level_ < (jumptarget << 16)) { if (level_ < (jumptarget << 16)) {
level_ = jumptarget << 16; level_ = jumptarget << 16;
@ -57,7 +85,8 @@ int32_t Env::getsample() {
level_ = targetlevel_; level_ = targetlevel_;
advance(ix_ + 1); advance(ix_ + 1);
} }
} else { // !rising }
else { // !rising
level_ -= inc_; level_ -= inc_;
if (level_ <= targetlevel_) { if (level_ <= targetlevel_) {
level_ = targetlevel_; level_ = targetlevel_;
@ -71,8 +100,8 @@ int32_t Env::getsample() {
void Env::keydown(bool d) { void Env::keydown(bool d) {
if (down_ != d) { if (down_ != d) {
down_ = d; down_ = d;
advance(d ? 0 : 3); advance(d ? 0 : 3);
} }
} }
@ -95,22 +124,40 @@ void Env::advance(int newix) {
int qrate = (rates_[ix_] * 41) >> 6; int qrate = (rates_[ix_] * 41) >> 6;
qrate += rate_scaling_; qrate += rate_scaling_;
qrate = min(qrate, 63); qrate = min(qrate, 63);
inc_ = (4 + (qrate & 3)) << (2 + LG_N + (qrate >> 2));
#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 // meh, this should be fixed elsewhere
inc_ = ((int64_t)inc_ * (int64_t)sr_multiplier) >> 24; 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) { void Env::update(const int r[4], const int l[4], int ol, int rate_scaling) {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
rates_[i] = r[i]; rates_[i] = r[i];
levels_[i] = l[i]; levels_[i] = l[i];
} }
outlevel_ = ol; outlevel_ = ol;
rate_scaling_ = rate_scaling; rate_scaling_ = rate_scaling;
if ( down_ ) { if ( down_ ) {
// for now we simply reset ourselve at level 3 // for now we simply reset ourselves at level 3
int newlevel = levels_[2]; int newlevel = levels_[2];
int actuallevel = scaleoutlevel(newlevel) >> 1; int actuallevel = scaleoutlevel(newlevel) >> 1;
actuallevel = (actuallevel << 6) - 4256; actuallevel = (actuallevel << 6) - 4256;
@ -121,21 +168,23 @@ void Env::update(const int r[4], const int l[4], int32_t ol, int rate_scaling) {
} }
void Env::getPosition(char *step) { void Env::getPosition(char *step) {
*step = ix_; *step = ix_;
} }
void Env::transfer(Env &src) { void Env::transfer(Env &src) {
for(int i=0;i<4;i++) { for (int i = 0; i < 4; i++) {
rates_[i] = src.rates_[i]; rates_[i] = src.rates_[i];
levels_[i] = src.levels_[i]; levels_[i] = src.levels_[i];
} }
outlevel_ = src.outlevel_; outlevel_ = src.outlevel_;
rate_scaling_ = src.rate_scaling_; rate_scaling_ = src.rate_scaling_;
level_ = src.level_; level_ = src.level_;
targetlevel_ = src.targetlevel_; targetlevel_ = src.targetlevel_;
rising_= src.rising_; rising_ = src.rising_;
ix_ = src.ix_; ix_ = src.ix_;
inc_ = src.inc_; down_ = src.down_;
down_ = src.down_; #ifdef ACCURATE_ENVELOPE
staticcount_ = src.staticcount_;
#endif
inc_ = src.inc_;
} }

125
env.h

@ -1,19 +1,19 @@
/* /*
* Copyright 2017 Pascal Gauthier. Copyright 2017 Pascal Gauthier.
* Copyright 2012 Google Inc. Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
#ifndef __ENV_H #ifndef __ENV_H
#define __ENV_H #define __ENV_H
@ -25,58 +25,57 @@
#define ACCURATE_ENVELOPE #define ACCURATE_ENVELOPE
class Env { class Env {
public: public:
// The rates and levels arrays are calibrated to match the Dx7 parameters // The rates and levels arrays are calibrated to match the Dx7 parameters
// (ie, value 0..99). The outlevel parameter is calibrated in microsteps // (ie, value 0..99). The outlevel parameter is calibrated in microsteps
// (ie units of approx .023 dB), with 99 * 32 = nominal full scale. The // (ie units of approx .023 dB), with 99 * 32 = nominal full scale. The
// rate_scaling parameter is in qRate units (ie 0..63). // rate_scaling parameter is in qRate units (ie 0..63).
void init(const int rates[4], const int levels[4], int32_t outlevel, void init(const int rates[4], const int levels[4], int outlevel,
int rate_scaling); int rate_scaling);
void update(const int rates[4], const int levels[4], int32_t outlevel, void update(const int rates[4], const int levels[4], int outlevel,
int rate_scaling); int rate_scaling);
// Result is in Q24/doubling log format. Also, result is subsampled // Result is in Q24/doubling log format. Also, result is subsampled
// for every N samples. // for every N samples.
// A couple more things need to happen for this to be used as a gain // A couple more things need to happen for this to be used as a gain
// value. First, the # of outputs scaling needs to be applied. Also, // value. First, the # of outputs scaling needs to be applied. Also,
// modulation. // modulation.
// Then, of course, log to linear. // Then, of course, log to linear.
int32_t getsample(); int32_t getsample();
void keydown(bool down); void keydown(bool down);
static int scaleoutlevel(int outlevel); static int scaleoutlevel(int outlevel);
void getPosition(char *step); void getPosition(char *step);
static void init_sr(FRAC_NUM sample_rate); static void init_sr(double sample_rate);
void transfer(Env &src); void transfer(Env &src);
private: private:
// PG: This code is normalized to 44100, need to put a multiplier // PG: This code is normalized to 44100, need to put a multiplier
// if we are not using 44100. // if we are not using 44100.
static uint32_t sr_multiplier; static uint32_t sr_multiplier;
int rates_[4]; int rates_[4];
int levels_[4]; int levels_[4];
int outlevel_; int outlevel_;
int rate_scaling_; int rate_scaling_;
// Level is stored so that 2^24 is one doubling, ie 16 more bits than // Level is stored so that 2^24 is one doubling, ie 16 more bits than
// the DX7 itself (fraction is stored in level rather than separate // the DX7 itself (fraction is stored in level rather than separate
// counter) // counter)
int32_t level_; int32_t level_;
int targetlevel_; int targetlevel_;
bool rising_; bool rising_;
int ix_; int ix_;
int inc_; int inc_;
#ifdef ACCURATE_ENVELOPE #ifdef ACCURATE_ENVELOPE
int staticcount_; int staticcount_;
#endif #endif
bool down_; bool down_;
void advance(int newix); void advance(int newix);
}; };
#endif // __ENV_H #endif // __ENV_H

@ -1,27 +1,27 @@
/* /*
* Copyright 2012 Google Inc. Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
class Exp2 { class Exp2 {
public: public:
Exp2(); Exp2();
static void init(); static void init();
// Q24 in, Q24 out // Q24 in, Q24 out
static int32_t lookup(int32_t x); static int32_t lookup(int32_t x);
}; };
#define EXP2_LG_N_SAMPLES 10 #define EXP2_LG_N_SAMPLES 10
@ -46,11 +46,11 @@ int32_t Exp2::lookup(int32_t x) {
#endif #endif
class Tanh { class Tanh {
public: public:
static void init(); static void init();
// Q24 in, Q24 out // Q24 in, Q24 out
static int32_t lookup(int32_t x); static int32_t lookup(int32_t x);
}; };
#define TANH_LG_N_SAMPLES 10 #define TANH_LG_N_SAMPLES 10
@ -66,7 +66,7 @@ int32_t Tanh::lookup(int32_t x) {
if (x >= (17 << 23)) { if (x >= (17 << 23)) {
return signum ^ (1 << 24); return signum ^ (1 << 24);
} }
int32_t sx = ((int64_t)-48408812 * (int64_t)x) >> 24; int32_t sx = ((int64_t) - 48408812 * (int64_t)x) >> 24;
return signum ^ ((1 << 24) - 2 * Exp2::lookup(sx)); return signum ^ ((1 << 24) - 2 * Exp2::lookup(sx));
} else { } else {
const int SHIFT = 26 - TANH_LG_N_SAMPLES; const int SHIFT = 26 - TANH_LG_N_SAMPLES;

@ -1,18 +1,18 @@
/* /*
* Copyright 2012 Google Inc. Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
#ifdef VERBOSE #ifdef VERBOSE
#include <iostream> #include <iostream>
@ -71,13 +71,13 @@ int n_out(const FmAlgorithm &alg) {
uint8_t FmCore::get_carrier_operators(uint8_t algorithm) uint8_t FmCore::get_carrier_operators(uint8_t algorithm)
{ {
uint8_t op_out=0; uint8_t op_out = 0;
FmAlgorithm alg=algorithms[algorithm]; FmAlgorithm alg = algorithms[algorithm];
for(uint8_t i=0; i<6;i++) for (uint8_t i = 0; i < 6; i++)
{ {
if((alg.ops[i]&OUT_BUS_ADD)==OUT_BUS_ADD) if ((alg.ops[i]&OUT_BUS_ADD) == OUT_BUS_ADD)
op_out|=1<<i; op_out |= 1 << i;
} }
return op_out; return op_out;
@ -105,45 +105,45 @@ void FmCore::dump() {
} }
void FmCore::render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int feedback_shift) { void FmCore::render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int feedback_shift) {
const int kLevelThresh = 1120; const int kLevelThresh = 1120;
const FmAlgorithm alg = algorithms[algorithm]; const FmAlgorithm alg = algorithms[algorithm];
bool has_contents[3] = { true, false, false }; bool has_contents[3] = { true, false, false };
for (int op = 0; op < 6; op++) { for (int op = 0; op < 6; op++) {
int flags = alg.ops[op]; int flags = alg.ops[op];
bool add = (flags & OUT_BUS_ADD) != 0; bool add = (flags & OUT_BUS_ADD) != 0;
FmOpParams &param = params[op]; FmOpParams &param = params[op];
int inbus = (flags >> 4) & 3; int inbus = (flags >> 4) & 3;
int outbus = flags & 3; int outbus = flags & 3;
int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get(); int32_t *outptr = (outbus == 0) ? output : buf_[outbus - 1].get();
int32_t gain1 = param.gain_out; int32_t gain1 = param.gain_out;
int32_t gain2 = Exp2::lookup(param.level_in - (14 * (1 << 24))); int32_t gain2 = Exp2::lookup(param.level_in - (14 * (1 << 24)));
param.gain_out = gain2; param.gain_out = gain2;
if (gain1 >= kLevelThresh || gain2 >= kLevelThresh) { if (gain1 >= kLevelThresh || gain2 >= kLevelThresh) {
if (!has_contents[outbus]) { if (!has_contents[outbus]) {
add = false; add = false;
} }
if (inbus == 0 || !has_contents[inbus]) { if (inbus == 0 || !has_contents[inbus]) {
// todo: more than one op in a feedback loop // todo: more than one op in a feedback loop
if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) { if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) {
// cout << op << " fb " << inbus << outbus << add << endl; // cout << op << " fb " << inbus << outbus << add << endl;
FmOpKernel::compute_fb(outptr, param.phase, param.freq, FmOpKernel::compute_fb(outptr, param.phase, param.freq,
gain1, gain2, gain1, gain2,
fb_buf, feedback_shift, add); fb_buf, feedback_shift, add);
} else { } else {
// cout << op << " pure " << inbus << outbus << add << endl; // cout << op << " pure " << inbus << outbus << add << endl;
FmOpKernel::compute_pure(outptr, param.phase, param.freq, FmOpKernel::compute_pure(outptr, param.phase, param.freq,
gain1, gain2, add); gain1, gain2, add);
}
} else {
// cout << op << " normal " << inbus << outbus << " " << param.freq << add << endl;
FmOpKernel::compute(outptr, buf_[inbus - 1].get(),
param.phase, param.freq, gain1, gain2, add);
}
has_contents[outbus] = true;
} else if (!add) {
has_contents[outbus] = false;
} }
param.phase += param.freq << LG_N; } else {
// cout << op << " normal " << inbus << outbus << " " << param.freq << add << endl;
FmOpKernel::compute(outptr, buf_[inbus - 1].get(),
param.phase, param.freq, gain1, gain2, add);
}
has_contents[outbus] = true;
} else if (!add) {
has_contents[outbus] = false;
} }
param.phase += param.freq << LG_N;
}
} }

@ -1,18 +1,18 @@
/* /*
* Copyright 2012 Google Inc. Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
#ifndef __FM_CORE_H #ifndef __FM_CORE_H
#define __FM_CORE_H #define __FM_CORE_H
@ -25,33 +25,33 @@
class FmOperatorInfo { class FmOperatorInfo {
public: public:
int in; int in;
int out; int out;
}; };
enum FmOperatorFlags { enum FmOperatorFlags {
OUT_BUS_ONE = 1 << 0, OUT_BUS_ONE = 1 << 0,
OUT_BUS_TWO = 1 << 1, OUT_BUS_TWO = 1 << 1,
OUT_BUS_ADD = 1 << 2, OUT_BUS_ADD = 1 << 2,
IN_BUS_ONE = 1 << 4, IN_BUS_ONE = 1 << 4,
IN_BUS_TWO = 1 << 5, IN_BUS_TWO = 1 << 5,
FB_IN = 1 << 6, FB_IN = 1 << 6,
FB_OUT = 1 << 7 FB_OUT = 1 << 7
}; };
class FmAlgorithm { class FmAlgorithm {
public: public:
int ops[6]; int ops[6];
}; };
class FmCore { class FmCore {
public: public:
virtual ~FmCore() {}; virtual ~FmCore() {};
static void dump(); static void dump();
uint8_t get_carrier_operators(uint8_t algorithm); uint8_t get_carrier_operators(uint8_t algorithm);
virtual void render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int feedback_gain); virtual void render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int feedback_gain);
protected: protected:
AlignedBuf<int32_t, _N_>buf_[2]; AlignedBuf<int32_t, _N_>buf_[2];
const static FmAlgorithm algorithms[32]; const static FmAlgorithm algorithms[32];
}; };

@ -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

@ -1,18 +1,18 @@
/* /*
* Copyright 2012 Google Inc. Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
#include "config.h" #include "config.h"
#include <math.h> #include <math.h>
@ -35,7 +35,7 @@ static bool hasNeon() {
extern "C" extern "C"
void neon_fm_kernel(const int *in, const int *busin, int *out, int count, 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); int32_t phase0, int32_t freq, int32_t gain1, int32_t dgain);
const int32_t __attribute__ ((aligned(16))) zeros[_N_] = {0}; const int32_t __attribute__ ((aligned(16))) zeros[_N_] = {0};
@ -54,7 +54,7 @@ void FmOpKernel::compute(int32_t *output, const int32_t *input,
if (hasNeon()) { if (hasNeon()) {
#ifdef HAVE_NEON #ifdef HAVE_NEON
neon_fm_kernel(input, add ? output : zeros, output, _N_, neon_fm_kernel(input, add ? output : zeros, output, _N_,
phase0, freq, gain, dgain); phase0, freq, gain, dgain);
#endif #endif
} else { } else {
if (add) { if (add) {
@ -85,7 +85,7 @@ void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
if (hasNeon()) { if (hasNeon()) {
#ifdef HAVE_NEON #ifdef HAVE_NEON
neon_fm_kernel(zeros, add ? output : zeros, output, _N_, neon_fm_kernel(zeros, add ? output : zeros, output, _N_,
phase0, freq, gain, dgain); phase0, freq, gain, dgain);
#endif #endif
} else { } else {
if (add) { if (add) {
@ -155,30 +155,30 @@ void FmOpKernel::compute_fb(int32_t *output, int32_t phase0, int32_t freq,
// high accuracy: 5.0 mean, 49 worst case // high accuracy: 5.0 mean, 49 worst case
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
int32_t gain1, int32_t gain2, bool add) { int32_t gain1, int32_t gain2, bool add) {
int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N; int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N;
int32_t gain = gain1; int32_t gain = gain1;
int32_t phase = phase0; int32_t phase = phase0;
#ifdef HIGH_ACCURACY #ifdef HIGH_ACCURACY
int32_t u = Sin::compute10(phase << 6); int32_t u = Sin::compute10(phase << 6);
u = ((int64_t)u * gain) >> 30; u = ((int64_t)u * gain) >> 30;
int32_t v = Sin::compute10((phase << 6) + (1 << 28)); // quarter cycle int32_t v = Sin::compute10((phase << 6) + (1 << 28)); // quarter cycle
v = ((int64_t)v * gain) >> 30; v = ((int64_t)v * gain) >> 30;
int32_t s = Sin::compute10(freq << 6); int32_t s = Sin::compute10(freq << 6);
int32_t c = Sin::compute10((freq << 6) + (1 << 28)); int32_t c = Sin::compute10((freq << 6) + (1 << 28));
#else #else
int32_t u = Sin::compute(phase); int32_t u = Sin::compute(phase);
u = ((int64_t)u * gain) >> 24; u = ((int64_t)u * gain) >> 24;
int32_t v = Sin::compute(phase + (1 << 22)); // quarter cycle int32_t v = Sin::compute(phase + (1 << 22)); // quarter cycle
v = ((int64_t)v * gain) >> 24; v = ((int64_t)v * gain) >> 24;
int32_t s = Sin::compute(freq) << 6; int32_t s = Sin::compute(freq) << 6;
int32_t c = Sin::compute(freq + (1 << 22)) << 6; int32_t c = Sin::compute(freq + (1 << 22)) << 6;
#endif #endif
for (int i = 0; i < _N_; i++) { for (int i = 0; i < _N_; i++) {
output[i] = u; output[i] = u;
int32_t t = ((int64_t)v * (int64_t)c - (int64_t)u * (int64_t)s) >> 30; 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; u = ((int64_t)u * (int64_t)c + (int64_t)v * (int64_t)s) >> 30;
v = t; v = t;
} }
} }
#endif #endif
@ -189,25 +189,25 @@ void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
// freq < 0.25: 17.9 mean, 78 worst // freq < 0.25: 17.9 mean, 78 worst
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
int32_t gain1, int32_t gain2, bool add) { int32_t gain1, int32_t gain2, bool add) {
int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N; int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N;
int32_t gain = gain1; int32_t gain = gain1;
int32_t phase = phase0; int32_t phase = phase0;
#ifdef HIGH_ACCURACY #ifdef HIGH_ACCURACY
int32_t u = floor(gain * sin(phase * (M_PI / (1 << 23))) + 0.5); 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 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); int32_t a = floor((1 << 25) * sin(freq * (M_PI / (1 << 24))) + 0.5);
#else #else
int32_t u = Sin::compute(phase); int32_t u = Sin::compute(phase);
u = ((int64_t)u * gain) >> 24; u = ((int64_t)u * gain) >> 24;
int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1)); int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1));
v = ((int64_t)v * gain) >> 24; v = ((int64_t)v * gain) >> 24;
int32_t a = Sin::compute(freq >> 1) << 1; int32_t a = Sin::compute(freq >> 1) << 1;
#endif #endif
for (int i = 0; i < _N_; i++) { for (int i = 0; i < _N_; i++) {
output[i] = u; output[i] = u;
v -= ((int64_t)a * (int64_t)u) >> 24; v -= ((int64_t)a * (int64_t)u) >> 24;
u += ((int64_t)a * (int64_t)v) >> 24; u += ((int64_t)a * (int64_t)v) >> 24;
} }
} }
#endif #endif
@ -217,38 +217,38 @@ void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
// with high accuracy: mean 4.2, worst 292 (near freq = 0.5) // 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, void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
int32_t gain1, int32_t gain2, bool add) { int32_t gain1, int32_t gain2, bool add) {
int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N; int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N;
int32_t gain = gain1; int32_t gain = gain1;
int32_t phase = phase0; int32_t phase = phase0;
#ifdef DOUBLE_ACCURACY #ifdef DOUBLE_ACCURACY
int32_t u = floor((1 << 30) * sin(phase * (M_PI / (1 << 23))) + 0.5); int32_t u = floor((1 << 30) * sin(phase * (M_PI / (1 << 23))) + 0.5);
FRAC_NUM a_d = sin(freq * (M_PI / (1 << 24))); FRAC_NUM a_d = sin(freq * (M_PI / (1 << 24)));
int32_t v = floor((1LL << 31) * a_d * cos((phase - freq * 0.5) * int32_t v = floor((1LL << 31) * a_d * cos((phase - freq * 0.5) *
(M_PI / (1 << 23))) + 0.5); (M_PI / (1 << 23))) + 0.5);
int32_t aa = floor((1LL << 31) * a_d * a_d + 0.5); int32_t aa = floor((1LL << 31) * a_d * a_d + 0.5);
#else #else
#ifdef HIGH_ACCURACY #ifdef HIGH_ACCURACY
int32_t u = Sin::compute10(phase << 6); int32_t u = Sin::compute10(phase << 6);
int32_t v = Sin::compute10((phase << 6) + (1 << 28) - (freq << 5)); int32_t v = Sin::compute10((phase << 6) + (1 << 28) - (freq << 5));
int32_t a = Sin::compute10(freq << 5); int32_t a = Sin::compute10(freq << 5);
v = ((int64_t)v * (int64_t)a) >> 29; v = ((int64_t)v * (int64_t)a) >> 29;
int32_t aa = ((int64_t)a * (int64_t)a) >> 29; int32_t aa = ((int64_t)a * (int64_t)a) >> 29;
#else #else
int32_t u = Sin::compute(phase) << 6; int32_t u = Sin::compute(phase) << 6;
int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1)); int32_t v = Sin::compute(phase + (1 << 22) - (freq >> 1));
int32_t a = Sin::compute(freq >> 1); int32_t a = Sin::compute(freq >> 1);
v = ((int64_t)v * (int64_t)a) >> 17; v = ((int64_t)v * (int64_t)a) >> 17;
int32_t aa = ((int64_t)a * (int64_t)a) >> 17; int32_t aa = ((int64_t)a * (int64_t)a) >> 17;
#endif #endif
#endif #endif
if (aa < 0) aa = (1 << 31) - 1; if (aa < 0) aa = (1 << 31) - 1;
for (int i = 0; i < _N_; i++) { for (int i = 0; i < _N_; i++) {
gain += dgain; gain += dgain;
output[i] = ((int64_t)u * (int64_t)gain) >> 30; output[i] = ((int64_t)u * (int64_t)gain) >> 30;
v -= ((int64_t)aa * (int64_t)u) >> 29; v -= ((int64_t)aa * (int64_t)u) >> 29;
u += v; u += v;
} }
} }
#endif #endif
@ -257,28 +257,27 @@ void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
// high accuracy 2.9 mean, 143 worst // high accuracy 2.9 mean, 143 worst
void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq, void FmOpKernel::compute_pure(int32_t *output, int32_t phase0, int32_t freq,
int32_t gain1, int32_t gain2, bool add) { int32_t gain1, int32_t gain2, bool add) {
int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N; int32_t dgain = (gain2 - gain1 + (_N_ >> 1)) >> LG_N;
int32_t gain = gain1; int32_t gain = gain1;
int32_t phase = phase0; int32_t phase = phase0;
#ifdef HIGH_ACCURACY #ifdef HIGH_ACCURACY
int32_t u = Sin::compute10(phase << 6); int32_t u = Sin::compute10(phase << 6);
int32_t lastu = Sin::compute10((phase - freq) << 6); int32_t lastu = Sin::compute10((phase - freq) << 6);
int32_t a = Sin::compute10((freq << 6) + (1 << 28)) << 1; int32_t a = Sin::compute10((freq << 6) + (1 << 28)) << 1;
#else #else
int32_t u = Sin::compute(phase) << 6; int32_t u = Sin::compute(phase) << 6;
int32_t lastu = Sin::compute(phase - freq) << 6; int32_t lastu = Sin::compute(phase - freq) << 6;
int32_t a = Sin::compute(freq + (1 << 22)) << 7; int32_t a = Sin::compute(freq + (1 << 22)) << 7;
#endif #endif
if (a < 0 && freq < 256) a = (1 << 31) - 1; if (a < 0 && freq < 256) a = (1 << 31) - 1;
if (a > 0 && freq > 0x7fff00) a = -(1 << 31); if (a > 0 && freq > 0x7fff00) a = -(1 << 31);
for (int i = 0; i < _N_; i++) { for (int i = 0; i < _N_; i++) {
gain += dgain; gain += dgain;
output[i] = ((int64_t)u * (int64_t)gain) >> 30; output[i] = ((int64_t)u * (int64_t)gain) >> 30;
//output[i] = u; //output[i] = u;
int32_t newu = (((int64_t)u * (int64_t)a) >> 30) - lastu; int32_t newu = (((int64_t)u * (int64_t)a) >> 30) - lastu;
lastu = u; lastu = u;
u = newu; u = newu;
} }
} }
#endif #endif

@ -1,47 +1,47 @@
/* /*
* Copyright 2012 Google Inc. Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
#ifndef __FM_OP_KERNEL_H #ifndef __FM_OP_KERNEL_H
#define __FM_OP_KERNEL_H #define __FM_OP_KERNEL_H
struct FmOpParams { struct FmOpParams {
int32_t level_in; // value to be computed (from level to gain[0]) int32_t level_in; // value to be computed (from level to gain[0])
int32_t gain_out; // computed value (gain[1] to gain[0]) int32_t gain_out; // computed value (gain[1] to gain[0])
int32_t freq; int32_t freq;
int32_t phase; int32_t phase;
}; };
class FmOpKernel { class FmOpKernel {
public: public:
// gain1 and gain2 represent linear step: gain for sample i is // gain1 and gain2 represent linear step: gain for sample i is
// gain1 + (1 + i) / 64 * (gain2 - gain1) // gain1 + (1 + i) / 64 * (gain2 - gain1)
// This is the basic FM operator. No feedback. // This is the basic FM operator. No feedback.
static void compute(int32_t *output, const int32_t *input, static void compute(int32_t *output, const int32_t *input,
int32_t phase0, int32_t freq, int32_t phase0, int32_t freq,
int32_t gain1, int32_t gain2, bool add); int32_t gain1, int32_t gain2, bool add);
// This is a sine generator, no feedback. // This is a sine generator, no feedback.
static void compute_pure(int32_t *output, int32_t phase0, int32_t freq, static void compute_pure(int32_t *output, int32_t phase0, int32_t freq,
int32_t gain1, int32_t gain2, bool add); int32_t gain1, int32_t gain2, bool add);
// One op with feedback, no add. // One op with feedback, no add.
static void compute_fb(int32_t *output, int32_t phase0, int32_t freq, static void compute_fb(int32_t *output, int32_t phase0, int32_t freq,
int32_t gain1, int32_t gain2, int32_t gain1, int32_t gain2,
int32_t *fb_buf, int fb_gain, bool add); int32_t *fb_buf, int fb_gain, bool add);
}; };
#endif #endif

@ -1,18 +1,18 @@
/* /*
* Copyright 2012 Google Inc. Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
// Resolve frequency signal (1.0 in Q24 format = 1 octave) to phase delta. // Resolve frequency signal (1.0 in Q24 format = 1 octave) to phase delta.

@ -1,23 +1,23 @@
/* /*
* Copyright 2012 Google Inc. Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
#include "synth.h" #include "synth.h"
class Freqlut { class Freqlut {
public: public:
static void init(FRAC_NUM sample_rate); static void init(FRAC_NUM sample_rate);
static int32_t lookup(int32_t logfreq); static int32_t lookup(int32_t logfreq);
}; };

@ -1,18 +1,18 @@
/* /*
* Copyright 2013 Google Inc. Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
// Low frequency oscillator, compatible with DX7 // Low frequency oscillator, compatible with DX7
@ -24,74 +24,74 @@
uint32_t Lfo::unit_; uint32_t Lfo::unit_;
void Lfo::init(FRAC_NUM sample_rate) { void Lfo::init(FRAC_NUM sample_rate) {
// constant is 1 << 32 / 15.5s / 11 // constant is 1 << 32 / 15.5s / 11
Lfo::unit_ = (int32_t)(_N_ * 25190424 / sample_rate + 0.5); Lfo::unit_ = (int32_t)(_N_ * 25190424 / sample_rate + 0.5);
} }
void Lfo::reset(const uint8_t params[6]) { void Lfo::reset(const uint8_t params[6]) {
int rate = params[0]; // 0..99 int rate = params[0]; // 0..99
int sr = rate == 0 ? 1 : (165 * rate) >> 6; int sr = rate == 0 ? 1 : (165 * rate) >> 6;
sr *= sr < 160 ? 11 : (11 + ((sr - 160) >> 4)); sr *= sr < 160 ? 11 : (11 + ((sr - 160) >> 4));
delta_ = unit_ * sr; delta_ = unit_ * sr;
int a = 99 - params[1]; // LFO delay int a = 99 - params[1]; // LFO delay
if (a == 99) { if (a == 99) {
delayinc_ = ~0u; delayinc_ = ~0u;
delayinc2_ = ~0u; delayinc2_ = ~0u;
} else { } else {
a = (16 + (a & 15)) << (1 + (a >> 4)); a = (16 + (a & 15)) << (1 + (a >> 4));
delayinc_ = unit_ * a; delayinc_ = unit_ * a;
a &= 0xff80; a &= 0xff80;
a = max(0x80, a); a = max(0x80, a);
delayinc2_ = unit_ * a; delayinc2_ = unit_ * a;
} }
waveform_ = params[5]; waveform_ = params[5];
sync_ = params[4] != 0; sync_ = params[4] != 0;
} }
int32_t Lfo::getsample() { int32_t Lfo::getsample() {
phase_ += delta_; phase_ += delta_;
int32_t x; int32_t x;
switch (waveform_) { switch (waveform_) {
case 0: // triangle case 0: // triangle
x = phase_ >> 7; x = phase_ >> 7;
x ^= -(phase_ >> 31); x ^= -(phase_ >> 31);
x &= (1 << 24) - 1; x &= (1 << 24) - 1;
return x; return x;
case 1: // sawtooth down case 1: // sawtooth down
return (~phase_ ^ (1U << 31)) >> 8; return (~phase_ ^ (1U << 31)) >> 8;
case 2: // sawtooth up case 2: // sawtooth up
return (phase_ ^ (1U << 31)) >> 8; return (phase_ ^ (1U << 31)) >> 8;
case 3: // square case 3: // square
return ((~phase_) >> 7) & (1 << 24); return ((~phase_) >> 7) & (1 << 24);
case 4: // sine case 4: // sine
return (1 << 23) + (Sin::lookup(phase_ >> 8) >> 1); return (1 << 23) + (Sin::lookup(phase_ >> 8) >> 1);
case 5: // s&h case 5: // s&h
if (phase_ < delta_) { if (phase_ < delta_) {
randstate_ = (randstate_ * 179 + 17) & 0xff; randstate_ = (randstate_ * 179 + 17) & 0xff;
} }
x = randstate_ ^ 0x80; x = randstate_ ^ 0x80;
return (x + 1) << 16; return (x + 1) << 16;
} }
return 1 << 23; return 1 << 23;
} }
int32_t Lfo::getdelay() { int32_t Lfo::getdelay() {
uint32_t delta = delaystate_ < (1U << 31) ? delayinc_ : delayinc2_; uint32_t delta = delaystate_ < (1U << 31) ? delayinc_ : delayinc2_;
uint64_t d = ((uint64_t)delaystate_) + delta; uint64_t d = ((uint64_t)delaystate_) + delta;
if (d > ~0u) { if (d > ~0u) {
return 1 << 24; return 1 << 24;
} }
delaystate_ = d; delaystate_ = d;
if (d < (1U << 31)) { if (d < (1U << 31)) {
return 0; return 0;
} else { } else {
return (d >> 7) & ((1 << 24) - 1); return (d >> 7) & ((1 << 24) - 1);
} }
} }
void Lfo::keydown() { void Lfo::keydown() {
if (sync_) { if (sync_) {
phase_ = (1U << 31) - 1; phase_ = (1U << 31) - 1;
} }
delaystate_ = 0; delaystate_ = 0;
} }

64
lfo.h

@ -1,43 +1,43 @@
/* /*
* Copyright 2013 Google Inc. Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
// Low frequency oscillator, compatible with DX7 // Low frequency oscillator, compatible with DX7
class Lfo { class Lfo {
public: public:
static void init(FRAC_NUM sample_rate); static void init(FRAC_NUM sample_rate);
void reset(const uint8_t params[6]); void reset(const uint8_t params[6]);
// result is 0..1 in Q24 // result is 0..1 in Q24
int32_t getsample(); int32_t getsample();
// result is 0..1 in Q24 // result is 0..1 in Q24
int32_t getdelay(); int32_t getdelay();
void keydown(); void keydown();
private: private:
static uint32_t unit_; static uint32_t unit_;
uint32_t phase_; // Q32 uint32_t phase_; // Q32
uint32_t delta_; uint32_t delta_;
uint8_t waveform_; uint8_t waveform_;
uint8_t randstate_; uint8_t randstate_;
bool sync_; bool sync_;
uint32_t delaystate_; uint32_t delaystate_;
uint32_t delayinc_; uint32_t delayinc_;
uint32_t delayinc2_; uint32_t delayinc2_;
}; };

@ -1,5 +1,5 @@
/************************************************* /*************************************************
* MIDI note values MIDI note values
*************************************************/ *************************************************/
#ifndef _MIDINOTES_H #ifndef _MIDINOTES_H

@ -1,18 +1,18 @@
/* /*
* Copyright 2012 Google Inc. Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
#ifndef SYNTH_MODULE_H #ifndef SYNTH_MODULE_H
#define SYNTH_MODULE_H #define SYNTH_MODULE_H
@ -20,12 +20,11 @@
#include <stdint.h> #include <stdint.h>
class Module { class Module {
public: public:
static const int lg_n = 6; static const int lg_n = 6;
static const int n = 1 << lg_n; static const int n = 1 << lg_n;
virtual void process(const int32_t **inbufs, const int32_t *control_in, virtual void process(const int32_t **inbufs, const int32_t *control_in,
const int32_t *control_last, int32_t **outbufs) = 0; const int32_t *control_last, int32_t **outbufs) = 0;
}; };
#endif // SYNTH_MODULE_H #endif // SYNTH_MODULE_H

@ -1,28 +1,28 @@
/* Audio Library for Teensy 3.X /* Audio Library for Teensy 3.X
* Copyright (c) 2018, Paul Stoffregen, paul@pjrc.com Copyright (c) 2018, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products. open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software. notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. THE SOFTWARE.
*/ */
// A fixed point implementation of Freeverb by Jezar at Dreampoint // A fixed point implementation of Freeverb by Jezar at Dreampoint
// http://blog.bjornroche.com/2012/06/freeverb-original-public-domain-code-by.html // http://blog.bjornroche.com/2012/06/freeverb-original-public-domain-code-by.html
@ -34,449 +34,450 @@
MyAudioEffectFreeverb::MyAudioEffectFreeverb() : AudioStream(1, inputQueueArray) MyAudioEffectFreeverb::MyAudioEffectFreeverb() : AudioStream(1, inputQueueArray)
{ {
memset(comb1buf, 0, sizeof(comb1buf)); memset(comb1buf, 0, sizeof(comb1buf));
memset(comb2buf, 0, sizeof(comb2buf)); memset(comb2buf, 0, sizeof(comb2buf));
memset(comb3buf, 0, sizeof(comb3buf)); memset(comb3buf, 0, sizeof(comb3buf));
memset(comb4buf, 0, sizeof(comb4buf)); memset(comb4buf, 0, sizeof(comb4buf));
memset(comb5buf, 0, sizeof(comb5buf)); memset(comb5buf, 0, sizeof(comb5buf));
memset(comb6buf, 0, sizeof(comb6buf)); memset(comb6buf, 0, sizeof(comb6buf));
memset(comb7buf, 0, sizeof(comb7buf)); memset(comb7buf, 0, sizeof(comb7buf));
memset(comb8buf, 0, sizeof(comb8buf)); memset(comb8buf, 0, sizeof(comb8buf));
comb1index = 0; comb1index = 0;
comb2index = 0; comb2index = 0;
comb3index = 0; comb3index = 0;
comb4index = 0; comb4index = 0;
comb5index = 0; comb5index = 0;
comb6index = 0; comb6index = 0;
comb7index = 0; comb7index = 0;
comb8index = 0; comb8index = 0;
comb1filter = 0; comb1filter = 0;
comb2filter = 0; comb2filter = 0;
comb3filter = 0; comb3filter = 0;
comb4filter = 0; comb4filter = 0;
comb5filter = 0; comb5filter = 0;
comb6filter = 0; comb6filter = 0;
comb7filter = 0; comb7filter = 0;
comb8filter = 0; comb8filter = 0;
combdamp1 = 6553; combdamp1 = 6553;
combdamp2 = 26215; combdamp2 = 26215;
combfeeback = 27524; combfeeback = 27524;
memset(allpass1buf, 0, sizeof(allpass1buf)); memset(allpass1buf, 0, sizeof(allpass1buf));
memset(allpass2buf, 0, sizeof(allpass2buf)); memset(allpass2buf, 0, sizeof(allpass2buf));
memset(allpass3buf, 0, sizeof(allpass3buf)); memset(allpass3buf, 0, sizeof(allpass3buf));
memset(allpass4buf, 0, sizeof(allpass4buf)); memset(allpass4buf, 0, sizeof(allpass4buf));
allpass1index = 0; allpass1index = 0;
allpass2index = 0; allpass2index = 0;
allpass3index = 0; allpass3index = 0;
allpass4index = 0; allpass4index = 0;
} }
// cleaner sat16 by http://www.moseleyinstruments.com/ // cleaner sat16 by http://www.moseleyinstruments.com/
static int16_t sat16(int32_t n, int rshift) { static int16_t sat16(int32_t n, int rshift) {
// we should always round towards 0 // we should always round towards 0
// to avoid recirculating round-off noise // to avoid recirculating round-off noise
// //
// a 2s complement positive number is always // a 2s complement positive number is always
// rounded down, so we only need to take // rounded down, so we only need to take
// care of negative numbers // care of negative numbers
if (n < 0) { if (n < 0) {
n = n + (~(0xFFFFFFFFUL << rshift)); n = n + (~(0xFFFFFFFFUL << rshift));
} }
n = n >> rshift; n = n >> rshift;
if (n > 32767) { if (n > 32767) {
return 32767; return 32767;
} }
if (n < -32768) { if (n < -32768) {
return -32768; return -32768;
} }
return n; return n;
} }
// TODO: move this to one of the data files, use in output_adat.cpp, output_tdm.cpp, etc // TODO: move this to one of the data files, use in output_adat.cpp, output_tdm.cpp, etc
static const audio_block_t zeroblock = { static const audio_block_t zeroblock = {
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, 0, 0, 0, 0, 0,
#if AUDIO_BLOCK_SAMPLES > 16 #if AUDIO_BLOCK_SAMPLES > 16
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,
#endif #endif
#if AUDIO_BLOCK_SAMPLES > 32 #if AUDIO_BLOCK_SAMPLES > 32
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,
#endif #endif
#if AUDIO_BLOCK_SAMPLES > 48 #if AUDIO_BLOCK_SAMPLES > 48
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,
#endif #endif
#if AUDIO_BLOCK_SAMPLES > 64 #if AUDIO_BLOCK_SAMPLES > 64
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,
#endif #endif
#if AUDIO_BLOCK_SAMPLES > 80 #if AUDIO_BLOCK_SAMPLES > 80
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,
#endif #endif
#if AUDIO_BLOCK_SAMPLES > 96 #if AUDIO_BLOCK_SAMPLES > 96
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,
#endif #endif
#if AUDIO_BLOCK_SAMPLES > 112 #if AUDIO_BLOCK_SAMPLES > 112
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,
#endif #endif
} }; }
};
void MyAudioEffectFreeverb::update() void MyAudioEffectFreeverb::update()
{ {
#if defined(__ARM_ARCH_7EM__) #if defined(__ARM_ARCH_7EM__)
const audio_block_t *block; const audio_block_t *block;
audio_block_t *outblock; audio_block_t *outblock;
int i; int i;
int16_t input, bufout, output; int16_t input, bufout, output;
int32_t sum; int32_t sum;
outblock = allocate(); outblock = allocate();
if (!outblock) { if (!outblock) {
audio_block_t *tmp = receiveReadOnly(0); audio_block_t *tmp = receiveReadOnly(0);
if (tmp) release(tmp); if (tmp) release(tmp);
return; return;
} }
block = receiveReadOnly(0); block = receiveReadOnly(0);
if (!block) block = &zeroblock; if (!block) block = &zeroblock;
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
// TODO: scale numerical range depending on roomsize & damping // TODO: scale numerical range depending on roomsize & damping
input = sat16(block->data[i] * 8738, 17); // for numerical headroom input = sat16(block->data[i] * 8738, 17); // for numerical headroom
sum = 0; sum = 0;
bufout = comb1buf[comb1index]; bufout = comb1buf[comb1index];
sum += bufout; sum += bufout;
comb1filter = sat16(bufout * combdamp2 + comb1filter * combdamp1, 15); comb1filter = sat16(bufout * combdamp2 + comb1filter * combdamp1, 15);
comb1buf[comb1index] = sat16(input + sat16(comb1filter * combfeeback, 15), 0); comb1buf[comb1index] = sat16(input + sat16(comb1filter * combfeeback, 15), 0);
if (++comb1index >= sizeof(comb1buf)/sizeof(int16_t)) comb1index = 0; if (++comb1index >= sizeof(comb1buf) / sizeof(int16_t)) comb1index = 0;
bufout = comb2buf[comb2index]; bufout = comb2buf[comb2index];
sum += bufout; sum += bufout;
comb2filter = sat16(bufout * combdamp2 + comb2filter * combdamp1, 15); comb2filter = sat16(bufout * combdamp2 + comb2filter * combdamp1, 15);
comb2buf[comb2index] = sat16(input + sat16(comb2filter * combfeeback, 15), 0); comb2buf[comb2index] = sat16(input + sat16(comb2filter * combfeeback, 15), 0);
if (++comb2index >= sizeof(comb2buf)/sizeof(int16_t)) comb2index = 0; if (++comb2index >= sizeof(comb2buf) / sizeof(int16_t)) comb2index = 0;
bufout = comb3buf[comb3index]; bufout = comb3buf[comb3index];
sum += bufout; sum += bufout;
comb3filter = sat16(bufout * combdamp2 + comb3filter * combdamp1, 15); comb3filter = sat16(bufout * combdamp2 + comb3filter * combdamp1, 15);
comb3buf[comb3index] = sat16(input + sat16(comb3filter * combfeeback, 15), 0); comb3buf[comb3index] = sat16(input + sat16(comb3filter * combfeeback, 15), 0);
if (++comb3index >= sizeof(comb3buf)/sizeof(int16_t)) comb3index = 0; if (++comb3index >= sizeof(comb3buf) / sizeof(int16_t)) comb3index = 0;
bufout = comb4buf[comb4index]; bufout = comb4buf[comb4index];
sum += bufout; sum += bufout;
comb4filter = sat16(bufout * combdamp2 + comb4filter * combdamp1, 15); comb4filter = sat16(bufout * combdamp2 + comb4filter * combdamp1, 15);
comb4buf[comb4index] = sat16(input + sat16(comb4filter * combfeeback, 15), 0); comb4buf[comb4index] = sat16(input + sat16(comb4filter * combfeeback, 15), 0);
if (++comb4index >= sizeof(comb4buf)/sizeof(int16_t)) comb4index = 0; if (++comb4index >= sizeof(comb4buf) / sizeof(int16_t)) comb4index = 0;
bufout = comb5buf[comb5index]; bufout = comb5buf[comb5index];
sum += bufout; sum += bufout;
comb5filter = sat16(bufout * combdamp2 + comb5filter * combdamp1, 15); comb5filter = sat16(bufout * combdamp2 + comb5filter * combdamp1, 15);
comb5buf[comb5index] = sat16(input + sat16(comb5filter * combfeeback, 15), 0); comb5buf[comb5index] = sat16(input + sat16(comb5filter * combfeeback, 15), 0);
if (++comb5index >= sizeof(comb5buf)/sizeof(int16_t)) comb5index = 0; if (++comb5index >= sizeof(comb5buf) / sizeof(int16_t)) comb5index = 0;
bufout = comb6buf[comb6index]; bufout = comb6buf[comb6index];
sum += bufout; sum += bufout;
comb6filter = sat16(bufout * combdamp2 + comb6filter * combdamp1, 15); comb6filter = sat16(bufout * combdamp2 + comb6filter * combdamp1, 15);
comb6buf[comb6index] = sat16(input + sat16(comb6filter * combfeeback, 15), 0); comb6buf[comb6index] = sat16(input + sat16(comb6filter * combfeeback, 15), 0);
if (++comb6index >= sizeof(comb6buf)/sizeof(int16_t)) comb6index = 0; if (++comb6index >= sizeof(comb6buf) / sizeof(int16_t)) comb6index = 0;
bufout = comb7buf[comb7index]; bufout = comb7buf[comb7index];
sum += bufout; sum += bufout;
comb7filter = sat16(bufout * combdamp2 + comb7filter * combdamp1, 15); comb7filter = sat16(bufout * combdamp2 + comb7filter * combdamp1, 15);
comb7buf[comb7index] = sat16(input + sat16(comb7filter * combfeeback, 15), 0); comb7buf[comb7index] = sat16(input + sat16(comb7filter * combfeeback, 15), 0);
if (++comb7index >= sizeof(comb7buf)/sizeof(int16_t)) comb7index = 0; if (++comb7index >= sizeof(comb7buf) / sizeof(int16_t)) comb7index = 0;
bufout = comb8buf[comb8index]; bufout = comb8buf[comb8index];
sum += bufout; sum += bufout;
comb8filter = sat16(bufout * combdamp2 + comb8filter * combdamp1, 15); comb8filter = sat16(bufout * combdamp2 + comb8filter * combdamp1, 15);
comb8buf[comb8index] = sat16(input + sat16(comb8filter * combfeeback, 15), 0); comb8buf[comb8index] = sat16(input + sat16(comb8filter * combfeeback, 15), 0);
if (++comb8index >= sizeof(comb8buf)/sizeof(int16_t)) comb8index = 0; if (++comb8index >= sizeof(comb8buf) / sizeof(int16_t)) comb8index = 0;
output = sat16(sum * 31457, 17); output = sat16(sum * 31457, 17);
bufout = allpass1buf[allpass1index]; bufout = allpass1buf[allpass1index];
allpass1buf[allpass1index] = output + (bufout >> 1); allpass1buf[allpass1index] = output + (bufout >> 1);
output = sat16(bufout - output, 1); output = sat16(bufout - output, 1);
if (++allpass1index >= sizeof(allpass1buf)/sizeof(int16_t)) allpass1index = 0; if (++allpass1index >= sizeof(allpass1buf) / sizeof(int16_t)) allpass1index = 0;
bufout = allpass2buf[allpass2index]; bufout = allpass2buf[allpass2index];
allpass2buf[allpass2index] = output + (bufout >> 1); allpass2buf[allpass2index] = output + (bufout >> 1);
output = sat16(bufout - output, 1); output = sat16(bufout - output, 1);
if (++allpass2index >= sizeof(allpass2buf)/sizeof(int16_t)) allpass2index = 0; if (++allpass2index >= sizeof(allpass2buf) / sizeof(int16_t)) allpass2index = 0;
bufout = allpass3buf[allpass3index]; bufout = allpass3buf[allpass3index];
allpass3buf[allpass3index] = output + (bufout >> 1); allpass3buf[allpass3index] = output + (bufout >> 1);
output = sat16(bufout - output, 1); output = sat16(bufout - output, 1);
if (++allpass3index >= sizeof(allpass3buf)/sizeof(int16_t)) allpass3index = 0; if (++allpass3index >= sizeof(allpass3buf) / sizeof(int16_t)) allpass3index = 0;
bufout = allpass4buf[allpass4index]; bufout = allpass4buf[allpass4index];
allpass4buf[allpass4index] = output + (bufout >> 1); allpass4buf[allpass4index] = output + (bufout >> 1);
output = sat16(bufout - output, 1); output = sat16(bufout - output, 1);
if (++allpass4index >= sizeof(allpass4buf)/sizeof(int16_t)) allpass4index = 0; if (++allpass4index >= sizeof(allpass4buf) / sizeof(int16_t)) allpass4index = 0;
outblock->data[i] = sat16(output * 30, 0); outblock->data[i] = sat16(output * 30, 0);
} }
transmit(outblock); transmit(outblock);
release(outblock); release(outblock);
if (block != &zeroblock) release((audio_block_t *)block); if (block != &zeroblock) release((audio_block_t *)block);
#elif defined(KINETISL) #elif defined(KINETISL)
audio_block_t *block; audio_block_t *block;
block = receiveReadOnly(0); block = receiveReadOnly(0);
if (block) release(block); if (block) release(block);
#endif #endif
} }
MyAudioEffectFreeverbStereo::MyAudioEffectFreeverbStereo() : AudioStream(1, inputQueueArray) MyAudioEffectFreeverbStereo::MyAudioEffectFreeverbStereo() : AudioStream(1, inputQueueArray)
{ {
memset(comb1bufL, 0, sizeof(comb1bufL)); memset(comb1bufL, 0, sizeof(comb1bufL));
memset(comb2bufL, 0, sizeof(comb2bufL)); memset(comb2bufL, 0, sizeof(comb2bufL));
memset(comb3bufL, 0, sizeof(comb3bufL)); memset(comb3bufL, 0, sizeof(comb3bufL));
memset(comb4bufL, 0, sizeof(comb4bufL)); memset(comb4bufL, 0, sizeof(comb4bufL));
memset(comb5bufL, 0, sizeof(comb5bufL)); memset(comb5bufL, 0, sizeof(comb5bufL));
memset(comb6bufL, 0, sizeof(comb6bufL)); memset(comb6bufL, 0, sizeof(comb6bufL));
memset(comb7bufL, 0, sizeof(comb7bufL)); memset(comb7bufL, 0, sizeof(comb7bufL));
memset(comb8bufL, 0, sizeof(comb8bufL)); memset(comb8bufL, 0, sizeof(comb8bufL));
comb1indexL = 0; comb1indexL = 0;
comb2indexL = 0; comb2indexL = 0;
comb3indexL = 0; comb3indexL = 0;
comb4indexL = 0; comb4indexL = 0;
comb5indexL = 0; comb5indexL = 0;
comb6indexL = 0; comb6indexL = 0;
comb7indexL = 0; comb7indexL = 0;
comb8indexL = 0; comb8indexL = 0;
comb1filterL = 0; comb1filterL = 0;
comb2filterL = 0; comb2filterL = 0;
comb3filterL = 0; comb3filterL = 0;
comb4filterL = 0; comb4filterL = 0;
comb5filterL = 0; comb5filterL = 0;
comb6filterL = 0; comb6filterL = 0;
comb7filterL = 0; comb7filterL = 0;
comb8filterL = 0; comb8filterL = 0;
memset(comb1bufR, 0, sizeof(comb1bufR)); memset(comb1bufR, 0, sizeof(comb1bufR));
memset(comb2bufR, 0, sizeof(comb2bufR)); memset(comb2bufR, 0, sizeof(comb2bufR));
memset(comb3bufR, 0, sizeof(comb3bufR)); memset(comb3bufR, 0, sizeof(comb3bufR));
memset(comb4bufR, 0, sizeof(comb4bufR)); memset(comb4bufR, 0, sizeof(comb4bufR));
memset(comb5bufR, 0, sizeof(comb5bufR)); memset(comb5bufR, 0, sizeof(comb5bufR));
memset(comb6bufR, 0, sizeof(comb6bufR)); memset(comb6bufR, 0, sizeof(comb6bufR));
memset(comb7bufR, 0, sizeof(comb7bufR)); memset(comb7bufR, 0, sizeof(comb7bufR));
memset(comb8bufR, 0, sizeof(comb8bufR)); memset(comb8bufR, 0, sizeof(comb8bufR));
comb1indexR = 0; comb1indexR = 0;
comb2indexR = 0; comb2indexR = 0;
comb3indexR = 0; comb3indexR = 0;
comb4indexR = 0; comb4indexR = 0;
comb5indexR = 0; comb5indexR = 0;
comb6indexR = 0; comb6indexR = 0;
comb7indexR = 0; comb7indexR = 0;
comb8indexR = 0; comb8indexR = 0;
comb1filterR = 0; comb1filterR = 0;
comb2filterR = 0; comb2filterR = 0;
comb3filterR = 0; comb3filterR = 0;
comb4filterR = 0; comb4filterR = 0;
comb5filterR = 0; comb5filterR = 0;
comb6filterR = 0; comb6filterR = 0;
comb7filterR = 0; comb7filterR = 0;
comb8filterR = 0; comb8filterR = 0;
combdamp1 = 6553; combdamp1 = 6553;
combdamp2 = 26215; combdamp2 = 26215;
combfeeback = 27524; combfeeback = 27524;
memset(allpass1bufL, 0, sizeof(allpass1bufL)); memset(allpass1bufL, 0, sizeof(allpass1bufL));
memset(allpass2bufL, 0, sizeof(allpass2bufL)); memset(allpass2bufL, 0, sizeof(allpass2bufL));
memset(allpass3bufL, 0, sizeof(allpass3bufL)); memset(allpass3bufL, 0, sizeof(allpass3bufL));
memset(allpass4bufL, 0, sizeof(allpass4bufL)); memset(allpass4bufL, 0, sizeof(allpass4bufL));
allpass1indexL = 0; allpass1indexL = 0;
allpass2indexL = 0; allpass2indexL = 0;
allpass3indexL = 0; allpass3indexL = 0;
allpass4indexL = 0; allpass4indexL = 0;
memset(allpass1bufR, 0, sizeof(allpass1bufR)); memset(allpass1bufR, 0, sizeof(allpass1bufR));
memset(allpass2bufR, 0, sizeof(allpass2bufR)); memset(allpass2bufR, 0, sizeof(allpass2bufR));
memset(allpass3bufR, 0, sizeof(allpass3bufR)); memset(allpass3bufR, 0, sizeof(allpass3bufR));
memset(allpass4bufR, 0, sizeof(allpass4bufR)); memset(allpass4bufR, 0, sizeof(allpass4bufR));
allpass1indexR = 0; allpass1indexR = 0;
allpass2indexR = 0; allpass2indexR = 0;
allpass3indexR = 0; allpass3indexR = 0;
allpass4indexR = 0; allpass4indexR = 0;
} }
void MyAudioEffectFreeverbStereo::update() void MyAudioEffectFreeverbStereo::update()
{ {
#if defined(__ARM_ARCH_7EM__) #if defined(__ARM_ARCH_7EM__)
const audio_block_t *block; const audio_block_t *block;
audio_block_t *outblockL; audio_block_t *outblockL;
audio_block_t *outblockR; audio_block_t *outblockR;
int i; int i;
int16_t input, bufout, outputL, outputR; int16_t input, bufout, outputL, outputR;
int32_t sum; int32_t sum;
block = receiveReadOnly(0); block = receiveReadOnly(0);
outblockL = allocate(); outblockL = allocate();
outblockR = allocate(); outblockR = allocate();
if (!outblockL || !outblockR) { if (!outblockL || !outblockR) {
if (outblockL) release(outblockL); if (outblockL) release(outblockL);
if (outblockR) release(outblockR); if (outblockR) release(outblockR);
if (block) release((audio_block_t *)block); if (block) release((audio_block_t *)block);
return; return;
} }
if (!block) block = &zeroblock; if (!block) block = &zeroblock;
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) { for (i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
// TODO: scale numerical range depending on roomsize & damping // TODO: scale numerical range depending on roomsize & damping
input = sat16(block->data[i] * 8738, 17); // for numerical headroom input = sat16(block->data[i] * 8738, 17); // for numerical headroom
sum = 0; sum = 0;
bufout = comb1bufL[comb1indexL]; bufout = comb1bufL[comb1indexL];
sum += bufout; sum += bufout;
comb1filterL = sat16(bufout * combdamp2 + comb1filterL * combdamp1, 15); comb1filterL = sat16(bufout * combdamp2 + comb1filterL * combdamp1, 15);
comb1bufL[comb1indexL] = sat16(input + sat16(comb1filterL * combfeeback, 15), 0); comb1bufL[comb1indexL] = sat16(input + sat16(comb1filterL * combfeeback, 15), 0);
if (++comb1indexL >= sizeof(comb1bufL)/sizeof(int16_t)) comb1indexL = 0; if (++comb1indexL >= sizeof(comb1bufL) / sizeof(int16_t)) comb1indexL = 0;
bufout = comb2bufL[comb2indexL]; bufout = comb2bufL[comb2indexL];
sum += bufout; sum += bufout;
comb2filterL = sat16(bufout * combdamp2 + comb2filterL * combdamp1, 15); comb2filterL = sat16(bufout * combdamp2 + comb2filterL * combdamp1, 15);
comb2bufL[comb2indexL] = sat16(input + sat16(comb2filterL * combfeeback, 15), 0); comb2bufL[comb2indexL] = sat16(input + sat16(comb2filterL * combfeeback, 15), 0);
if (++comb2indexL >= sizeof(comb2bufL)/sizeof(int16_t)) comb2indexL = 0; if (++comb2indexL >= sizeof(comb2bufL) / sizeof(int16_t)) comb2indexL = 0;
bufout = comb3bufL[comb3indexL]; bufout = comb3bufL[comb3indexL];
sum += bufout; sum += bufout;
comb3filterL = sat16(bufout * combdamp2 + comb3filterL * combdamp1, 15); comb3filterL = sat16(bufout * combdamp2 + comb3filterL * combdamp1, 15);
comb3bufL[comb3indexL] = sat16(input + sat16(comb3filterL * combfeeback, 15), 0); comb3bufL[comb3indexL] = sat16(input + sat16(comb3filterL * combfeeback, 15), 0);
if (++comb3indexL >= sizeof(comb3bufL)/sizeof(int16_t)) comb3indexL = 0; if (++comb3indexL >= sizeof(comb3bufL) / sizeof(int16_t)) comb3indexL = 0;
bufout = comb4bufL[comb4indexL]; bufout = comb4bufL[comb4indexL];
sum += bufout; sum += bufout;
comb4filterL = sat16(bufout * combdamp2 + comb4filterL * combdamp1, 15); comb4filterL = sat16(bufout * combdamp2 + comb4filterL * combdamp1, 15);
comb4bufL[comb4indexL] = sat16(input + sat16(comb4filterL * combfeeback, 15), 0); comb4bufL[comb4indexL] = sat16(input + sat16(comb4filterL * combfeeback, 15), 0);
if (++comb4indexL >= sizeof(comb4bufL)/sizeof(int16_t)) comb4indexL = 0; if (++comb4indexL >= sizeof(comb4bufL) / sizeof(int16_t)) comb4indexL = 0;
bufout = comb5bufL[comb5indexL]; bufout = comb5bufL[comb5indexL];
sum += bufout; sum += bufout;
comb5filterL = sat16(bufout * combdamp2 + comb5filterL * combdamp1, 15); comb5filterL = sat16(bufout * combdamp2 + comb5filterL * combdamp1, 15);
comb5bufL[comb5indexL] = sat16(input + sat16(comb5filterL * combfeeback, 15), 0); comb5bufL[comb5indexL] = sat16(input + sat16(comb5filterL * combfeeback, 15), 0);
if (++comb5indexL >= sizeof(comb5bufL)/sizeof(int16_t)) comb5indexL = 0; if (++comb5indexL >= sizeof(comb5bufL) / sizeof(int16_t)) comb5indexL = 0;
bufout = comb6bufL[comb6indexL]; bufout = comb6bufL[comb6indexL];
sum += bufout; sum += bufout;
comb6filterL = sat16(bufout * combdamp2 + comb6filterL * combdamp1, 15); comb6filterL = sat16(bufout * combdamp2 + comb6filterL * combdamp1, 15);
comb6bufL[comb6indexL] = sat16(input + sat16(comb6filterL * combfeeback, 15), 0); comb6bufL[comb6indexL] = sat16(input + sat16(comb6filterL * combfeeback, 15), 0);
if (++comb6indexL >= sizeof(comb6bufL)/sizeof(int16_t)) comb6indexL = 0; if (++comb6indexL >= sizeof(comb6bufL) / sizeof(int16_t)) comb6indexL = 0;
bufout = comb7bufL[comb7indexL]; bufout = comb7bufL[comb7indexL];
sum += bufout; sum += bufout;
comb7filterL = sat16(bufout * combdamp2 + comb7filterL * combdamp1, 15); comb7filterL = sat16(bufout * combdamp2 + comb7filterL * combdamp1, 15);
comb7bufL[comb7indexL] = sat16(input + sat16(comb7filterL * combfeeback, 15), 0); comb7bufL[comb7indexL] = sat16(input + sat16(comb7filterL * combfeeback, 15), 0);
if (++comb7indexL >= sizeof(comb7bufL)/sizeof(int16_t)) comb7indexL = 0; if (++comb7indexL >= sizeof(comb7bufL) / sizeof(int16_t)) comb7indexL = 0;
bufout = comb8bufL[comb8indexL]; bufout = comb8bufL[comb8indexL];
sum += bufout; sum += bufout;
comb8filterL = sat16(bufout * combdamp2 + comb8filterL * combdamp1, 15); comb8filterL = sat16(bufout * combdamp2 + comb8filterL * combdamp1, 15);
comb8bufL[comb8indexL] = sat16(input + sat16(comb8filterL * combfeeback, 15), 0); comb8bufL[comb8indexL] = sat16(input + sat16(comb8filterL * combfeeback, 15), 0);
if (++comb8indexL >= sizeof(comb8bufL)/sizeof(int16_t)) comb8indexL = 0; if (++comb8indexL >= sizeof(comb8bufL) / sizeof(int16_t)) comb8indexL = 0;
outputL = sat16(sum * 31457, 17); outputL = sat16(sum * 31457, 17);
sum = 0; sum = 0;
bufout = comb1bufR[comb1indexR]; bufout = comb1bufR[comb1indexR];
sum += bufout; sum += bufout;
comb1filterR = sat16(bufout * combdamp2 + comb1filterR * combdamp1, 15); comb1filterR = sat16(bufout * combdamp2 + comb1filterR * combdamp1, 15);
comb1bufR[comb1indexR] = sat16(input + sat16(comb1filterR * combfeeback, 15), 0); comb1bufR[comb1indexR] = sat16(input + sat16(comb1filterR * combfeeback, 15), 0);
if (++comb1indexR >= sizeof(comb1bufR)/sizeof(int16_t)) comb1indexR = 0; if (++comb1indexR >= sizeof(comb1bufR) / sizeof(int16_t)) comb1indexR = 0;
bufout = comb2bufR[comb2indexR]; bufout = comb2bufR[comb2indexR];
sum += bufout; sum += bufout;
comb2filterR = sat16(bufout * combdamp2 + comb2filterR * combdamp1, 15); comb2filterR = sat16(bufout * combdamp2 + comb2filterR * combdamp1, 15);
comb2bufR[comb2indexR] = sat16(input + sat16(comb2filterR * combfeeback, 15), 0); comb2bufR[comb2indexR] = sat16(input + sat16(comb2filterR * combfeeback, 15), 0);
if (++comb2indexR >= sizeof(comb2bufR)/sizeof(int16_t)) comb2indexR = 0; if (++comb2indexR >= sizeof(comb2bufR) / sizeof(int16_t)) comb2indexR = 0;
bufout = comb3bufR[comb3indexR]; bufout = comb3bufR[comb3indexR];
sum += bufout; sum += bufout;
comb3filterR = sat16(bufout * combdamp2 + comb3filterR * combdamp1, 15); comb3filterR = sat16(bufout * combdamp2 + comb3filterR * combdamp1, 15);
comb3bufR[comb3indexR] = sat16(input + sat16(comb3filterR * combfeeback, 15), 0); comb3bufR[comb3indexR] = sat16(input + sat16(comb3filterR * combfeeback, 15), 0);
if (++comb3indexR >= sizeof(comb3bufR)/sizeof(int16_t)) comb3indexR = 0; if (++comb3indexR >= sizeof(comb3bufR) / sizeof(int16_t)) comb3indexR = 0;
bufout = comb4bufR[comb4indexR]; bufout = comb4bufR[comb4indexR];
sum += bufout; sum += bufout;
comb4filterR = sat16(bufout * combdamp2 + comb4filterR * combdamp1, 15); comb4filterR = sat16(bufout * combdamp2 + comb4filterR * combdamp1, 15);
comb4bufR[comb4indexR] = sat16(input + sat16(comb4filterR * combfeeback, 15), 0); comb4bufR[comb4indexR] = sat16(input + sat16(comb4filterR * combfeeback, 15), 0);
if (++comb4indexR >= sizeof(comb4bufR)/sizeof(int16_t)) comb4indexR = 0; if (++comb4indexR >= sizeof(comb4bufR) / sizeof(int16_t)) comb4indexR = 0;
bufout = comb5bufR[comb5indexR]; bufout = comb5bufR[comb5indexR];
sum += bufout; sum += bufout;
comb5filterR = sat16(bufout * combdamp2 + comb5filterR * combdamp1, 15); comb5filterR = sat16(bufout * combdamp2 + comb5filterR * combdamp1, 15);
comb5bufR[comb5indexR] = sat16(input + sat16(comb5filterR * combfeeback, 15), 0); comb5bufR[comb5indexR] = sat16(input + sat16(comb5filterR * combfeeback, 15), 0);
if (++comb5indexR >= sizeof(comb5bufR)/sizeof(int16_t)) comb5indexR = 0; if (++comb5indexR >= sizeof(comb5bufR) / sizeof(int16_t)) comb5indexR = 0;
bufout = comb6bufR[comb6indexR]; bufout = comb6bufR[comb6indexR];
sum += bufout; sum += bufout;
comb6filterR = sat16(bufout * combdamp2 + comb6filterR * combdamp1, 15); comb6filterR = sat16(bufout * combdamp2 + comb6filterR * combdamp1, 15);
comb6bufR[comb6indexR] = sat16(input + sat16(comb6filterR * combfeeback, 15), 0); comb6bufR[comb6indexR] = sat16(input + sat16(comb6filterR * combfeeback, 15), 0);
if (++comb6indexR >= sizeof(comb6bufR)/sizeof(int16_t)) comb6indexR = 0; if (++comb6indexR >= sizeof(comb6bufR) / sizeof(int16_t)) comb6indexR = 0;
bufout = comb7bufR[comb7indexR]; bufout = comb7bufR[comb7indexR];
sum += bufout; sum += bufout;
comb7filterR = sat16(bufout * combdamp2 + comb7filterR * combdamp1, 15); comb7filterR = sat16(bufout * combdamp2 + comb7filterR * combdamp1, 15);
comb7bufR[comb7indexR] = sat16(input + sat16(comb7filterR * combfeeback, 15), 0); comb7bufR[comb7indexR] = sat16(input + sat16(comb7filterR * combfeeback, 15), 0);
if (++comb7indexR >= sizeof(comb7bufR)/sizeof(int16_t)) comb7indexR = 0; if (++comb7indexR >= sizeof(comb7bufR) / sizeof(int16_t)) comb7indexR = 0;
bufout = comb8bufR[comb8indexR]; bufout = comb8bufR[comb8indexR];
sum += bufout; sum += bufout;
comb8filterR = sat16(bufout * combdamp2 + comb8filterR * combdamp1, 15); comb8filterR = sat16(bufout * combdamp2 + comb8filterR * combdamp1, 15);
comb8bufR[comb8indexR] = sat16(input + sat16(comb8filterR * combfeeback, 15), 0); comb8bufR[comb8indexR] = sat16(input + sat16(comb8filterR * combfeeback, 15), 0);
if (++comb8indexR >= sizeof(comb8bufR)/sizeof(int16_t)) comb8indexR = 0; if (++comb8indexR >= sizeof(comb8bufR) / sizeof(int16_t)) comb8indexR = 0;
outputR = sat16(sum * 31457, 17); outputR = sat16(sum * 31457, 17);
bufout = allpass1bufL[allpass1indexL]; bufout = allpass1bufL[allpass1indexL];
allpass1bufL[allpass1indexL] = outputL + (bufout >> 1); allpass1bufL[allpass1indexL] = outputL + (bufout >> 1);
outputL = sat16(bufout - outputL, 1); outputL = sat16(bufout - outputL, 1);
if (++allpass1indexL >= sizeof(allpass1bufL)/sizeof(int16_t)) allpass1indexL = 0; if (++allpass1indexL >= sizeof(allpass1bufL) / sizeof(int16_t)) allpass1indexL = 0;
bufout = allpass2bufL[allpass2indexL]; bufout = allpass2bufL[allpass2indexL];
allpass2bufL[allpass2indexL] = outputL + (bufout >> 1); allpass2bufL[allpass2indexL] = outputL + (bufout >> 1);
outputL = sat16(bufout - outputL, 1); outputL = sat16(bufout - outputL, 1);
if (++allpass2indexL >= sizeof(allpass2bufL)/sizeof(int16_t)) allpass2indexL = 0; if (++allpass2indexL >= sizeof(allpass2bufL) / sizeof(int16_t)) allpass2indexL = 0;
bufout = allpass3bufL[allpass3indexL]; bufout = allpass3bufL[allpass3indexL];
allpass3bufL[allpass3indexL] = outputL + (bufout >> 1); allpass3bufL[allpass3indexL] = outputL + (bufout >> 1);
outputL = sat16(bufout - outputL, 1); outputL = sat16(bufout - outputL, 1);
if (++allpass3indexL >= sizeof(allpass3bufL)/sizeof(int16_t)) allpass3indexL = 0; if (++allpass3indexL >= sizeof(allpass3bufL) / sizeof(int16_t)) allpass3indexL = 0;
bufout = allpass4bufL[allpass4indexL]; bufout = allpass4bufL[allpass4indexL];
allpass4bufL[allpass4indexL] = outputL + (bufout >> 1); allpass4bufL[allpass4indexL] = outputL + (bufout >> 1);
outputL = sat16(bufout - outputL, 1); outputL = sat16(bufout - outputL, 1);
if (++allpass4indexL >= sizeof(allpass4bufL)/sizeof(int16_t)) allpass4indexL = 0; if (++allpass4indexL >= sizeof(allpass4bufL) / sizeof(int16_t)) allpass4indexL = 0;
outblockL->data[i] = sat16(outputL * 30, 0); outblockL->data[i] = sat16(outputL * 30, 0);
bufout = allpass1bufR[allpass1indexR]; bufout = allpass1bufR[allpass1indexR];
allpass1bufR[allpass1indexR] = outputR + (bufout >> 1); allpass1bufR[allpass1indexR] = outputR + (bufout >> 1);
outputR = sat16(bufout - outputR, 1); outputR = sat16(bufout - outputR, 1);
if (++allpass1indexR >= sizeof(allpass1bufR)/sizeof(int16_t)) allpass1indexR = 0; if (++allpass1indexR >= sizeof(allpass1bufR) / sizeof(int16_t)) allpass1indexR = 0;
bufout = allpass2bufR[allpass2indexR]; bufout = allpass2bufR[allpass2indexR];
allpass2bufR[allpass2indexR] = outputR + (bufout >> 1); allpass2bufR[allpass2indexR] = outputR + (bufout >> 1);
outputR = sat16(bufout - outputR, 1); outputR = sat16(bufout - outputR, 1);
if (++allpass2indexR >= sizeof(allpass2bufR)/sizeof(int16_t)) allpass2indexR = 0; if (++allpass2indexR >= sizeof(allpass2bufR) / sizeof(int16_t)) allpass2indexR = 0;
bufout = allpass3bufR[allpass3indexR]; bufout = allpass3bufR[allpass3indexR];
allpass3bufR[allpass3indexR] = outputR + (bufout >> 1); allpass3bufR[allpass3indexR] = outputR + (bufout >> 1);
outputR = sat16(bufout - outputR, 1); outputR = sat16(bufout - outputR, 1);
if (++allpass3indexR >= sizeof(allpass3bufR)/sizeof(int16_t)) allpass3indexR = 0; if (++allpass3indexR >= sizeof(allpass3bufR) / sizeof(int16_t)) allpass3indexR = 0;
bufout = allpass4bufR[allpass4indexR]; bufout = allpass4bufR[allpass4indexR];
allpass4bufR[allpass4indexR] = outputR + (bufout >> 1); allpass4bufR[allpass4indexR] = outputR + (bufout >> 1);
outputR = sat16(bufout - outputR, 1); outputR = sat16(bufout - outputR, 1);
if (++allpass4indexR >= sizeof(allpass4bufR)/sizeof(int16_t)) allpass4indexR = 0; if (++allpass4indexR >= sizeof(allpass4bufR) / sizeof(int16_t)) allpass4indexR = 0;
outblockR->data[i] = sat16(outputL * 30, 0); outblockR->data[i] = sat16(outputL * 30, 0);
} }
transmit(outblockL, 0); transmit(outblockL, 0);
transmit(outblockR, 1); transmit(outblockR, 1);
release(outblockL); release(outblockL);
release(outblockR); release(outblockR);
if (block != &zeroblock) release((audio_block_t *)block); if (block != &zeroblock) release((audio_block_t *)block);
#elif defined(KINETISL) #elif defined(KINETISL)
audio_block_t *block; audio_block_t *block;
block = receiveReadOnly(0); block = receiveReadOnly(0);
if (block) release(block); if (block) release(block);
#endif #endif
} }

@ -1,28 +1,28 @@
/* Audio Library for Teensy 3.X /* Audio Library for Teensy 3.X
* Copyright (c) 2018, Paul Stoffregen, paul@pjrc.com Copyright (c) 2018, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products. open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software. notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE. THE SOFTWARE.
*/ */
#ifndef my_effect_freeverb_h_ #ifndef my_effect_freeverb_h_
#define my_effect_freeverb_h_ #define my_effect_freeverb_h_
@ -31,153 +31,153 @@
class MyAudioEffectFreeverb : public AudioStream class MyAudioEffectFreeverb : public AudioStream
{ {
public: public:
MyAudioEffectFreeverb(); MyAudioEffectFreeverb();
virtual void update(); virtual void update();
void roomsize(float n) { void roomsize(float n) {
if (n > 1.0f) n = 1.0f; if (n > 1.0f) n = 1.0f;
else if (n < 0.0) n = 0.0f; else if (n < 0.0) n = 0.0f;
combfeeback = (int)(n * 9175.04f) + 22937; combfeeback = (int)(n * 9175.04f) + 22937;
} }
void damping(float n) { void damping(float n) {
if (n > 1.0f) n = 1.0f; if (n > 1.0f) n = 1.0f;
else if (n < 0.0) n = 0.0f; else if (n < 0.0) n = 0.0f;
int x1 = (int)(n * 13107.2f); int x1 = (int)(n * 13107.2f);
int x2 = 32768 - x1; int x2 = 32768 - x1;
__disable_irq(); __disable_irq();
combdamp1 = x1; combdamp1 = x1;
combdamp2 = x2; combdamp2 = x2;
__enable_irq(); __enable_irq();
} }
private: private:
audio_block_t *inputQueueArray[1]; audio_block_t *inputQueueArray[1];
int16_t comb1buf[1116]; int16_t comb1buf[1116];
int16_t comb2buf[1188]; int16_t comb2buf[1188];
int16_t comb3buf[1277]; int16_t comb3buf[1277];
int16_t comb4buf[1356]; int16_t comb4buf[1356];
int16_t comb5buf[1422]; int16_t comb5buf[1422];
int16_t comb6buf[1491]; int16_t comb6buf[1491];
int16_t comb7buf[1557]; int16_t comb7buf[1557];
int16_t comb8buf[1617]; int16_t comb8buf[1617];
uint16_t comb1index; uint16_t comb1index;
uint16_t comb2index; uint16_t comb2index;
uint16_t comb3index; uint16_t comb3index;
uint16_t comb4index; uint16_t comb4index;
uint16_t comb5index; uint16_t comb5index;
uint16_t comb6index; uint16_t comb6index;
uint16_t comb7index; uint16_t comb7index;
uint16_t comb8index; uint16_t comb8index;
int16_t comb1filter; int16_t comb1filter;
int16_t comb2filter; int16_t comb2filter;
int16_t comb3filter; int16_t comb3filter;
int16_t comb4filter; int16_t comb4filter;
int16_t comb5filter; int16_t comb5filter;
int16_t comb6filter; int16_t comb6filter;
int16_t comb7filter; int16_t comb7filter;
int16_t comb8filter; int16_t comb8filter;
int16_t combdamp1; int16_t combdamp1;
int16_t combdamp2; int16_t combdamp2;
int16_t combfeeback; int16_t combfeeback;
int16_t allpass1buf[556]; int16_t allpass1buf[556];
int16_t allpass2buf[441]; int16_t allpass2buf[441];
int16_t allpass3buf[341]; int16_t allpass3buf[341];
int16_t allpass4buf[225]; int16_t allpass4buf[225];
uint16_t allpass1index; uint16_t allpass1index;
uint16_t allpass2index; uint16_t allpass2index;
uint16_t allpass3index; uint16_t allpass3index;
uint16_t allpass4index; uint16_t allpass4index;
}; };
class MyAudioEffectFreeverbStereo : public AudioStream class MyAudioEffectFreeverbStereo : public AudioStream
{ {
public: public:
MyAudioEffectFreeverbStereo(); MyAudioEffectFreeverbStereo();
virtual void update(); virtual void update();
void roomsize(float n) { void roomsize(float n) {
if (n > 1.0f) n = 1.0f; if (n > 1.0f) n = 1.0f;
else if (n < 0.0) n = 0.0f; else if (n < 0.0) n = 0.0f;
combfeeback = (int)(n * 9175.04f) + 22937; combfeeback = (int)(n * 9175.04f) + 22937;
} }
void damping(float n) { void damping(float n) {
if (n > 1.0f) n = 1.0f; if (n > 1.0f) n = 1.0f;
else if (n < 0.0) n = 0.0f; else if (n < 0.0) n = 0.0f;
int x1 = (int)(n * 13107.2f); int x1 = (int)(n * 13107.2f);
int x2 = 32768 - x1; int x2 = 32768 - x1;
__disable_irq(); __disable_irq();
combdamp1 = x1; combdamp1 = x1;
combdamp2 = x2; combdamp2 = x2;
__enable_irq(); __enable_irq();
} }
private: private:
audio_block_t *inputQueueArray[1]; audio_block_t *inputQueueArray[1];
int16_t comb1bufL[1116]; int16_t comb1bufL[1116];
int16_t comb2bufL[1188]; int16_t comb2bufL[1188];
int16_t comb3bufL[1277]; int16_t comb3bufL[1277];
int16_t comb4bufL[1356]; int16_t comb4bufL[1356];
int16_t comb5bufL[1422]; int16_t comb5bufL[1422];
int16_t comb6bufL[1491]; int16_t comb6bufL[1491];
int16_t comb7bufL[1557]; int16_t comb7bufL[1557];
int16_t comb8bufL[1617]; int16_t comb8bufL[1617];
uint16_t comb1indexL; uint16_t comb1indexL;
uint16_t comb2indexL; uint16_t comb2indexL;
uint16_t comb3indexL; uint16_t comb3indexL;
uint16_t comb4indexL; uint16_t comb4indexL;
uint16_t comb5indexL; uint16_t comb5indexL;
uint16_t comb6indexL; uint16_t comb6indexL;
uint16_t comb7indexL; uint16_t comb7indexL;
uint16_t comb8indexL; uint16_t comb8indexL;
int16_t comb1filterL; int16_t comb1filterL;
int16_t comb2filterL; int16_t comb2filterL;
int16_t comb3filterL; int16_t comb3filterL;
int16_t comb4filterL; int16_t comb4filterL;
int16_t comb5filterL; int16_t comb5filterL;
int16_t comb6filterL; int16_t comb6filterL;
int16_t comb7filterL; int16_t comb7filterL;
int16_t comb8filterL; int16_t comb8filterL;
int16_t comb1bufR[1139]; int16_t comb1bufR[1139];
int16_t comb2bufR[1211]; int16_t comb2bufR[1211];
int16_t comb3bufR[1300]; int16_t comb3bufR[1300];
int16_t comb4bufR[1379]; int16_t comb4bufR[1379];
int16_t comb5bufR[1445]; int16_t comb5bufR[1445];
int16_t comb6bufR[1514]; int16_t comb6bufR[1514];
int16_t comb7bufR[1580]; int16_t comb7bufR[1580];
int16_t comb8bufR[1640]; int16_t comb8bufR[1640];
uint16_t comb1indexR; uint16_t comb1indexR;
uint16_t comb2indexR; uint16_t comb2indexR;
uint16_t comb3indexR; uint16_t comb3indexR;
uint16_t comb4indexR; uint16_t comb4indexR;
uint16_t comb5indexR; uint16_t comb5indexR;
uint16_t comb6indexR; uint16_t comb6indexR;
uint16_t comb7indexR; uint16_t comb7indexR;
uint16_t comb8indexR; uint16_t comb8indexR;
int16_t comb1filterR; int16_t comb1filterR;
int16_t comb2filterR; int16_t comb2filterR;
int16_t comb3filterR; int16_t comb3filterR;
int16_t comb4filterR; int16_t comb4filterR;
int16_t comb5filterR; int16_t comb5filterR;
int16_t comb6filterR; int16_t comb6filterR;
int16_t comb7filterR; int16_t comb7filterR;
int16_t comb8filterR; int16_t comb8filterR;
int16_t combdamp1; int16_t combdamp1;
int16_t combdamp2; int16_t combdamp2;
int16_t combfeeback; int16_t combfeeback;
int16_t allpass1bufL[556]; int16_t allpass1bufL[556];
int16_t allpass2bufL[441]; int16_t allpass2bufL[441];
int16_t allpass3bufL[341]; int16_t allpass3bufL[341];
int16_t allpass4bufL[225]; int16_t allpass4bufL[225];
uint16_t allpass1indexL; uint16_t allpass1indexL;
uint16_t allpass2indexL; uint16_t allpass2indexL;
uint16_t allpass3indexL; uint16_t allpass3indexL;
uint16_t allpass4indexL; uint16_t allpass4indexL;
int16_t allpass1bufR[579]; int16_t allpass1bufR[579];
int16_t allpass2bufR[464]; int16_t allpass2bufR[464];
int16_t allpass3bufR[364]; int16_t allpass3bufR[364];
int16_t allpass4bufR[248]; int16_t allpass4bufR[248];
uint16_t allpass1indexR; uint16_t allpass1indexR;
uint16_t allpass2indexR; uint16_t allpass2indexR;
uint16_t allpass3indexR; uint16_t allpass3indexR;
uint16_t allpass4indexR; uint16_t allpass4indexR;
}; };

@ -5,7 +5,7 @@
// Do not change this part. This exact format is required by USB. // Do not change this part. This exact format is required by USB.
struct usb_string_descriptor_struct usb_string_product_name = { struct usb_string_descriptor_struct usb_string_product_name = {
2 + MIDI_NAME_LEN * 2, 2 + MIDI_NAME_LEN * 2,
3, 3,
MIDI_NAME MIDI_NAME
}; };

@ -1,18 +1,18 @@
/* /*
* Copyright 2012 Google Inc. Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
#include "synth.h" #include "synth.h"
#include "pitchenv.h" #include "pitchenv.h"
@ -91,5 +91,3 @@ void PitchEnv::advance(int newix) {
void PitchEnv::getPosition(char *step) { void PitchEnv::getPosition(char *step) {
*step = ix_; *step = ix_;
} }

@ -1,18 +1,18 @@
/* /*
* Copyright 2013 Google Inc. Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
#ifndef __PITCHENV_H #ifndef __PITCHENV_H
#define __PITCHENV_H #define __PITCHENV_H
@ -20,34 +20,33 @@
// Computation of the DX7 pitch envelope // Computation of the DX7 pitch envelope
class PitchEnv { class PitchEnv {
public: public:
static void init(FRAC_NUM sample_rate); static void init(FRAC_NUM sample_rate);
// The rates and levels arrays are calibrated to match the Dx7 parameters // The rates and levels arrays are calibrated to match the Dx7 parameters
// (ie, value 0..99). // (ie, value 0..99).
void set(const int rates[4], const int levels[4]); void set(const int rates[4], const int levels[4]);
// Result is in Q24/octave // Result is in Q24/octave
int32_t getsample(); int32_t getsample();
void keydown(bool down); void keydown(bool down);
void getPosition(char *step); void getPosition(char *step);
private: private:
static int unit_; static int unit_;
int rates_[4]; int rates_[4];
int levels_[4]; int levels_[4];
int32_t level_; int32_t level_;
int targetlevel_; int targetlevel_;
bool rising_; bool rising_;
int ix_; int ix_;
int inc_; int inc_;
bool down_; bool down_;
void advance(int newix); void advance(int newix);
}; };
extern const uint8_t pitchenv_rate[]; extern const uint8_t pitchenv_rate[];
extern const int8_t pitchenv_tab[]; extern const int8_t pitchenv_tab[];
#endif // __PITCHENV_H #endif // __PITCHENV_H

42
sin.h

@ -1,29 +1,29 @@
/* /*
* Copyright 2012 Google Inc. Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
* You may obtain a copy of the License at You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ */
class Sin { class Sin {
public: public:
Sin(); Sin();
static void init(); static void init();
static int32_t lookup(int32_t phase); static int32_t lookup(int32_t phase);
static int32_t compute(int32_t phase); static int32_t compute(int32_t phase);
// A more accurate sine, both input and output Q30 // A more accurate sine, both input and output Q30
static int32_t compute10(int32_t phase); static int32_t compute10(int32_t phase);
}; };
#define SIN_LG_N_SAMPLES 10 #define SIN_LG_N_SAMPLES 10

@ -14,7 +14,7 @@ class AudioSourceMicroDexed : public AudioStream, public Dexed {
void update(void) void update(void)
{ {
if (in_update==true) if (in_update == true)
{ {
xrun++; xrun++;
return; return;

Loading…
Cancel
Save