|
|
@ -1,19 +1,19 @@ |
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* Copyright 2016-2017 Pascal Gauthier. |
|
|
|
Copyright 2016-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> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <stdlib.h> |
|
|
@ -26,8 +26,8 @@ |
|
|
|
const int FEEDBACK_BITDEPTH = 8; |
|
|
|
const int FEEDBACK_BITDEPTH = 8; |
|
|
|
|
|
|
|
|
|
|
|
int32_t midinote_to_logfreq(int midinote) { |
|
|
|
int32_t midinote_to_logfreq(int midinote) { |
|
|
|
const int base = 50857777; // (1 << 24) * (log(440) / log(2) - 69/12)
|
|
|
|
const int32_t base = 50857777; // (1 << 24) * (log(440) / log(2) - 69/12)
|
|
|
|
const int step = (1 << 24) / 12; |
|
|
|
const int32_t step = (1 << 24) / 12; |
|
|
|
return base + step * midinote; |
|
|
|
return base + step * midinote; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -44,9 +44,8 @@ int32_t osc_freq(int midinote, int mode, int coarse, int fine, int detune) { |
|
|
|
int32_t logfreq; |
|
|
|
int32_t logfreq; |
|
|
|
if (mode == 0) { |
|
|
|
if (mode == 0) { |
|
|
|
logfreq = midinote_to_logfreq(midinote); |
|
|
|
logfreq = midinote_to_logfreq(midinote); |
|
|
|
|
|
|
|
|
|
|
|
// could use more precision, closer enough for now. those numbers comes from my DX7
|
|
|
|
// could use more precision, closer enough for now. those numbers comes from my DX7
|
|
|
|
double detuneRatio = 0.0209 * exp(-0.396 * (((float)logfreq)/(1<<24))) / 7; |
|
|
|
double detuneRatio = 0.0209 * exp(-0.396 * (((float)logfreq) / (1 << 24))) / 7; |
|
|
|
logfreq += detuneRatio * logfreq * (detune - 7); |
|
|
|
logfreq += detuneRatio * logfreq * (detune - 7); |
|
|
|
|
|
|
|
|
|
|
|
logfreq += coarsemul[coarse & 31]; |
|
|
|
logfreq += coarsemul[coarse & 31]; |
|
|
@ -122,9 +121,9 @@ int ScaleLevel(int midinote, int break_pt, int left_depth, int right_depth, |
|
|
|
int left_curve, int right_curve) { |
|
|
|
int left_curve, int right_curve) { |
|
|
|
int offset = midinote - break_pt - 17; |
|
|
|
int offset = midinote - break_pt - 17; |
|
|
|
if (offset >= 0) { |
|
|
|
if (offset >= 0) { |
|
|
|
return ScaleCurve((offset+1) / 3, right_depth, right_curve); |
|
|
|
return ScaleCurve((offset + 1) / 3, right_depth, right_curve); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
return ScaleCurve(-(offset-1) / 3, left_depth, left_curve); |
|
|
|
return ScaleCurve(-(offset - 1) / 3, left_depth, left_curve); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -138,7 +137,7 @@ static const uint32_t ampmodsenstab[] = { |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
Dx7Note::Dx7Note() { |
|
|
|
Dx7Note::Dx7Note() { |
|
|
|
for(int op=0;op<6;op++) { |
|
|
|
for (int op = 0; op < 6; op++) { |
|
|
|
params_[op].phase = 0; |
|
|
|
params_[op].phase = 0; |
|
|
|
params_[op].gain_out = 0; |
|
|
|
params_[op].gain_out = 0; |
|
|
|
} |
|
|
|
} |
|
|
@ -215,20 +214,20 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Co |
|
|
|
pitch_mod += pitch_base; |
|
|
|
pitch_mod += pitch_base; |
|
|
|
|
|
|
|
|
|
|
|
// ==== AMP MOD ====
|
|
|
|
// ==== AMP MOD ====
|
|
|
|
lfo_val = (1<<24) - lfo_val; |
|
|
|
lfo_val = (1 << 24) - lfo_val; |
|
|
|
uint32_t amod_1 = (uint32_t)(((int64_t) ampmoddepth_ * (int64_t) lfo_delay) >> 8); // Q24 :D
|
|
|
|
uint32_t amod_1 = (uint32_t)(((int64_t) ampmoddepth_ * (int64_t) lfo_delay) >> 8); // Q24 :D
|
|
|
|
amod_1 = (uint32_t)(((int64_t) amod_1 * (int64_t) lfo_val) >> 24); |
|
|
|
amod_1 = (uint32_t)(((int64_t) amod_1 * (int64_t) lfo_val) >> 24); |
|
|
|
uint32_t amod_2 = (uint32_t)(((int64_t) ctrls->amp_mod * (int64_t) lfo_val) >> 7); // Q?? :|
|
|
|
|
uint32_t amod_2 = (uint32_t)(((int64_t) ctrls->amp_mod * (int64_t) lfo_val) >> 7); // Q?? :|
|
|
|
|
uint32_t amd_mod = max(amod_1, amod_2); |
|
|
|
uint32_t amd_mod = max(amod_1, amod_2); |
|
|
|
|
|
|
|
|
|
|
|
// ==== EG AMP MOD ====
|
|
|
|
// ==== EG AMP MOD ====
|
|
|
|
uint32_t amod_3 = (ctrls->eg_mod+1) << 17; |
|
|
|
uint32_t amod_3 = (ctrls->eg_mod + 1) << 17; |
|
|
|
amd_mod = max((1<<24) - amod_3, amd_mod); |
|
|
|
amd_mod = max((1 << 24) - amod_3, amd_mod); |
|
|
|
|
|
|
|
|
|
|
|
// ==== OP RENDER ====
|
|
|
|
// ==== OP RENDER ====
|
|
|
|
for (int op = 0; op < 6; op++) { |
|
|
|
for (int op = 0; op < 6; op++) { |
|
|
|
// if ( ctrls->opSwitch[op] == '0' ) {
|
|
|
|
// if ( ctrls->opSwitch[op] == '0' ) {
|
|
|
|
if (!(ctrls->opSwitch & (1<<op))) {
|
|
|
|
if (!(ctrls->opSwitch & (1 << op))) { |
|
|
|
env_[op].getsample(); // advance the envelop even if it is not playing
|
|
|
|
env_[op].getsample(); // advance the envelop even if it is not playing
|
|
|
|
params_[op].level_in = 0; |
|
|
|
params_[op].level_in = 0; |
|
|
|
} else { |
|
|
|
} else { |
|
|
@ -244,8 +243,8 @@ void Dx7Note::compute(int32_t *buf, int32_t lfo_val, int32_t lfo_delay, const Co |
|
|
|
uint32_t sensamp = (uint32_t)(((uint64_t) amd_mod) * ((uint64_t) ampmodsens_[op]) >> 24); |
|
|
|
uint32_t sensamp = (uint32_t)(((uint64_t) amd_mod) * ((uint64_t) ampmodsens_[op]) >> 24); |
|
|
|
|
|
|
|
|
|
|
|
// TODO: mehhh.. this needs some real tuning.
|
|
|
|
// TODO: mehhh.. this needs some real tuning.
|
|
|
|
uint32_t pt = exp(((float)sensamp)/262144 * 0.07 + 12.2); |
|
|
|
uint32_t pt = exp(((float)sensamp) / 262144 * 0.07 + 12.2); |
|
|
|
uint32_t ldiff = (uint32_t)(((uint64_t)level) * (((uint64_t)pt<<4)) >> 28); |
|
|
|
uint32_t ldiff = (uint32_t)(((uint64_t)level) * (((uint64_t)pt << 4)) >> 28); |
|
|
|
level -= ldiff; |
|
|
|
level -= ldiff; |
|
|
|
} |
|
|
|
} |
|
|
|
params_[op].level_in = level; |
|
|
|
params_[op].level_in = level; |
|
|
@ -299,7 +298,7 @@ void Dx7Note::update(const uint8_t patch[156], int midinote, int velocity) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Dx7Note::peekVoiceStatus(VoiceStatus &status) { |
|
|
|
void Dx7Note::peekVoiceStatus(VoiceStatus &status) { |
|
|
|
for(int i=0;i<6;i++) { |
|
|
|
for (int i = 0; i < 6; i++) { |
|
|
|
status.amp[i] = Exp2::lookup(params_[i].level_in - (14 * (1 << 24))); |
|
|
|
status.amp[i] = Exp2::lookup(params_[i].level_in - (14 * (1 << 24))); |
|
|
|
env_[i].getPosition(&status.ampStep[i]); |
|
|
|
env_[i].getPosition(&status.ampStep[i]); |
|
|
|
} |
|
|
|
} |
|
|
@ -307,10 +306,10 @@ void Dx7Note::peekVoiceStatus(VoiceStatus &status) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Used in monophonic mode to transfert voice state from different notes |
|
|
|
Used in monophonic mode to transfert voice state from different notes |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
void Dx7Note::transferState(Dx7Note &src) { |
|
|
|
void Dx7Note::transferState(Dx7Note &src) { |
|
|
|
for (int i=0;i<6;i++) { |
|
|
|
for (int i = 0; i < 6; i++) { |
|
|
|
env_[i].transfer(src.env_[i]); |
|
|
|
env_[i].transfer(src.env_[i]); |
|
|
|
params_[i].gain_out = src.params_[i].gain_out; |
|
|
|
params_[i].gain_out = src.params_[i].gain_out; |
|
|
|
params_[i].phase = src.params_[i].phase; |
|
|
|
params_[i].phase = src.params_[i].phase; |
|
|
@ -318,14 +317,14 @@ void Dx7Note::transferState(Dx7Note &src) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Dx7Note::transferSignal(Dx7Note &src) { |
|
|
|
void Dx7Note::transferSignal(Dx7Note &src) { |
|
|
|
for (int i=0;i<6;i++) { |
|
|
|
for (int i = 0; i < 6; i++) { |
|
|
|
params_[i].gain_out = src.params_[i].gain_out; |
|
|
|
params_[i].gain_out = src.params_[i].gain_out; |
|
|
|
params_[i].phase = src.params_[i].phase; |
|
|
|
params_[i].phase = src.params_[i].phase; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void Dx7Note::oscSync() { |
|
|
|
void Dx7Note::oscSync() { |
|
|
|
for (int i=0;i<6;i++) { |
|
|
|
for (int i = 0; i < 6; i++) { |
|
|
|
params_[i].gain_out = 0; |
|
|
|
params_[i].gain_out = 0; |
|
|
|
params_[i].phase = 0; |
|
|
|
params_[i].phase = 0; |
|
|
|
} |
|
|
|
} |
|
|
|