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__;
|
|
|
|
|
2020-11-15 14:49:05 -07:00
|
|
|
#include <Adafruit_NeoTrellisM4.h>
|
2023-04-18 19:40:38 -06:00
|
|
|
Adafruit_NeoTrellisM4 trellis = Adafruit_NeoTrellisM4();
|
|
|
|
|
2020-11-15 14:49:05 -07:00
|
|
|
|
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
|
|
|
|
2023-04-18 19:40:38 -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
|
2020-10-24 20:15:18 -06:00
|
|
|
FMVoice Chanter;
|
2020-11-25 17:13:54 -07:00
|
|
|
FMVoice Drones[NUM_DRONES];
|
|
|
|
FMVoice Regulators[NUM_REGULATORS];
|
2020-10-24 20:15:18 -06:00
|
|
|
|
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
|
|
|
AudioOutputAnalogStereo out1;
|
2020-11-22 17:21:47 -07:00
|
|
|
|
2020-10-24 20:15:18 -06:00
|
|
|
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-24 20:15:18 -06:00
|
|
|
};
|
2020-10-11 20:29:04 -06:00
|
|
|
|
2023-04-18 19:40:38 -06:00
|
|
|
void blink(int count, bool forever) {
|
2020-11-11 16:29:09 -07:00
|
|
|
for (;;) {
|
2023-04-18 19:40:38 -06:00
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
digitalWrite(LED_BUILTIN, true);
|
|
|
|
delay(200);
|
|
|
|
digitalWrite(LED_BUILTIN, false);
|
|
|
|
delay(200);
|
|
|
|
}
|
2020-11-24 16:56:58 -07:00
|
|
|
if (!forever) {
|
|
|
|
return;
|
|
|
|
}
|
2023-04-18 19:40:38 -06:00
|
|
|
delay(1200);
|
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);
|
2020-11-24 21:33:55 -07:00
|
|
|
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);
|
2020-11-24 21:33:55 -07:00
|
|
|
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"
|
|
|
|
|
2020-10-24 20:15:18 -06:00
|
|
|
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)) {
|
2023-04-18 19:40:38 -06:00
|
|
|
blink(2, true);
|
2020-11-11 16:29:09 -07:00
|
|
|
}
|
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-24 16:56:58 -07:00
|
|
|
diag("Trellis...");
|
2020-11-15 14:49:05 -07:00
|
|
|
trellis.begin();
|
|
|
|
|
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?");
|
2023-04-18 19:40:38 -06:00
|
|
|
blink(3, 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-10-25 11:36:58 -06:00
|
|
|
|
2020-11-25 17:13:54 -07:00
|
|
|
diag("Synth...");
|
|
|
|
loadPatch(0);
|
|
|
|
loadPatch(1);
|
|
|
|
loadPatch(2);
|
2023-04-18 19:40:38 -06:00
|
|
|
noise.amplitude(0.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-24 21:33:55 -07:00
|
|
|
}
|
2020-11-26 18:49:09 -07:00
|
|
|
biquad1.setNotch(0, PITCH_CONCERT_A4, 0.001);
|
2020-11-24 21:33:55 -07:00
|
|
|
|
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-24 21:33:55 -07:00
|
|
|
}
|
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();
|
|
|
|
trellis.tick();
|
2020-11-23 18:11:19 -07:00
|
|
|
|
2023-04-18 19:40:38 -06:00
|
|
|
if (trellis.justPressed(0)) {
|
|
|
|
upSetting = !upSetting;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (upSetting) {
|
|
|
|
trellis.setPixelColor(0, 0x200000);
|
|
|
|
doSetup();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = 0; i < 12; i += 1) {
|
|
|
|
trellis.setPixelColor(i, 0xffffff * pipe.KeyPressure[i]);
|
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
|
|
|
}
|