Added Insert FX and Juno Chorus

pull/764/head
jnonis 7 months ago
parent afa72d21aa
commit d98c7cf701
  1. 1
      src/Makefile
  2. 63
      src/effect.cpp
  3. 42
      src/effect.h
  4. 73
      src/effect_chorus.cpp
  5. 33
      src/effect_chorus.h
  6. 26
      src/effect_delay.cpp
  7. 26
      src/effect_delay.h
  8. 131
      src/minidexed.cpp
  9. 23
      src/minidexed.h
  10. 127
      src/uimenu.cpp
  11. 6
      src/uimenu.h
  12. 143
      src/ykchorus/Chorus.h
  13. 114
      src/ykchorus/ChorusEngine.h
  14. 45
      src/ykchorus/DCBlock.h
  15. 44
      src/ykchorus/OnePoleLP.h

@ -9,6 +9,7 @@ CMSIS_DIR = ../CMSIS_5/CMSIS
OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \
mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \
sysexfileloader.o performanceconfig.o perftimer.o \
effect.o effect_chorus.o effect_delay.o \
effect_compressor.o effect_platervbstereo.o uibuttons.o midipin.o
OPTIMIZE = -O3

@ -0,0 +1,63 @@
#include "effect.h"
AudioEffect::AudioEffect(float32_t samplerate)
{
this->samplerate = samplerate;
}
AudioEffect::~AudioEffect()
{
}
void AudioEffect::setBypass(bool bypass)
{
this->bypass = bypass;
}
bool AudioEffect::getBypass()
{
return bypass;
}
unsigned AudioEffect::getId()
{
return EFFECT_NONE;
}
void AudioEffect::process(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len)
{
if (bypass) {
return;
}
doProcess(inblockL, inblockR, outblockL, outblockR, len);
}
void AudioEffect::doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len) {
for (uint16_t i=0; i < len; i++)
{
outblockL[i] = inblockL[i];
outblockR[i] = inblockR[i];
}
}
AudioEffectNone::AudioEffectNone(float32_t samplerate) : AudioEffect(samplerate)
{
}
AudioEffectNone::~AudioEffectNone()
{
}
void AudioEffectNone::doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len)
{
for (uint16_t i=0; i < len; i++)
{
outblockL[i] = inblockL[i];
outblockR[i] = inblockR[i];
}
}
unsigned AudioEffectNone::getId()
{
return EFFECT_NONE;
}

@ -0,0 +1,42 @@
#ifndef _EFFECT_H
#define _EFFECT_H
#include <stdint.h>
#include <arm_math.h>
#include "common.h"
#define EFFECT_NONE 0
#define EFFECT_CHORUS 1
#define EFFECT_DELAY 2
class AudioEffect
{
public:
AudioEffect(float32_t samplerate);
virtual ~AudioEffect();
void setBypass(bool bypass);
bool getBypass();
virtual unsigned getId();
void process(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len);
protected:
bool bypass = false;
float32_t samplerate;
virtual void doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len);
};
class AudioEffectNone : public AudioEffect
{
public:
AudioEffectNone(float32_t samplerate);
virtual ~AudioEffectNone();
virtual unsigned getId();
protected:
virtual void doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len);
};
#endif // _EFFECT_H

@ -0,0 +1,73 @@
#include <circle/logger.h>
#include "effect_chorus.h"
LOGMODULE ("fx chorus");
AudioEffectChorus::AudioEffectChorus(float32_t samplerate) : AudioEffect(samplerate)
{
engine = new ChorusEngine(samplerate);
engine->setEnablesChorus(true, true);
engine->setChorus1LfoRate(5.0f / 10.0f);
engine->setChorus2LfoRate(8.3f / 10.0f);
}
AudioEffectChorus::~AudioEffectChorus()
{
delete engine;
}
unsigned AudioEffectChorus::getId()
{
return EFFECT_CHORUS;
}
void AudioEffectChorus::doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len)
{
for (uint16_t i=0; i < len; i++)
{
outblockL[i] = inblockL[i];
outblockR[i] = inblockR[i];
engine->process(&outblockL[i], &outblockR[i]);
}
}
unsigned AudioEffectChorus::getChorusI()
{
return engine->isChorus1Enabled;
}
void AudioEffectChorus::setChorusI(unsigned enable)
{
engine->setEnablesChorus(enable == 1, engine->isChorus2Enabled);
}
unsigned AudioEffectChorus::getChorusII()
{
return engine->isChorus2Enabled;
}
void AudioEffectChorus::setChorusII(unsigned enable)
{
engine->setEnablesChorus(engine->isChorus1Enabled, enable == 1);
}
unsigned AudioEffectChorus::getChorusIRate()
{
return (int) roundf(engine->chorus1L->rate * 100);
}
void AudioEffectChorus::setChorusIRate(unsigned int rate)
{
engine->setChorus1LfoRate(((float) rate) / 100.0f);
}
unsigned AudioEffectChorus::getChorusIIRate()
{
return (int) roundf(engine->chorus2L->rate * 100);
}
void AudioEffectChorus::setChorusIIRate(unsigned int rate)
{
engine->setChorus2LfoRate(((float) rate) / 100.0f);
}

@ -0,0 +1,33 @@
#ifndef _EFFECT_CHORUS_H
#define _EFFECT_CHORUS_H
#include "effect.h"
#include "ykchorus/ChorusEngine.h"
class AudioEffectChorus : public AudioEffect
{
public:
AudioEffectChorus(float32_t samplerate);
virtual ~AudioEffectChorus();
virtual unsigned getId();
unsigned getChorusI();
void setChorusI(unsigned enable);
unsigned getChorusII();
void setChorusII(unsigned enable);
unsigned getChorusIRate();
void setChorusIRate(unsigned int rate);
unsigned getChorusIIRate();
void setChorusIIRate(unsigned int rate);
protected:
virtual void doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len);
private:
ChorusEngine *engine;
};
#endif // _EFFECT_CHORUS_H

@ -0,0 +1,26 @@
#include <circle/logger.h>
#include "effect_delay.h"
LOGMODULE ("fx chorus");
AudioEffectDelay::AudioEffectDelay(float32_t samplerate) : AudioEffect(samplerate)
{
}
AudioEffectDelay::~AudioEffectDelay()
{
}
unsigned AudioEffectDelay::getId()
{
return EFFECT_DELAY;
}
void AudioEffectDelay::doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len)
{
for (uint16_t i=0; i < len; i++)
{
outblockL[i] = inblockL[i];
outblockR[i] = inblockR[i];
}
}

@ -0,0 +1,26 @@
#ifndef _EFFECT_DELAY_H
#define _EFFECT_DELAY_H
#include "effect.h"
class AudioEffectDelay : public AudioEffect
{
public:
AudioEffectDelay(float32_t samplerate);
virtual ~AudioEffectDelay();
virtual unsigned getId();
protected:
virtual void doProcess(const float32_t* inblockL, const float32_t* inblockR, float32_t* outblockL, float32_t* outblockR, uint16_t len);
// private:
// const size_t MaxSampleDelayTime;
// unsigned write_pos_L_;
// unsigned write_pos_R_;
// float32_t* buffer_L_;
// float32_t* buffer_R_;
// float32_t delay_time_L_; // Left delay time in seconds (0.0 - 2.0)
// float32_t delay_time_R_; // Right delay time in seconds (0.0 - 2.0)
// float32_t feedback_; // Feedback (0.0 - 1.0)
};
#endif // _EFFECT_DELAY_H

@ -91,6 +91,7 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
m_nAftertouchRange[i]=99;
m_nAftertouchTarget[i]=0;
m_InsertFX[i] = new AudioEffectNone(pConfig->GetSampleRate ());
m_nReverbSend[i] = 0;
m_uchOPMask[i] = 0b111111; // All operators on
@ -403,7 +404,9 @@ void CMiniDexed::Run (unsigned nCore)
for (unsigned i = 0; i < CConfig::TGsCore23; i++, nTG++)
{
assert (m_pTG[nTG]);
float32_t Dummy[m_nFramesToProcess];
m_pTG[nTG]->getSamples (m_OutputLevel[nTG],m_nFramesToProcess);
m_InsertFX[nTG]->process(m_OutputLevel[nTG], Dummy, m_OutputLevel[nTG], Dummy, m_nFramesToProcess);
}
}
}
@ -584,6 +587,31 @@ void CMiniDexed::SetPan (unsigned nPan, unsigned nTG)
m_UI.ParameterChanged ();
}
void CMiniDexed::setInsertFXType (unsigned nType, unsigned nTG)
{
nType=constrain((int) nType, 0, 2);
assert (nTG < CConfig::ToneGenerators);
delete m_InsertFX[nTG];
switch (nType)
{
case EFFECT_CHORUS:
m_InsertFX[nTG] = new AudioEffectChorus(m_pConfig->GetSampleRate());
break;
case EFFECT_DELAY:
m_InsertFX[nTG] = new AudioEffectDelay(m_pConfig->GetSampleRate());
break;
case EFFECT_NONE:
default:
m_InsertFX[nTG] = new AudioEffectNone(m_pConfig->GetSampleRate());
break;
}
m_UI.ParameterChanged ();
}
void CMiniDexed::SetReverbSend (unsigned nReverbSend, unsigned nTG)
{
nReverbSend=constrain((int)nReverbSend,0,99);
@ -922,6 +950,12 @@ void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nT
break;
case TGParameterReverbSend: SetReverbSend (nValue, nTG); break;
case TGParameterInsertFXType: setInsertFXType(nValue, nTG); break;
case TGParameterFXChorusI: setChorusIEnable(nTG, nValue); break;
case TGParameterFXChorusII: setChorusIIEnable(nTG, nValue); break;
case TGParameterFXChorusIRate: setChorusIRate(nTG, nValue); break;
case TGParameterFXChorusIIRate: setChorusIIRate(nTG, nValue); break;
default:
assert (0);
@ -946,6 +980,7 @@ int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG)
case TGParameterResonance: return m_nResonance[nTG];
case TGParameterMIDIChannel: return m_nMIDIChannel[nTG];
case TGParameterReverbSend: return m_nReverbSend[nTG];
case TGParameterInsertFXType: return m_InsertFX[nTG]->getId();
case TGParameterPitchBendRange: return m_nPitchBendRange[nTG];
case TGParameterPitchBendStep: return m_nPitchBendStep[nTG];
case TGParameterPortamentoMode: return m_nPortamentoMode[nTG];
@ -973,6 +1008,10 @@ int CMiniDexed::GetTGParameter (TTGParameter Parameter, unsigned nTG)
case TGParameterATAmplitude: return getModController(3, 2, nTG);
case TGParameterATEGBias: return getModController(3, 3, nTG);
case TGParameterFXChorusI: return getChorusIEnable(nTG);
case TGParameterFXChorusII: return getChorusIIEnable(nTG);
case TGParameterFXChorusIRate: return getChorusIRate(nTG);
case TGParameterFXChorusIIRate: return getChorusIIRate(nTG);
default:
assert (0);
@ -1064,7 +1103,9 @@ void CMiniDexed::ProcessSound (void)
}
float32_t SampleBuffer[nFrames];
float32_t Dummy[nFrames];
m_pTG[0]->getSamples (SampleBuffer, nFrames);
m_InsertFX[0]->process(SampleBuffer, Dummy, SampleBuffer, Dummy, nFrames);
// Convert single float array (mono) to int16 array
int16_t tmp_int[nFrames];
@ -1110,7 +1151,9 @@ void CMiniDexed::ProcessSound (void)
for (unsigned i = 0; i < CConfig::TGsCore1; i++)
{
assert (m_pTG[i]);
float32_t Dummy[nFrames];
m_pTG[i]->getSamples (m_OutputLevel[i], nFrames);
m_InsertFX[i]->process(m_OutputLevel[i], Dummy, m_OutputLevel[i], Dummy, nFrames);
}
// wait for cores 2 and 3 to complete their work
@ -1942,3 +1985,91 @@ unsigned CMiniDexed::getModController (unsigned controller, unsigned parameter,
}
}
unsigned CMiniDexed::getChorusIEnable (uint8_t nTG)
{
AudioEffect* effect = m_InsertFX[nTG];
if (effect->getId() != EFFECT_CHORUS) {
return 0;
}
AudioEffectChorus* chorus = (AudioEffectChorus*) effect;
return chorus->getChorusI();
}
void CMiniDexed::setChorusIEnable (uint8_t nTG, unsigned enable)
{
AudioEffect* effect = m_InsertFX[nTG];
if (effect->getId() != EFFECT_CHORUS) {
return;
}
AudioEffectChorus* chorus = (AudioEffectChorus*) effect;
return chorus->setChorusI(enable);
}
unsigned CMiniDexed::getChorusIIEnable (uint8_t nTG)
{
AudioEffect* effect = m_InsertFX[nTG];
if (effect->getId() != EFFECT_CHORUS) {
return 0;
}
AudioEffectChorus* chorus = (AudioEffectChorus*) effect;
return chorus->getChorusII();
}
void CMiniDexed::setChorusIIEnable (uint8_t nTG, unsigned enable)
{
AudioEffect* effect = m_InsertFX[nTG];
if (effect->getId() != EFFECT_CHORUS) {
return;
}
AudioEffectChorus* chorus = (AudioEffectChorus*) effect;
return chorus->setChorusII(enable);
}
unsigned CMiniDexed::getChorusIRate (uint8_t nTG)
{
AudioEffect* effect = m_InsertFX[nTG];
if (effect->getId() != EFFECT_CHORUS) {
return 0;
}
AudioEffectChorus* chorus = (AudioEffectChorus*) effect;
return chorus->getChorusIRate();
}
void CMiniDexed::setChorusIRate (uint8_t nTG, unsigned int rate)
{
AudioEffect* effect = m_InsertFX[nTG];
if (effect->getId() != EFFECT_CHORUS) {
return;
}
AudioEffectChorus* chorus = (AudioEffectChorus*) effect;
return chorus->setChorusIRate(rate);
}
unsigned CMiniDexed::getChorusIIRate (uint8_t nTG)
{
AudioEffect* effect = m_InsertFX[nTG];
if (effect->getId() != EFFECT_CHORUS) {
return 0;
}
AudioEffectChorus* chorus = (AudioEffectChorus*) effect;
return chorus->getChorusIIRate();
}
void CMiniDexed::setChorusIIRate (uint8_t nTG, unsigned int rate)
{
AudioEffect* effect = m_InsertFX[nTG];
if (effect->getId() != EFFECT_CHORUS) {
return;
}
AudioEffectChorus* chorus = (AudioEffectChorus*) effect;
return chorus->setChorusIIRate(rate);
}

@ -44,6 +44,9 @@
#include "effect_mixer.hpp"
#include "effect_platervbstereo.h"
#include "effect_compressor.h"
#include "effect.h"
#include "effect_chorus.h"
#include "effect_delay.h"
class CMiniDexed
#ifdef ARM_ALLOW_MULTI_CORE
@ -94,6 +97,8 @@ public:
void setBreathController (uint8_t value, unsigned nTG);
void setAftertouch (uint8_t value, unsigned nTG);
void setInsertFXType (unsigned nType, unsigned nTG);
void SetReverbSend (unsigned nReverbSend, unsigned nTG); // 0 .. 127
void setMonoMode(uint8_t mono, uint8_t nTG);
@ -178,6 +183,7 @@ public:
TGParameterProgram,
TGParameterVolume,
TGParameterPan,
TGParameterInsertFXType,
TGParameterMasterTune,
TGParameterCutoff,
TGParameterResonance,
@ -188,7 +194,7 @@ public:
TGParameterPortamentoMode,
TGParameterPortamentoGlissando,
TGParameterPortamentoTime,
TGParameterMonoMode,
TGParameterMonoMode,
TGParameterMWRange,
TGParameterMWPitch,
@ -209,6 +215,11 @@ public:
TGParameterATPitch,
TGParameterATAmplitude,
TGParameterATEGBias,
TGParameterFXChorusI,
TGParameterFXChorusIRate,
TGParameterFXChorusII,
TGParameterFXChorusIIRate,
TGParameterUnknown
};
@ -234,6 +245,15 @@ private:
void LoadPerformanceParameters(void);
void ProcessSound (void);
unsigned getChorusIEnable(uint8_t nTG);
void setChorusIEnable(uint8_t nTG, unsigned enable);
unsigned getChorusIIEnable(uint8_t nTG);
void setChorusIIEnable(uint8_t nTG, unsigned enable);
unsigned getChorusIRate(uint8_t nTG);
void setChorusIRate(uint8_t nTG, unsigned int rate);
unsigned getChorusIIRate(uint8_t nTG);
void setChorusIIRate(uint8_t nTG, unsigned int rate);
#ifdef ARM_ALLOW_MULTI_CORE
enum TCoreStatus
{
@ -283,6 +303,7 @@ private:
unsigned m_nNoteLimitHigh[CConfig::ToneGenerators];
int m_nNoteShift[CConfig::ToneGenerators];
AudioEffect* m_InsertFX[CConfig::ToneGenerators];
unsigned m_nReverbSend[CConfig::ToneGenerators];
uint8_t m_nRawVoiceData[156];

@ -35,7 +35,7 @@ LOGMODULE ("uimenu");
const CUIMenu::TMenuItem CUIMenu::s_MenuRoot[] =
{
{"MiniDexed", MenuHandler, s_MainMenu},
{"MiniDexed JN", MenuHandler, s_MainMenu},
{0}
};
@ -65,6 +65,7 @@ const CUIMenu::TMenuItem CUIMenu::s_TGMenu[] =
#ifdef ARM_ALLOW_MULTI_CORE
{"Pan", EditTGParameter, 0, CMiniDexed::TGParameterPan},
#endif
{"Insert FX", MenuHandler, s_InsertFX},
{"Reverb-Send", EditTGParameter, 0, CMiniDexed::TGParameterReverbSend},
{"Detune", EditTGParameter, 0, CMiniDexed::TGParameterMasterTune},
{"Cutoff", EditTGParameter, 0, CMiniDexed::TGParameterCutoff},
@ -136,6 +137,28 @@ const CUIMenu::TMenuItem CUIMenu::s_ReverbMenu[] =
#endif
const CUIMenu::TMenuItem CUIMenu::s_InsertFX[] =
{
{"Type", EditTGParameter2, 0, CMiniDexed::TGParameterInsertFXType},
{"Edit", EditInsertFX},
{0}
};
const CUIMenu::TMenuItem CUIMenu::s_FXNone[] =
{
{"None", EditTGParameter2},
{0}
};
const CUIMenu::TMenuItem CUIMenu::s_FXChorus[] =
{
{"Chorus I", EditTGParameter2, 0, CMiniDexed::TGParameterFXChorusI},
{"Chorus II", EditTGParameter2, 0, CMiniDexed::TGParameterFXChorusII},
{"Rate I", EditTGParameter2, 0, CMiniDexed::TGParameterFXChorusIRate},
{"Rate II", EditTGParameter2, 0, CMiniDexed::TGParameterFXChorusIIRate},
{0}
};
// inserting menu items before "OP1" affect OPShortcutHandler()
const CUIMenu::TMenuItem CUIMenu::s_EditVoiceMenu[] =
{
@ -227,6 +250,7 @@ const CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown]
{0, CSysExFileLoader::VoicesPerBank-1, 1}, // TGParameterProgram
{0, 127, 8, ToVolume}, // TGParameterVolume
{0, 127, 8, ToPan}, // TGParameterPan
{0, 2, 1, ToFXType}, // TGParameterInsertFXType
{-99, 99, 1}, // TGParameterMasterTune
{0, 99, 1}, // TGParameterCutoff
{0, 99, 1}, // TGParameterResonance
@ -253,7 +277,12 @@ const CUIMenu::TParameter CUIMenu::s_TGParameter[CMiniDexed::TGParameterUnknown]
{0, 99, 1}, //AT Range
{0, 1, 1, ToOnOff}, //AT Pitch
{0, 1, 1, ToOnOff}, //AT Amp
{0, 1, 1, ToOnOff} //AT EGBias
{0, 1, 1, ToOnOff}, //AT EGBias
{0, 1, 1, ToOnOff}, // TGParameterFXChorusI
{0, 100, 1}, // TGParameterFXChorusIRate
{0, 1, 1, ToOnOff}, // TGParameterFXChorusII
{0, 100, 1}, // TGParameterFXChorusIIRate
};
// must match DexedVoiceParameters in Synth_Dexed
@ -701,14 +730,14 @@ void CUIMenu::EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event)
void CUIMenu::EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) // second menu level. Redundant code but in order to not modified original code
{
unsigned nTG = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-2];
unsigned nTG = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-2];
CMiniDexed::TTGParameter Param = (CMiniDexed::TTGParameter) pUIMenu->m_nCurrentParameter;
const TParameter &rParam = s_TGParameter[Param];
int nValue = pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG);
switch (Event)
{
case MenuEventUpdate:
@ -750,7 +779,82 @@ void CUIMenu::EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) // second me
pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name,
Value.c_str (),
nValue > rParam.Minimum, nValue < rParam.Maximum);
}
void CUIMenu::EditInsertFX (CUIMenu *pUIMenu, TMenuEvent Event)
{
unsigned nTG = pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth-2];
int fxType = pUIMenu->m_pMiniDexed->GetTGParameter(CMiniDexed::TGParameterInsertFXType, nTG);
switch (fxType)
{
case EFFECT_CHORUS:
pUIMenu->m_pCurrentMenu = s_FXChorus;
break;
default:
pUIMenu->m_pCurrentMenu = s_FXNone;
break;
}
switch (Event)
{
case MenuEventUpdate:
break;
case MenuEventSelect: // push menu
assert (pUIMenu->m_nCurrentMenuDepth < MaxMenuDepth);
pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth] = pUIMenu->m_pParentMenu;
pUIMenu->m_MenuStackMenu[pUIMenu->m_nCurrentMenuDepth] = pUIMenu->m_pCurrentMenu;
pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth]
= pUIMenu->m_nCurrentMenuItem;
pUIMenu->m_nMenuStackSelection[pUIMenu->m_nCurrentMenuDepth]
= pUIMenu->m_nCurrentSelection;
pUIMenu->m_nMenuStackParameter[pUIMenu->m_nCurrentMenuDepth]
= pUIMenu->m_nCurrentParameter;
pUIMenu->m_nCurrentMenuDepth++;
pUIMenu->m_pParentMenu = pUIMenu->m_pCurrentMenu;
pUIMenu->m_nCurrentParameter =
pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Parameter;
pUIMenu->m_pCurrentMenu =
pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].MenuItem;
pUIMenu->m_nCurrentMenuItem = pUIMenu->m_nCurrentSelection;
pUIMenu->m_nCurrentSelection = 0;
break;
case MenuEventStepDown:
if (pUIMenu->m_nCurrentSelection > 0)
{
pUIMenu->m_nCurrentSelection--;
}
break;
case MenuEventStepUp:
++pUIMenu->m_nCurrentSelection;
if (!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name) // more entries?
{
pUIMenu->m_nCurrentSelection--;
}
break;
default:
return;
}
if (pUIMenu->m_pCurrentMenu) // if this is another menu?
{
pUIMenu->m_pUI->DisplayWrite (
pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name,
"",
pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name,
pUIMenu->m_nCurrentSelection > 0,
!!pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection+1].Name);
}
else
{
pUIMenu->EventHandler (MenuEventUpdate); // no, update parameter display
}
}
void CUIMenu::EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event)
@ -1146,6 +1250,17 @@ string CUIMenu::ToPolyMono (int nValue)
}
}
string CUIMenu::ToFXType (int nValue)
{
switch (nValue)
{
case EFFECT_CHORUS: return "Juno Chorus";
case EFFECT_DELAY: return "Delay";
case EFFECT_NONE:
default: return "None";
}
}
void CUIMenu::TGShortcutHandler (TMenuEvent Event)
{
assert (m_nCurrentMenuDepth >= 2);

@ -92,6 +92,8 @@ private:
static void PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event);
static void SavePerformanceNewFile (CUIMenu *pUIMenu, TMenuEvent Event);
static void EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event);
static void EditInsertFX (CUIMenu *pUIMenu, TMenuEvent Event);
static std::string GetGlobalValueString (unsigned nParameter, int nValue);
static std::string GetTGValueString (unsigned nTGParameter, int nValue);
@ -113,6 +115,7 @@ private:
static std::string ToPortaMode (int nValue);
static std::string ToPortaGlissando (int nValue);
static std::string ToPolyMono (int nValue);
static std::string ToFXType (int nValue);
void TGShortcutHandler (TMenuEvent Event);
void OPShortcutHandler (TMenuEvent Event);
@ -147,6 +150,9 @@ private:
static const TMenuItem s_TGMenu[];
static const TMenuItem s_EffectsMenu[];
static const TMenuItem s_ReverbMenu[];
static const TMenuItem s_InsertFX[];
static const TMenuItem s_FXNone[];
static const TMenuItem s_FXChorus[];
static const TMenuItem s_EditVoiceMenu[];
static const TMenuItem s_OperatorMenu[];
static const TMenuItem s_SaveMenu[];

@ -0,0 +1,143 @@
/*
==============================================================================
This file is part of Tal-NoiseMaker by Patrick Kunz.
Copyright(c) 2005-2010 Patrick Kunz, TAL
Togu Audio Line, Inc.
http://kunz.corrupt.ch
This file may be licensed under the terms of of the
GNU General Public License Version 2 (the ``GPL'').
Software distributed under the License is distributed
on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
express or implied. See the GPL for the specific language
governing rights and limitations.
You should have received a copy of the GPL along with this
program. If not, go to http://www.gnu.org/licenses/gpl.html
or write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
==============================================================================
*/
#if !defined(__Chorus_h)
#define __Chorus_h
#include "OnePoleLP.h"
#include "math.h"
class Chorus {
public:
float *delayLineStart;
float *delayLineEnd;
float *writePtr;
int delayLineLength;
float rate;
float delayLineOutput;
float sampleRate;
float delayTime;
// Runtime variables
float offset, diff, frac, *ptr, *ptr2;
int readPos;
OnePoleLP *lp;
float z1;
float mult, sign;
// lfo
float lfoPhase, lfoStepSize, lfoSign;
Chorus(float sampleRate, float phase, float rate, float delayTime) {
this->rate = rate;
this->sampleRate = sampleRate;
this->delayTime = delayTime;
z1 = 0.0f;
sign = 0;
lfoPhase = phase * 2.0f - 1.0f;
lfoStepSize = (4.0f * rate / sampleRate);
lfoSign = 1.0f;
// Compute required buffer size for desired delay and allocate it
// Add extra point to aid in interpolation later
delayLineLength = ((int)floorf(delayTime * sampleRate * 0.001f) * 2);
delayLineStart = new float[delayLineLength];
// Set up pointers for delay line
delayLineEnd = delayLineStart + delayLineLength;
writePtr = delayLineStart;
// Zero out the buffer (silence)
do {
*writePtr = 0.0f;
}
while (++writePtr < delayLineEnd);
// Set read pointer to end of delayline. Setting it to the end
// ensures the interpolation below works correctly to produce
// the first non-zero sample.
writePtr = delayLineStart + delayLineLength -1;
delayLineOutput = 0.0f;
lp = new OnePoleLP();
}
~Chorus() {
delete[] delayLineStart;
delete lp;
}
void setLfoRate(float rate) {
this->rate = rate;
lfoStepSize = (4.0f * rate / sampleRate);
}
float process(float *sample) {
// Get delay time
offset = (nextLFO() * 0.3f + 0.4f) * delayTime * sampleRate * 0.001f;
// Compute the largest read pointer based on the offset. If ptr
// is before the first delayline location, wrap around end point
ptr = writePtr - (int)floorf(offset);
if (ptr < delayLineStart)
ptr += delayLineLength;
ptr2 = ptr - 1;
if (ptr2 < delayLineStart)
ptr2 += delayLineLength;
frac = offset - (int)floorf(offset);
delayLineOutput = *ptr2 + *ptr * (1 - frac) - (1 - frac) * z1;
z1 = delayLineOutput;
// Low pass
lp->tick(&delayLineOutput, 0.95f);
// Write the input sample and any feedback to delayline
*writePtr = *sample;
// Increment buffer index and wrap if necesary
if (++writePtr >= delayLineEnd) {
writePtr = delayLineStart;
}
return delayLineOutput;
}
inline float nextLFO() {
if (lfoPhase >= 1.0f)
{
lfoSign = -1.0f;
}
else if (lfoPhase <= -1.0f)
{
lfoSign = +1.0f;
}
lfoPhase += lfoStepSize * lfoSign;
return lfoPhase;
}
};
#endif

@ -0,0 +1,114 @@
/*
==============================================================================
This file is part of Tal-NoiseMaker by Patrick Kunz.
Copyright(c) 2005-2010 Patrick Kunz, TAL
Togu Audio Line, Inc.
http://kunz.corrupt.ch
This file may be licensed under the terms of of the
GNU General Public License Version 2 (the ``GPL'').
Software distributed under the License is distributed
on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
express or implied. See the GPL for the specific language
governing rights and limitations.
You should have received a copy of the GPL along with this
program. If not, go to http://www.gnu.org/licenses/gpl.html
or write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
==============================================================================
*/
#if !defined(__ChorusEngine_h)
#define __ChorusEngine_h
#include "Chorus.h"
#include "DCBlock.h"
class ChorusEngine {
public:
Chorus *chorus1L;
Chorus *chorus1R;
Chorus *chorus2L;
Chorus *chorus2R;
DCBlock *dcBlock1L;
DCBlock *dcBlock1R;
DCBlock *dcBlock2L;
DCBlock *dcBlock2R;
bool isChorus1Enabled;
bool isChorus2Enabled;
ChorusEngine(float sampleRate) {
dcBlock1L = new DCBlock();
dcBlock1R = new DCBlock();
dcBlock2L = new DCBlock();
dcBlock2R = new DCBlock();
setUpChorus(sampleRate);
}
~ChorusEngine() {
delete chorus1L;
delete chorus1R;
delete chorus2L;
delete chorus2R;
delete dcBlock1L;
delete dcBlock1R;
delete dcBlock2L;
delete dcBlock2R;
}
void setSampleRate(float sampleRate) {
setUpChorus(sampleRate);
}
void setEnablesChorus(bool isChorus1Enabled, bool isChorus2Enabled) {
this->isChorus1Enabled = isChorus1Enabled;
this->isChorus2Enabled = isChorus2Enabled;
}
void setChorus1LfoRate(float rate) {
chorus1L->setLfoRate(rate);
chorus1R->setLfoRate(rate);
}
void setChorus2LfoRate(float rate) {
chorus2L->setLfoRate(rate);
chorus2R->setLfoRate(rate);
}
void setUpChorus(float sampleRate) {
chorus1L = new Chorus(sampleRate, 1.0f, 0.5f, 7.0f);
chorus1R = new Chorus(sampleRate, 0.0f, 0.5f, 7.0f);
chorus2L = new Chorus(sampleRate, 0.0f, 0.83f, 7.0f);
chorus2R = new Chorus(sampleRate, 1.0f, 0.83f, 7.0f);
}
inline void process(float *sampleL, float *sampleR) {
float resultR = 0.0f;
float resultL = 0.0f;
if (isChorus1Enabled)
{
resultL += chorus1L->process(sampleL);
resultR += chorus1R->process(sampleR);
dcBlock1L->tick(&resultL, 0.01f);
dcBlock1R->tick(&resultR, 0.01f);
}
if (isChorus2Enabled)
{
resultL += chorus2L->process(sampleL);
resultR += chorus2R->process(sampleR);
dcBlock2L->tick(&resultL, 0.01f);
dcBlock2R->tick(&resultR, 0.01f);
}
*sampleL = *sampleL + resultL * 1.4f;
*sampleR = *sampleR + resultR * 1.4f;
}
};
#endif

@ -0,0 +1,45 @@
/*
==============================================================================
This file is part of Tal-NoiseMaker by Patrick Kunz.
Copyright(c) 2005-2010 Patrick Kunz, TAL
Togu Audio Line, Inc.
http://kunz.corrupt.ch
This file may be licensed under the terms of of the
GNU General Public License Version 2 (the ``GPL'').
Software distributed under the License is distributed
on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
express or implied. See the GPL for the specific language
governing rights and limitations.
You should have received a copy of the GPL along with this
program. If not, go to http://www.gnu.org/licenses/gpl.html
or write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
==============================================================================
*/
#if !defined(__DCBlock_h)
#define __DCBlock_h
class DCBlock {
public:
float inputs, outputs, lastOutput;
DCBlock() {
lastOutput = inputs = outputs = 0.0f;
}
~DCBlock() {}
inline void tick(float *sample, float cutoff) {
outputs = *sample - inputs + (0.999f - cutoff * 0.4f) * outputs;
inputs = *sample;
lastOutput = outputs;
*sample = lastOutput;
}
};
#endif

@ -0,0 +1,44 @@
/*
==============================================================================
This file is part of Tal-NoiseMaker by Patrick Kunz.
Copyright(c) 2005-2010 Patrick Kunz, TAL
Togu Audio Line, Inc.
http://kunz.corrupt.ch
This file may be licensed under the terms of of the
GNU General Public License Version 2 (the ``GPL'').
Software distributed under the License is distributed
on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
express or implied. See the GPL for the specific language
governing rights and limitations.
You should have received a copy of the GPL along with this
program. If not, go to http://www.gnu.org/licenses/gpl.html
or write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
==============================================================================
*/
#if !defined(__OnePoleLP_h)
#define __OnePoleLP_h
class OnePoleLP {
public:
float inputs, outputs, lastOutput;
OnePoleLP() {
lastOutput = inputs = outputs = 0.0f;
}
~OnePoleLP() {}
void tick(float *sample, float cutoff) {
float p = (cutoff * 0.98f) * (cutoff * 0.98f) * (cutoff * 0.98f) * (cutoff * 0.98f);
outputs = (1.0f - p) * (*sample) + p * outputs;
*sample = outputs;
}
};
#endif
Loading…
Cancel
Save