Glissando working again

This commit is contained in:
Neale Pickett 2020-11-26 18:49:09 -07:00
parent d31398ed63
commit 8e39c5118f
5 changed files with 71 additions and 73 deletions

View File

@ -19,21 +19,21 @@ void doPlay(bool forceDisplayUpdate) {
display.display(); display.display();
} }
if (pipe.silent) { if (pipe.Silent) {
Chanter.NoteOff(); Chanter.NoteOff();
} else { } else {
// Calculate pitch, and glissando pitch // Calculate pitch, and glissando pitch
float pitch = tuning.GetPitch(pipe.note); float pitch = tuning.GetPitch(pipe.CurrentNote);
float glissandoPitch = tuning.GetPitch(pipe.glissandoNote); float glissandoPitch = tuning.GetPitch(pipe.GlissandoNote);
// Bend pitch if fewer than 3 half steps away // Bend pitch if fewer than 3 half steps away
if (abs(pipe.glissandoNote - pipe.note) < 3) { if (abs(pipe.GlissandoNote - pipe.CurrentNote) < 3) {
float diff = glissandoPitch - pitch; float diff = glissandoPitch - pitch;
pitch += diff * pipe.glissandoOpenness; pitch = glissandoPitch - (diff * pipe.GlissandoPressure);
} }
// Apply a low shelf filter if this is the alternate fingering // Apply a low shelf filter if this is the alternate fingering
if (pipe.altFingering) { if (pipe.AltFingering) {
biquad1.setLowShelf(0, 2000, 0.2, 1); biquad1.setLowShelf(0, 2000, 0.2, 1);
} else { } else {
biquad1.setHighShelf(0, 1000, 1.0, 1); biquad1.setHighShelf(0, 1000, 1.0, 1);
@ -47,17 +47,16 @@ void doPlay(bool forceDisplayUpdate) {
} }
} }
if (pipe.note != last_note) { if (pipe.CurrentNote != last_note) {
updateDisplay = true; updateDisplay = true;
} }
diag("%d %f", pipe.keys, pipe.glissandoOpenness);
#if 0 #if 0
if (updateDisplay) { if (updateDisplay) {
// Look up the note name // Look up the note name
const char *note_name = NoteName(pipe.note); const char *noteName = NoteName(pipe.CurrentNote);
if (pipe.silent) { if (pipe.Silent) {
note_name = "--"; noteName = "--";
updateDisplay = true; updateDisplay = true;
} }
@ -65,10 +64,10 @@ void doPlay(bool forceDisplayUpdate) {
display.setFont(&FreeSans9pt7b); display.setFont(&FreeSans9pt7b);
display.setCursor(0, 16); display.setCursor(0, 16);
display.print(note_name); display.print(noteName);
display.display(); display.display();
last_note = pipe.note; last_note = pipe.CurrentNote;
} }
#endif #endif
} }

View File

@ -36,7 +36,10 @@ void setupVolume() {
break; break;
case ADJUST_UP: case ADJUST_UP:
case ADJUST_DOWN: case ADJUST_DOWN:
volume[i] += float(volAdjust)*0.02; {
float vol = volume[i] + float(volAdjust)*0.02;
volume[i] = min(max(vol, 1.0), 0.0);
}
break; break;
default: default:
break; break;
@ -143,6 +146,9 @@ void setupInfo() {
display.print("FC-1"); display.print("FC-1");
display.setCursor(0, 24); display.setCursor(0, 24);
display.print(buildDate); display.print(buildDate);
display.setCursor(0, 0);
display.print("M:");
display.print(AudioMemoryUsageMax());
} }
/** doSetup performs "setup mode" behavior for the pipe. /** doSetup performs "setup mode" behavior for the pipe.

View File

@ -8,7 +8,7 @@
#define GLISSANDO_STEPS (OPENVAL - CLOSEDVAL) #define GLISSANDO_STEPS (OPENVAL - CLOSEDVAL)
Pipe::Pipe() { Pipe::Pipe() {
keysLast = 0; KeysLast = 0;
} }
bool Pipe::Init() { bool Pipe::Init() {
@ -17,11 +17,11 @@ bool Pipe::Init() {
return false; return false;
} }
// Proximity sensor // Knee sensor
if (paj7620Init()) { if (!kneeSensor.begin()) {
return false; return false;
} }
// Bag button // Bag button
bagSensor.begin(); bagSensor.begin();
// This library takes the entire program out if you poll it 5-40 times without anything connected // This library takes the entire program out if you poll it 5-40 times without anything connected
@ -33,70 +33,72 @@ bool Pipe::Init() {
void Pipe::Update() { void Pipe::Update() {
uint8_t glissandoKeys = 0; uint8_t glissandoKeys = 0;
keysLast = keys; KeysLast = Keys;
keys = 0; Keys = 0;
// Read the bag state, if there's a bag. // Read the bag state, if there's a bag.
// if there isn't a bag, don't try, or this library will crash the program. // if there isn't a bag, don't try, or this library will crash the program.
if (bag_enabled) { if (bag_enabled) {
bag = bagSensor.isPressed(); Bag = bagSensor.isPressed();
} else { } else {
bag = false; Bag = false;
} }
// 0x6c is actually 8 bytes, but all 8 are always the same... // 0x6c is actually 8 bytes, but all 8 are always the same...
paj7620ReadReg(0x6c, 1, &kneeClosedness); KneeClosedness = 255 - kneeSensor.readRange();
for (int i = 0; i < NUM_KEYS; ++i) { for (int i = 0; i < NUM_KEYS; ++i) {
uint16_t val = max(capSensor.filteredData(i), CLOSEDVAL); uint16_t sensorReading = capSensor.filteredData(i);
keyOpen[i] = ((val - CLOSEDVAL) / float(GLISSANDO_STEPS)); uint16_t val = OPENVAL - min(max(sensorReading, CLOSEDVAL), OPENVAL);
KeyPressure[i] = val / float(GLISSANDO_STEPS);
// keys = all keys which are at least touched // keys = all keys which are at least touched
// glissandoKeys = all keys which are fully closed // glissandoKeys = all keys which are fully closed
// The glissando operation computes the difference. // The glissando operation computes the difference.
if (keyOpen[i] < 1.0) { if (KeyPressure[i] > 0.0) {
glissandoOpenness = max(glissandoOpenness, keyOpen[i]); bitSet(Keys, i);
bitSet(keys, i);
} }
if (keyOpen[i] == 0.0) { if (KeyPressure[i] == 1.0) {
bitSet(glissandoKeys, i); bitSet(glissandoKeys, i);
} }
} }
// Compute glissando amount // Compute glissando amount
glissandoOpenness = 0.0; GlissandoPressure = 1.0;
for (int i = 0; i < 8; ++i) { for (int i = 0; i < 8; ++i) {
glissandoOpenness = max(glissandoOpenness, keyOpen[i]); if (KeyPressure[i] > 0) {
GlissandoPressure = min(GlissandoPressure, KeyPressure[i]);
}
} }
// Look up notes in the big table // Look up notes in the big table
struct Fingering f = FingeredNote(keys); struct Fingering f = FingeredNote(Keys);
struct Fingering gf = FingeredNote(glissandoKeys); struct Fingering gf = FingeredNote(glissandoKeys);
note = f.note; CurrentNote = f.note;
glissandoNote = gf.note; GlissandoNote = gf.note;
// Was the high bit set? That indicates "alternate fingering", which sounds different. // Was the high bit set? That indicates "alternate fingering", which sounds different.
altFingering = f.alt; AltFingering = f.alt;
// If the bag is squished, jump up an octave // If the bag is squished, jump up an octave
// But only if the left thumb is down! // But only if the left thumb is down!
if (bag && (keys & bit(7))) { if (Bag && (Keys & bit(7))) {
note += NOTE_OCTAVE; CurrentNote += NOTE_OCTAVE;
glissandoNote += NOTE_OCTAVE; GlissandoNote += NOTE_OCTAVE;
} }
// All keys closed + knee = no sound // All keys closed + knee = no sound
silent = ((kneeClosedness > 240) && (keys == 0xff)); Silent = ((KneeClosedness > 240) && (Keys == 0xff));
} }
bool Pipe::Pressed(uint8_t key) { bool Pipe::Pressed(uint8_t key) {
return bitRead(keys, key); return bitRead(Keys, key);
} }
bool Pipe::JustPressed(uint8_t key) { bool Pipe::JustPressed(uint8_t key) {
if (bitRead(keys, key)) { if (bitRead(Keys, key)) {
return !bitRead(keysLast, key); return !bitRead(KeysLast, key);
} }
return false; return false;
} }
@ -136,4 +138,4 @@ Adjust Pipe::ReadAdjust(uint8_t keyUp, uint8_t keyDown, uint16_t delay, uint16_t
return ADJUST_DOWN; return ADJUST_DOWN;
} }
return ADJUST_NONE; return ADJUST_NONE;
} }

27
pipe.h
View File

@ -1,12 +1,12 @@
#pragma once #pragma once
#include <Adafruit_MPR121.h> #include <Adafruit_MPR121.h>
#include <Adafruit_VL6180X.h>
#include <SparkFun_Qwiic_Button.h> #include <SparkFun_Qwiic_Button.h>
#include <paj7620.h>
#include <stdint.h> #include <stdint.h>
#include "tuning.h" #include "tuning.h"
#define NUM_KEYS 8 #define NUM_KEYS 12
enum Adjust { enum Adjust {
ADJUST_DOWN = -1, ADJUST_DOWN = -1,
@ -18,31 +18,31 @@ enum Adjust {
class Pipe { class Pipe {
public: public:
// kneeClosedness indicates how "closed" the knee sensor is. 0 = wide open. // kneeClosedness indicates how "closed" the knee sensor is. 0 = wide open.
uint8_t kneeClosedness; uint8_t KneeClosedness;
// keys are which keys are being pressed. // keys are which keys are being pressed.
uint16_t keys; uint16_t Keys;
uint16_t keysLast; uint16_t KeysLast;
float keyOpen[NUM_KEYS]; float KeyPressure[NUM_KEYS];
// note holds the note being played, according to the fingering chart. // note holds the note being played, according to the fingering chart.
Note note; Note CurrentNote;
// glissandoNote is the note that would be played if partially open keys were fully open. // glissandoNote is the note that would be played if partially open keys were fully open.
Note glissandoNote; Note GlissandoNote;
// glissandoOpenness is how "open" the holes are in the direction of the glissandoNote. // glissandoPressure is how "closed" the holes are in the direction away from the glissandoNote.
float glissandoOpenness; float GlissandoPressure;
// silent is true if all keys and the knee are closed. // silent is true if all keys and the knee are closed.
bool silent; bool Silent;
// bag is true if the bag is being squished. // bag is true if the bag is being squished.
bool bag; bool Bag;
// altFingering is true if the "alternate fingering" is being played. // altFingering is true if the "alternate fingering" is being played.
// This should sound different than the standard fingering. // This should sound different than the standard fingering.
bool altFingering; bool AltFingering;
Pipe(); Pipe();
@ -70,6 +70,7 @@ class Pipe {
private: private:
Adafruit_MPR121 capSensor; Adafruit_MPR121 capSensor;
Adafruit_VL6180X kneeSensor;
QwiicButton bagSensor; QwiicButton bagSensor;
bool bag_enabled; bool bag_enabled;
unsigned long nextRepeat[NUM_KEYS]; unsigned long nextRepeat[NUM_KEYS];

View File

@ -1,10 +1,7 @@
#include <Adafruit_GFX.h> #include <Adafruit_GFX.h>
#include <Adafruit_MPR121.h>
#include <Adafruit_SSD1306.h> #include <Adafruit_SSD1306.h>
#include <Audio.h> #include <Audio.h>
#include <Fonts/FreeSans9pt7b.h> #include <Fonts/FreeSans9pt7b.h>
#include <Wire.h>
#include <paj7620.h>
#include <stdio.h> #include <stdio.h>
#include "patches.h" #include "patches.h"
@ -26,7 +23,7 @@ Adafruit_SSD1306 display(128, 32, &Wire, -1);
// Settings // Settings
uint8_t patch[4] = {0}; uint8_t patch[4] = {0};
float volume[4] = {0}; float volume[5] = {0.75, 0.75, 0.75, 0.75, 0.3};
// Pipes // Pipes
#define NUM_DRONES 3 #define NUM_DRONES 3
@ -132,13 +129,6 @@ void diag(const char *fmt, ...) {
#include "main-setup.h" #include "main-setup.h"
void setup() { void setup() {
// Initialize settings
// XXX: Read these from persistent storage later
for (int i = 0; i < 4; i++) {
patch[i] = 0;
volume[i] = 0.75;
}
// PREPARE TO BLINK // PREPARE TO BLINK
pinMode(LED_BUILTIN, OUTPUT); pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, true); digitalWrite(LED_BUILTIN, true);
@ -160,16 +150,16 @@ void setup() {
diag("Pipe..."); diag("Pipe...");
while (!pipe.Init()) { while (!pipe.Init()) {
diag("No pipe. Is it connected?"); diag("Pipe connected?");
blink(false); blink(false);
} }
diag("Audio..."); diag("Audio...");
AudioMemory(20); AudioMemory(120);
AudioProcessorUsageMaxReset(); AudioProcessorUsageMaxReset();
AudioMemoryUsageMaxReset(); AudioMemoryUsageMaxReset();
sgtl5000.enable(); sgtl5000.enable();
sgtl5000.volume(0.3); sgtl5000.volume(volume[4]);
diag("Synth..."); diag("Synth...");
loadPatch(0); loadPatch(0);
@ -188,7 +178,7 @@ void setup() {
for (int i = 0; i < NUM_DRONES; ++i) { for (int i = 0; i < NUM_DRONES; ++i) {
mixDrones.gain(i, 1); mixDrones.gain(i, 1);
} }
biquad1.setBandpass(0, PITCH_CONCERT_A4, 1.0); biquad1.setNotch(0, PITCH_CONCERT_A4, 0.001);
diag("Drones..."); diag("Drones...");
playDrones(); playDrones();
@ -231,12 +221,12 @@ void loop() {
// If we're infinitely (for the sensor) off the knee, // If we're infinitely (for the sensor) off the knee,
// we might be in setup mode. // we might be in setup mode.
if (pipe.kneeClosedness == 0) { if (pipe.KneeClosedness == 0) {
// We only enter into setup mode if no keys are pressed. // We only enter into setup mode if no keys are pressed.
// This hopefully avoids accidentally entering setup while playing. // This hopefully avoids accidentally entering setup while playing.
// Like say you're playing a jaunty tune and suddenly there's an earthquake. // Like say you're playing a jaunty tune and suddenly there's an earthquake.
// You ought to be able to finish the tune off before your pipe goes into setup mode. // You ought to be able to finish the tune off before your pipe goes into setup mode.
if (upSetting || (pipe.keys == 0)) { if (upSetting || (pipe.Keys == 0)) {
doSetup(); doSetup();
upSetting = true; upSetting = true;
return; return;