aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordakkar <dakkar@thenautilus.net>2020-08-23 10:02:48 +0100
committerdakkar <dakkar@thenautilus.net>2020-08-23 10:02:48 +0100
commit89241b71e0fb7bb91758abfaf07ac120028c9018 (patch)
tree3c29341d6def44cf0354985086ce15c043182dbd
parentbring the tone down (diff)
downloadlego-piano-89241b71e0fb7bb91758abfaf07ac120028c9018.tar.gz
lego-piano-89241b71e0fb7bb91758abfaf07ac120028c9018.tar.bz2
lego-piano-89241b71e0fb7bb91758abfaf07ac120028c9018.zip
trying to use a soundfont
I get very weird exceptions when calling `tsf_note_on`?
-rw-r--r--.gitmodules3
m---------ESP8266Audio0
-rw-r--r--esp32/lego-piano.ino164
3 files changed, 109 insertions, 58 deletions
diff --git a/.gitmodules b/.gitmodules
index af12410..a863510 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "3d-print/LEGO.scad"]
path = 3d-print/LEGO.scad
url = https://github.com/cfinke/LEGO.scad.git
+[submodule "ESP8266Audio"]
+ path = ESP8266Audio
+ url = https://github.com/earlephilhower/ESP8266Audio
diff --git a/ESP8266Audio b/ESP8266Audio
new file mode 160000
+Subproject cd42e28ca5ac09f5b6267ea2eb2b665c90cdb6b
diff --git a/esp32/lego-piano.ino b/esp32/lego-piano.ino
index 575f55e..7826f31 100644
--- a/esp32/lego-piano.ino
+++ b/esp32/lego-piano.ino
@@ -17,9 +17,11 @@
*/
#include <driver/dac.h>
+#define TSF_IMPLEMENTATION
+#define TSF_NO_STDIO
+#include "../ESP8266Audio/src/libtinysoundfont/tsf.h"
int currentLed = 0;
-int lastSeen = -1;
#define DEBUG 0
@@ -33,6 +35,73 @@ const int ampEnable = 32;
const int octave_shift = 2;
+char pressed[row_count*col_count] = { 0 };
+
+hw_timer_t * timer = NULL;
+portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;
+tsf* g_TinySoundFont = 0;
+bool playing = false;
+
+//This is a minimal SoundFont with a single loopin saw-wave sample/instrument/preset (484 bytes)
+const static unsigned char MinimalSoundFont[] PROGMEM =
+{
+ #define TEN0 0,0,0,0,0,0,0,0,0,0
+ 'R','I','F','F',220,1,0,0,'s','f','b','k',
+ 'L','I','S','T',88,1,0,0,'p','d','t','a',
+ 'p','h','d','r',76,TEN0,TEN0,TEN0,TEN0,0,0,0,0,TEN0,0,0,0,0,0,0,0,255,0,255,0,1,TEN0,0,0,0,
+ 'p','b','a','g',8,0,0,0,0,0,0,0,1,0,0,0,'p','m','o','d',10,TEN0,0,0,0,'p','g','e','n',8,0,0,0,41,0,0,0,0,0,0,0,
+ 'i','n','s','t',44,TEN0,TEN0,0,0,0,0,0,0,0,0,TEN0,0,0,0,0,0,0,0,1,0,
+ 'i','b','a','g',8,0,0,0,0,0,0,0,2,0,0,0,'i','m','o','d',10,TEN0,0,0,0,
+ 'i','g','e','n',12,0,0,0,54,0,1,0,53,0,0,0,0,0,0,0,
+ 's','h','d','r',92,TEN0,TEN0,0,0,0,0,0,0,0,50,0,0,0,0,0,0,0,49,0,0,0,34,86,0,0,60,0,0,0,1,TEN0,TEN0,TEN0,TEN0,0,0,0,0,0,0,0,
+ 'L','I','S','T',112,0,0,0,'s','d','t','a','s','m','p','l',100,0,0,0,86,0,119,3,31,7,147,10,43,14,169,17,58,21,189,24,73,28,204,31,73,35,249,38,46,42,71,46,250,48,150,53,242,55,126,60,151,63,108,66,126,72,207,
+ 70,86,83,100,72,74,100,163,39,241,163,59,175,59,179,9,179,134,187,6,186,2,194,5,194,15,200,6,202,96,206,159,209,35,213,213,216,45,220,221,223,76,227,221,230,91,234,242,237,105,241,8,245,118,248,32,252
+};
+
+class DblBuffer {
+ const static size_t _size = 1000;
+ short samples[2][_size];
+ size_t readPtr;
+ char which;
+ bool has_data[2];
+
+ public:
+ DblBuffer() :which(0), readPtr(0) {
+ has_data[0]=false;
+ has_data[1]=false;
+ }
+
+ bool needsWriting() {
+ return !has_data[1-which];
+ }
+ size_t size() { return _size; }
+ short* ptr() { return samples[1-which]; }
+ void writingDone() {
+ has_data[1-which]=true;
+ }
+
+ short pop() {
+ if (readPtr >= _size) {
+ has_data[which]=false;
+ which=1-which;readPtr=0;
+ }
+ if (!has_data[which]) return 0;
+
+ return samples[which][readPtr++];
+ }
+} buffer;
+
+void IRAM_ATTR onTimer() {
+ return;
+ if (!g_TinySoundFont) return;
+
+ portENTER_CRITICAL_ISR(&timerMux);
+
+ dac_output_voltage(DAC_CHANNEL_1, buffer.pop() >> 8);
+
+ portEXIT_CRITICAL_ISR(&timerMux);
+}
+
void setup() {
Serial.begin(115200);
@@ -51,27 +120,22 @@ void setup() {
}
currentLed = 0;
- lastSeen = -1;
-}
-
-void play(uint32_t freq) {
- dac_cw_config_t wave_config = {
- en_ch: DAC_CHANNEL_1,
- scale: DAC_CW_SCALE_2,
- phase: DAC_CW_PHASE_0,
- freq: octave_shift*freq,
- offset: 0,
- };
-
- dac_cw_generator_config(&wave_config);
- dac_cw_generator_enable();
-
- digitalWrite(ampEnable, HIGH);
-}
-
-void mute() {
- digitalWrite(ampEnable, LOW);
- dac_cw_generator_disable();
+ playing = false;
+
+ g_TinySoundFont = tsf_load_memory(MinimalSoundFont, sizeof(MinimalSoundFont));
+ if (g_TinySoundFont) {
+ // render at 20kHz
+ tsf_set_output(g_TinySoundFont, TSF_MONO, 20000, 0);
+
+ // pre-scaling by 4k, then calling on every 1 tick, should give us 20kHz
+ timer = timerBegin(0, 1000, true);
+ timerAttachInterrupt(timer, &onTimer, true);
+ timerAlarmWrite(timer, 4, true);
+ timerAlarmEnable(timer);
+ }
+ else {
+ Serial.println("failed to start tsf");
+ }
}
void tristate(int pin) {
@@ -123,36 +187,6 @@ int sense(int led) {
return value < 500;
}
-uint32_t notes[] = {
- 261, // C4
- 277,
- 294, // D4
- 311,
- 330, // E4
- 349, // F4
- 370,
- 392, // G4
- 415,
- 440, // A4
- 466,
- 494, // B4
-
- 523, // C5
- 554,
- 587, // D5
- 622,
- 659, // E5
- 698, // F5
- 740,
- 783, // G5
- 831,
- 880, // A5
- 932,
- 988, // B5
-
- 1046, // C6
-};
-
void loop() {
#if DEBUG & 0x01
Serial.print("current led ");
@@ -162,17 +196,31 @@ void loop() {
enableLed(currentLed);
delay(5);
if (sense(currentLed)) {
- if (lastSeen != currentLed) {
- lastSeen = currentLed;
+ if (!pressed[currentLed]) {
Serial.print(currentLed);
Serial.println(" proximity!");
- play(notes[currentLed]);
+
+ pressed[currentLed]=1;
+ if (g_TinySoundFont) {
+ portENTER_CRITICAL_ISR(&timerMux);
+ tsf_note_on(g_TinySoundFont, 0, 60 + currentLed, 1.0f);
+ portEXIT_CRITICAL_ISR(&timerMux);
+ }
}
}
- else if (lastSeen == currentLed) {
- lastSeen = -1;
- mute();
+ else if (pressed[currentLed]) {
+ pressed[currentLed]=0;
+ if (g_TinySoundFont) {
+ portENTER_CRITICAL_ISR(&timerMux);
+ tsf_note_off(g_TinySoundFont, 0, 60 + currentLed);
+ portEXIT_CRITICAL_ISR(&timerMux);
+ }
}
currentLed = (currentLed+1)%(row_count*col_count);
+
+ if (buffer.needsWriting()) {
+ tsf_render_short(g_TinySoundFont, buffer.ptr(), buffer.size(), 0);
+ buffer.writingDone();
+ }
} \ No newline at end of file