diff --git a/android/res/layout/piano2.xml b/android/res/layout/piano2.xml
index 83e7b4a..90571ea 100644
--- a/android/res/layout/piano2.xml
+++ b/android/res/layout/piano2.xml
@@ -19,7 +19,9 @@
android:id="@+id/resonanceLabel"
android:gravity="center_horizontal" />
+
+ android:layout_span="3" >
Cutoff
Resonance
+ Overdrive
Attack
@@ -79,4 +80,7 @@
Capture
+
+ Settings
+
diff --git a/android/src/com/levien/synthesizer/android/ui/PianoActivity2.java b/android/src/com/levien/synthesizer/android/ui/PianoActivity2.java
index 12e5d4e..c62efef 100644
--- a/android/src/com/levien/synthesizer/android/ui/PianoActivity2.java
+++ b/android/src/com/levien/synthesizer/android/ui/PianoActivity2.java
@@ -68,6 +68,7 @@ public class PianoActivity2 extends Activity {
piano_ = (PianoView)findViewById(R.id.piano);
cutoffKnob_ = (KnobView)findViewById(R.id.cutoffKnob);
resonanceKnob_ = (KnobView)findViewById(R.id.resonanceKnob);
+ overdriveKnob_ = (KnobView)findViewById(R.id.overdriveKnob);
presetSpinner_ = (Spinner)findViewById(R.id.presetSpinner);
AudioParams params = new AudioParams(44100, 64);
@@ -108,13 +109,19 @@ public class PianoActivity2 extends Activity {
public void onKnobChanged(double newValue) {
int value = (int)Math.round(newValue * 127);
androidGlue_.onController(0, 1, value);
- }
+ }
});
resonanceKnob_.setKnobListener(new KnobListener() {
public void onKnobChanged(double newValue) {
int value = (int)Math.round(newValue * 127);
androidGlue_.onController(0, 2, value);
- }
+ }
+ });
+ overdriveKnob_.setKnobListener(new KnobListener() {
+ public void onKnobChanged(double newValue) {
+ int value = (int)Math.round(newValue * 127);
+ androidGlue_.onController(0, 3, value);
+ }
});
piano_.bindTo(androidGlue_);
@@ -289,6 +296,7 @@ public class PianoActivity2 extends Activity {
private PianoView piano_;
private KnobView cutoffKnob_;
private KnobView resonanceKnob_;
+ private KnobView overdriveKnob_;
private Spinner presetSpinner_;
private Handler statusHandler_;
private Runnable statusRunnable_;
diff --git a/cpp/src/resofilter.cc b/cpp/src/resofilter.cc
index 431aff1..43f50af 100644
--- a/cpp/src/resofilter.cc
+++ b/cpp/src/resofilter.cc
@@ -23,10 +23,12 @@
#include
#include
+#include
#include "synth.h"
#include "freqlut.h"
#include "exp2.h"
+#include "aligned_buf.h"
#include "resofilter.h"
double this_sample_rate;
@@ -173,19 +175,49 @@ void test_matrix() {
}
#if defined(USE_MATRIX)
+static float sigmoid(float x, float overdrive) {
+ float xs = overdrive * x * (1.0 / (1 << 24));
+ float isq = 1.0 / sqrtf(1 + xs * xs);
+ return x * isq;
+}
+
void ResoFilter::process(const int32_t **inbufs, const int32_t *control_in,
const int32_t *control_last, int32_t **outbufs) {
- float a[20];
- make_state_transition(a, compute_alpha(control_in[0]), control_in[1]);
+ AlignedBuf a;
+ make_state_transition(a.get(), compute_alpha(control_in[0]), control_in[1]);
+ float overdrive = control_in[2] * (1.0 / (1 << 24));
const int32_t *ibuf = inbufs[0];
int32_t *obuf = outbufs[0];
- for (int i = 0; i < n; i++) {
- float signal = ibuf[i];
- float tmp[4];
- matvec4(tmp, a + 4, x);
- for (int k = 0; k < 4; k++) {
- x[k] = tmp[k] + signal * a[k];
- obuf[i] = x[3];
+ if (overdrive == 0) {
+ for (int i = 0; i < n; i++) {
+ float signal = ibuf[i];
+ float tmp[4];
+ matvec4(tmp, a.get() + 4, x);
+ for (int k = 0; k < 4; k++) {
+ x[k] = tmp[k] + signal * a.get()[k];
+ obuf[i] = x[3];
+ }
+ }
+ } else {
+ float ogain = 1 + overdrive;
+ float k = control_in[1] * (1.0 / (1<<24));
+ for (int i = 0; i < 4; i++) {
+ a.get()[4 + 5 * i] -= 1.0;
+ a.get()[16 + i] += k * a.get()[i];
+ }
+ for (int i = 0; i < n; i++) {
+ float signal = ibuf[i];
+ float tmp[4];
+ float tx[4];
+ for (int j = 0; j < 4; j++) {
+ tx[j] = sigmoid(x[j], overdrive);
+ }
+ matvec4(tmp, a.get() + 4, tx);
+ float xin = sigmoid(signal - k * x[3], overdrive);
+ for (int j = 0; j < 4; j++) {
+ x[j] += tmp[j] + xin * a.get()[j];
+ obuf[i] = x[3] * ogain;
+ }
}
}
}
diff --git a/cpp/src/synth_unit.cc b/cpp/src/synth_unit.cc
index 546766a..9a69f5d 100644
--- a/cpp/src/synth_unit.cc
+++ b/cpp/src/synth_unit.cc
@@ -49,6 +49,7 @@ char epiano[] = {
void SynthUnit::Init(double sample_rate) {
Freqlut::init(sample_rate);
Exp2::init();
+ Tanh::init();
Sin::init();
Lfo::init(sample_rate);
PitchEnv::init(sample_rate);
@@ -68,6 +69,7 @@ SynthUnit::SynthUnit(RingBuffer *ring_buffer) {
current_note_ = 0;
filter_control_[0] = 258847126;
filter_control_[1] = 0;
+ filter_control_[2] = 0;
controllers_.values_[kControllerPitch] = 0x2000;
sustain_ = false;
extra_buf_size_ = 0;
@@ -121,6 +123,7 @@ void SynthUnit::SetController(int controller, int value) {
int SynthUnit::ProcessMidiMessage(const uint8_t *buf, int buf_size) {
uint8_t cmd = buf[0];
uint8_t cmd_type = cmd & 0xf0;
+ //LOGI("got %d midi: %02x %02x %02x", buf_size, buf[0], buf[1], buf[2]);
if (cmd_type == 0x80 || (cmd_type == 0x90 && buf[2] == 0)) {
if (buf_size >= 3) {
// note off
@@ -163,6 +166,8 @@ int SynthUnit::ProcessMidiMessage(const uint8_t *buf, int buf_size) {
filter_control_[0] = 142365917 + value * 917175;
} else if (controller == 2) {
filter_control_[1] = value * 528416;
+ } else if (controller == 3) {
+ filter_control_[2] = value * 528416;
} else if (controller == 64) {
sustain_ = value != 0;
if (!sustain_) {
diff --git a/cpp/src/synth_unit.h b/cpp/src/synth_unit.h
index 597345f..1dd6777 100644
--- a/cpp/src/synth_unit.h
+++ b/cpp/src/synth_unit.h
@@ -70,7 +70,7 @@ class SynthUnit {
Controllers controllers_;
ResoFilter filter_;
- int32_t filter_control_[2];
+ int32_t filter_control_[3];
bool sustain_;
// Extra buffering for when GetSamples wants a buffer not a multiple of N