Skip to content
Snippets Groups Projects
Commit ee72acc1 authored by David Huss's avatar David Huss :speech_balloon:
Browse files

Working demo code

parent 54fdea48
No related branches found
No related tags found
No related merge requests found
......@@ -10,6 +10,7 @@
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#include <CpuLoadMeter.h>
#include "leds.h"
#include "potentiometers.h"
......@@ -26,9 +27,13 @@ static float DSY_SDRAM_BSS buffer[buffer_length];
static atoav::Looper looper;
static PitchShifter pitch_shifter;
static atoav::EnvelopeFollower envelope_follower;
static atoav::EnvelopeFollower output_envelope_follower;
DelayLine<float, 24000> delayline;
Resonator res;
DSY_SDRAM_BSS ReverbSc reverb;
static Compressor compressor;
// Resonator res;
CpuLoadMeter load;
// Buttons
Button button_1 = Button(D7);
......@@ -61,29 +66,35 @@ uint16_t waveform_cache[SCREEN_WIDTH] = {0};
DaisyHardware hw;
size_t num_channels;
float blocksize;
double last_render = 0.0;
float drywetmix = 0.0f;
float delaymix = 0.0f;
float resmix = 0.0f;
float delaytime = 100.0f;
void AudioCallback(float **in, float **out, size_t size) {
float output = 0.0f;
float no_delay = 0.0f;
float wet_delay;
delayline.SetDelay(delaytime);
float out1, out2;
for (size_t i = 0; i < size; i++) {
res.SetDamping(0.1+delaymix*0.2f);
// res.SetDamping(0.1+delaymix*0.2f);
auto looper_out = looper.Process(in[1][i]);
// FIXME:
envelope_follower.Process(in[1][i]);
float input_envelope = input_envelope_follower.Process(in[1][i]);
output = drywetmix * pitch_shifter.Process(looper_out) + in[1][i] * (1.0f - drywetmix);
// output = output * (1.0f - resmix) + res.Process(output*resmix);
// no_delay = output;
// wet_delay = delayline.Read();
// delayline.Write((wet_delay * delaymix * 0.99f) + no_delay*delaymix);
no_delay = output;
wet_delay = delayline.Read();
delayline.Write((wet_delay * delaymix * 0.95f)/2.0f + (no_delay*delaymix)/2.0f);
output += wet_delay * delaymix;
compressor.Process(output);
reverb.Process(output, output, &out1, &out2);
// output += wet_delay*delaymix;
out[0][i] = out[1][i] = output;
out[0][i] = out[1][i] = out1;
}
}
......@@ -118,19 +129,33 @@ void setup() {
float sample_rate;
// Initialize for Daisy pod at 48kHz
hw = DAISY.init(DAISY_SEED, AUDIO_SR_48K);
DAISY.SetAudioBlockSize(64);
num_channels = hw.num_channels;
sample_rate = DAISY.get_samplerate();
blocksize = 64.0f;
looper.Init(buffer, buffer_length);
envelope_follower.Init(sample_rate);
envelope_follower.SetAttack(100.0);
envelope_follower.SetDecay(1000.0);
input_envelope_follower.Init(sample_rate);
input_envelope_follower.SetAttack(100.0);
input_envelope_follower.SetDecay(1000.0);
reverb.Init(sample_rate);
reverb.SetFeedback(0.85f);
reverb.SetLpFreq(18000.0f);
compressor.SetThreshold(-64.0f);
compressor.SetRatio(2.0f);
compressor.SetAttack(0.005f);
compressor.SetRelease(0.1250);
pitch_shifter.Init(sample_rate);
delayline.Init();
delayline.SetDelay(48000.0f);
res.Init(.015, 24, sample_rate);
res.SetStructure(-7.f);
// res.Init(.015, 24, sample_rate);
// res.SetStructure(-7.f);
load.Init(sample_rate, blocksize);
Serial.begin(250000);
......@@ -171,13 +196,11 @@ void setup() {
pot_3.setDisplayMode("Pitch", 12.0f, POT_DISPLAY_MODE_PITCH);
pot_4.setDisplayMode("Mix", 100.0f, POT_DISPLAY_MODE_PERCENT);
pot_5.setDisplayMode("Delay", 100.0f, POT_DISPLAY_MODE_PERCENT);
pot_6.setDisplayMode("Resonator", 100.0f, POT_DISPLAY_MODE_PERCENT);
pot_7.setDisplayMode("Structure", 100.0f, POT_DISPLAY_MODE_PERCENT);
pot_6.setDisplayMode("Time", 100.0f, POT_DISPLAY_MODE_PERCENT);
// pot_7.setDisplayMode("Structure", 100.0f, POT_DISPLAY_MODE_PERCENT);
// Set Knob Scaling Modes
pot_2.setExponential();
pot_3.setBipolar();
pot_5.setExponential();
// Initialize Buttons
button_1.init();
......@@ -215,22 +238,24 @@ void loop() {
// Value should go 1 octave up/down (12 semitones)
pitch_val = 12.0f * p3;
pitch_shifter.SetTransposition(pitch_val);
res.SetFreq(10.0f + p3 * 1500.0f);
// res.SetFreq(10.0f + p3 * 1500.0f);
// Set other parameters
drywetmix = p4;
delaymix = p5;
resmix = p6;
res.SetStructure(p7);
delaytime = 100.0f + p6 * 23900.0f;
// res.SetStructure(p7);
// Toggle record
looper.SetRecording(record_on, overdub_on);
// Render UI
// load.OnBlockStart();
renderBuffer();
// load.OnBlockEnd();
rgb_led.setAudioLevelIndicator(int(input_envelope_follower.getValue() * 255));
Serial.println(envelope_follower.value);
rgb_led.setAudioLevelIndicator(int(envelope_follower.value * 255));
// Serial.println(load.GetMaxCpuLoad());
}
......@@ -320,7 +345,7 @@ void renderBuffer() {
pot_4.renderUi();
pot_5.renderUi();
pot_6.renderUi();
pot_7.renderUi();
// pot_7.renderUi();
// After pressing the rec mode button display info
if (display_rec_mode) {
......
#include "wiring_constants.h"
#ifndef Env_follower_h
#define Env_follower_h
#include "Arduino.h"
namespace atoav {
class SmoothingFilter {
public:
void Init(float smoothing_time_ms, float sample_rate) {
a = exp(-TWO_PI / (smoothing_time_ms * 0.001f * sample_rate));
b = 1.0f - a;
z = 0.0f;
}
inline float Process(float in) {
z = (in * b) + (z * a);
return z;
}
void setSmoothing(float smoothing_time_ms, float sample_rate) {
a = exp(-TWO_PI / (smoothing_time_ms * 0.001f * sample_rate));
b = 1.0f - a;
}
private:
float a;
float b;
float z;
};
class EnvelopeFollower {
public:
void Init(float sample_rate) {
sample_rate = sample_rate;
attack = 200.0f;
decay = 4000.0f;
smoothing = 50.0f;
value = 0.0f;
smoothing_filter.Init(smoothing, sample_rate);
}
void SetAttack(float attack_ms) {
......@@ -18,27 +49,43 @@ class EnvelopeFollower {
decay = pow(0.01, 1.0 / (decay_ms * sample_rate * 0.001));
}
void SetSmoothing(float smoothing_ms) {
smoothing_filter.setSmoothing(smoothing_ms, sample_rate);
}
float Process(float in) {
abs_value = abs(in);
if (abs_value > value)
abs_value = smoothing_filter.Process(abs(in));
if (abs_value > value) {
value = attack * (value - abs_value) + abs_value;
else
} else {
value = decay * (value - abs_value) + abs_value;
}
return value;
}
float value = 0.0f;
float value;
float getValue() {
if (value == 0.0f || value == -0.0f) {
return value;
}
return max(0.0f, (3.0f + log10(value)) / 3.0f);
// return value;
}
private:
float sample_rate;
float attack;
float decay;
float smoothing;
float abs_value = 0.0f;
SmoothingFilter smoothing_filter;
};
};
#endif
\ No newline at end of file
......@@ -38,7 +38,8 @@ class Looper {
_pending_loop_length = max(kMinLoopLength, static_cast<size_t>(loop_length * _buffer_length));
// CHECK if this is truly good
_loop_length = _pending_loop_length;
// _loop_length = _pending_loop_length;
// _loop_length = _pending_loop_length;
//If the current loop length is not set yet, set it too
if (!_is_loop_set) _loop_length = _pending_loop_length;
......@@ -125,7 +126,7 @@ class Looper {
}
private:
static const size_t kFadeLength = 20; //orig: 600
static const size_t kFadeLength = 200; //orig: 600
static const size_t kMinLoopLength = 2 * kFadeLength;
float* _buffer;
......
This diff is collapsed.
......@@ -99,25 +99,30 @@ float Potentiometer::read() {
for (int i=0; i<POT_MOVING_AVERAGE_SIZE; i++) {
reading += (this->readings)[i];
}
reading = reading / POT_MOVING_AVERAGE_SIZE;
// Convert the last reading to a float and return
float current_reading = reading / 4096.0f;
// Depending on the Mode
reading = reading / POT_MOVING_AVERAGE_SIZE;
if (this->mode == POT_MODE_EXP ) {
reading = exp_lookup[reading];
} else if (this->mode == POT_MODE_BIP) {
reading = bip_lookup[reading];
current_reading = get_from_table(exp_lookup, current_reading);
}
// Convert the last reading to a float and return
float current_reading = reading / 4096.0f;
if (this->mode == POT_MODE_BIP) {
current_reading = get_from_table(bip_lookup, current_reading);
// Bipolar Knobs go from -1.0 to +1.0 (Centered = 0.0)
if (this->mode == POT_MODE_BIP) {
current_reading = (current_reading - 0.5f) * 2.0f;
}
// If the difference to the last reading is big enough assume the knob has been touched
if (this->last_reading && abs(current_reading - this->last_reading) > 0.002) {
// Serial.print("Touched Potentiometer: ");
// Serial.print("Touched Potentiometer ");
// Serial.print(this->name);
// Serial.print(": ");
// Serial.print(input);
// Serial.print(" --> ");
// Serial.println(current_reading);
if (display_value_changes) {
last_displayed = millis();
......@@ -211,8 +216,8 @@ void Potentiometer::renderUi() {
centeredText(text_buffer, x_center, y_center+4, SH110X_WHITE);
}
// Show this for 200 ms after it has been last touched
if (now - this->last_displayed > 700.0) {
// Show this for 700 ms after it has been last touched
if ((now - this->last_displayed) > 700.0) {
this->should_display = false;
}
}
......
#include "wiring_constants.h"
#ifndef Env_follower_h
#define Env_follower_h
#include "Arduino.h"
namespace atoav {
class SmoothingFilter {
public:
void Init(float smoothing_time_ms, float sample_rate) {
a = exp(-TWO_PI / (smoothing_time_ms * 0.001f * sample_rate));
b = 1.0f - a;
z = 0.0f;
}
inline float Process(float in) {
z = (in * b) + (z * a);
return z;
}
void setSmoothing(float smoothing_time_ms, float sample_rate) {
a = exp(-TWO_PI / (smoothing_time_ms * 0.001f * sample_rate));
b = 1.0f - a;
}
private:
float a;
float b;
float z;
};
class EnvelopeFollower {
public:
void Init(float sample_rate) {
sample_rate = sample_rate;
attack = 200.0f;
decay = 4000.0f;
smoothing = 50.0f;
value = 0.0f;
smoothing_filter.Init(smoothing, sample_rate);
}
void SetAttack(float attack_ms) {
attack = pow(0.01, 1.0 / (attack_ms * sample_rate * 0.001));
}
void SetDecay(float decay_ms) {
decay = pow(0.01, 1.0 / (decay_ms * sample_rate * 0.001));
}
void SetSmoothing(float smoothing_ms) {
smoothing_filter.setSmoothing(smoothing_ms, sample_rate);
}
float Process(float in) {
abs_value = smoothing_filter.Process(abs(in));
if (abs_value > value) {
value = attack * (value - abs_value) + abs_value;
} else {
value = decay * (value - abs_value) + abs_value;
}
return value;
}
float value;
float getValue() {
if (value == 0.0f || value == -0.0f) {
return value;
}
return max(0.0f, (3.0f + log10(value)) / 3.0f);
// return value;
}
private:
float sample_rate;
float attack;
float decay;
float smoothing;
float abs_value = 0.0f;
SmoothingFilter smoothing_filter;
};
};
#endif
\ No newline at end of file
#ifndef Leds_h
#define Leds_h
#include "Arduino.h"
// Lookup Table for Red LED Channel
int red_lookup[] = {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, 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, 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, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 24, 24, 25, 27, 28, 31, 33, 37, 40, 45, 50, 56, 63, 70, 78, 88, 98, 109, 122, 135, 150, 166, 183, 202, 222, 243, 255, 255, 255, 255, 255};
// Lookup Table for Green LED Channel
int green_lookup[] = {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, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 15, 15, 16, 17, 17, 18, 19, 20, 20, 21, 22, 23, 24, 25, 25, 26, 27, 28, 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, 40, 42, 43, 43, 43, 42, 42, 42, 42, 41, 41, 41, 41, 41, 40, 40, 40, 40, 39, 39, 39, 39, 39, 38, 38, 38, 38, 37, 37, 37, 37, 37, 36, 36, 36, 36, 35, 35, 35, 35, 35, 34, 34, 34, 34, 33, 33, 33, 33, 32, 32, 32, 32, 32, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29, 29, 29, 29, 28, 28, 28, 28, 28, 27, 27, 27, 27, 26, 26, 26, 26, 26, 25, 25, 25, 25, 24, 24, 24, 24, 24, 23, 23, 23, 23, 22, 22, 22, 22, 21, 21, 21, 21, 21, 20, 20, 20, 20, 19, 19, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 14, 14, 14, 14, 13, 13, 13, 13, 13, 12, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 10, 10, 9, 9, 9, 9, 8};
// Lookup Table for Blue LED Channel
int blue_lookup[] = {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 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, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0};
class RGBLed {
int pin_red;
int pin_green;
int pin_blue;
public:
RGBLed(int pin_red, int pin_green, int pin_blue);
void init();
void off();
void setColor(int r, int g, int b);
void setAudioLevelIndicator(int level);
};
RGBLed::RGBLed(int pin_red, int pin_green, int pin_blue) {
this->pin_red = pin_red;
this->pin_green = pin_green;
this->pin_blue = pin_blue;
}
void RGBLed::init() {
pinMode(this->pin_red, OUTPUT);
pinMode(this->pin_green, OUTPUT);
pinMode(this->pin_blue, OUTPUT);
}
void RGBLed::off() {
digitalWrite(this->pin_red, LOW);
digitalWrite(this->pin_green, LOW);
digitalWrite(this->pin_blue, LOW);
}
void RGBLed::setColor(int r, int g, int b) {
r = min(255, max(0, r));
g = min(255, max(0, g));
b = min(255, max(0, b));
analogWrite(this->pin_red, r);
analogWrite(this->pin_green, g);
analogWrite(this->pin_blue, b);
}
void RGBLed::setAudioLevelIndicator(int level) {
level = min(255, max(0, level));
this->setColor(red_lookup[level], green_lookup[level], blue_lookup[level]);
}
#endif
\ No newline at end of file
// Title: Envelope Follower
// Description: Drives an RGB-LED from an Envelope follower
// Hardware: Daisy Seed
// Author: David Huss
#include "DaisyDuino.h"
#include "env_follower.h"
#include "leds.h"
DaisyHardware hw;
// Create an instance of the envelope folower
atoav::EnvelopeFollower envelope_follower;
// LED R G B
RGBLed rgb_led = RGBLed(A10, A9, A11);
size_t num_channels;
void AudioCallback(float **in, float **out, size_t size) {
for (size_t i = 0; i < size; i++) {
// Generate the envelope (only use channel 2)
envelope_follower.Process(in[1][i]);
// Input goes directly to output
for (size_t chn = 0; chn < num_channels; chn++) {
out[chn][i] = in[chn][i];
}
}
}
void setup() {
float samplerate;
// Initialize for Daisy pod at 48kHz
hw = DAISY.init(DAISY_SEED, AUDIO_SR_48K);
// Initialize some variables
num_channels = hw.num_channels;
samplerate = DAISY.get_samplerate();
// Initialize the Envelope follower
envelope_follower.Init(samplerate);
envelope_follower.SetAttack(50.0);
envelope_follower.SetDecay(200.0);
DAISY.begin(AudioCallback);
rgb_led.init();
Serial.begin(250000);
}
void loop() {
// Get the value from the envelope
float envelope_reading = envelope_follower.getValue();
// Set the brightness and Color of the LED depending on the envelope
rgb_led.setAudioLevelIndicator(int(envelope_reading * 255));
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment