uilleann/uilleann.ino

241 lines
5.2 KiB
Arduino
Raw Normal View History

2020-11-11 16:29:09 -07:00
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
2020-11-24 16:56:58 -07:00
#include <Audio.h>
#include <Fonts/FreeSans9pt7b.h>
#include <stdio.h>
2020-10-11 20:29:04 -06:00
#include "patches.h"
2020-11-11 20:20:21 -07:00
#include "pipe.h"
2020-11-24 16:56:58 -07:00
#include "synth.h"
#include "tuning.h"
2020-10-11 20:29:04 -06:00
2020-11-25 17:13:54 -07:00
const char *buildDate = __DATE__;
#if defined(ADAFRUIT_TRELLIS_MAdafruit_SSD1306EXPRESS)
2020-11-15 14:49:05 -07:00
#include <Adafruit_NeoTrellisM4.h>
2020-11-24 16:56:58 -07:00
Adafruit_NeoTrellisM4 trellis; // = Adafruit_NeoTrellisM4();
2020-11-15 14:49:05 -07:00
#endif
2020-11-11 20:20:21 -07:00
Pipe pipe;
2020-11-24 16:56:58 -07:00
Tuning tuning = Tuning(NOTE_D4, PITCH_CONCERT_D4, TUNINGSYSTEM_JUST);
2020-11-11 20:20:21 -07:00
Adafruit_SSD1306 display(128, 32, &Wire, -1);
2020-10-11 20:29:04 -06:00
2020-11-24 16:56:58 -07:00
// Settings
2020-11-26 19:30:19 -07:00
#define VOLUME_INITIAL 0.8
2020-11-24 16:56:58 -07:00
uint8_t patch[4] = {0};
2020-11-26 19:30:19 -07:00
float volume[5] = {VOLUME_INITIAL, VOLUME_INITIAL, VOLUME_INITIAL, VOLUME_INITIAL, 0.5};
2020-11-24 16:56:58 -07:00
// Pipes
2020-11-25 17:13:54 -07:00
#define NUM_DRONES 3
#define NUM_REGULATORS 3
FMVoice Chanter;
2020-11-25 17:13:54 -07:00
FMVoice Drones[NUM_DRONES];
FMVoice Regulators[NUM_REGULATORS];
2020-11-24 16:56:58 -07:00
AudioFilterBiquad biquad1;
AudioMixer4 mixDrones;
AudioMixer4 mixRegulators;
AudioMixer4 mixL;
AudioMixer4 mixR;
2020-11-11 16:29:09 -07:00
AudioSynthNoiseWhite noise;
2020-10-25 11:36:58 -06:00
2020-11-15 14:49:05 -07:00
#if defined(ADAFRUIT_TRELLIS_M4_EXPRESS)
AudioOutputAnalogStereo out1;
#else
2020-11-24 16:56:58 -07:00
AudioOutputI2S out1;
2020-11-15 14:49:05 -07:00
#endif
2020-11-22 17:21:47 -07:00
AudioControlSGTL5000 sgtl5000;
AudioConnection FMVoicePatchCords[] = {
2020-11-24 16:56:58 -07:00
{noise, 0, mixL, 3},
{noise, 0, mixR, 3},
{Chanter.outputMixer, 0, biquad1, 0},
{biquad1, 0, mixL, 0},
{biquad1, 0, mixR, 0},
{Drones[0].outputMixer, 0, mixDrones, 0},
{Drones[1].outputMixer, 0, mixDrones, 1},
{Drones[2].outputMixer, 0, mixDrones, 2},
{mixDrones, 0, mixL, 1},
{mixDrones, 0, mixR, 1},
{Regulators[0].outputMixer, 0, mixRegulators, 0},
{Regulators[1].outputMixer, 0, mixRegulators, 1},
{Regulators[2].outputMixer, 0, mixRegulators, 2},
{mixRegulators, 0, mixL, 2},
{mixRegulators, 0, mixR, 2},
{mixL, 0, out1, 0},
{mixR, 0, out1, 1},
FMVoiceWiring(Chanter),
FMVoiceWiring(Drones[0]),
FMVoiceWiring(Drones[1]),
FMVoiceWiring(Drones[2]),
FMVoiceWiring(Regulators[0]),
FMVoiceWiring(Regulators[1]),
FMVoiceWiring(Regulators[2]),
};
2020-10-11 20:29:04 -06:00
2020-11-11 16:29:09 -07:00
void blink(bool forever) {
for (;;) {
digitalWrite(LED_BUILTIN, true);
delay(200);
digitalWrite(LED_BUILTIN, false);
delay(200);
2020-11-24 16:56:58 -07:00
if (!forever) {
return;
}
2020-11-11 16:29:09 -07:00
}
}
2020-10-11 20:29:04 -06:00
2020-11-24 16:56:58 -07:00
void diag(const char *fmt, ...) {
va_list args;
char s[80];
va_start(args, fmt);
vsnprintf(s, sizeof(s) - 1, fmt, args);
2020-11-24 16:56:58 -07:00
va_end(args);
display.clearDisplay();
display.drawRect(124, 16, 4, 16, SSD1306_WHITE);
display.setTextColor(SSD1306_WHITE);
2020-11-25 17:13:54 -07:00
display.setFont();
2020-11-24 16:56:58 -07:00
display.setTextSize(1);
display.setCursor(56, 24);
display.print(buildDate);
2020-11-24 16:56:58 -07:00
#if 0
display.setCursor(0, 16);
display.print(fn);
display.print(":");
display.print(lineno);
#endif
display.setCursor(0, 0);
display.print(s);
display.display();
}
2020-11-25 17:13:54 -07:00
// The right way to do this would be to make a Uilleann object,
// and pass that around.
// The Auido library makes this sort of a pain,
// and honestly, is anybody other than me going to use this?
#include "main-play.h"
#include "main-setup.h"
void setup() {
2020-11-15 14:49:05 -07:00
// PREPARE TO BLINK
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, true);
2020-11-25 17:13:54 -07:00
// Set up I2C. Apparently this needs a bit of startup delay.
Wire.begin();
2020-11-11 20:20:21 -07:00
// Initialize display
2020-11-11 16:29:09 -07:00
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3c)) {
blink(true);
}
2020-11-25 17:13:54 -07:00
digitalWrite(LED_BUILTIN, false);
2020-11-24 16:56:58 -07:00
diag("Hello!");
2020-10-18 09:57:06 -06:00
2020-11-15 14:49:05 -07:00
#if defined(ADAFRUIT_TRELLIS_M4_EXPRESS)
2020-11-24 16:56:58 -07:00
diag("Trellis...");
2020-11-15 14:49:05 -07:00
trellis.begin();
#endif
2020-11-24 16:56:58 -07:00
diag("Pipe...");
2020-11-11 20:20:21 -07:00
while (!pipe.Init()) {
2020-11-26 18:49:09 -07:00
diag("Pipe connected?");
2020-11-11 16:29:09 -07:00
blink(false);
2020-10-11 20:29:04 -06:00
}
2020-11-24 16:56:58 -07:00
diag("Audio...");
2020-11-26 18:49:09 -07:00
AudioMemory(120);
2020-10-11 20:29:04 -06:00
AudioProcessorUsageMaxReset();
AudioMemoryUsageMaxReset();
2020-11-25 17:13:54 -07:00
sgtl5000.enable();
2020-11-26 18:49:09 -07:00
sgtl5000.volume(volume[4]);
2020-10-25 11:36:58 -06:00
2020-11-25 17:13:54 -07:00
diag("Synth...");
loadPatch(0);
loadPatch(1);
loadPatch(2);
2020-11-26 19:05:51 -07:00
noise.amplitude(1.0);
2020-10-25 19:20:18 -06:00
2020-11-25 17:13:54 -07:00
diag("Mixer...");
2020-10-25 19:20:18 -06:00
// Turn on all mixer channels
2020-11-24 16:56:58 -07:00
for (int i = 0; i < 4; i++) {
2020-11-25 17:13:54 -07:00
mixL.gain(i, volume[i]);
mixR.gain(i, volume[i]);
2020-10-25 19:20:18 -06:00
}
2020-11-25 17:13:54 -07:00
for (int i = 0; i < NUM_REGULATORS; ++i) {
mixRegulators.gain(i, 1);
2020-11-15 14:49:05 -07:00
}
2020-11-25 17:13:54 -07:00
for (int i = 0; i < NUM_DRONES; ++i) {
mixDrones.gain(i, 1);
}
2020-11-26 18:49:09 -07:00
biquad1.setNotch(0, PITCH_CONCERT_A4, 0.001);
2020-11-25 17:13:54 -07:00
diag("Drones...");
playDrones();
2020-11-23 18:11:19 -07:00
2020-11-25 17:13:54 -07:00
diag("Done!");
2020-11-25 21:38:29 -07:00
display.dim(true);
2020-11-25 17:13:54 -07:00
}
2020-11-24 16:56:58 -07:00
2020-11-25 17:13:54 -07:00
void loadPatch(uint8_t where) {
FMPatch *p = &Bank[where];
2020-11-24 16:56:58 -07:00
2020-11-25 17:13:54 -07:00
switch (where) {
case 0:
Chanter.LoadPatch(p);
break;
case 1:
for (int i = 0; i < NUM_REGULATORS; ++i) {
Regulators[i].LoadPatch(p);
2020-11-24 16:56:58 -07:00
}
2020-11-25 17:13:54 -07:00
break;
case 2:
for (int i = 0; i < NUM_DRONES; ++i) {
Drones[i].LoadPatch(p);
}
2020-11-25 17:13:54 -07:00
break;
default:
break;
2020-11-23 18:11:19 -07:00
}
2020-11-11 20:20:21 -07:00
}
2020-10-11 20:29:04 -06:00
2020-11-11 16:29:09 -07:00
2020-11-25 17:13:54 -07:00
void loop() {
2020-11-25 21:38:29 -07:00
static bool upSetting = true; // GET IT?
2020-11-11 20:20:21 -07:00
2020-11-25 17:13:54 -07:00
pipe.Update();
2020-11-11 20:20:21 -07:00
2020-11-25 17:13:54 -07:00
#if defined(ADAFRUIT_TRELLIS_M4_EXPRESS)
trellis.tick();
#endif
2020-11-23 18:11:19 -07:00
2020-11-25 17:13:54 -07:00
// If we're infinitely (for the sensor) off the knee,
// we might be in setup mode.
2020-11-26 18:49:09 -07:00
if (pipe.KneeClosedness == 0) {
2020-11-25 17:13:54 -07:00
// 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.
2020-11-26 18:49:09 -07:00
if (upSetting || (pipe.Keys == 0)) {
2020-11-25 17:13:54 -07:00
doSetup();
upSetting = true;
return;
}
2020-11-11 16:29:09 -07:00
}
2020-11-25 17:13:54 -07:00
2020-11-25 21:38:29 -07:00
doPlay(upSetting);
2020-11-25 17:13:54 -07:00
upSetting = false;
2020-10-11 20:29:04 -06:00
}