|
|
|
@ -77,6 +77,7 @@ Dexed::Dexed(int rate) |
|
|
|
|
controllers.opSwitch = 0x3f; // enable all operators
|
|
|
|
|
//controllers.opSwitch=0x00;
|
|
|
|
|
lastKeyDown = -1; |
|
|
|
|
vuSignal = 0.0; |
|
|
|
|
|
|
|
|
|
lfo.reset(data + 137); |
|
|
|
|
|
|
|
|
@ -115,6 +116,8 @@ void Dexed::getSamples(uint16_t n_samples, int16_t* buffer) |
|
|
|
|
uint16_t i, j; |
|
|
|
|
uint8_t note; |
|
|
|
|
float sumbuf[n_samples]; |
|
|
|
|
float s; |
|
|
|
|
const double decayFactor = 0.99992; |
|
|
|
|
|
|
|
|
|
if (refreshVoice) |
|
|
|
|
{ |
|
|
|
@ -148,9 +151,18 @@ void Dexed::getSamples(uint16_t n_samples, int16_t* buffer) |
|
|
|
|
|
|
|
|
|
for (j = 0; j < _N_; ++j) |
|
|
|
|
{ |
|
|
|
|
//sumbuf[i + j] += static_cast<float>(signed_saturate_rshift(audiobuf.get()[j] >> 5, 24, 9)) / 0x8000;
|
|
|
|
|
sumbuf[i + j] += signed_saturate_rshift(audiobuf.get()[j] >> 5, 24, 9) / 32768.0; |
|
|
|
|
sumbuf[i + j] += signed_saturate_rshift(audiobuf.get()[j] >> 4, 24, 9) / 32768.0; |
|
|
|
|
audiobuf.get()[j] = 0; |
|
|
|
|
/*
|
|
|
|
|
int32_t val = audiobuf.get()[j]; |
|
|
|
|
val = val >> 4; |
|
|
|
|
int32_t clip_val = val < -(1 << 24) ? 0x8000 : val >= (1 << 24) ? 0x7fff : val >> 9; |
|
|
|
|
float f = ((float) clip_val) / (float) 0x8000; |
|
|
|
|
if ( f > 1.0 ) f = 1.0; |
|
|
|
|
if ( f < -1.0 ) f = -1.0; |
|
|
|
|
sumbuf[j] += f; |
|
|
|
|
audiobuf.get()[j] = 0; |
|
|
|
|
*/ |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -158,6 +170,18 @@ void Dexed::getSamples(uint16_t n_samples, int16_t* buffer) |
|
|
|
|
|
|
|
|
|
fx.process(sumbuf, n_samples); // Needed for fx.Gain()!!!
|
|
|
|
|
|
|
|
|
|
// mild compression
|
|
|
|
|
for (i = 0; i < n_samples; i++) |
|
|
|
|
{ |
|
|
|
|
s = abs(sumbuf[i]); |
|
|
|
|
if (s > vuSignal) |
|
|
|
|
vuSignal = s; |
|
|
|
|
else if (vuSignal > 0.001f) |
|
|
|
|
vuSignal *= decayFactor; |
|
|
|
|
else |
|
|
|
|
vuSignal = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//arm_scale_f32(sumbuf, 0.00015, sumbuf, AUDIO_BLOCK_SAMPLES);
|
|
|
|
|
arm_float_to_q15(sumbuf, buffer, AUDIO_BLOCK_SAMPLES); |
|
|
|
|
} |
|
|
|
@ -636,74 +660,6 @@ bool Dexed::loadVoiceParameters(uint8_t* new_data) |
|
|
|
|
return (true); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*bool Dexed::loadGlobalParameters(uint8_t* new_data)
|
|
|
|
|
{ |
|
|
|
|
uint8_t* p_data = data; |
|
|
|
|
|
|
|
|
|
controllers.values_[kControllerPitchRange] = new_data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PITCHBEND_RANGE]; |
|
|
|
|
controllers.values_[kControllerPitchStep] = new_data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_PITCHBEND_STEP]; |
|
|
|
|
controllers.wheel.setRange(new_data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MODWHEEL_RANGE]); |
|
|
|
|
controllers.wheel.setTarget(new_data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MODWHEEL_ASSIGN]); |
|
|
|
|
controllers.foot.setRange(new_data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_FOOTCTRL_RANGE]); |
|
|
|
|
controllers.foot.setTarget(new_data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_FOOTCTRL_ASSIGN]); |
|
|
|
|
controllers.breath.setRange(new_data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_BREATHCTRL_RANGE]); |
|
|
|
|
controllers.breath.setTarget(new_data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_BREATHCTRL_ASSIGN]); |
|
|
|
|
controllers.at.setRange(new_data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_AT_RANGE]); |
|
|
|
|
controllers.at.setTarget(new_data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_AT_ASSIGN]); |
|
|
|
|
controllers.masterTune = (int(new_data[DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MASTER_TUNE] / 100.0) * 0x4000 << 11) * (1.0 / 12); |
|
|
|
|
controllers.refresh(); |
|
|
|
|
|
|
|
|
|
setOPs((*(p_data + DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_OP1_ENABLE) << 5) | |
|
|
|
|
(*(p_data + DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_OP2_ENABLE) << 4) | |
|
|
|
|
(*(p_data + DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_OP3_ENABLE) << 3) | |
|
|
|
|
(*(p_data + DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_OP4_ENABLE) << 2) | |
|
|
|
|
(*(p_data + DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_OP5_ENABLE) << 1) | |
|
|
|
|
(p_data + DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_OP6_ENABLE )); |
|
|
|
|
setMaxNotes(*(p_data + DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MAX_NOTES)); |
|
|
|
|
|
|
|
|
|
setMaxNotes(*(p_data + DEXED_GLOBAL_PARAMETER_OFFSET + DEXED_MAX_NOTES)); |
|
|
|
|
//panic();
|
|
|
|
|
doRefreshVoice(); |
|
|
|
|
//activate();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG |
|
|
|
|
Serial.println(F("Global parameters loaded.")); |
|
|
|
|
#endif |
|
|
|
|
return (true); |
|
|
|
|
}*/ |
|
|
|
|
|
|
|
|
|
/*bool Dexed::initGlobalParameters(void)
|
|
|
|
|
{ |
|
|
|
|
uint8_t init_data[18]; |
|
|
|
|
|
|
|
|
|
#ifdef DEBUG |
|
|
|
|
Serial.println(F("Initializing global parameters")); |
|
|
|
|
#endif |
|
|
|
|
init_data[DEXED_PITCHBEND_RANGE] = 1; |
|
|
|
|
init_data[DEXED_PITCHBEND_STEP] = 1; |
|
|
|
|
init_data[DEXED_MODWHEEL_RANGE] = 99; |
|
|
|
|
init_data[DEXED_MODWHEEL_ASSIGN] = 7; |
|
|
|
|
init_data[DEXED_FOOTCTRL_RANGE] = 99; |
|
|
|
|
init_data[DEXED_FOOTCTRL_ASSIGN] = 7; |
|
|
|
|
init_data[DEXED_BREATHCTRL_RANGE] = 99; |
|
|
|
|
init_data[DEXED_BREATHCTRL_ASSIGN] = 7; |
|
|
|
|
init_data[DEXED_AT_RANGE] = 99; |
|
|
|
|
init_data[DEXED_AT_ASSIGN] = 7; |
|
|
|
|
init_data[DEXED_MASTER_TUNE] = 0; |
|
|
|
|
init_data[DEXED_OP1_ENABLE] = 1; |
|
|
|
|
init_data[DEXED_OP2_ENABLE] = 1; |
|
|
|
|
init_data[DEXED_OP3_ENABLE] = 1; |
|
|
|
|
init_data[DEXED_OP4_ENABLE] = 1; |
|
|
|
|
init_data[DEXED_OP5_ENABLE] = 1; |
|
|
|
|
init_data[DEXED_OP6_ENABLE] = 1; |
|
|
|
|
init_data[DEXED_MAX_NOTES] = MAX_NOTES; |
|
|
|
|
|
|
|
|
|
loadGlobalParameters(init_data); |
|
|
|
|
|
|
|
|
|
return (true); |
|
|
|
|
}*/ |
|
|
|
|
|
|
|
|
|
void Dexed::setPBController(uint8_t pb_range, uint8_t pb_step) |
|
|
|
|
{ |
|
|
|
|
#ifdef DEBUG |
|
|
|
@ -801,81 +757,82 @@ void Dexed::setPortamentoMode(uint8_t portamento_mode, uint8_t portamento_glissa |
|
|
|
|
controllers.refresh(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// https://www.musicdsp.org/en/latest/Effects/169-compressor.html#
|
|
|
|
|
void compress |
|
|
|
|
( |
|
|
|
|
float* wav_in, // signal
|
|
|
|
|
int n, // N samples
|
|
|
|
|
double threshold, // threshold (percents)
|
|
|
|
|
double slope, // slope angle (percents)
|
|
|
|
|
int sr, // sample rate (smp/sec)
|
|
|
|
|
double tla, // lookahead (ms)
|
|
|
|
|
double twnd, // window time (ms)
|
|
|
|
|
double tatt, // attack time (ms)
|
|
|
|
|
double trel // release time (ms)
|
|
|
|
|
) |
|
|
|
|
{ |
|
|
|
|
typedef float stereodata[2]; |
|
|
|
|
stereodata* wav = (stereodata*) wav_in; // our stereo signal
|
|
|
|
|
threshold *= 0.01; // threshold to unity (0...1)
|
|
|
|
|
slope *= 0.01; // slope to unity
|
|
|
|
|
tla *= 1e-3; // lookahead time to seconds
|
|
|
|
|
twnd *= 1e-3; // window time to seconds
|
|
|
|
|
tatt *= 1e-3; // attack time to seconds
|
|
|
|
|
trel *= 1e-3; // release time to seconds
|
|
|
|
|
|
|
|
|
|
// attack and release "per sample decay"
|
|
|
|
|
double att = (tatt == 0.0) ? (0.0) : exp (-1.0 / (sr * tatt)); |
|
|
|
|
double rel = (trel == 0.0) ? (0.0) : exp (-1.0 / (sr * trel)); |
|
|
|
|
|
|
|
|
|
// envelope
|
|
|
|
|
double env = 0.0; |
|
|
|
|
|
|
|
|
|
// sample offset to lookahead wnd start
|
|
|
|
|
int lhsmp = (int) (sr * tla); |
|
|
|
|
|
|
|
|
|
// samples count in lookahead window
|
|
|
|
|
int nrms = (int) (sr * twnd); |
|
|
|
|
|
|
|
|
|
// for each sample...
|
|
|
|
|
for (int i = 0; i < n; ++i) |
|
|
|
|
{ |
|
|
|
|
// now compute RMS
|
|
|
|
|
double summ = 0; |
|
|
|
|
|
|
|
|
|
// for each sample in window
|
|
|
|
|
for (int j = 0; j < nrms; ++j) |
|
|
|
|
{ |
|
|
|
|
int lki = i + j + lhsmp; |
|
|
|
|
double smp; |
|
|
|
|
/*
|
|
|
|
|
// https://www.musicdsp.org/en/latest/Effects/169-compressor.html#
|
|
|
|
|
void compress |
|
|
|
|
( |
|
|
|
|
float* wav_in, // signal
|
|
|
|
|
int n, // N samples
|
|
|
|
|
double threshold, // threshold (percents)
|
|
|
|
|
double slope, // slope angle (percents)
|
|
|
|
|
int sr, // sample rate (smp/sec)
|
|
|
|
|
double tla, // lookahead (ms)
|
|
|
|
|
double twnd, // window time (ms)
|
|
|
|
|
double tatt, // attack time (ms)
|
|
|
|
|
double trel // release time (ms)
|
|
|
|
|
) |
|
|
|
|
{ |
|
|
|
|
typedef float stereodata[2]; |
|
|
|
|
stereodata* wav = (stereodata*) wav_in; // our stereo signal
|
|
|
|
|
threshold *= 0.01; // threshold to unity (0...1)
|
|
|
|
|
slope *= 0.01; // slope to unity
|
|
|
|
|
tla *= 1e-3; // lookahead time to seconds
|
|
|
|
|
twnd *= 1e-3; // window time to seconds
|
|
|
|
|
tatt *= 1e-3; // attack time to seconds
|
|
|
|
|
trel *= 1e-3; // release time to seconds
|
|
|
|
|
|
|
|
|
|
// attack and release "per sample decay"
|
|
|
|
|
double att = (tatt == 0.0) ? (0.0) : exp (-1.0 / (sr * tatt)); |
|
|
|
|
double rel = (trel == 0.0) ? (0.0) : exp (-1.0 / (sr * trel)); |
|
|
|
|
|
|
|
|
|
// envelope
|
|
|
|
|
double env = 0.0; |
|
|
|
|
|
|
|
|
|
// sample offset to lookahead wnd start
|
|
|
|
|
int lhsmp = (int) (sr * tla); |
|
|
|
|
|
|
|
|
|
// samples count in lookahead window
|
|
|
|
|
int nrms = (int) (sr * twnd); |
|
|
|
|
|
|
|
|
|
// for each sample...
|
|
|
|
|
for (int i = 0; i < n; ++i) |
|
|
|
|
{ |
|
|
|
|
// now compute RMS
|
|
|
|
|
double summ = 0; |
|
|
|
|
|
|
|
|
|
// if we in bounds of signal?
|
|
|
|
|
// if so, convert to mono
|
|
|
|
|
if (lki < n) |
|
|
|
|
smp = 0.5 * wav[lki][0] + 0.5 * wav[lki][1]; |
|
|
|
|
else |
|
|
|
|
smp = 0.0; // if we out of bounds we just get zero in smp
|
|
|
|
|
// for each sample in window
|
|
|
|
|
for (int j = 0; j < nrms; ++j) |
|
|
|
|
{ |
|
|
|
|
int lki = i + j + lhsmp; |
|
|
|
|
double smp; |
|
|
|
|
|
|
|
|
|
summ += smp * smp; // square em..
|
|
|
|
|
} |
|
|
|
|
// if we in bounds of signal?
|
|
|
|
|
// if so, convert to mono
|
|
|
|
|
if (lki < n) |
|
|
|
|
smp = 0.5 * wav[lki][0] + 0.5 * wav[lki][1]; |
|
|
|
|
else |
|
|
|
|
smp = 0.0; // if we out of bounds we just get zero in smp
|
|
|
|
|
|
|
|
|
|
double rms = sqrt (summ / nrms); // root-mean-square
|
|
|
|
|
summ += smp * smp; // square em..
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// dynamic selection: attack or release?
|
|
|
|
|
double theta = rms > env ? att : rel; |
|
|
|
|
double rms = sqrt (summ / nrms); // root-mean-square
|
|
|
|
|
|
|
|
|
|
// smoothing with capacitor, envelope extraction...
|
|
|
|
|
// here be aware of pIV denormal numbers glitch
|
|
|
|
|
env = (1.0 - theta) * rms + theta * env; |
|
|
|
|
// dynamic selection: attack or release?
|
|
|
|
|
double theta = rms > env ? att : rel; |
|
|
|
|
|
|
|
|
|
// the very easy hard knee 1:N compressor
|
|
|
|
|
double gain = 1.0; |
|
|
|
|
if (env > threshold) |
|
|
|
|
gain = gain - (env - threshold) * slope; |
|
|
|
|
// smoothing with capacitor, envelope extraction...
|
|
|
|
|
// here be aware of pIV denormal numbers glitch
|
|
|
|
|
env = (1.0 - theta) * rms + theta * env; |
|
|
|
|
|
|
|
|
|
// result - two hard kneed compressed channels...
|
|
|
|
|
float leftchannel = wav[i][0] * gain; |
|
|
|
|
float rightchannel = wav[i][1] * gain; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// the very easy hard knee 1:N compressor
|
|
|
|
|
double gain = 1.0; |
|
|
|
|
if (env > threshold) |
|
|
|
|
gain = gain - (env - threshold) * slope; |
|
|
|
|
|
|
|
|
|
// result - two hard kneed compressed channels...
|
|
|
|
|
float leftchannel = wav[i][0] * gain; |
|
|
|
|
float rightchannel = wav[i][1] * gain; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|