/* MicroDexed MicroDexed is a port of the Dexed sound engine Dexed ist heavily based on https://github.com/google/music-synthesizer-for-android This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA effect_delay_ext8 is a special delay class for APS6404L-3SQR based memory chips on a Teensy-4.1. The cod is a combination of the PJRC delay_ext class and suggestions from https://forum.pjrc.com/threads/29276-Limits-of-delay-effect-in-audio-library/page5?highlight=APS6404L-3SQR */ #include #include "effect_delay_ext8.h" #define SPISETTING SPISettings(20000000, MSBFIRST, SPI_MODE0) #define SPIRAM_MOSI_PIN 11 //----------------- #define SPIRAM_MISO_PIN 12 // for Teensy 4.1 #define SPIRAM_SCK_PIN 13 // #define SPIRAM_CS_PIN 36 //----------------- #define MEMBOARD_CS0_PIN 2 #define MEMBOARD_CS1_PIN 3 #define MEMBOARD_CS2_PIN 4 void AudioEffectDelayExternal8::update(void) { audio_block_t *block; uint32_t n, channel, read_offset; // grab incoming data and put it into the memory block = receiveReadOnly(); if (block) { if (head_offset + AUDIO_BLOCK_SAMPLES <= memory_length) { // a single write is enough write(head_offset, AUDIO_BLOCK_SAMPLES, block->data); head_offset += AUDIO_BLOCK_SAMPLES; } else { // write wraps across end-of-memory n = memory_length - head_offset; write(head_offset, n, block->data); head_offset = AUDIO_BLOCK_SAMPLES - n; write(0, head_offset, block->data + n); } release(block); } else { // if no input, store zeros, so later playback will // not be random garbage previously stored in memory if (head_offset + AUDIO_BLOCK_SAMPLES <= memory_length) { zero(head_offset, AUDIO_BLOCK_SAMPLES); head_offset += AUDIO_BLOCK_SAMPLES; } else { n = memory_length - head_offset; zero(head_offset, n); head_offset = AUDIO_BLOCK_SAMPLES - n; zero(0, head_offset); } } // transmit the delayed outputs for (channel = 0; channel < 8; channel++) { if (!(activemask & (1<data); } else { // read wraps across end-of-memory n = memory_length - read_offset; read(read_offset, n, block->data); read(0, AUDIO_BLOCK_SAMPLES - n, block->data + n); } transmit(block, channel); release(block); } } uint32_t AudioEffectDelayExternal8::allocated = 0; void AudioEffectDelayExternal8::initialize(uint32_t samples) { uint32_t memsize, avail; activemask = 0; head_offset = 0; SPI.setMOSI(SPIRAM_MOSI_PIN); SPI.setMISO(SPIRAM_MISO_PIN); SPI.setSCK(SPIRAM_SCK_PIN); SPI.setCS(SPIRAM_CS_PIN); // added for Teensy 4.1 SPI.begin(); memsize = (2^23); // 8388608 bytes pinMode(SPIRAM_CS_PIN, OUTPUT); digitalWriteFast(SPIRAM_CS_PIN, HIGH); avail = memsize - allocated; if (avail < AUDIO_BLOCK_SAMPLES*2+1) { return; } if (samples > avail) samples = avail; memory_begin = allocated; allocated += samples; memory_length = samples; zero(0, memory_length); } void AudioEffectDelayExternal8::read(uint32_t offset, uint32_t count, int16_t *data) { uint32_t addr = memory_begin + offset; addr *= 2; SPI.beginTransaction(SPISETTING); digitalWriteFast(SPIRAM_CS_PIN, LOW); SPI.transfer16((0x03 << 8) | (addr >> 16)); SPI.transfer16(addr & 0xFFFF); while (count) { *data++ = (int16_t)(SPI.transfer16(0)); count--; } digitalWriteFast(SPIRAM_CS_PIN, HIGH); SPI.endTransaction(); } void AudioEffectDelayExternal8::write(uint32_t offset, uint32_t count, const int16_t *data) { uint32_t addr = memory_begin + offset; addr *= 2; SPI.beginTransaction(SPISETTING); digitalWriteFast(SPIRAM_CS_PIN, LOW); SPI.transfer(0x06); //write-enable before every write digitalWriteFast(SPIRAM_CS_PIN, HIGH); asm volatile ("NOP\n NOP\n NOP\n NOP\n NOP\n NOP\n"); digitalWriteFast(SPIRAM_CS_PIN, LOW); SPI.transfer16((0x02 << 8) | (addr >> 16)); SPI.transfer16(addr & 0xFFFF); while (count) { int16_t w = 0; if (data) w = *data++; SPI.transfer16(w); count--; } digitalWriteFast(SPIRAM_CS_PIN, HIGH); SPI.endTransaction(); }