Compare commits
No commits in common. "d563a4d497d99024b3a0e1cf7b9add83dab4d821" and "a2469f83c79801df17e011ca729b21bb84163cc6" have entirely different histories.
d563a4d497
...
a2469f83c7
|
@ -51,6 +51,7 @@ void doPlay(bool forceDisplayUpdate) {
|
||||||
updateDisplay = true;
|
updateDisplay = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (updateDisplay) {
|
if (updateDisplay) {
|
||||||
// Look up the note name
|
// Look up the note name
|
||||||
const char *noteName = NoteName(pipe.CurrentNote);
|
const char *noteName = NoteName(pipe.CurrentNote);
|
||||||
|
@ -68,4 +69,5 @@ void doPlay(bool forceDisplayUpdate) {
|
||||||
display.display();
|
display.display();
|
||||||
last_note = pipe.CurrentNote;
|
last_note = pipe.CurrentNote;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
35
pipe.cpp
35
pipe.cpp
|
@ -16,8 +16,16 @@ bool Pipe::Init() {
|
||||||
if (!capSensor.begin(0x5A)) {
|
if (!capSensor.begin(0x5A)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Knee sensor
|
||||||
|
if (!kneeSensor.begin()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Bag button
|
// Bag button
|
||||||
|
bagSensor.begin();
|
||||||
|
// This library takes the entire program out if you poll it 5-40 times without anything connected
|
||||||
|
bag_enabled = bagSensor.isConnected();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -29,31 +37,29 @@ void Pipe::Update() {
|
||||||
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 (bag_enabled) {
|
if (bag_enabled) {
|
||||||
// XXX: re-enable the bag sensor at some point
|
Bag = bagSensor.isPressed();
|
||||||
//Bag = bagSensor.isPressed();
|
|
||||||
} else {
|
} else {
|
||||||
Bag = false;
|
Bag = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < NUM_KEYS; ++i) {
|
// 0x6c is actually 8 bytes, but all 8 are always the same...
|
||||||
int key = KeySensor[i];
|
KneeClosedness = 255 - kneeSensor.readRange();
|
||||||
if (key == -1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_KEYS; ++i) {
|
||||||
uint16_t sensorReading = capSensor.filteredData(i);
|
uint16_t sensorReading = capSensor.filteredData(i);
|
||||||
uint16_t val = OPENVAL - min(max(sensorReading, CLOSEDVAL), OPENVAL);
|
uint16_t val = OPENVAL - min(max(sensorReading, CLOSEDVAL), OPENVAL);
|
||||||
KeyPressure[key] = val / float(GLISSANDO_STEPS);
|
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 (KeyPressure[key] > 0.0) {
|
if (KeyPressure[i] > 0.0) {
|
||||||
bitSet(Keys, key);
|
bitSet(Keys, i);
|
||||||
}
|
}
|
||||||
if (KeyPressure[key] == 1.0) {
|
if (KeyPressure[i] == 1.0) {
|
||||||
bitSet(glissandoKeys, key);
|
bitSet(glissandoKeys, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,9 +81,6 @@ void Pipe::Update() {
|
||||||
// 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;
|
||||||
|
|
||||||
// All keys closed + knee = no sound
|
|
||||||
Silent = ((KeyPressure[11] > 0) && (CurrentNote == NOTE_D4));
|
|
||||||
|
|
||||||
// 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))) {
|
||||||
|
@ -85,6 +88,8 @@ void Pipe::Update() {
|
||||||
GlissandoNote += NOTE_OCTAVE;
|
GlissandoNote += NOTE_OCTAVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// All keys closed + knee = no sound
|
||||||
|
Silent = ((KneeClosedness > 240) && (Keys == 0xff));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pipe::Pressed(uint8_t key) {
|
bool Pipe::Pressed(uint8_t key) {
|
||||||
|
|
8
pipe.h
8
pipe.h
|
@ -8,9 +8,6 @@
|
||||||
|
|
||||||
#define NUM_KEYS 12
|
#define NUM_KEYS 12
|
||||||
|
|
||||||
// A mapping of MPR121 input to pipe key
|
|
||||||
const int KeySensor[NUM_KEYS] = { 11, -1, 0, 1, 2, 3, 4, 5, 6, 7, -1, -1 };
|
|
||||||
|
|
||||||
enum Adjust {
|
enum Adjust {
|
||||||
ADJUST_DOWN = -1,
|
ADJUST_DOWN = -1,
|
||||||
ADJUST_NONE = 0,
|
ADJUST_NONE = 0,
|
||||||
|
@ -20,6 +17,9 @@ enum Adjust {
|
||||||
|
|
||||||
class Pipe {
|
class Pipe {
|
||||||
public:
|
public:
|
||||||
|
// kneeClosedness indicates how "closed" the knee sensor is. 0 = wide open.
|
||||||
|
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;
|
||||||
|
@ -70,6 +70,8 @@ class Pipe {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Adafruit_MPR121 capSensor;
|
Adafruit_MPR121 capSensor;
|
||||||
|
Adafruit_VL6180X kneeSensor;
|
||||||
|
QwiicButton bagSensor;
|
||||||
bool bag_enabled;
|
bool bag_enabled;
|
||||||
unsigned long nextRepeat[NUM_KEYS];
|
unsigned long nextRepeat[NUM_KEYS];
|
||||||
bool typematicEvent(uint8_t key, uint16_t delay, uint16_t repeat);
|
bool typematicEvent(uint8_t key, uint16_t delay, uint16_t repeat);
|
||||||
|
|
63
uilleann.ino
63
uilleann.ino
|
@ -11,14 +11,15 @@
|
||||||
|
|
||||||
const char *buildDate = __DATE__;
|
const char *buildDate = __DATE__;
|
||||||
|
|
||||||
|
#if defined(ADAFRUIT_TRELLIS_MAdafruit_SSD1306EXPRESS)
|
||||||
#include <Adafruit_NeoTrellisM4.h>
|
#include <Adafruit_NeoTrellisM4.h>
|
||||||
Adafruit_NeoTrellisM4 trellis = Adafruit_NeoTrellisM4();
|
Adafruit_NeoTrellisM4 trellis; // = Adafruit_NeoTrellisM4();
|
||||||
|
#endif
|
||||||
|
|
||||||
Pipe pipe;
|
Pipe pipe;
|
||||||
Tuning tuning = Tuning(NOTE_D4, PITCH_CONCERT_D4, TUNINGSYSTEM_JUST);
|
Tuning tuning = Tuning(NOTE_D4, PITCH_CONCERT_D4, TUNINGSYSTEM_JUST);
|
||||||
Adafruit_SSD1306 display(128, 32, &Wire, -1);
|
|
||||||
|
|
||||||
|
Adafruit_SSD1306 display(128, 32, &Wire, -1);
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
#define VOLUME_INITIAL 0.8
|
#define VOLUME_INITIAL 0.8
|
||||||
|
@ -39,7 +40,13 @@ AudioMixer4 mixL;
|
||||||
AudioMixer4 mixR;
|
AudioMixer4 mixR;
|
||||||
AudioSynthNoiseWhite noise;
|
AudioSynthNoiseWhite noise;
|
||||||
|
|
||||||
|
#if defined(ADAFRUIT_TRELLIS_M4_EXPRESS)
|
||||||
AudioOutputAnalogStereo out1;
|
AudioOutputAnalogStereo out1;
|
||||||
|
#else
|
||||||
|
AudioOutputI2S out1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
AudioControlSGTL5000 sgtl5000;
|
||||||
|
|
||||||
AudioConnection FMVoicePatchCords[] = {
|
AudioConnection FMVoicePatchCords[] = {
|
||||||
{noise, 0, mixL, 3},
|
{noise, 0, mixL, 3},
|
||||||
|
@ -73,18 +80,15 @@ AudioConnection FMVoicePatchCords[] = {
|
||||||
FMVoiceWiring(Regulators[2]),
|
FMVoiceWiring(Regulators[2]),
|
||||||
};
|
};
|
||||||
|
|
||||||
void blink(int count, bool forever) {
|
void blink(bool forever) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
for (int i = 0; i < count; i++) {
|
digitalWrite(LED_BUILTIN, true);
|
||||||
digitalWrite(LED_BUILTIN, true);
|
delay(200);
|
||||||
delay(200);
|
digitalWrite(LED_BUILTIN, false);
|
||||||
digitalWrite(LED_BUILTIN, false);
|
delay(200);
|
||||||
delay(200);
|
|
||||||
}
|
|
||||||
if (!forever) {
|
if (!forever) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
delay(1200);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,30 +139,34 @@ void setup() {
|
||||||
|
|
||||||
// Initialize display
|
// Initialize display
|
||||||
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c)) {
|
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c)) {
|
||||||
blink(2, true);
|
blink(true);
|
||||||
}
|
}
|
||||||
digitalWrite(LED_BUILTIN, false);
|
digitalWrite(LED_BUILTIN, false);
|
||||||
diag("Hello!");
|
diag("Hello!");
|
||||||
|
|
||||||
|
#if defined(ADAFRUIT_TRELLIS_M4_EXPRESS)
|
||||||
diag("Trellis...");
|
diag("Trellis...");
|
||||||
trellis.begin();
|
trellis.begin();
|
||||||
|
#endif
|
||||||
|
|
||||||
diag("Pipe...");
|
diag("Pipe...");
|
||||||
while (!pipe.Init()) {
|
while (!pipe.Init()) {
|
||||||
diag("Pipe connected?");
|
diag("Pipe connected?");
|
||||||
blink(3, false);
|
blink(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
diag("Audio...");
|
diag("Audio...");
|
||||||
AudioMemory(120);
|
AudioMemory(120);
|
||||||
AudioProcessorUsageMaxReset();
|
AudioProcessorUsageMaxReset();
|
||||||
AudioMemoryUsageMaxReset();
|
AudioMemoryUsageMaxReset();
|
||||||
|
sgtl5000.enable();
|
||||||
|
sgtl5000.volume(volume[4]);
|
||||||
|
|
||||||
diag("Synth...");
|
diag("Synth...");
|
||||||
loadPatch(0);
|
loadPatch(0);
|
||||||
loadPatch(1);
|
loadPatch(1);
|
||||||
loadPatch(2);
|
loadPatch(2);
|
||||||
noise.amplitude(0.0);
|
noise.amplitude(1.0);
|
||||||
|
|
||||||
diag("Mixer...");
|
diag("Mixer...");
|
||||||
// Turn on all mixer channels
|
// Turn on all mixer channels
|
||||||
|
@ -208,20 +216,23 @@ void loop() {
|
||||||
static bool upSetting = true; // GET IT?
|
static bool upSetting = true; // GET IT?
|
||||||
|
|
||||||
pipe.Update();
|
pipe.Update();
|
||||||
|
|
||||||
|
#if defined(ADAFRUIT_TRELLIS_M4_EXPRESS)
|
||||||
trellis.tick();
|
trellis.tick();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (trellis.justPressed(0)) {
|
// If we're infinitely (for the sensor) off the knee,
|
||||||
upSetting = !upSetting;
|
// we might be in setup mode.
|
||||||
}
|
if (pipe.KneeClosedness == 0) {
|
||||||
|
// We only enter into setup mode if no keys are pressed.
|
||||||
if (upSetting) {
|
// This hopefully avoids accidentally entering setup while playing.
|
||||||
trellis.setPixelColor(0, 0x200000);
|
// Like say you're playing a jaunty tune and suddenly there's an earthquake.
|
||||||
doSetup();
|
// You ought to be able to finish the tune off before your pipe goes into setup mode.
|
||||||
return;
|
if (upSetting || (pipe.Keys == 0)) {
|
||||||
}
|
doSetup();
|
||||||
|
upSetting = true;
|
||||||
for (int i = 0; i < 12; i += 1) {
|
return;
|
||||||
trellis.setPixelColor(i, 0xffffff * pipe.KeyPressure[i]);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
doPlay(upSetting);
|
doPlay(upSetting);
|
||||||
|
|
Loading…
Reference in New Issue