Compare commits

..

2 Commits

4 changed files with 44 additions and 64 deletions

View File

@ -51,7 +51,6 @@ 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);
@ -69,5 +68,4 @@ void doPlay(bool forceDisplayUpdate) {
display.display(); display.display();
last_note = pipe.CurrentNote; last_note = pipe.CurrentNote;
} }
#endif
} }

View File

@ -16,16 +16,8 @@ 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;
} }
@ -37,29 +29,31 @@ 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) {
Bag = bagSensor.isPressed(); // XXX: re-enable the bag sensor at some point
//Bag = bagSensor.isPressed();
} else { } else {
Bag = false; 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) { for (int i = 0; i < NUM_KEYS; ++i) {
int key = KeySensor[i];
if (key == -1) {
continue;
}
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[i] = val / float(GLISSANDO_STEPS); KeyPressure[key] = 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[i] > 0.0) { if (KeyPressure[key] > 0.0) {
bitSet(Keys, i); bitSet(Keys, key);
} }
if (KeyPressure[i] == 1.0) { if (KeyPressure[key] == 1.0) {
bitSet(glissandoKeys, i); bitSet(glissandoKeys, key);
} }
} }
@ -81,6 +75,9 @@ 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))) {
@ -88,8 +85,6 @@ 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
View File

@ -8,6 +8,9 @@
#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,
@ -17,9 +20,6 @@ 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,8 +70,6 @@ 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);

View File

@ -11,16 +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
uint8_t patch[4] = {0}; uint8_t patch[4] = {0};
@ -40,13 +39,7 @@ 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},
@ -80,15 +73,18 @@ AudioConnection FMVoicePatchCords[] = {
FMVoiceWiring(Regulators[2]), FMVoiceWiring(Regulators[2]),
}; };
void blink(bool forever) { void blink(int count, bool forever) {
for (;;) { for (;;) {
digitalWrite(LED_BUILTIN, true); for (int i = 0; i < count; i++) {
delay(200); digitalWrite(LED_BUILTIN, true);
digitalWrite(LED_BUILTIN, false); delay(200);
delay(200); digitalWrite(LED_BUILTIN, false);
delay(200);
}
if (!forever) { if (!forever) {
return; return;
} }
delay(1200);
} }
} }
@ -139,34 +135,30 @@ void setup() {
// Initialize display // Initialize display
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c)) { if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c)) {
blink(true); blink(2, 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(false); blink(3, 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(1.0); noise.amplitude(0.0);
diag("Mixer..."); diag("Mixer...");
// Turn on all mixer channels // Turn on all mixer channels
@ -216,23 +208,20 @@ 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 we're infinitely (for the sensor) off the knee, if (trellis.justPressed(0)) {
// we might be in setup mode. upSetting = !upSetting;
if (pipe.KneeClosedness == 0) { }
// We only enter into setup mode if no keys are pressed.
// This hopefully avoids accidentally entering setup while playing. if (upSetting) {
// Like say you're playing a jaunty tune and suddenly there's an earthquake. trellis.setPixelColor(0, 0x200000);
// You ought to be able to finish the tune off before your pipe goes into setup mode. doSetup();
if (upSetting || (pipe.Keys == 0)) { return;
doSetup(); }
upSetting = true;
return; for (int i = 0; i < 12; i += 1) {
} trellis.setPixelColor(i, 0xffffff * pipe.KeyPressure[i]);
} }
doPlay(upSetting); doPlay(upSetting);