Merge remote-tracking branch 'upstream/dev' into dev

Updated to have UI compile (incude order)
pull/3/head
Dirk Niggemann 5 years ago
commit b91a705157
  1. 404
      MicroDexed.ino
  2. 46
      SoftenValue.hpp
  3. 815
      UI.hpp
  4. 130
      config.h
  5. BIN
      doc/Audio-Chain.png
  6. 68
      effect_stereo_mono.cpp
  7. 51
      effect_stereo_mono.h

@ -30,89 +30,93 @@
#include <SD.h>
#include <MIDI.h>
#include <EEPROM.h>
#include "UI.hpp"
#include "EEPROMAnything.h"
#include "midi_devices.hpp"
#include "dexed.h"
#include "dexed_sysex.h"
#include "effect_modulated_delay.h"
#include "effect_stereo_mono.h"
#include "PluginFx.h"
#include "SoftenValue.hpp"
#include "UI.hpp"
AudioPlayQueue queue1;
AudioAnalyzePeak peak1;
AudioEffectDelay delay1;
#ifdef USE_REVERB
AudioEffectFreeverbStereo freeverbs1;
#endif
AudioEffectModulatedDelay modchorus;
#if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT
AudioFilterBiquad modchorus_filter;
#endif
AudioSynthWaveform modulator;
AudioMixer4 chorus_mixer;
AudioMixer4 delay_mixer;
AudioMixer4 delay_fb_mixer;
AudioMixer4 reverb_mixer_r;
AudioMixer4 reverb_mixer_l;
AudioMixer4 master_mixer_r;
AudioMixer4 master_mixer_l;
AudioAmplifier volume_r;
AudioAmplifier volume_l;
#if defined(AUDIO_DEVICE_USB)
AudioOutputUSB usb1;
#endif
AudioEffectStereoMono stereomono1;
AudioConnection patchCord0(queue1, peak1);
AudioConnection patchCord1(queue1, 0, chorus_mixer, 0);
AudioConnection patchCord3(queue1, 0, delay_mixer, 0);
AudioConnection patchCord4(queue1, 0, delay_fb_mixer, 0);
#ifdef USE_REVERB
AudioConnection patchCord5(queue1, 0, reverb_mixer_r, 0);
AudioConnection patchCord6(queue1, 0, reverb_mixer_l, 0);
#endif
AudioConnection patchCord7(queue1, 0, modchorus, 0);
AudioConnection patchCord8(modulator, 0, modchorus, 1);
AudioConnection patchCord1(queue1, 0, delay_fb_mixer, 0);
AudioConnection patchCord2(queue1, 0, modchorus, 0);
AudioConnection patchCord3(queue1, 0 , master_mixer_r, 0);
AudioConnection patchCord4(queue1, 0 , master_mixer_l, 0);
AudioConnection patchCord5(modulator, 0, modchorus, 1);
#if MOD_FILTER_OUTPUT != MOD_NO_FILTER_OUTPUT
AudioConnection patchCord9(modchorus, modchorus_filter);
AudioConnection patchCord10(modchorus_filter, 0, chorus_mixer, 1);
#else
AudioConnection patchCord9(modchorus, 0, chorus_mixer, 1);
#endif
AudioConnection patchCord11(chorus_mixer, 0, delay_mixer, 1);
AudioConnection patchCord12(delay_fb_mixer, 0, delay_mixer, 1);
AudioConnection patchCord13(delay_mixer, 0, reverb_mixer_r, 0);
AudioConnection patchCord14(delay_mixer, 0, reverb_mixer_l, 0);
AudioConnection patchCord15(delay1, 0, delay_mixer, 2);
AudioConnection patchCord16(delay_fb_mixer, delay1);
#ifdef USE_REVERB
AudioConnection patchCord17(delay_mixer, 0, freeverbs1, 0);
AudioConnection patchCord18(delay_mixer, 0, freeverbs1, 1);
AudioConnection patchCord19(freeverbs1, 0, reverb_mixer_r, 1);
AudioConnection patchCord20(freeverbs1, 1, reverb_mixer_l, 1);
AudioConnection patchCord21(reverb_mixer_r, volume_r);
AudioConnection patchCord22(reverb_mixer_l, volume_l);
AudioFilterBiquad modchorus_filter;
AudioConnection patchCord6(modchorus, modchorus_filter);
AudioConnection patchCord7(modchorus_filter, 0, master_mixer_r, 3);
AudioConnection patchCord8(modchorus_filter, 0, master_mixer_l, 3);
#else
AudioConnection patchCord17(delay_mixer, volume_r);
AudioConnection patchCord18(delay_mixer, volume_l);
AudioConnection patchCord9(modchorus, 0, master_mixer_r, 3);
AudioConnection patchCord10(modchorus, 0, master_mixer_l, 3);
#endif
#if defined(AUDIO_DEVICE_USB)
AudioConnection patchCord23(volume_r, 0, usb1, 0);
AudioConnection patchCord24(volume_l, 0, usb1, 1);
#if defined(USE_REVERB)
AudioEffectFreeverbStereo freeverbs1;
AudioConnection patchCord11(queue1, 0, freeverbs1, 0);
AudioConnection patchCord12(queue1, 0, freeverbs1, 1);
AudioConnection patchCord13(freeverbs1, 0, master_mixer_r, 1);
AudioConnection patchCord14(freeverbs1, 1, master_mixer_l, 1);
#endif
#if defined(TEENSY_AUDIO_BOARD) || defined (I2S_AUDIO_ONLY)
AudioOutputI2S i2s1;
AudioConnection patchCord25(volume_r, 0, i2s1, 0);
AudioConnection patchCord26(volume_l, 0, i2s1, 1);
AudioConnection patchCord15(delay_fb_mixer, delay1);
AudioConnection patchCord16(delay1, 0, delay_fb_mixer, 1);
AudioConnection patchCord17(delay1, 0, master_mixer_r, 2);
AudioConnection patchCord18(delay1, 0, master_mixer_l, 2);
AudioConnection patchCord19(master_mixer_r, volume_r);
AudioConnection patchCord20(master_mixer_l, volume_l);
AudioConnection patchCord21(volume_r, 0, stereomono1, 0);
AudioConnection patchCord22(volume_l, 0, stereomono1, 1);
#ifdef AUDIO_DEVICE_USB
AudioConnection patchCord23(stereomono1, 0, usb1, 0);
AudioConnection patchCord24(stereomono1, 1, usb1, 1);
#endif
#if defined(TEENSY_AUDIO_BOARD)
AudioOutputI2S i2s1;
AudioConnection patchCord25(stereomono1, 0, i2s1, 0);
AudioConnection patchCord26(stereomono1, 0, i2s1, 1);
AudioControlSGTL5000 sgtl5000_1;
#elif defined (I2S_AUDIO_ONLY)
AudioOutputI2S i2s1;
AudioConnection patchCord27(stereomono1, 0, i2s1, 0);
AudioConnection patchCord28(stereomono1, 0, i2s1, 1);
#elif defined(TGA_AUDIO_BOARD)
AudioOutputI2S i2s1;
AudioConnection patchCord27(volume_r, 0, i2s1, 0);
AudioConnection patchCord28(volume_l, 0, i2s1, 1);
AudioConnection patchCord29(stereomono1, 0, i2s1, 0);
AudioConnection patchCord30(stereomono1, 1, i2s1, 1);
AudioControlWM8731master wm8731_1;
#elif !defined(I2S_AUDIO_ONLY)
#elif defined(PT8211_AUDIO)
AudioOutputPT8211 pt8211_1;
AudioConnection patchCord29(volume_r, 0, pt8211_1, 0);
AudioConnection patchCord30(volume_l, 0, pt8211_1, 1);
AudioConnection patchCord31(stereomono1, 0, pt8211_1, 0);
AudioConnection patchCord32(stereomono1, 1, pt8211_1, 1);
#elif defined(TEENSY_DAC_SYMMETRIC)
AudioOutputAnalogStereo dacOut;
AudioMixer4 invMixer;
AudioConnection patchCord33(stereomono1, 0, dacOut , 0);
AudioConnection patchCord34(stereomono1, 1, invMixer, 0);
AudioConnection patchCord35(invMixer, 0, dacOut , 1);
#else
AudioOutputAnalogStereo dacOut;
AudioConnection patchCord36(stereomono1, 0, dacOut, 0);
AudioConnection patchCord37(stereomono1, 1, dacOut, 1);
#endif
Dexed* MicroDexed[NUM_DEXED];
@ -132,26 +136,35 @@ uint8_t midi_timing_counter = 0; // 24 per qarter
elapsedMillis midi_timing_timestep;
uint16_t midi_timing_quarter = 0;
elapsedMillis long_button_pressed;
//SoftenValue <uint8_t> effect_filter_volume[NUM_DEXED](SOFTEN_VALUE_CHANGE_STEPS);
//SoftenValue <uint8_t> soften_filter_res[NUM_DEXED](SOFTEN_VALUE_CHANGE_STEPS);
//SoftenValue <uint8_t> soften_filter_cut[NUM_DEXED](SOFTEN_VALUE_CHANGE_STEPS);
uint8_t effect_filter_cutoff = 0;
uint8_t effect_filter_resonance = 0;
uint8_t effect_delay_time = 0;
uint8_t effect_delay_feedback = 0;
uint8_t effect_delay_volume = 0;
bool effect_delay_sync = 0;
SoftenValue <uint8_t> soften_volume;
SoftenValue <uint8_t> soften_filter_res[NUM_DEXED];
SoftenValue <uint8_t> soften_filter_cut[NUM_DEXED];
elapsedMicros fill_audio_buffer;
elapsedMillis control_rate;
uint8_t active_voices = 0;
#ifdef SHOW_CPU_LOAD_MSEC
elapsedMillis cpu_mem_millis;
#endif
config_t configuration = {0xffff, 0, 0, VOLUME, 0.5f, 0, DEFAULT_MIDI_CHANNEL};
config_t configuration = {
0xffff,
SYSEXBANK_DEFAULT,
SYSEXSOUND_DEFAULT,
VOLUME_DEFAULT,
PANORAMA_DEFAULT, // pan
MONO_DEFAULT, // mono
DEFAULT_MIDI_CHANNEL,
REVERB_ROOMSIZE_DEFAULT,
REVERB_DAMPING_DEFAULT,
REVERB_LEVEL_DEFAULT,
CHORUS_FREQUENCY_DEFAULT,
CHORUS_WAVEFORM_DEFAULT,
CHORUS_DEPTH_DEFAULT,
CHORUS_LEVEL_DEFAULT,
FILTER_CUTOFF_DEFAULT,
FILTER_RESONANCE_DEFAULT,
LOUDNESS_DEFAULT
};
bool eeprom_update_flag = false;
value_change_t soften_volume = {0.0, 0};
value_change_t soften_filter_res = {0.0, 0};
value_change_t soften_filter_cut = {0.0, 0};
// Allocate the delay lines for left and right channels
short delayline[MOD_DELAY_SAMPLE_BUFFER];
@ -211,7 +224,7 @@ void setup()
AudioNoInterrupts();
AudioMemory(AUDIO_MEM);
#ifdef TEENSY_AUDIO_BOARD
#if defined(TEENSY_AUDIO_BOARD)
sgtl5000_1.enable();
sgtl5000_1.dacVolumeRamp();
//sgtl5000_1.dacVolumeRampLinear();
@ -246,8 +259,13 @@ void setup()
Serial.println(F("TGA board enabled."));
#elif defined(I2S_AUDIO_ONLY)
Serial.println(F("I2S enabled."));
#else
#elif defined(PT8211_AUDIO)
Serial.println(F("PT8211 enabled."));
#elif defined(TEENSY_DAC_SYMMETRIC)
invMixer.gain(0, -1.f);
Serial.println(F("Internal DAC using symmetric outputs enabled."));
#else
Serial.println(F("Internal DAC enabled."));
#endif
// start SD card
@ -309,6 +327,21 @@ void setup()
Serial.print(MOD_DELAY_SAMPLE_BUFFER, DEC);
Serial.println(F(" samples"));
#endif
master_mixer_r.gain(0, 1.0);
master_mixer_l.gain(0, 1.0);
freeverbs1.roomsize(configuration.reverb_roomsize / 100.0);
freeverbs1.damping(configuration.reverb_damping / 100.0);
master_mixer_r.gain(1, 0.0);
master_mixer_l.gain(1, 0.0);
delay1.delay(0, 0.0);
// delay_fb_mixer is the feedback-adding mixer
delay_fb_mixer.gain(0, 1.0 - configuration.delay_feedback / 100.0); // original signal
delay_fb_mixer.gain(1, configuration.delay_feedback / 100.0); // amount of feedback
master_mixer_r.gain(2, 0.0);
master_mixer_l.gain(2, 0.0);
modulator.begin(MOD_WAVEFORM);
modulator.phase(0);
modulator.amplitude(0.5);
@ -327,32 +360,21 @@ void setup()
modchorus_filter.setLowpass(2, MOD_FILTER_CUTOFF_HZ, 0.54);
modchorus_filter.setLowpass(3, MOD_FILTER_CUTOFF_HZ, 1.3);
#endif
chorus_mixer.gain(0, 1.0);
chorus_mixer.gain(1, 0.0);
delay1.delay(0, mapfloat(effect_delay_feedback, 0, ENC_DELAY_TIME_STEPS, 0.0, DELAY_MAX_TIME));
// delay_fb_mixer is the feedback-adding mixer, delay_mixer_r the whole delay (with/without feedback) mixer
delay_fb_mixer.gain(0, 1.0); // original signal
delay_fb_mixer.gain(1, mapfloat(effect_delay_feedback, 0, ENC_DELAY_FB_STEPS, 0.0, 1.0)); // amount of feedback
delay_mixer.gain(0, 1.0 - mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // original signal
delay_mixer.gain(1, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // delayed signal (including feedback)
delay_mixer.gain(2, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // only delayed signal (without feedback)
reverb_mixer_r.gain(0, 1.0);
reverb_mixer_l.gain(0, 1.0);
reverb_mixer_r.gain(1, 0.0);
reverb_mixer_l.gain(1, 0.0);
master_mixer_r.gain(3, 0.0);
master_mixer_l.gain(3, 0.0);
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
soften_filter_res[i].init(1.0, 0.0, 1.0);
soften_filter_cut[i].init(1.0, 0.0, 1.0);
MicroDexed[i]->fx.Gain = 1.0;
MicroDexed[i]->fx.Reso = 1.0 - float(effect_filter_resonance) / ENC_FILTER_RES_STEPS;
MicroDexed[i]->fx.Cutoff = 1.0 - float(effect_filter_cutoff) / ENC_FILTER_CUT_STEPS;
MicroDexed[i]->fx.Reso = 1.0;
MicroDexed[i]->fx.Cutoff = 1.0;
}
// set initial volume and pan (read from EEPROM)
set_volume(configuration.vol, configuration.pan);
soften_volume.init(configuration.vol, VOLUME_MIN, VOLUME_MAX);
#if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC)
// Initialize processor and memory measurements
@ -412,10 +434,6 @@ void loop()
if (peak1.read() > 0.99)
peak++;
}
#ifndef TEENSY_AUDIO_BOARD
for (uint8_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
audio_buffer[i] *= configuration.vol;
#endif
queue1.playBuffer();
}
@ -445,62 +463,56 @@ void loop()
#endif
control_rate = 0;
// Shutdown unused voices
// check for value changes and unused voices
soften_volume.tick();
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
active_voices = MicroDexed[i]->getNumNotesPlaying();
}
// check for value changes
if (soften_volume.steps > 0)
{
// soften volume value
soften_volume.steps--;
set_volume(configuration.vol + soften_volume.diff, configuration.pan);
#ifdef DEBUG
Serial.print(F("Volume: "));
Serial.print(configuration.vol, 5);
Serial.print(F(" Volume step: "));
Serial.print(soften_volume.steps);
Serial.print(F(" Volume diff: "));
Serial.println(soften_volume.diff, 5);
#endif
}
if (soften_filter_res.steps > 0)
{
// soften filter resonance value
soften_filter_res.steps--;
for (uint8_t i = 0; i < NUM_DEXED; i++)
soften_filter_res[i].tick();
soften_filter_cut[i].tick();
if (soften_filter_res[i].running())
{
MicroDexed[i]->fx.Reso = MicroDexed[i]->fx.Reso + soften_filter_res.diff;
// soften filter resonance value
MicroDexed[i]->fx.Reso = soften_filter_res[i].value();
#ifdef DEBUG
Serial.print(F("Filter-Resonance: "));
Serial.print(MicroDexed[i]->fx.Reso, 5);
Serial.print(F(" Filter-Resonance step: "));
Serial.print(soften_filter_res.steps);
Serial.print(soften_filter_res[i].steps());
Serial.print(F(" Filter-Resonance diff: "));
Serial.println(soften_filter_res.diff, 5);
Serial.println(soften_filter_res[i].diff(), 5);
#endif
}
}
if (soften_filter_cut.steps > 0)
{
// soften filter cutoff value
soften_filter_cut.steps--;
for (uint8_t i = 0; i < NUM_DEXED; i++)
if (soften_filter_cut[i].running())
{
MicroDexed[i]->fx.Cutoff = MicroDexed[i]->fx.Cutoff + soften_filter_cut.diff;
MicroDexed[i]->fx.Cutoff = soften_filter_cut[i].value();
#ifdef DEBUG
Serial.print(F("Filter-Cutoff: "));
Serial.print(MicroDexed[i]->fx.Cutoff, 5);
Serial.print(F(" Filter-Cutoff step: "));
Serial.print(soften_filter_cut.steps);
Serial.print(soften_filter_cut[i].steps());
Serial.print(F(" Filter-Cutoff diff: "));
Serial.println(soften_filter_cut.diff, 5);
Serial.println(soften_filter_cut[i].diff(), 5);
#endif
}
}
if (soften_volume.running())
{
set_volume(soften_volume.value(), configuration.pan);
#ifdef DEBUG
Serial.print(F("Volume: "));
Serial.print(configuration.vol, DEC);
Serial.print(F(" step: "));
Serial.print(soften_volume.steps());
Serial.print(F(" diff: "));
Serial.println(soften_volume.diff(), 5);
#endif
}
}
#if defined (DEBUG) && defined (SHOW_CPU_LOAD_MSEC)
@ -551,73 +563,107 @@ void handleControlChange(byte inChannel, byte inCtrl, byte inValue)
}
break;
case 1:
MicroDexed[0]->controllers.modwheel_cc = inValue;
MicroDexed[0]->controllers.refresh();
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->controllers.modwheel_cc = inValue;
MicroDexed[i]->controllers.refresh();
}
break;
case 2:
MicroDexed[0]->controllers.breath_cc = inValue;
MicroDexed[0]->controllers.refresh();
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->controllers.breath_cc = inValue;
MicroDexed[i]->controllers.refresh();
}
break;
case 4:
MicroDexed[0]->controllers.foot_cc = inValue;
MicroDexed[0]->controllers.refresh();
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->controllers.foot_cc = inValue;
MicroDexed[i]->controllers.refresh();
}
break;
case 7: // Volume
configuration.vol = float(inValue) / 0x7f;
set_volume(configuration.vol, configuration.pan);
configuration.vol = map(inValue, 0, 0x7f, VOLUME_MIN, VOLUME_MAX);
soften_volume.update(configuration.vol, SOFTEN_VALUE_CHANGE_STEPS);
break;
case 10: // Pan
configuration.pan = float(inValue) / 128;
configuration.pan = map(inValue, 0, 0x7f, PANORAMA_MIN, PANORAMA_MAX);
set_volume(configuration.vol, configuration.pan);
break;
case 32: // BankSelect LSB
configuration.bank = inValue;
break;
case 64:
MicroDexed[0]->setSustain(inValue > 63);
if (!MicroDexed[0]->getSustain()) {
for (uint8_t note = 0; note < MicroDexed[0]->getMaxNotes(); note++) {
if (MicroDexed[0]->voices[note].sustained && !MicroDexed[0]->voices[note].keydown) {
MicroDexed[0]->voices[note].dx7_note->keyup();
MicroDexed[0]->voices[note].sustained = false;
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->setSustain(inValue > 63);
if (!MicroDexed[i]->getSustain()) {
for (uint8_t note = 0; note < MicroDexed[0]->getMaxNotes(); note++) {
if (MicroDexed[i]->voices[note].sustained && !MicroDexed[i]->voices[note].keydown) {
MicroDexed[i]->voices[note].dx7_note->keyup();
MicroDexed[i]->voices[note].sustained = false;
}
}
}
}
break;
case 103: // CC 103: filter resonance
effect_filter_resonance = map(inValue, 0, 127, 0, ENC_FILTER_RES_STEPS);
MicroDexed[0]->fx.Reso = 1.0 - float(effect_filter_resonance) / ENC_FILTER_RES_STEPS;
configuration.filter_resonance = map(inValue, 0, 0x7f, FILTER_RESONANCE_MIN, FILTER_RESONANCE_MAX);
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->fx.Reso = configuration.filter_resonance / 100.0;
}
break;
case 104: // CC 104: filter cutoff
effect_filter_cutoff = map(inValue, 0, 127, 0, ENC_FILTER_CUT_STEPS);
MicroDexed[0]->fx.Cutoff = 1.0 - float(effect_filter_cutoff) / ENC_FILTER_CUT_STEPS;
configuration.filter_cutoff = map(inValue, 0, 0x7f, FILTER_CUTOFF_MIN, FILTER_CUTOFF_MAX);
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->fx.Cutoff = configuration.filter_cutoff / 100.0;
}
break;
case 105: // CC 105: delay time
effect_delay_time = map(inValue, 0, 127, 0, ENC_DELAY_TIME_STEPS);
////delay.delay(0, mapfloat(effect_delay_time, 0, ENC_DELAY_TIME_STEPS, 0.0, DELAY_MAX_TIME));
break;
configuration.delay_time = map(inValue, 0, 0x7f, DELAY_TIME_MIN, DELAY_TIME_MAX);
delay1.delay(0, configuration.delay_time * 10);
case 106: // CC 106: delay feedback
effect_delay_feedback = map(inValue, 0, 127, 0, ENC_DELAY_FB_STEPS);
////delay_mixer_r.gain(1, mapfloat(float(effect_delay_feedback), 0, ENC_DELAY_FB_STEPS, 0.0, 1.0));
configuration.delay_feedback = map(inValue, 0, 0x7f, DELAY_FEEDBACK_MIN , DELAY_FEEDBACK_MAX);
delay_fb_mixer.gain(1, configuration.delay_feedback / 100.0 ); // amount of feedback
delay_fb_mixer.gain(0, 1.0 - configuration.delay_feedback / 100.0); // original signalbreak;
break;
case 107: // CC 107: delay volume
effect_delay_volume = map(inValue, 0, 127, 0, ENC_DELAY_VOLUME_STEPS);
////delay_mixer_l.gain(1, mapfloat(effect_delay_volume, 0, ENC_DELAY_VOLUME_STEPS, 0.0, 1.0)); // delay tap1 signal (with added feedback)
configuration.delay_level = map(inValue, 0, 0x7f, DELAY_LEVEL_MIN, DELAY_LEVEL_MAX);
master_mixer_r.gain(2, configuration.delay_level / 100.0);
master_mixer_l.gain(2, configuration.delay_level / 100.0);
break;
case 120:
MicroDexed[0]->panic();
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->panic();
}
break;
case 121:
MicroDexed[0]->resetControllers();
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->resetControllers();
}
break;
case 123:
MicroDexed[0]->notesOff();
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->notesOff();
}
break;
case 126:
MicroDexed[0]->setMonoMode(true);
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->setMonoMode(true);
}
break;
case 127:
MicroDexed[0]->setMonoMode(false);
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->setMonoMode(false);
}
break;
}
}
@ -625,13 +671,19 @@ void handleControlChange(byte inChannel, byte inCtrl, byte inValue)
void handleAfterTouch(byte inChannel, byte inPressure)
{
MicroDexed[0]->controllers.aftertouch_cc = inPressure;
MicroDexed[0]->controllers.refresh();
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->controllers.aftertouch_cc = inPressure;
MicroDexed[i]->controllers.refresh();
}
}
void handlePitchBend(byte inChannel, int inPitch)
{
MicroDexed[0]->controllers.values_[kControllerPitch] = inPitch + 0x2000; // -8192 to +8191 --> 0 to 16383
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->controllers.values_[kControllerPitch] = inPitch + 0x2000; // -8192 to +8191 --> 0 to 16383
}
}
void handleProgramChange(byte inChannel, byte inProgram)
@ -928,19 +980,23 @@ bool checkMidiChannel(byte inChannel)
VOLUME HELPER
******************************************************************************/
void set_volume(float v, float p)
void set_volume(uint8_t v, int8_t p)
{
configuration.vol = v;
configuration.pan = p;
MicroDexed[0]->fx.Gain = v;
uint16_t tmp = v * 1023.0 + 0.5;
float tmp2 = configuration.pan;
uint16_t tmp = v / 100.0 * 1023.0 + 0.5;
float tmp2 = mapfloat(configuration.pan, PANORAMA_MIN, PANORAMA_MAX, 0.0, 1.0);
float tmp3 = (float)(tmp * (tmp + 2)) / (float)(1 << 20);
#ifdef SHOW_DEBUG
// float v = (float)(a * (a + 2))/(float)(1 << 20); // (pseudo-) logarithmic curve for volume control
// http://files.csound-tutorial.net/floss_manual/Release03/Cs_FM_03_ScrapBook/b-panning-and-spatialization.html
volume_r.gain(tmp3 * sinf(tmp2 * PI / 2));
volume_l.gain(tmp3 * cosf(tmp2 * PI / 2));
#ifdef DEBUG
Serial.print(F("Setting volume: VOL="));
Serial.print(value, DEC);
Serial.print(configuration.vol, DEC);
Serial.print(F("["));
Serial.print(tmp3, 3);
Serial.print(F("] PAN="));
@ -953,15 +1009,21 @@ void set_volume(float v, float p)
Serial.println(tmp3 * cosf(tmp2 * PI / 2), 3);
#endif
// float v = (float)(a * (a + 2))/(float)(1 << 20); // (pseudo-) logarithmic curve for volume control
// http://files.csound-tutorial.net/floss_manual/Release03/Cs_FM_03_ScrapBook/b-panning-and-spatialization.html
volume_r.gain(tmp3 * sinf(tmp2 * PI / 2));
volume_l.gain(tmp3 * cosf(tmp2 * PI / 2));
if (configuration.mono == 2)
{
volume_r.gain(1.0);
volume_l.gain(0.0);
}
else if (configuration.mono == 3)
{
volume_r.gain(0.0);
volume_l.gain(1.0);
}
else
{
volume_r.gain(1.0);
volume_l.gain(1.0);
}
}
// https://www.dr-lex.be/info-stuff/volumecontrols.html#table1
@ -1005,10 +1067,8 @@ void initial_values_from_eeprom(void)
Serial.println();
#endif
if (configuration.vol > 1.0)
configuration.vol = 1.0;
else if (configuration.vol < 0.0)
configuration.vol = 0.0;
if (configuration.vol > 100)
configuration.vol = 100;
}
void eeprom_write(void)

@ -24,19 +24,26 @@
*/
#ifndef SOFTEN_VALUE_H_INCLUDED
#define SOFTEN_VALUE_H_INCLUDED 1
template <class T>
class SoftenValue
{
public:
SoftenValue(uint16_t steps = 10);
SoftenValue(T from, T to, uint16_t steps = 10)
init(T value, T minimum, T maximum)
{
_from = value;
_to = value;
_steps = 0;
_diff = 0.0;
_min = minimum;
_max = maximum;
}
void update(T to, uint16_t steps)
{
_from = from;
_to = to;
_steps = steps;
_diff = (from - to) / _steps;
_calculate();
}
@ -58,6 +65,12 @@ class SoftenValue
{
_from -= _diff;
_steps--;
#ifdef DEBUG
Serial.print(F("Steps: "));
Serial.print(_steps, DEC);
Serial.print(F(" Diff="));
Serial.println(_diff, 5);
#endif
}
}
@ -74,11 +87,21 @@ class SoftenValue
return (_steps);
}
T diff(void)
{
return (_diff);
}
T value(void)
{
if (_steps == 0)
return (_to);
if (_from < _min)
_from = _min;
else if (_from > _max)
_from = _max;
if (std::is_same<T, float>::value)
return (_from);
else
@ -90,6 +113,8 @@ class SoftenValue
float _to;
uint16_t _steps;
float _diff;
T _min;
T _max;
void _calculate(void)
{
@ -100,6 +125,17 @@ class SoftenValue
}
else
_diff = (_from - _to) / _steps;
#ifdef DEBUG
Serial.print(F("Update SoftenValue: from="));
Serial.print(_from, 5);
Serial.print(F(" to="));
Serial.print(_to, 5);
Serial.print(F(" diff="));
Serial.print(_diff, 5);
Serial.print(F(" steps="));
Serial.println(_steps, DEC);
#endif
}
};

815
UI.hpp

@ -54,9 +54,22 @@ extern bool load_sysex(uint8_t b, uint8_t v);
#ifdef DISPLAY_LCD_SPI
extern void change_disp_sd(bool d);
#endif
extern value_change_t soften_volume;
extern value_change_t soften_filter_res;
extern value_change_t soften_filter_cut;
extern SoftenValue <uint8_t> soften_volume;
extern SoftenValue <uint8_t> soften_filter_res[NUM_DEXED];
extern SoftenValue <uint8_t> soften_filter_cut[NUM_DEXED];
extern AudioEffectDelay delay1;
#ifdef USE_REVERB
extern AudioEffectFreeverbStereo freeverbs1;
#endif
extern AudioEffectModulatedDelay modchorus;
extern AudioSynthWaveform modulator;
extern AudioMixer4 delay_fb_mixer;
extern AudioMixer4 master_mixer_r;
extern AudioMixer4 master_mixer_l;
extern AudioAmplifier volume_r;
extern AudioAmplifier volume_l;
extern Dexed* MicroDexed[NUM_DEXED];
extern void set_volume(uint8_t v, int8_t p);
/***********************************************************************
GLOBAL
@ -111,6 +124,7 @@ void UI_func_reverb_roomsize(uint8_t param);
void UI_func_reverb_damping(uint8_t param);
void UI_func_reverb_level(uint8_t param);
void UI_func_chorus_frequency(uint8_t param);
void UI_func_chorus_waveform(uint8_t param);
void UI_func_chorus_depth(uint8_t param);
void UI_func_chorus_level(uint8_t param);
void UI_func_delay_time(uint8_t param);
@ -129,6 +143,8 @@ void UI_func_voice_selection(uint8_t param);
void UI_func_volume(uint8_t param);
void UI_func_back(uint8_t param);
void UI_func_goToRootMenu(uint8_t param);
void lcd_display_int(int16_t var, uint8_t size, bool zeros, bool brackets, bool sign);
void lcd_display_float(float var, uint8_t size_number, uint8_t size_fraction, bool zeros, bool brackets, bool sign);
// normal menu
@ -144,25 +160,26 @@ LCDML_add(4, LCDML_0_2_1, 2, "Damping", UI_func_reverb_damping);
LCDML_add(5, LCDML_0_2_1, 3, "Level", UI_func_reverb_level);
LCDML_add(6, LCDML_0_2, 2, "Chorus", NULL);
LCDML_add(7, LCDML_0_2_2, 1, "Frequency", UI_func_chorus_frequency);
LCDML_add(8, LCDML_0_2_2, 2, "Depth", UI_func_chorus_depth);
LCDML_add(9, LCDML_0_2_2, 3, "Level", UI_func_chorus_level);
LCDML_add(10, LCDML_0_2, 3, "Delay", NULL);
LCDML_add(11, LCDML_0_2_3, 1, "Time", UI_func_delay_time);
LCDML_add(12, LCDML_0_2_3, 2, "Feedback", UI_func_delay_feedback);
LCDML_add(13, LCDML_0_2_3, 3, "Level", UI_func_delay_level);
LCDML_add(14, LCDML_0_2, 4, "Filter", NULL);
LCDML_add(15, LCDML_0_2_4, 1, "Cutoff", UI_func_filter_cutoff);
LCDML_add(16, LCDML_0_2_4, 2, "Resonance", UI_func_filter_resonance);
LCDML_add(17, LCDML_0, 3, "Store", NULL);
LCDML_add(18, LCDML_0, 4, "System", NULL);
LCDML_add(19, LCDML_0_4, 1, "MIDI Channel", UI_func_midi_channel);
LCDML_add(20, LCDML_0_4, 2, "Loudness", UI_func_loudness);
LCDML_add(21, LCDML_0_4, 3, "Panorama", UI_func_panorama);
LCDML_add(22, LCDML_0_4, 4, "Stereo/Mono", UI_func_stereo_mono);
LCDML_add(23, LCDML_0_4, 5, "Polyphony", UI_func_polyphony);
LCDML_add(24, LCDML_0_4, 6, "Engine", UI_func_engine);
LCDML_add(25, LCDML_0, 5, "Info", UI_func_information);
#define _LCDML_DISP_cnt 25
LCDML_add(8, LCDML_0_2_2, 2, "Waveform", UI_func_chorus_waveform);
LCDML_add(9, LCDML_0_2_2, 3, "Depth", UI_func_chorus_depth);
LCDML_add(10, LCDML_0_2_2, 4, "Level", UI_func_chorus_level);
LCDML_add(11, LCDML_0_2, 3, "Delay", NULL);
LCDML_add(12, LCDML_0_2_3, 1, "Time", UI_func_delay_time);
LCDML_add(13, LCDML_0_2_3, 2, "Feedback", UI_func_delay_feedback);
LCDML_add(14, LCDML_0_2_3, 3, "Level", UI_func_delay_level);
LCDML_add(15, LCDML_0_2, 4, "Filter", NULL);
LCDML_add(16, LCDML_0_2_4, 1, "Cutoff", UI_func_filter_cutoff);
LCDML_add(17, LCDML_0_2_4, 2, "Resonance", UI_func_filter_resonance);
LCDML_add(18, LCDML_0, 3, "Store", NULL);
LCDML_add(19, LCDML_0, 4, "System", NULL);
LCDML_add(20, LCDML_0_4, 1, "MIDI Channel", UI_func_midi_channel);
LCDML_add(21, LCDML_0_4, 2, "Loudness", UI_func_loudness);
LCDML_add(22, LCDML_0_4, 3, "Panorama", UI_func_panorama);
LCDML_add(23, LCDML_0_4, 4, "Stereo/Mono", UI_func_stereo_mono);
LCDML_add(24, LCDML_0_4, 5, "Polyphony", UI_func_polyphony);
LCDML_add(25, LCDML_0_4, 6, "Engine", UI_func_engine);
LCDML_add(26, LCDML_0, 5, "Info", UI_func_information);
#define _LCDML_DISP_cnt 26
// create menu
LCDML_createMenu(_LCDML_DISP_cnt);
@ -417,7 +434,7 @@ void encoder_right_up(void)
}
break;
case MENU_VOICE_SOUND:
if (configuration.voice < MAX_VOICES-1)
if (configuration.voice < MAX_VOICES - 1)
configuration.voice++;
else
{
@ -540,12 +557,11 @@ void encoder_left_up(void)
#ifdef DEBUG
Serial.println(F("Volume +"));
#endif
if (configuration.vol < 0.96)
{
soften_volume.diff = 0.05 / SOFTEN_VALUE_CHANGE_STEPS;
soften_volume.steps = SOFTEN_VALUE_CHANGE_STEPS;
eeprom_write();
}
if (configuration.vol < VOLUME_MAX)
soften_volume.update(soften_volume.value() + (VOLUME_MAX - VOLUME_MIN) / VOLUME_ENC_STEPS, SOFTEN_VALUE_CHANGE_STEPS);
else
soften_volume.update(VOLUME_MAX, SOFTEN_VALUE_CHANGE_STEPS);
eeprom_write();
UI_func_volume(0);
}
@ -554,12 +570,11 @@ void encoder_left_down(void)
#ifdef DEBUG
Serial.println(F("Volume -"));
#endif
if (configuration.vol > 0.04)
{
soften_volume.diff = -0.05 / SOFTEN_VALUE_CHANGE_STEPS;
soften_volume.steps = SOFTEN_VALUE_CHANGE_STEPS;
eeprom_write();
}
if (configuration.vol > VOLUME_MIN)
soften_volume.update(soften_volume.value() - (VOLUME_MAX - VOLUME_MIN) / VOLUME_ENC_STEPS, SOFTEN_VALUE_CHANGE_STEPS);
else
soften_volume.update(VOLUME_MIN, SOFTEN_VALUE_CHANGE_STEPS);
eeprom_write();
UI_func_volume(0);
}
@ -736,9 +751,9 @@ void UI_func_sound(uint8_t param)
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Filter Res."));
lcd.print(F("Sound"));
lcd.setCursor(0, 1);
lcd.print(F("<value>"));
lcd.print(F("not implemented"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
@ -757,77 +772,704 @@ void UI_func_sound(uint8_t param)
void UI_func_reverb_roomsize(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Reverb Roomsize"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.reverb_roomsize < REVERB_ROOMSIZE_MAX)
{
configuration.reverb_roomsize++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.reverb_roomsize > REVERB_ROOMSIZE_MIN)
{
configuration.reverb_roomsize--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.reverb_roomsize, 3, true, true, false);
freeverbs1.roomsize(configuration.reverb_roomsize / 100.0);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_reverb_damping(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Reverb Damping"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.reverb_damping < REVERB_DAMPING_MAX)
{
configuration.reverb_damping++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.reverb_damping > REVERB_DAMPING_MIN)
{
configuration.reverb_damping--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.reverb_damping, 3, true, true, false);
freeverbs1.damping(configuration.reverb_damping / 100.0);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_reverb_level(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Reverb Level"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.reverb_level < REVERB_LEVEL_MAX)
{
configuration.reverb_level++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.reverb_level > REVERB_LEVEL_MIN)
{
configuration.reverb_level--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.reverb_level, 3, true, true, false);
master_mixer_r.gain(1, configuration.reverb_level / 100.0);
master_mixer_l.gain(1, configuration.reverb_level / 100.0);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_chorus_frequency(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Chorus Frequency"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.chorus_frequency < CHORUS_FREQUENCY_MAX)
{
configuration.chorus_frequency++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.chorus_frequency > CHORUS_FREQUENCY_MIN)
{
configuration.chorus_frequency--;
}
}
lcd.setCursor(0, 1);
lcd_display_float(configuration.chorus_frequency / 10.0, 2, 1, false, true, false);
lcd.print(" Hz");
modulator.frequency(configuration.chorus_frequency / 10.0);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_chorus_waveform(uint8_t param)
{
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Chorus Waveform"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.chorus_waveform < CHORUS_WAVEFORM_MAX)
{
configuration.chorus_waveform++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.chorus_waveform > CHORUS_WAVEFORM_MIN)
{
configuration.chorus_waveform--;
}
}
lcd.setCursor(0, 1);
switch (configuration.chorus_waveform)
{
case 0:
modulator.begin(WAVEFORM_TRIANGLE);
lcd.print("[TRIANGLE]");
break;
case 1:
modulator.begin(WAVEFORM_SINE);
lcd.print("[SINE ]");
break;
default:
modulator.begin(WAVEFORM_TRIANGLE);
lcd.print("[TRIANGLE]");
break;
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_chorus_depth(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Chorus Depth"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.chorus_depth < CHORUS_DEPTH_MAX)
{
configuration.chorus_depth++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.chorus_depth > CHORUS_DEPTH_MIN)
{
configuration.chorus_depth--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.chorus_depth, 3, true, true, false);
modulator.amplitude(configuration.chorus_depth / 100.0);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_chorus_level(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Chorus Level"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.chorus_level < CHORUS_LEVEL_MAX)
{
configuration.chorus_level++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.chorus_level > CHORUS_LEVEL_MIN)
{
configuration.chorus_level--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.chorus_level, 3, true, true, false);
master_mixer_r.gain(3, configuration.chorus_level / 100.0);
master_mixer_l.gain(3, configuration.chorus_level / 100.0);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_delay_time(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Delay Time"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.delay_time < DELAY_TIME_MAX)
{
configuration.delay_time += 10;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.delay_time > DELAY_TIME_MIN)
{
configuration.delay_time -= 10;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.delay_time * 10, 3, true, true, false);
delay1.delay(0, configuration.delay_time * 10);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_delay_feedback(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Delay Feedback"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.delay_feedback < DELAY_FEEDBACK_MAX)
{
configuration.delay_feedback++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.delay_feedback > DELAY_FEEDBACK_MIN)
{
configuration.delay_feedback--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.delay_feedback, 3, true, true, false);
delay_fb_mixer.gain(1, configuration.delay_feedback / 100.0 ); // amount of feedback
delay_fb_mixer.gain(0, 1.0 - configuration.delay_feedback / 100.0); // original signal
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_delay_level(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Delay Level"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.delay_level < DELAY_LEVEL_MAX)
{
configuration.delay_level++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.delay_level > DELAY_LEVEL_MIN)
{
configuration.delay_level--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.delay_level, 3, true, true, false);
master_mixer_r.gain(2, configuration.delay_level / 100.0);
master_mixer_l.gain(2, configuration.delay_level / 100.0);
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_filter_cutoff(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Filter Cut-Off"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.filter_cutoff < FILTER_CUTOFF_MAX)
{
configuration.filter_cutoff++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.filter_cutoff > FILTER_CUTOFF_MIN)
{
configuration.filter_cutoff--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.filter_cutoff, 3, true, true, false);
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->fx.Cutoff = configuration.filter_cutoff / 100.0;
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_filter_resonance(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Filter Resonance"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.filter_resonance < FILTER_RESONANCE_MAX)
{
configuration.filter_resonance++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.filter_resonance > FILTER_RESONANCE_MIN)
{
configuration.filter_resonance--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.filter_resonance, 3, true, true, false);
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->fx.Reso = configuration.filter_resonance / 100.0;
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_midi_channel(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("MIDI Channel"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.midi_channel < MIDI_CHANNEL_MAX)
{
configuration.midi_channel++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.midi_channel > MIDI_CHANNEL_MIN)
{
configuration.midi_channel--;
}
}
lcd.setCursor(0, 1);
if (configuration.midi_channel == 0)
{
lcd.print(F("[OMNI]"));
}
else
{
lcd_display_int(configuration.midi_channel, 4, false, true, false);
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_loudness(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Loudness"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.loudness < LOUDNESS_MAX)
{
configuration.loudness++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.loudness > LOUDNESS_MIN)
{
configuration.loudness--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.loudness, 3, true, true, false);
for (uint8_t i = 0; i < NUM_DEXED; i++)
{
MicroDexed[i]->fx.Gain = configuration.loudness / 100.0;
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_panorama(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Panorama"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.pan < PANORAMA_MAX)
{
configuration.pan++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.loudness > PANORAMA_MIN)
{
configuration.pan--;
}
}
lcd.setCursor(0, 1);
lcd_display_int(configuration.pan, 2, false, true, true);
}
set_volume(configuration.vol, configuration.pan);
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_stereo_mono(uint8_t param)
{
;
if (LCDML.FUNC_setup()) // ****** SETUP *********
{
// setup function
lcd.setCursor(0, 0);
lcd.print(F("Stereo/Mono"));
}
if (LCDML.FUNC_loop()) // ****** LOOP *********
{
if (LCDML.BT_checkEnter())
{
LCDML.FUNC_goBackToMenu();
}
else if (LCDML.BT_checkDown())
{
if (configuration.mono < MONO_MAX)
{
configuration.mono++;
}
}
else if (LCDML.BT_checkUp())
{
if (configuration.mono > MONO_MIN)
{
configuration.mono--;
}
}
lcd.setCursor(0, 1);
switch (configuration.mono)
{
case 0:
lcd.print(F("[MONO ]"));
break;
case 1:
lcd.print(F("[STEREO]"));
break;
case 2:
lcd.print(F("[MONO-R]"));
break;
case 3:
lcd.print(F("[MONO-L]"));
break;
}
}
if (LCDML.FUNC_close()) // ****** STABLE END *********
{
// you can here reset some global vars or do nothing
}
}
void UI_func_polyphony(uint8_t param)
@ -920,11 +1562,11 @@ void UI_func_volume(uint8_t param)
// update LCD content
LCDML.DISP_clear();
lcd.show(0, 0, 8, "Volume: ");
lcd.show(0, 9, 3, configuration.vol * 100.0 + 0.5);
lcd.show(0, 9, 3, configuration.vol);
lcd.setCursor(1, 1);
for (uint8_t i = 0; i < LCD_cols; i++)
{
if (i < int((LCD_cols - 2) * configuration.vol + 0.5))
if (i < int((LCD_cols - 2) * configuration.vol / 100.0))
lcd.print("*");
else
lcd.print(" ");
@ -932,5 +1574,70 @@ void UI_func_volume(uint8_t param)
lcd.show(1, 0, 1, "[");
lcd.show(1, 15, 1, "]");
}
void lcd_display_int(int16_t var, uint8_t size, bool zeros, bool brackets, bool sign)
{
int16_t tmp = 0;
uint16_t p;
if (size < 1)
return;
if (brackets == true)
lcd.print(F("["));
if (sign == true)
{
if (var < 0)
{
lcd.print(F("-"));
var = abs(var);
}
else if (var > 0)
lcd.print(F("+"));
else
lcd.print(F(" "));
}
for (int8_t i = size - 1 ; i >= 0; i--)
{
p = int(pow(10, i));
tmp = int(var / p);
if (tmp == 0)
{
if (zeros == true)
lcd.print(F("0"));
else
lcd.print(F(" "));
}
else
lcd.print(tmp);
var -= (tmp * p);
}
if (brackets == true)
lcd.print(F("]"));
}
void lcd_display_float(float var, uint8_t size_number, uint8_t size_fraction, bool zeros, bool brackets, bool sign)
{
float fraction;
float number;
if (size_number < 1 || size_fraction < 1)
return;
fraction = modff(var, &number);
if (brackets == true)
lcd.print(F("["));
lcd_display_int(int(number), size_number, zeros, false, sign);
lcd.print(F("."));
lcd_display_int(round(fraction * pow(10, size_fraction)), size_fraction, true, false, false);
if (brackets == true)
lcd.print(F("]"));
}
#endif
#endif

@ -46,16 +46,20 @@
// MIDI
#define MIDI_DEVICE_DIN Serial1
//#define AUDIO_DEVICE_USB
//#define MIDI_DEVICE_USB 1
//#define MIDI_DEVICE_USB_HOST 1
//#define MIDI_DEVICE_NUMBER 0
// AUDIO
// If nothing is defined PT8211 is used as audio output device!
//#define AUDIO_DEVICE_USB
//#define TEENSY_AUDIO_BOARD 1
// If nothing is defined Teensy internal DAC is used as audio output device!
// Left and right channel audio signal is presented on pins A21 and A22.//#define AUDIO_DEVICE_USB
//#define TEENSY_DAC
//#define TEENSY_DAC_SYMMETRIC
//#define TEENSY_AUDIO_BOARD
#define I2S_AUDIO_ONLY
//#define TGA_AUDIO_BOARD
//#define PT8211_AUDIO
//*************************************************************************************************
//* MIDI SETTINGS
@ -63,28 +67,25 @@
#define DEFAULT_MIDI_CHANNEL MIDI_CHANNEL_OMNI
#define MIDI_MERGE_THRU 1
#define DEFAULT_SYSEXBANK 0
#define DEFAULT_SYSEXSOUND 0
#define SYSEXBANK_DEFAULT 0
#define SYSEXSOUND_DEFAULT 0
//*************************************************************************************************
//* DEXED AND EFECTS SETTINGS
//*************************************************************************************************
#define DEXED_ENGINE DEXED_ENGINE_MODERN // DEXED_ENGINE_MARKI // DEXED_ENGINE_OPL
// EFFECTS
#define FILTER_MAX_FREQ 10000
// CHORUS parameters
#define MOD_DELAY_SAMPLE_BUFFER int32_t(TIME_MS2SAMPLES(20.0)) // 20.0 ms delay buffer.
#define MOD_WAVEFORM WAVEFORM_TRIANGLE // WAVEFORM_SINE WAVEFORM_TRIANGLE WAVEFORM_SAWTOOTH WAVEFORM_SAWTOOTH_REVERSE
#define MOD_FILTER_OUTPUT MOD_LINKWITZ_RILEY_FILTER_OUTPUT // MOD_LINKWITZ_RILEY_FILTER_OUTPUT MOD_BUTTERWORTH_FILTER_OUTPUT MOD_NO_FILTER_OUTPUT
#define MOD_FILTER_CUTOFF_HZ 3000
//#define USE_REVERB 1
#define USE_REVERB 1
//*************************************************************************************************
//* AUDIO SETTINGS
//*************************************************************************************************
// https://rechneronline.de/funktionsgraphen/
#define VOLUME 0.8
#define VOLUME_CURVE 0.07
#ifndef TEENSY_AUDIO_BOARD
#if AUDIO_BLOCK_SAMPLES == 64
@ -92,7 +93,7 @@
#else
#define AUDIO_MEM 225
#endif
#define DELAY_MAX_TIME 600.0
#define DELAY_MAX_TIME 600
#define REDUCE_LOUDNESS 1
#else
#if AUDIO_BLOCK_SAMPLES == 64
@ -100,7 +101,7 @@
#else
#define AUDIO_MEM 450
#endif
#define DELAY_MAX_TIME 1200.0
#define DELAY_MAX_TIME 1200
#define REDUCE_LOUDNESS 1
#endif
#define SAMPLE_RATE 44100
@ -161,12 +162,7 @@
#define SDCARD_SCK_PIN 13 // not actually used
// Encoder with button
#define ENC_FILTER_RES_STEPS 100
#define ENC_FILTER_CUT_STEPS 100
#define ENC_DELAY_TIME_STEPS 50
#define ENC_DELAY_FB_STEPS 35
#define ENC_DELAY_VOLUME_STEPS 50
#define ENC_VOLUME_STEPS 20
#define ENCODER_USE_INTERRUPTS
#define NUM_ENCODER 2
#define ENC_L_PIN_A 3
#define ENC_L_PIN_B 2
@ -203,22 +199,30 @@
#ifdef MIDI_DEVICE_USB
#define USBCON 1
#endif
#if defined(__IMXRT1062__) //Teensy-4.0
#undef MIDI_DEVICE_USB_HOST
#undef MIDI_DEVICE_USB
#define MAX_NOTES 16
#endif
#if defined(__MK66FX1M0__) // Teensy-3.6
// Teensy-3.6 settings
#define MIDI_DEVICE_USB_HOST 1
#if defined(USE_REVERB)
#define MAX_NOTES 16
#else
#define MAX_NOTES 14
#endif
#endif
#if defined (__MK64FX512__)
// Teensy-3.5 settings
#undef MIDI_DEVICE_USB_HOST
#define MAX_NOTES 11
#undef USE_REVERB
#endif
#define TRANSPOSE_FIX 24
// Audio
@ -238,15 +242,103 @@
#define MOD_BUTTERWORTH_FILTER_OUTPUT 1
#define MOD_LINKWITZ_RILEY_FILTER_OUTPUT 2
#if defined(TEENSY_DAC_SYMMETRIC)
#define MONO_MIN 1
#define MONO_MAX 1
#define MONO_DEFAULT 1
#else
#define MONO_MIN 0
#define MONO_MAX 3
#define MONO_DEFAULT 1
#endif
#define VOLUME_MIN 0
#define VOLUME_MAX 100
#define VOLUME_DEFAULT 80
#define VOLUME_ENC_STEPS 20
#define PANORAMA_MIN -20
#define PANORAMA_MAX 20
#define PANORAMA_DEFAULT 0
#define MIDI_CHANNEL_MIN MIDI_CHANNEL_OMNI
#define MIDI_CHANNEL_MAX 16
#define MIDI_CHANNEL_DEFAULT MIDI_CHANNEL_OMNI
#define REVERB_ROOMSIZE_MIN 0
#define REVERB_ROOMSIZE_MAX 100
#define REVERB_ROOMSIZE_DEFAULT 0
#define REVERB_DAMPING_MIN 0
#define REVERB_DAMPING_MAX 100
#define REVERB_DAMPING_DEFAULT 0
#define REVERB_LEVEL_MIN 0
#define REVERB_LEVEL_MAX 100
#define REVERB_LEVEL_DEFAULT 0
#define CHORUS_FREQUENCY_MIN 0
#define CHORUS_FREQUENCY_MAX 100
#define CHORUS_FREQUENCY_DEFAULT 0
#define CHORUS_WAVEFORM_MIN 0
#define CHORUS_WAVEFORM_MAX 1
#define CHORUS_WAVEFORM_DEFAULT 0
#define CHORUS_DEPTH_MIN 0
#define CHORUS_DEPTH_MAX 100
#define CHORUS_DEPTH_DEFAULT 0
#define CHORUS_LEVEL_MIN 0
#define CHORUS_LEVEL_MAX 100
#define CHORUS_LEVEL_DEFAULT 0
#define DELAY_TIME_MIN 0
#define DELAY_TIME_MAX DELAY_MAX_TIME/10
#define DELAY_TIME_DEFAULT 0
#define DELAY_FEEDBACK_MIN 0
#define DELAY_FEEDBACK_MAX 100
#define DELAY_FEEDBACK_DEFAULT 0
#define DELAY_LEVEL_MIN 0
#define DELAY_LEVEL_MAX 100
#define DELAY_LEVEL_DEFAULT 0
#define FILTER_CUTOFF_MIN 0
#define FILTER_CUTOFF_MAX 100
#define FILTER_CUTOFF_DEFAULT 0
#define FILTER_RESONANCE_MIN 0
#define FILTER_RESONANCE_MAX 100
#define FILTER_RESONANCE_DEFAULT 0
#define LOUDNESS_MIN 0
#define LOUDNESS_MAX 100
#define LOUDNESS_DEFAULT 100
// struct for holding the current configuration
struct config_t {
uint32_t checksum;
uint8_t bank;
uint8_t voice;
float vol;
float pan;
uint8_t vol;
int8_t pan;
uint8_t mono;
uint8_t midi_channel;
uint8_t reverb_roomsize;
uint8_t reverb_damping;
uint8_t reverb_level;
uint8_t chorus_frequency;
uint8_t chorus_waveform;
uint8_t chorus_depth;
uint8_t chorus_level;
uint8_t delay_time;
uint8_t delay_feedback;
uint8_t delay_level;
uint8_t filter_cutoff;
uint8_t filter_resonance;
uint8_t loudness;
};
// struct for smoothing value changes

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

@ -0,0 +1,68 @@
/* Audio Library for Teensy 3.X
Copyright (c) 2019, Holger Wirtz
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 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.
*/
#include <Arduino.h>
#include <Audio.h>
#include "effect_stereo_mono.h"
/*************************************************************************/
// A u d i o E f f e c t S t e r e o M o n o
// Written by Holger Wirtz
// 20191023 - inital version
void AudioEffectStereoMono::stereo(bool mode)
{
_enabled = mode;
}
void AudioEffectStereoMono::update(void)
{
audio_block_t *block[2];
block[0] = receiveWritable(0);
block[1] = receiveWritable(1);
if (_enabled == true)
{
if (block[0] && block[1])
{
int16_t *bp[2] = { block[0]->data, block[1]->data };
for (uint16_t i = 0; i < AUDIO_BLOCK_SAMPLES; i++)
{
*bp[0]++ = *bp[0] >> 1 + *bp[1] >> 1;
*bp[1]++ = *bp[0];
}
}
}
if (block[0])
{
transmit(block[0], 0);
release(block[0]);
}
if (block[1])
{
transmit(block[1], 1);
release(block[1]);
}
}

@ -0,0 +1,51 @@
/* Audio Library for Teensy 3.X
Copyright (c) 2019, Holger Wirtz
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 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.
*/
#ifndef effect_stereo_mono_h_
#define effect_stereo_mono_h_
#include "Arduino.h"
#include "AudioStream.h"
/*************************************************************************/
// A u d i o E f f e c t M o d u l a t e d D e l a y
// Written by Holger Wirtz
// 20191023 - inital version
class AudioEffectStereoMono : public AudioStream
{
public:
AudioEffectStereoMono(void):
AudioStream(2, inputQueueArray)
{
_enabled = false;
}
virtual void update(void);
virtual void stereo(bool mode);
private:
audio_block_t *inputQueueArray[2];
bool _enabled;
};
#endif
Loading…
Cancel
Save