Compare commits
2 Commits
a2469f83c7
...
d563a4d497
Author | SHA1 | Date |
---|---|---|
Neale Pickett | d563a4d497 | |
Neale Pickett | 46538e2db0 |
|
@ -51,7 +51,6 @@ void doPlay(bool forceDisplayUpdate) {
|
|||
updateDisplay = true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (updateDisplay) {
|
||||
// Look up the note name
|
||||
const char *noteName = NoteName(pipe.CurrentNote);
|
||||
|
@ -69,5 +68,4 @@ void doPlay(bool forceDisplayUpdate) {
|
|||
display.display();
|
||||
last_note = pipe.CurrentNote;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
35
pipe.cpp
35
pipe.cpp
|
@ -17,15 +17,7 @@ bool Pipe::Init() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Knee sensor
|
||||
if (!kneeSensor.begin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
@ -37,29 +29,31 @@ void Pipe::Update() {
|
|||
Keys = 0;
|
||||
|
||||
// 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) {
|
||||
Bag = bagSensor.isPressed();
|
||||
// XXX: re-enable the bag sensor at some point
|
||||
//Bag = bagSensor.isPressed();
|
||||
} else {
|
||||
Bag = false;
|
||||
}
|
||||
|
||||
// 0x6c is actually 8 bytes, but all 8 are always the same...
|
||||
KneeClosedness = 255 - kneeSensor.readRange();
|
||||
|
||||
for (int i = 0; i < NUM_KEYS; ++i) {
|
||||
int key = KeySensor[i];
|
||||
if (key == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t sensorReading = capSensor.filteredData(i);
|
||||
uint16_t val = OPENVAL - min(max(sensorReading, CLOSEDVAL), OPENVAL);
|
||||
KeyPressure[i] = val / float(GLISSANDO_STEPS);
|
||||
KeyPressure[key] = val / float(GLISSANDO_STEPS);
|
||||
|
||||
// keys = all keys which are at least touched
|
||||
// glissandoKeys = all keys which are fully closed
|
||||
// The glissando operation computes the difference.
|
||||
if (KeyPressure[i] > 0.0) {
|
||||
bitSet(Keys, i);
|
||||
if (KeyPressure[key] > 0.0) {
|
||||
bitSet(Keys, key);
|
||||
}
|
||||
if (KeyPressure[i] == 1.0) {
|
||||
bitSet(glissandoKeys, i);
|
||||
if (KeyPressure[key] == 1.0) {
|
||||
bitSet(glissandoKeys, key);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,6 +75,9 @@ void Pipe::Update() {
|
|||
// Was the high bit set? That indicates "alternate fingering", which sounds different.
|
||||
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
|
||||
// But only if the left thumb is down!
|
||||
if (Bag && (Keys & bit(7))) {
|
||||
|
@ -88,8 +85,6 @@ void Pipe::Update() {
|
|||
GlissandoNote += NOTE_OCTAVE;
|
||||
}
|
||||
|
||||
// All keys closed + knee = no sound
|
||||
Silent = ((KneeClosedness > 240) && (Keys == 0xff));
|
||||
}
|
||||
|
||||
bool Pipe::Pressed(uint8_t key) {
|
||||
|
|
8
pipe.h
8
pipe.h
|
@ -8,6 +8,9 @@
|
|||
|
||||
#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 {
|
||||
ADJUST_DOWN = -1,
|
||||
ADJUST_NONE = 0,
|
||||
|
@ -17,9 +20,6 @@ enum Adjust {
|
|||
|
||||
class Pipe {
|
||||
public:
|
||||
// kneeClosedness indicates how "closed" the knee sensor is. 0 = wide open.
|
||||
uint8_t KneeClosedness;
|
||||
|
||||
// keys are which keys are being pressed.
|
||||
uint16_t Keys;
|
||||
uint16_t KeysLast;
|
||||
|
@ -70,8 +70,6 @@ class Pipe {
|
|||
|
||||
private:
|
||||
Adafruit_MPR121 capSensor;
|
||||
Adafruit_VL6180X kneeSensor;
|
||||
QwiicButton bagSensor;
|
||||
bool bag_enabled;
|
||||
unsigned long nextRepeat[NUM_KEYS];
|
||||
bool typematicEvent(uint8_t key, uint16_t delay, uint16_t repeat);
|
||||
|
|
49
uilleann.ino
49
uilleann.ino
|
@ -11,16 +11,15 @@
|
|||
|
||||
const char *buildDate = __DATE__;
|
||||
|
||||
#if defined(ADAFRUIT_TRELLIS_MAdafruit_SSD1306EXPRESS)
|
||||
#include <Adafruit_NeoTrellisM4.h>
|
||||
Adafruit_NeoTrellisM4 trellis; // = Adafruit_NeoTrellisM4();
|
||||
#endif
|
||||
Adafruit_NeoTrellisM4 trellis = Adafruit_NeoTrellisM4();
|
||||
|
||||
|
||||
Pipe pipe;
|
||||
Tuning tuning = Tuning(NOTE_D4, PITCH_CONCERT_D4, TUNINGSYSTEM_JUST);
|
||||
|
||||
Adafruit_SSD1306 display(128, 32, &Wire, -1);
|
||||
|
||||
|
||||
// Settings
|
||||
#define VOLUME_INITIAL 0.8
|
||||
uint8_t patch[4] = {0};
|
||||
|
@ -40,13 +39,7 @@ AudioMixer4 mixL;
|
|||
AudioMixer4 mixR;
|
||||
AudioSynthNoiseWhite noise;
|
||||
|
||||
#if defined(ADAFRUIT_TRELLIS_M4_EXPRESS)
|
||||
AudioOutputAnalogStereo out1;
|
||||
#else
|
||||
AudioOutputI2S out1;
|
||||
#endif
|
||||
|
||||
AudioControlSGTL5000 sgtl5000;
|
||||
|
||||
AudioConnection FMVoicePatchCords[] = {
|
||||
{noise, 0, mixL, 3},
|
||||
|
@ -80,15 +73,18 @@ AudioConnection FMVoicePatchCords[] = {
|
|||
FMVoiceWiring(Regulators[2]),
|
||||
};
|
||||
|
||||
void blink(bool forever) {
|
||||
void blink(int count, bool forever) {
|
||||
for (;;) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
digitalWrite(LED_BUILTIN, true);
|
||||
delay(200);
|
||||
digitalWrite(LED_BUILTIN, false);
|
||||
delay(200);
|
||||
}
|
||||
if (!forever) {
|
||||
return;
|
||||
}
|
||||
delay(1200);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,34 +135,30 @@ void setup() {
|
|||
|
||||
// Initialize display
|
||||
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c)) {
|
||||
blink(true);
|
||||
blink(2, true);
|
||||
}
|
||||
digitalWrite(LED_BUILTIN, false);
|
||||
diag("Hello!");
|
||||
|
||||
#if defined(ADAFRUIT_TRELLIS_M4_EXPRESS)
|
||||
diag("Trellis...");
|
||||
trellis.begin();
|
||||
#endif
|
||||
|
||||
diag("Pipe...");
|
||||
while (!pipe.Init()) {
|
||||
diag("Pipe connected?");
|
||||
blink(false);
|
||||
blink(3, false);
|
||||
}
|
||||
|
||||
diag("Audio...");
|
||||
AudioMemory(120);
|
||||
AudioProcessorUsageMaxReset();
|
||||
AudioMemoryUsageMaxReset();
|
||||
sgtl5000.enable();
|
||||
sgtl5000.volume(volume[4]);
|
||||
|
||||
diag("Synth...");
|
||||
loadPatch(0);
|
||||
loadPatch(1);
|
||||
loadPatch(2);
|
||||
noise.amplitude(1.0);
|
||||
noise.amplitude(0.0);
|
||||
|
||||
diag("Mixer...");
|
||||
// Turn on all mixer channels
|
||||
|
@ -216,23 +208,20 @@ void loop() {
|
|||
static bool upSetting = true; // GET IT?
|
||||
|
||||
pipe.Update();
|
||||
|
||||
#if defined(ADAFRUIT_TRELLIS_M4_EXPRESS)
|
||||
trellis.tick();
|
||||
#endif
|
||||
|
||||
// If we're infinitely (for the sensor) off the knee,
|
||||
// we might be in setup mode.
|
||||
if (pipe.KneeClosedness == 0) {
|
||||
// We only enter into setup mode if no keys are pressed.
|
||||
// This hopefully avoids accidentally entering setup while playing.
|
||||
// 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.
|
||||
if (upSetting || (pipe.Keys == 0)) {
|
||||
if (trellis.justPressed(0)) {
|
||||
upSetting = !upSetting;
|
||||
}
|
||||
|
||||
if (upSetting) {
|
||||
trellis.setPixelColor(0, 0x200000);
|
||||
doSetup();
|
||||
upSetting = true;
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 12; i += 1) {
|
||||
trellis.setPixelColor(i, 0xffffff * pipe.KeyPressure[i]);
|
||||
}
|
||||
|
||||
doPlay(upSetting);
|
||||
|
|
Loading…
Reference in New Issue