Correct feedback implementation for Algo 4 and 6

pull/1/head
asb2m10 8 years ago
parent 2eb5c6213d
commit b2a81f7da6
  1. 1
      README.md
  2. 2
      Source/DXComponents.h
  3. 8
      Source/DXLookNFeel.h
  4. 192
      Source/EngineMkI.cpp
  5. 2
      Source/EngineMkI.h
  6. 8
      Source/OperatorEditor.h
  7. 4
      Source/msfa/fm_core.cc

@ -20,6 +20,7 @@ Changelog
#### Version 0.9.2 #### Version 0.9.2
* Added operator mute switch * Added operator mute switch
* Added Tune (MASTER TUNE ADJ) knob * Added Tune (MASTER TUNE ADJ) knob
* Correct feedback implementation for Algo 4 and 6
* Single click program select * Single click program select
* Fix sysex issue with wrong machine ID * Fix sysex issue with wrong machine ID

@ -63,7 +63,7 @@ class ComboBoxImage : public ComboBox {
public: public:
ComboBoxImage(); ComboBoxImage();
virtual void paint(Graphics &g); virtual void paint(Graphics &g) override;
virtual void showPopup() override; virtual void showPopup() override;
void setImage(Image image); void setImage(Image image);
void setImage(Image image, int pos[]); void setImage(Image image, int pos[]);

@ -39,8 +39,8 @@ public:
Image imageOperator, imageGlobal; Image imageOperator, imageGlobal;
/* overriden methods */ /* overriden methods */
virtual void drawRotarySlider(Graphics &g, int x, int y, int width, int height, float sliderPosProportional, float rotaryStartAngle, float rotaryEndAngle, Slider &slider ); virtual void drawRotarySlider(Graphics &g, int x, int y, int width, int height, float sliderPosProportional, float rotaryStartAngle, float rotaryEndAngle, Slider &slider ) override;
virtual void drawToggleButton(Graphics& g, ToggleButton& button, bool isMouseOverButton, bool isButtonDown); virtual void drawToggleButton(Graphics& g, ToggleButton& button, bool isMouseOverButton, bool isButtonDown) override;
virtual void drawLinearSliderBackground (Graphics&, int x, int y, int width, int height, virtual void drawLinearSliderBackground (Graphics&, int x, int y, int width, int height,
float sliderPos, float minSliderPos, float maxSliderPos, float sliderPos, float minSliderPos, float maxSliderPos,
const Slider::SliderStyle, Slider&) override; const Slider::SliderStyle, Slider&) override;
@ -50,8 +50,8 @@ public:
virtual void drawButtonBackground (Graphics&, Button&, const Colour& backgroundColour, virtual void drawButtonBackground (Graphics&, Button&, const Colour& backgroundColour,
bool isMouseOverButton, bool isButtonDown) override; bool isMouseOverButton, bool isButtonDown) override;
virtual Font getTextButtonFont(TextButton&, int buttonHeight) override; virtual Font getTextButtonFont(TextButton&, int buttonHeight) override;
virtual Typeface::Ptr getTypefaceForFont(const Font &); virtual Typeface::Ptr getTypefaceForFont(const Font &) override;
virtual void positionComboBoxText (ComboBox& box, Label& label); virtual void positionComboBoxText (ComboBox& box, Label& label) override;
static DXLookNFeel *getLookAndFeel(); static DXLookNFeel *getLookAndFeel();
static Colour fillColour; static Colour fillColour;

@ -57,6 +57,8 @@ 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;
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);
@ -200,183 +202,105 @@ void EngineMkI::compute_fb(int32_t *output, int32_t phase0, int32_t freq,
fb_buf[1] = y; fb_buf[1] = y;
} }
/* // exclusively used for ALGO 6 with feedback
void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm, void EngineMkI::compute_fb2(int32_t *output, FmOpParams *parms, int32_t gain01, int32_t gain02, int32_t *fb_buf, int fb_shift) {
int32_t *fb_buf, int feedback_shift) { int32_t dgain[2];
const uint16_t ENV_MAX = 1<<ENV_BITDEPTH; int32_t gain[2];
const uint16_t kLevelThresh = ENV_MAX-100; // really ???? uhuhuh int32_t phase[2];
const FmAlgorithm alg = algorithms[algorithm];
bool has_contents[3] = { true, false, false };
for (int op = 0; op < 6; op++) {
int flags = alg.ops[op];
bool add = (flags & OUT_BUS_ADD) != 0;
FmOpParams &param = params[op];
int inbus = (flags >> 4) & 3;
int outbus = flags & 3;
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 gain2 = ENV_MAX-(param.level_in >> (28-ENV_BITDEPTH));
param.gain_out = gain2;
if (gain1 <= kLevelThresh || gain2 <= kLevelThresh) {
if (!has_contents[outbus]) {
add = false;
}
if (inbus == 0 || !has_contents[inbus]) {
// todo: more than one op in a feedback loop
if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) {
// cout << op << " fb " << inbus << outbus << add << endl;
compute_fb(outptr, param.phase, param.freq,
gain1, gain2,
fb_buf, feedback_shift, add);
} else {
// cout << op << " pure " << inbus << outbus << add << endl;
compute_pure(outptr, param.phase, param.freq,
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;
}
}
*/
const FmAlgorithm EngineMkI::algo2[32] = {
{ { 0xc1, 0x11, 0x11, 0x14, 0x01, 0x14 } }, // 1
{ { 0x01, 0x11, 0x11, 0x14, 0xc1, 0x14 } }, // 2
{ { 0xc1, 0x11, 0x14, 0x01, 0x11, 0x14 } }, // 3
{ { 0xc4, 0x00, 0x00, 0x01, 0x11, 0x14 } }, // 4 ** EXCEPTION VIA CODE
{ { 0xc1, 0x14, 0x01, 0x14, 0x01, 0x14 } }, // 5
{ { 0xc4, 0x00, 0x01, 0x14, 0x01, 0x14 } }, // 6 ** EXCEPTION VIA CODE
{ { 0xc1, 0x11, 0x05, 0x14, 0x01, 0x14 } }, // 7
{ { 0x01, 0x11, 0xc5, 0x14, 0x01, 0x14 } }, // 8
{ { 0x01, 0x11, 0x05, 0x14, 0xc1, 0x14 } }, // 9
{ { 0x01, 0x05, 0x14, 0xc1, 0x11, 0x14 } }, // 10
{ { 0xc1, 0x05, 0x14, 0x01, 0x11, 0x14 } }, // 11
{ { 0x01, 0x05, 0x05, 0x14, 0xc1, 0x14 } }, // 12
{ { 0xc1, 0x05, 0x05, 0x14, 0x01, 0x14 } }, // 13
{ { 0xc1, 0x05, 0x11, 0x14, 0x01, 0x14 } }, // 14
{ { 0x01, 0x05, 0x11, 0x14, 0xc1, 0x14 } }, // 15
{ { 0xc1, 0x11, 0x02, 0x25, 0x05, 0x14 } }, // 16
{ { 0x01, 0x11, 0x02, 0x25, 0xc5, 0x14 } }, // 17
{ { 0x01, 0x11, 0x11, 0xc5, 0x05, 0x14 } }, // 18
{ { 0xc1, 0x14, 0x14, 0x01, 0x11, 0x14 } }, // 19
{ { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x14 } }, // 20
{ { 0x01, 0x14, 0x14, 0xc1, 0x14, 0x14 } }, // 21
{ { 0xc1, 0x14, 0x14, 0x14, 0x01, 0x14 } }, // 22
{ { 0xc1, 0x14, 0x14, 0x01, 0x14, 0x04 } }, // 23
{ { 0xc1, 0x14, 0x14, 0x14, 0x04, 0x04 } }, // 24
{ { 0xc1, 0x14, 0x14, 0x04, 0x04, 0x04 } }, // 25
{ { 0xc1, 0x05, 0x14, 0x01, 0x14, 0x04 } }, // 26
{ { 0x01, 0x05, 0x14, 0xc1, 0x14, 0x04 } }, // 27
{ { 0x04, 0xc1, 0x11, 0x14, 0x01, 0x14 } }, // 28
{ { 0xc1, 0x14, 0x01, 0x14, 0x04, 0x04 } }, // 29
{ { 0x04, 0xc1, 0x11, 0x14, 0x04, 0x04 } }, // 30
{ { 0xc1, 0x14, 0x04, 0x04, 0x04, 0x04 } }, // 31
{ { 0xc4, 0x04, 0x04, 0x04, 0x04, 0x04 } }, // 32
};
// 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) {
int32_t dgain[3];
int32_t gain[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;
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; gain[1] = parms[1].gain_out == 0 ? (ENV_MAX-1) : parms[1].gain_out;
gain[2] = 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));
parms[1].gain_out = Exp2::lookup(parms[1].level_in - (14 * (1 << 24)));
dgain[1] = (parms[1].gain_out - gain[1] + (N >> 1)) >> LG_N;
parms[2].gain_out = Exp2::lookup(parms[2].level_in - (14 * (1 << 24)));
dgain[2] = (parms[1].gain_out - gain[2] + (N >> 1)) >> LG_N;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1);
// op 0 // op 0
gain[0] += dgain[0]; gain[0] += dgain[0];
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1); // tsk tsk tsk: this needs some tuning
y0 = y; y0 = y;
y = Sin::lookup(phase[0] + scaled_fb); y = mkiSin(phase[0]+scaled_fb, gain[0]);
y = ((int64_t)y * (int64_t)gain[0]) >> 24;
phase[0] += parms[0].freq; phase[0] += parms[0].freq;
// op 1 // op 1
gain[1] += dgain[1]; gain[1] += dgain[1];
y = Sin::lookup(phase[1] + y); y = mkiSin(phase[1]+y, gain[1]);
y = ((int64_t)y * (int64_t)gain[1]) >> 24;
phase[1] += parms[1].freq; phase[1] += parms[1].freq;
// op 2
gain[2] += dgain[2];
y = Sin::lookup(phase[2] + y);
y = ((int64_t)y * (int64_t)gain[2]) >> 24;
output[i] = y; output[i] = y;
phase[2] += parms[2].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 4 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_fb3(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[3];
int32_t gain[2]; int32_t gain[3];
int32_t phase[2]; 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;
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)));
gain[0] = gain01; gain[0] = gain01;
gain[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;
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[2] = (parms[2].gain_out - (parms[2].gain_out == 0 ? (ENV_MAX-1) : parms[2].gain_out));
parms[1].gain_out = Exp2::lookup(parms[1].level_in - (14 * (1 << 24)));
dgain[1] = (parms[1].gain_out - gain[1] + (N >> 1)) >> LG_N;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1);
// op 0 // op 0
gain[0] += dgain[0]; gain[0] += dgain[0];
int32_t scaled_fb = (y0 + y) >> (fb_shift + 1);
y0 = y; y0 = y;
y = Sin::lookup(phase[0] + scaled_fb); y = mkiSin(phase[0]+scaled_fb, gain[0]);
y = ((int64_t)y * (int64_t)gain[0]) >> 24;
phase[0] += parms[0].freq; phase[0] += parms[0].freq;
// op 1 // op 1
gain[1] += dgain[1]; gain[1] += dgain[1];
y = Sin::lookup(phase[1] + y); y = mkiSin(phase[1]+y, gain[1]);
y = ((int64_t)y * (int64_t)gain[1]) >> 24;
output[i] = y;
phase[1] += parms[1].freq; phase[1] += parms[1].freq;
// op 2
gain[2] += dgain[2];
y = mkiSin(phase[2]+y, gain[2]);
phase[2] += parms[2].freq;
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, int feedback_shift) { void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm, int32_t *fb_buf, int feedback_shift) {
const uint16_t ENV_MAX = 1<<ENV_BITDEPTH;
const int kLevelThresh = ENV_MAX-100; const int kLevelThresh = ENV_MAX-100;
const FmAlgorithm alg = algo2[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;
switch(algorithm) {
case 3 : case 5 :
if ( fb_on )
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];
@ -397,15 +321,8 @@ void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm, int32
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...
// still needs some tuning... if ((flags & 0xc0) == 0xc0 && fb_on) {
if ((flags & 0xc0) == 0xc0 && feedback_shift < 16) {
switch ( algorithm ) { switch ( algorithm ) {
// two operator feedback, process exception for ALGO 6
case 5 :
compute_fb2(outptr, params, gain1, gain2, fb_buf, feedback_shift);
params[1].phase += params[1].freq << LG_N; // yuk, hack, we already processed op-5
op++; // ignore next operator;
break;
// 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, feedback_shift); compute_fb3(outptr, params, gain1, gain2, fb_buf, feedback_shift);
@ -413,24 +330,25 @@ void EngineMkI::render(int32_t *output, FmOpParams *params, int algorithm, int32
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
case 5 :
compute_fb2(outptr, params, gain1, gain2, fb_buf, feedback_shift);
params[1].phase += params[1].freq << LG_N; // yuk, hack, we already processed op-5
op++; // ignore next operator;
break;
default: default:
// one operator feedback, normal proces // one operator feedback, normal proces
//cout << "\t" << op << " fb " << inbus << outbus << add << endl; 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 {
// cout << op << " pure " << inbus << outbus << add << endl;
compute_pure(outptr, param.phase, param.freq, gain1, gain2, add); compute_pure(outptr, param.phase, param.freq, gain1, gain2, add);
} }
} else { } else {
// cout << op << " normal " << inbus << outbus << " " << param.freq << add << endl;
compute(outptr, buf_[inbus - 1].get(), param.phase, param.freq, gain1, gain2, add); compute(outptr, buf_[inbus - 1].get(), param.phase, param.freq, gain1, gain2, add);
} }
has_contents[outbus] = true; has_contents[outbus] = true;
} else if (!add) { } else if (!add) {
has_contents[outbus] = false; has_contents[outbus] = false;
} }

@ -26,8 +26,6 @@
class EngineMkI : public FmCore { class EngineMkI : public FmCore {
//refacter this when it is working
const static FmAlgorithm algo2[32];
public: public:
EngineMkI(); EngineMkI();

@ -56,10 +56,10 @@ public:
void mouseDown(const MouseEvent& e) override; void mouseDown(const MouseEvent& e) override;
//[/UserMethods] //[/UserMethods]
void paint (Graphics& g); void paint (Graphics& g) override;
void resized(); void resized() override;
void sliderValueChanged (Slider* sliderThatWasMoved); void sliderValueChanged (Slider* sliderThatWasMoved) override;
void buttonClicked (Button* buttonThatWasClicked); void buttonClicked (Button* buttonThatWasClicked) override;

@ -30,9 +30,9 @@ const FmAlgorithm FmCore::algorithms[32] = {
{ { 0xc1, 0x11, 0x11, 0x14, 0x01, 0x14 } }, // 1 { { 0xc1, 0x11, 0x11, 0x14, 0x01, 0x14 } }, // 1
{ { 0x01, 0x11, 0x11, 0x14, 0xc1, 0x14 } }, // 2 { { 0x01, 0x11, 0x11, 0x14, 0xc1, 0x14 } }, // 2
{ { 0xc1, 0x11, 0x14, 0x01, 0x11, 0x14 } }, // 3 { { 0xc1, 0x11, 0x14, 0x01, 0x11, 0x14 } }, // 3
{ { 0xc1, 0x11, 0x94, 0x01, 0x11, 0x14 } }, // 4 ** EXCEPTION VIA CODE { { 0xc1, 0x11, 0x94, 0x01, 0x11, 0x14 } }, // 4
{ { 0xc1, 0x14, 0x01, 0x14, 0x01, 0x14 } }, // 5 { { 0xc1, 0x14, 0x01, 0x14, 0x01, 0x14 } }, // 5
{ { 0xc1, 0x94, 0x01, 0x14, 0x01, 0x14 } }, // 6 ** EXCEPTION VIA CODE { { 0xc1, 0x94, 0x01, 0x14, 0x01, 0x14 } }, // 6
{ { 0xc1, 0x11, 0x05, 0x14, 0x01, 0x14 } }, // 7 { { 0xc1, 0x11, 0x05, 0x14, 0x01, 0x14 } }, // 7
{ { 0x01, 0x11, 0xc5, 0x14, 0x01, 0x14 } }, // 8 { { 0x01, 0x11, 0xc5, 0x14, 0x01, 0x14 } }, // 8
{ { 0x01, 0x11, 0x05, 0x14, 0xc1, 0x14 } }, // 9 { { 0x01, 0x11, 0x05, 0x14, 0xc1, 0x14 } }, // 9

Loading…
Cancel
Save