/* matrix-scan a set of QRD1114 or similar, each maps to a note, play those notes via a soundfont */ #include #include #define TSF_IMPLEMENTATION #define TSF_NO_STDIO #include "../ESP8266Audio/src/libtinysoundfont/tsf.h" #include "../RingBuffer/src/RingBuf.h" // 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; // 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; 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, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .channel_format = I2S_CHANNEL_FMT_ALL_RIGHT, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // high interrupt priority .dma_buf_count = 8, .dma_buf_len = 64, .use_apll = false }; i2s_driver_install(i2sPort, &i2s_config, 0, NULL); // 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 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 // if successful value=buffer[0] + 32768; // tsf produces *signed* shorts, i2s wants *unsigned* i2s_write(i2sPort, &value, sizeof(value), &written, 0); 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