Added arpeggiato, fixed notes. TODO: Fix menu options for arpeggio. Persistent config/save+load option
This commit is contained in:
parent
07917c0e6e
commit
e780df7d22
|
|
@ -28,12 +28,19 @@ Adafruit_SSD1306 display(OLED_W, OLED_H, &Wire);
|
|||
|
||||
// Modes
|
||||
int mode = 0;
|
||||
String mode_names[4] = {"Vol", "Sou", "Oct", "Env"};
|
||||
String mode_names[7] = { "Vol", "Sou", "Oct", "Env", "Arp", "ArpΔ", "Arp"};
|
||||
int mode_count = sizeof(mode_names) / sizeof(mode_names[0]);
|
||||
|
||||
// Octave
|
||||
int octave = 2;
|
||||
|
||||
// Arpeggio
|
||||
//int arp_pattern[5] = {1 ,3 ,5 ,3 ,1 };
|
||||
int arp_pattern[5] = {0 ,4 ,7 ,3 ,1 };
|
||||
int arpeggio = 1; // 0 = Off, 1 =
|
||||
int arp_notes = 3; // Now many notes to arpeggiate
|
||||
int arp_delay = 150; // 300 ms
|
||||
|
||||
|
||||
// ---- Audio ----
|
||||
//constexpr uint32_t SAMPLE_RATE = 96000;
|
||||
|
|
@ -80,10 +87,13 @@ void initNotes() {
|
|||
struct Voice {
|
||||
bool active = false;
|
||||
float freq = 0;
|
||||
float startFreq = 0;
|
||||
float phase1 = 0;
|
||||
float phase2 = 0;
|
||||
float env = 0;
|
||||
float amp = 0;
|
||||
long arp_time = 0;
|
||||
int arp_position = 0;
|
||||
};
|
||||
|
||||
Voice voices[MAX_VOICES];
|
||||
|
|
@ -92,8 +102,11 @@ void noteOn(float freq) {
|
|||
for (auto &v : voices) {
|
||||
if (!v.active) {
|
||||
v.active = true;
|
||||
v.freq = freq*(funcKey ? 1.25f : 1.0f);
|
||||
v.freq = freq;
|
||||
v.startFreq = freq;
|
||||
v.env = VOL;
|
||||
v.arp_time = millis();
|
||||
v.arp_position = 0;
|
||||
v.phase1 = 0.5f;
|
||||
v.phase2 = 0.5f;
|
||||
return;
|
||||
|
|
@ -103,7 +116,7 @@ void noteOn(float freq) {
|
|||
|
||||
void noteOff(float freq) {
|
||||
for (auto &v : voices) {
|
||||
if (v.active && fabs(v.freq - freq) < 0.01f) {
|
||||
if (v.active && fabs(v.startFreq - freq) < 0.01f) {
|
||||
v.active = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -146,11 +159,16 @@ int genWaveTable(){
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
float transposeSemitones(float freq, int semitones) {
|
||||
return freq * powf(2.0f, semitones / 12.0f);
|
||||
}
|
||||
/* =========================================================
|
||||
SYNTH STREAM
|
||||
========================================================= */
|
||||
|
||||
class JunoStream : public Stream {
|
||||
class SynthStream : public Stream {
|
||||
public:
|
||||
uint8_t frame[4];
|
||||
uint8_t index = 4;
|
||||
|
|
@ -167,7 +185,9 @@ public:
|
|||
float scope[128]{};
|
||||
int scopeIndex = 0;
|
||||
|
||||
int available() override { return 4; }
|
||||
int available() override {
|
||||
return 4;
|
||||
}
|
||||
|
||||
int read() override {
|
||||
if (index >= 4) {
|
||||
|
|
@ -177,8 +197,12 @@ public:
|
|||
return frame[index++];
|
||||
}
|
||||
|
||||
int peek() override { return -1; }
|
||||
size_t write(uint8_t) override { return 0; }
|
||||
int peek() override {
|
||||
return -1;
|
||||
}
|
||||
size_t write(uint8_t) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void generate() {
|
||||
|
|
@ -188,6 +212,13 @@ private:
|
|||
if (!v.active) continue;
|
||||
float osc = 0.0f;
|
||||
|
||||
|
||||
if (arpeggio>0 && (millis()-v.arp_time)>arp_delay){
|
||||
v.arp_time = millis();
|
||||
v.arp_position++;
|
||||
v.arp_position = v.arp_position % arp_notes;
|
||||
v.freq = transposeSemitones(v.startFreq, arp_pattern[v.arp_position]);
|
||||
}
|
||||
// Defined voices
|
||||
switch (sound) {
|
||||
// Saw+Sine
|
||||
|
|
@ -228,10 +259,13 @@ private:
|
|||
|
||||
mix += osc * v.amp;
|
||||
}
|
||||
// Handle reverb
|
||||
mix = (handleReverb(mix) + mix) / 2.0f;
|
||||
|
||||
|
||||
lp += cutoff * (mix - lp);
|
||||
float out = lp * 0.4f;
|
||||
//out = (handleReverb(out)+out)/2.0f;
|
||||
|
||||
|
||||
int r = (delayIndex - 480 + DELAY_SAMPLES) % DELAY_SAMPLES;
|
||||
float ch = out + delayL[r] * 0.6f;
|
||||
|
|
@ -256,7 +290,7 @@ private:
|
|||
========================================================= */
|
||||
|
||||
I2SStream i2s;
|
||||
JunoStream synth;
|
||||
SynthStream synth;
|
||||
StreamCopy copier(i2s, synth);
|
||||
|
||||
/* =========================================================
|
||||
|
|
@ -269,7 +303,7 @@ uint16_t scanMatrix() {
|
|||
|
||||
for (int x = 0; x < 4; x++) {
|
||||
digitalWrite(X_PINS[x], HIGH);
|
||||
delayMicroseconds(5);
|
||||
delayMicroseconds(10);
|
||||
|
||||
for (int y = 0; y < 4; y++) {
|
||||
if (digitalRead(Y_PINS[y])) {
|
||||
|
|
@ -311,7 +345,8 @@ void handleInputs(){
|
|||
if (keys & (1 << 13)) {
|
||||
switch (mode) {
|
||||
case 0: // Volume
|
||||
if(VOL > 0.1f){ VOL-=0.1f; } break;
|
||||
if (VOL > 0.1f) { VOL -= 0.1f; }
|
||||
break;
|
||||
case 1: // Sound
|
||||
sound = sound - 1;
|
||||
if (sound < 0) { sound = sound_count - 1; }
|
||||
|
|
@ -396,8 +431,7 @@ void drawScope() {
|
|||
mid - synth.scope[i1] * scale * height,
|
||||
x + 1,
|
||||
mid - synth.scope[i2] * scale * height,
|
||||
SSD1306_WHITE
|
||||
);
|
||||
SSD1306_WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -432,8 +466,6 @@ void drawInfo(){
|
|||
display.print(mode_names[mode]);
|
||||
display.setCursor(90, 18);
|
||||
display.print("Oct:" + String(octave));
|
||||
|
||||
|
||||
}
|
||||
|
||||
void updateOLED(uint16_t keys) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue