Glissando working again
This commit is contained in:
parent
d31398ed63
commit
8e39c5118f
25
main-play.h
25
main-play.h
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
|
60
pipe.cpp
60
pipe.cpp
|
@ -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
27
pipe.h
|
@ -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];
|
||||||
|
|
24
uilleann.ino
24
uilleann.ino
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue