Added code for APS6404L-3SQR based memory used for more delay time.

dev
Holger Wirtz 1 year ago
parent c1f3ae4d53
commit e31138e135
  1. 11
      MicroDexed.ino
  2. 114
      UI.hpp
  3. 5
      config.h
  4. 171
      effect_delay_ext8.cpp
  5. 80
      effect_delay_ext8.h

@ -55,6 +55,9 @@
#include "synth_mda_epiano.h"
#include <effect_stereo_panorama.h>
#endif
#if defined(USE_DELAY_8M)
#include "effect_delay_ext8.h"
#endif
// Audio engines
AudioSynthDexed* MicroDexed[NUM_DEXED];
@ -70,7 +73,11 @@ AudioFilterBiquad* modchorus_filter[NUM_DEXED];
AudioEffectModulatedDelay* modchorus[NUM_DEXED];
AudioMixer<2>* chorus_mixer[NUM_DEXED];
AudioMixer<2>* delay_fb_mixer[NUM_DEXED];
#if defined(USE_DELAY_8M)
AudioEffectDelayExternal8* delay_fx[NUM_DEXED];
#else
AudioEffectDelay* delay_fx[NUM_DEXED];
#endif
AudioMixer<2>* delay_mixer[NUM_DEXED];
#endif
AudioEffectMonoStereo* mono2stereo[NUM_DEXED];
@ -289,7 +296,11 @@ FLASHMEM void create_audio_dexed_chain(uint8_t instance_id) {
modchorus[instance_id] = new AudioEffectModulatedDelay();
chorus_mixer[instance_id] = new AudioMixer<2>();
delay_fb_mixer[instance_id] = new AudioMixer<2>();
#if defined(USE_DELAY_8M)
delay_fx[instance_id] = new AudioEffectDelayExternal8(DELAY_MAX_TIME);
#else
delay_fx[instance_id] = new AudioEffectDelay();
#endif
delay_mixer[instance_id] = new AudioMixer<2>();
#endif

114
UI.hpp

@ -43,6 +43,9 @@
#include "synth_mda_epiano.h"
#include <effect_stereo_panorama.h>
#endif
#if defined(USE_DELAY_8M)
#include "effect_delay_ext8.h"
#endif
#define _LCDML_DISP_cols LCD_cols
#define _LCDML_DISP_rows LCD_rows
@ -92,7 +95,11 @@ extern AudioSynthWaveform* chorus_modulator[NUM_DEXED];
extern AudioEffectModulatedDelay* modchorus[NUM_DEXED];
extern AudioMixer<2>* chorus_mixer[NUM_DEXED];
extern AudioMixer<2>* delay_fb_mixer[NUM_DEXED];
#if defined(USE_DELAY_8M)
extern AudioEffectDelayExternal8* delay_fx[NUM_DEXED];
#else
extern AudioEffectDelay* delay_fx[NUM_DEXED];
#endif
extern AudioMixer<2>* delay_mixer[NUM_DEXED];
#endif
extern AudioEffectMonoStereo* mono2stereo[NUM_DEXED];
@ -4135,7 +4142,7 @@ void UI_func_drums_main_volume(uint8_t param) {
configuration.drums.main_vol = constrain(configuration.drums.main_vol - ENCODER[ENC_L].speed(), DRUMS_MAIN_VOL_MIN, DRUMS_MAIN_VOL_MAX);
}
display_bar_int("DRM Main Vol", configuration.drums.main_vol, 1.0, DRUMS_MAIN_VOL_MIN, DRUMS_MAIN_VOL_MAX, 3, false, false, false);
float tmp_vol=configuration.drums.main_vol/100.0;
float tmp_vol = configuration.drums.main_vol / 100.0;
master_mixer_r.gain(MASTER_MIX_CH_DRUMS, tmp_vol);
master_mixer_l.gain(MASTER_MIX_CH_DRUMS, tmp_vol);
}
@ -6237,65 +6244,60 @@ bool UI_select_name(uint8_t y, uint8_t x, char* edit_string, uint8_t len, bool i
}
if (LCDML.BT_checkDown() || LCDML.BT_checkUp() || LCDML.BT_checkEnter()) {
switch (edit_mode) {
case true:
edit_value = search_accepted_char(edit_string[edit_pos]);
if (LCDML.BT_checkDown()) {
if (edit_value < sizeof(accepted_chars) - 2)
edit_value++;
} else if (LCDML.BT_checkUp()) {
if (edit_value > 0)
edit_value--;
} else if (LCDML.BT_checkEnter()) {
if (edit_mode) {
edit_value = search_accepted_char(edit_string[edit_pos]);
if (LCDML.BT_checkDown()) {
if (edit_value < sizeof(accepted_chars) - 2)
edit_value++;
} else if (LCDML.BT_checkUp()) {
if (edit_value > 0)
edit_value--;
} else if (LCDML.BT_checkEnter()) {
edit_mode = !edit_mode;
display.setCursor(LCD_cols - 1, 0);
display.print(F(" "));
}
edit_string[edit_pos] = accepted_chars[edit_value];
display.setCursor(x + edit_pos, y);
display.print(edit_string[edit_pos]);
} else {
if (LCDML.BT_checkDown()) {
if (edit_pos < len - 1)
edit_pos++;
} else if (LCDML.BT_checkUp()) {
if (edit_pos > 0)
edit_pos--;
} else if (LCDML.BT_checkEnter()) {
if (edit_pos == len - 1) { // OK pressed
edit_pos = 0;
edit_mode = false;
string_trim(edit_string);
return (true);
} else {
edit_mode = !edit_mode;
display.setCursor(LCD_cols - 1, 0);
display.print(F(" "));
}
edit_string[edit_pos] = accepted_chars[edit_value];
display.setCursor(x + edit_pos, y);
display.print(edit_string[edit_pos]);
break;
case false:
if (LCDML.BT_checkDown()) {
if (edit_pos < len - 1)
edit_pos++;
} else if (LCDML.BT_checkUp()) {
if (edit_pos > 0)
edit_pos--;
} else if (LCDML.BT_checkEnter()) {
if (edit_pos == len - 1) { // OK pressed
edit_pos = 0;
edit_mode = false;
string_trim(edit_string);
return (true);
} else {
edit_mode = !edit_mode;
display.setCursor(LCD_cols - 1, 0);
display.write(0);
}
}
if (edit_pos > len - 2) {
display.noBlink();
display.setCursor(x - 1, y);
display.print(F(" "));
display.setCursor(x + len - 1, y);
display.print(F(" "));
display.setCursor(LCD_cols - 4, y);
display.print(F("[OK]"));
} else if (edit_pos == len - 2) {
display.setCursor(x - 1, y);
display.print(F("["));
display.setCursor(x + len - 1, y);
display.print(F("]"));
display.setCursor(LCD_cols - 4, y);
display.print(F(" "));
display.blink();
display.write(0);
}
}
break;
if (edit_pos > len - 2) {
display.noBlink();
display.setCursor(x - 1, y);
display.print(F(" "));
display.setCursor(x + len - 1, y);
display.print(F(" "));
display.setCursor(LCD_cols - 4, y);
display.print(F("[OK]"));
} else if (edit_pos == len - 2) {
display.setCursor(x - 1, y);
display.print(F("["));
display.setCursor(x + len - 1, y);
display.print(F("]"));
display.setCursor(LCD_cols - 4, y);
display.print(F(" "));
display.blink();
}
}
}

@ -154,11 +154,16 @@
#endif
// DELAYTIME
#define USE_DELAY_8M 1
#if NUM_DEXED > 1
#if defined(ARDUINO_TEENSY41)
#define DELAY_MAX_TIME 500
#elif defined(ARDUINO_TEENSY41)
#if defined(USE_DELAY_8M)
#define DELAY_MAX_TIME 5000
#else
#define DELAY_MAX_TIME 250
#endif
#else
#define DELAY_MAX_TIME 100
#endif

@ -0,0 +1,171 @@
/*
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 <Arduino.h>
#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<<channel))) continue;
block = allocate();
if (!block) continue;
// compute the delayed location where we read
if (delay_length[channel] <= head_offset) {
read_offset = head_offset - delay_length[channel];
} else {
read_offset = memory_length + head_offset - delay_length[channel];
}
if (read_offset + AUDIO_BLOCK_SAMPLES <= memory_length) {
// a single read will do it
read(read_offset, AUDIO_BLOCK_SAMPLES, block->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();
}

@ -0,0 +1,80 @@
/*
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
*/
#ifndef effect_delay_ext8_h_
#define effect_delay_ext8_h_
#include "Arduino.h"
#include "AudioStream.h"
#include "spi_interrupt.h"
class AudioEffectDelayExternal8 : public AudioStream
{
public:
AudioEffectDelayExternal8() : AudioStream(1, inputQueueArray) {
initialize(4194304);
}
AudioEffectDelayExternal8(float milliseconds=1e6)
: AudioStream(1, inputQueueArray) {
uint32_t n = (milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f;
initialize(n);
}
void delay(uint8_t channel, float milliseconds) {
if (channel >= 8) return;
if (milliseconds < 0.0f) milliseconds = 0.0f;
uint32_t n = (milliseconds*(AUDIO_SAMPLE_RATE_EXACT/1000.0f))+0.5f;
n += AUDIO_BLOCK_SAMPLES;
if (n > memory_length - AUDIO_BLOCK_SAMPLES)
n = memory_length - AUDIO_BLOCK_SAMPLES;
delay_length[channel] = n;
uint8_t mask = activemask;
if (activemask == 0) AudioStartUsingSPI();
activemask = mask | (1<<channel);
}
void disable(uint8_t channel) {
if (channel >= 8) return;
uint8_t mask = activemask & ~(1<<channel);
activemask = mask;
if (mask == 0) AudioStopUsingSPI();
}
virtual void update(void);
private:
void initialize(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) {
write(address, count, NULL);
}
uint32_t memory_begin; // the first address in the memory we're using
uint32_t memory_length; // the amount of memory we're using
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;
audio_block_t *inputQueueArray[1];
};
#endif
Loading…
Cancel
Save