diff --git a/third-party/effect_delay_ext8/examples/AudioDelay8M/AudioDelay8M.ino b/third-party/effect_delay_ext8/examples/AudioDelay8M/AudioDelay8M.ino new file mode 100644 index 0000000..b650432 --- /dev/null +++ b/third-party/effect_delay_ext8/examples/AudioDelay8M/AudioDelay8M.ino @@ -0,0 +1,56 @@ +#include +#include +#include +#include + +// GUItool: begin automatically generated code +AudioSynthWaveformSine sine1; //xy=382,432 +AudioAmplifier amp1; //xy=606,441 +AudioEffectDelayExternal delayExt1; //xy=770,321 +AudioMixer4 mixer1; //xy=983,386 +AudioOutputI2S i2s1; //xy=1131,343 +AudioConnection patchCord1(sine1, amp1); +AudioConnection patchCord2(amp1, delayExt1); +AudioConnection patchCord3(amp1, 0, mixer1, 1); +AudioConnection patchCord4(delayExt1, 0, mixer1, 0); +AudioConnection patchCord5(mixer1, 0, i2s1, 0); +AudioConnection patchCord6(mixer1, 0, i2s1, 1); +AudioControlSGTL5000 sgtl5000; //xy=943,541 +// GUItool: end automatically generated code + + +void setup() { + AudioMemory(100); + + sgtl5000.enable(); + sgtl5000.lineOutLevel(29); + sgtl5000.dacVolumeRamp(); + sgtl5000.dacVolume(1.0); + sgtl5000.unmuteHeadphone(); + sgtl5000.unmuteLineout(); + sgtl5000.volume(0.8,0.8); // Headphone volume + sgtl5000.audioProcessorDisable(); + sgtl5000.autoVolumeDisable(); + sgtl5000.surroundSoundDisable(); + sgtl5000.enhanceBassDisable(); + delayExt1.delay(0,100); + sine1.amplitude(1.0); + sine1.frequency(440); + sine1.phase(0.0); + mixer1.gain(0,0.5); + mixer1.gain(1,1.0); + amp1.gain(1.0); +} + +void loop() { + static bool on_off; + + if(on_off) + amp1.gain(0.0); + else + amp1.gain(1.0); + + on_off=!on_off; + + delay(1000); +} diff --git a/third-party/effect_delay_ext8/src/effect_delay_ext8.cpp b/third-party/effect_delay_ext8/src/effect_delay_ext8.cpp index 2a72c1f..a8ddfc7 100644 --- a/third-party/effect_delay_ext8/src/effect_delay_ext8.cpp +++ b/third-party/effect_delay_ext8/src/effect_delay_ext8.cpp @@ -1,39 +1,60 @@ -/* - 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 - -*/ +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice, development funding notice, and this permission + * notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/* Added AUDIO_MEMORY_PSRAM_8MB + * see https://forum.pjrc.com/threads/29276-Limits-of-delay-effect-in-audio-library/page5?highlight=APS6404L-3SQR + * wirtz@parasitstudio.de + */ #include #include "effect_delay_ext8.h" +//#define INTERNAL_TEST + +// While 20 MHz (Teensy actually uses 16 MHz in most cases) and even 24 MHz +// have worked well in testing at room temperature with 3.3V power, to fully +// meet all the worst case timing specs, the SPI clock low time would need +// to be 40ns (12.5 MHz clock) for the single chip case and 51ns (9.8 MHz +// clock) for the 6-chip memoryboard with 74LCX126 buffers. +// +// Timing analysis and info is here: +// https://forum.pjrc.com/threads/29276-Limits-of-delay-effect-in-audio-library?p=97506&viewfull=1#post97506 #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 //----------------- +// Use these with the audio adaptor board (should be adjustable by the user...) +//#define SPIRAM_MOSI_PIN 7 +//#define SPIRAM_MISO_PIN 12 +//#define SPIRAM_SCK_PIN 14 +//#define SPIRAM_CS_PIN 6 + +#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 @@ -45,6 +66,11 @@ void AudioEffectDelayExternal8::update(void) // grab incoming data and put it into the memory block = receiveReadOnly(); + if (memory_type >= AUDIO_MEMORY8_UNDEFINED) { + // ignore input and do nothing if undefined memory type + release(block); + return; + } if (block) { if (head_offset + AUDIO_BLOCK_SAMPLES <= memory_length) { // a single write is enough @@ -97,75 +123,189 @@ void AudioEffectDelayExternal8::update(void) } } -uint32_t AudioEffectDelayExternal8::allocated = 0; +uint32_t AudioEffectDelayExternal8::allocated[2] = {0, 0}; -void AudioEffectDelayExternal8::initialize(uint32_t samples) +void AudioEffectDelayExternal8::initialize(AudioEffectDelayMemoryType8_t type, uint32_t samples) { uint32_t memsize, avail; activemask = 0; head_offset = 0; + memory_type = type; 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 (type == AUDIO_MEMORY8_23LC1024) { +#ifdef INTERNAL_TEST + memsize = 8000; +#else + memsize = 65536; +#endif + pinMode(SPIRAM_CS_PIN, OUTPUT); + digitalWriteFast(SPIRAM_CS_PIN, HIGH); + } else if (type == AUDIO_MEMORY8_MEMORYBOARD) { + memsize = 393216; + pinMode(MEMBOARD_CS0_PIN, OUTPUT); + pinMode(MEMBOARD_CS1_PIN, OUTPUT); + pinMode(MEMBOARD_CS2_PIN, OUTPUT); + digitalWriteFast(MEMBOARD_CS0_PIN, LOW); + digitalWriteFast(MEMBOARD_CS1_PIN, LOW); + digitalWriteFast(MEMBOARD_CS2_PIN, LOW); + } else if (type == AUDIO_MEMORY8_CY15B104) { +#ifdef INTERNAL_TEST + memsize = 8000; +#else + memsize = 262144; +#endif + pinMode(SPIRAM_CS_PIN, OUTPUT); + digitalWriteFast(SPIRAM_CS_PIN, HIGH); + } else if (type == AUDIO_MEMORY8_PSRAM_8MB) { + #ifdef INTERNAL_TEST + memsize = 8000; + #else + memsize = (2^23); // 8388608 bytes + #endif + pinMode(SPIRAM_CS_PIN, OUTPUT); + digitalWriteFast(SPIRAM_CS_PIN, HIGH); + } else { + return; + } + avail = memsize - allocated[type]; if (avail < AUDIO_BLOCK_SAMPLES*2+1) { + memory_type = AUDIO_MEMORY8_UNDEFINED; return; } if (samples > avail) samples = avail; - memory_begin = allocated; - allocated += samples; + memory_begin = allocated[type]; + allocated[type] += samples; memory_length = samples; zero(0, memory_length); } + +#ifdef INTERNAL_TEST +static int16_t testmem[8000]; // testing only +#endif + 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--; +#ifdef INTERNAL_TEST + while (count) { *data++ = testmem[addr++]; count--; } // testing only +#else + if (memory_type == AUDIO_MEMORY8_23LC1024 || + memory_type == AUDIO_MEMORY8_CY15B104 || + memory_type == AUDIO_MEMORY8_PSRAM_8MB) + { + 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(); + } else if (memory_type == AUDIO_MEMORY8_MEMORYBOARD) { + SPI.beginTransaction(SPISETTING); + while (count) { + uint32_t chip = (addr >> 16) + 1; + digitalWriteFast(MEMBOARD_CS0_PIN, chip & 1); + digitalWriteFast(MEMBOARD_CS1_PIN, chip & 2); + digitalWriteFast(MEMBOARD_CS2_PIN, chip & 4); + uint32_t chipaddr = (addr & 0xFFFF) << 1; + SPI.transfer16((0x03 << 8) | (chipaddr >> 16)); + SPI.transfer16(chipaddr & 0xFFFF); + uint32_t num = 0x10000 - (addr & 0xFFFF); + if (num > count) num = count; + count -= num; + addr += num; + do { + *data++ = (int16_t)(SPI.transfer16(0)); + } while (--num > 0); + } + digitalWriteFast(MEMBOARD_CS0_PIN, LOW); + digitalWriteFast(MEMBOARD_CS1_PIN, LOW); + digitalWriteFast(MEMBOARD_CS2_PIN, LOW); + SPI.endTransaction(); } - digitalWriteFast(SPIRAM_CS_PIN, HIGH); - SPI.endTransaction(); +#endif } 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--; +#ifdef INTERNAL_TEST + while (count) { testmem[addr++] = *data++; count--; } // testing only +#else + if (memory_type == AUDIO_MEMORY8_23LC1024 || + memory_type == AUDIO_MEMORY8_PSRAM_8MB ) { + addr *= 2; + SPI.beginTransaction(SPISETTING); + 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(); + } else if (memory_type == AUDIO_MEMORY8_CY15B104) { + 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(); + } else if (memory_type == AUDIO_MEMORY8_MEMORYBOARD) { + SPI.beginTransaction(SPISETTING); + while (count) { + uint32_t chip = (addr >> 16) + 1; + digitalWriteFast(MEMBOARD_CS0_PIN, chip & 1); + digitalWriteFast(MEMBOARD_CS1_PIN, chip & 2); + digitalWriteFast(MEMBOARD_CS2_PIN, chip & 4); + uint32_t chipaddr = (addr & 0xFFFF) << 1; + SPI.transfer16((0x02 << 8) | (chipaddr >> 16)); + SPI.transfer16(chipaddr & 0xFFFF); + uint32_t num = 0x10000 - (addr & 0xFFFF); + if (num > count) num = count; + count -= num; + addr += num; + do { + int16_t w = 0; + if (data) w = *data++; + SPI.transfer16(w); + } while (--num > 0); + } + digitalWriteFast(MEMBOARD_CS0_PIN, LOW); + digitalWriteFast(MEMBOARD_CS1_PIN, LOW); + digitalWriteFast(MEMBOARD_CS2_PIN, LOW); + SPI.endTransaction(); } - digitalWriteFast(SPIRAM_CS_PIN, HIGH); - SPI.endTransaction(); +#endif } diff --git a/third-party/effect_delay_ext8/src/effect_delay_ext8.h b/third-party/effect_delay_ext8/src/effect_delay_ext8.h index 947cd7e..d9fb838 100644 --- a/third-party/effect_delay_ext8/src/effect_delay_ext8.h +++ b/third-party/effect_delay_ext8/src/effect_delay_ext8.h @@ -1,49 +1,61 @@ -/* - 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 - -*/ - -#pragma once +/* Audio Library for Teensy 3.X + * Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com + * + * Development of this audio library was funded by PJRC.COM, LLC by sales of + * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop + * open source software by purchasing Teensy or other PJRC products. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice, development funding notice, and this permission + * notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +/* Added AUDIO_MEMORY_PSRAM_8MB + * see https://forum.pjrc.com/threads/29276-Limits-of-delay-effect-in-audio-library/page5?highlight=APS6404L-3SQR + * wirtz@parasitstudio.de + */ +#ifndef effect_delay_ext8_h_ +#define effect_delay_ext8_h_ #include "Arduino.h" #include "AudioStream.h" #include "spi_interrupt.h" +enum AudioEffectDelayMemoryType8_t { + AUDIO_MEMORY8_23LC1024 = 0, // 128k x 8 S-RAM + AUDIO_MEMORY8_MEMORYBOARD = 1, + AUDIO_MEMORY8_CY15B104 = 2, // 512k x 8 F-RAM + AUDIO_MEMORY8_PSRAM_8MB = 3, // 8192k x 8 PS-RAM + AUDIO_MEMORY8_UNDEFINED = 4 +}; + class AudioEffectDelayExternal8 : public AudioStream { public: AudioEffectDelayExternal8() : AudioStream(1, inputQueueArray) { - initialize(4194304); + initialize(AUDIO_MEMORY8_23LC1024, 65536); } - AudioEffectDelayExternal8(float milliseconds=1e6) + AudioEffectDelayExternal8(AudioEffectDelayMemoryType8_t type, float milliseconds=1e6) : AudioStream(1, inputQueueArray) { uint32_t n = (milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f; - initialize(n); + initialize(type, n); } void delay(uint8_t channel, float milliseconds) { - if (channel >= 8) return; + if (channel >= 8 || memory_type >= AUDIO_MEMORY8_UNDEFINED) return; if (milliseconds < 0.0f) milliseconds = 0.0f; uint32_t n = (milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f; n += AUDIO_BLOCK_SAMPLES; @@ -62,7 +74,7 @@ public: } virtual void update(void); private: - void initialize(uint32_t samples); + void initialize(AudioEffectDelayMemoryType8_t type, uint32_t samples); void read(uint32_t address, uint32_t count, int16_t *data); void write(uint32_t address, uint32_t count, const int16_t *data); void zero(uint32_t address, uint32_t count) { @@ -73,6 +85,9 @@ private: uint32_t head_offset; // head index (incoming) data into external memory uint32_t delay_length[8]; // # of sample delay for each channel (128 = no delay) uint8_t activemask; // which output channels are active - static uint32_t allocated; + uint8_t memory_type; // 0=23LC1024, 1=Frank's Memoryboard + static uint32_t allocated[2]; audio_block_t *inputQueueArray[1]; }; + +#endif