From 1dc203ef9909b930342ba4649de892cf7296d18f Mon Sep 17 00:00:00 2001 From: dakkar Date: Sat, 29 Aug 2020 10:44:28 +0100 Subject: comment the code --- esp32/lego-piano.ino | 138 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 89 insertions(+), 49 deletions(-) diff --git a/esp32/lego-piano.ino b/esp32/lego-piano.ino index 01b3bb7..6a8ff09 100644 --- a/esp32/lego-piano.ino +++ b/esp32/lego-piano.ino @@ -1,19 +1,7 @@ /* - matrix-scan a set of LEDs + matrix-scan a set of QRD1114 or similar, each maps to a note, play + those notes via a soundfont - pins: - - "rows" 12 & 13 go to a 220Ω resistor, then to 2 LEDs each (positive - / long stem side); also to a 10kΩ resistor then to 2 - phototransistors (collector / long stem side) - - also, from between the 10kΩ and the phototransistors, wire goes to - A1 & A2 - - "columns" - 14 & 15 go to 2 LEDs each (negative / short stem side) - - so that given one of 12|13 and one of 14|15, one LED is identified */ #include @@ -24,38 +12,66 @@ #include "../ESP8266Audio/src/libtinysoundfont/tsf.h" #include "../RingBuffer/src/RingBuf.h" -#include "font.h" -int currentLed = 0; +// this is the soundfont, we embed it in the program's memory +#include "font.h" #define DEBUG 0 +// how many rows & columns does the matrix have? const size_t row_count = 5; const size_t col_count = 5; +/* + which pins to use + + each "row" pins goes to a current-limiting resistor (~220Ω) and then + to the LED anodes, also to a pull-up resistor (~10kΩ) and then to + the transistor collectors + + each "column" pin goes to LED cathodes and transistor emitters + + each "adc" pin goes between pull-up and collector +*/ const int rows[row_count] = { 5, 23, 19, 18, 26 }; const int cols[col_count] = { 17, 33, 16, 21, 22 }; const int adc[row_count] = { 2, 4, 12, 27, 14 }; +// this turns on the amplifier const int ampEnable = 32; -const int octave_shift = 2; - +// sample rate to render the soundfont at; higher means theoretically +// better quality, but slows down everything, so not worth it const int sampleRate = 11025; +// nothing to customise below this point + +const i2s_port_t i2sPort = I2S_NUM_0; + +// state of the matrix char pressed[row_count*col_count] = { 0 }; +int currentSensor = 0; + +// buffers to exchange data between soundfont renderer and I2S driver +const size_t bufferSize = 1000; +RingBuf buffer; +short intermediateBuffer[bufferSize]; +// the soundfont renderer tsf* g_TinySoundFont = 0; -const i2s_port_t i2sPort = I2S_NUM_0; void setup() { + // for debugging Serial.begin(115200); + // turn the amplifier off while we set things up pinMode(ampEnable, OUTPUT); digitalWrite(ampEnable, LOW); + // set up the DAC and the I2S driver dac_i2s_enable(); dac_output_enable(DAC_CHANNEL_1); + // 16-bit single channel I2S using the internal DAC static const i2s_config_t i2s_config = { .mode = (i2s_mode_t)( I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN ), .sample_rate = sampleRate, @@ -66,10 +82,12 @@ void setup() { .dma_buf_len = 64, .use_apll = false }; - i2s_driver_install(i2sPort, &i2s_config, 0, NULL); - i2s_set_dac_mode(I2S_DAC_CHANNEL_RIGHT_EN); // only dac1 + // only dac1: we don't need stereo, also we're using the dac2 pin as + // GPIO + i2s_set_dac_mode(I2S_DAC_CHANNEL_RIGHT_EN); + // set pins' role for (int i=0;i buffer; -short intermediateBuffer[bufferSize]; - void loop() { #if DEBUG & 0x01 - Serial.print("current led "); - Serial.println(currentLed); + Serial.print("current sensor "); + Serial.println(currentSensor); #endif - enableLed(currentLed); + enableSensor(currentSensor); unsigned long t = millis(); + + // the sensor needs at least a millisecond to see anything, let's do + // work in the meantime + size_t written=100; short value; - // fill the I2S buffer + // fill the I2S buffer from our ringbuffer; the I2S API doesn't tell + // us how much space it has in its internal buffers, so we must send + // one short at a time, without blocking, until it fails (which + // means the buffers are full) while (written > 0) { // we don't want to drop an element from the buffer if we then // can't write it! so we peek at the buffer, try to write, and pop @@ -165,42 +195,52 @@ void loop() { if (written > 0) buffer.pop(value); } + // fill the ringbuffer from the renderer int toFill = buffer.maxSize() - buffer.size(); if (toFill > 100) { + // our buffer tells us how much space it has, but it can't give us + // a contiguous segment of RAM to write into; we need an + // intermediate buffer tsf_render_short(g_TinySoundFont, intermediateBuffer, toFill, 0); for (int i=0;i