From c39c980a7a4d22368e74caed3c8ea85082985eaa Mon Sep 17 00:00:00 2001 From: Rene Stange Date: Fri, 2 Apr 2021 10:50:41 +0200 Subject: [PATCH] Make MIDI CC mapping configurable The MIDI CC mapping can be configured with the file midi-cc.txt on the SD card now. The file format should be self explanatory. A default config file is the config/ directory. Issue #12 --- README.md | 8 ++++-- config/midi-cc.txt | 27 ++++++++++++++++++ src/Makefile | 2 +- src/midiccmap.cpp | 67 +++++++++++++++++++++++++++++++++++++++++++++ src/midiccmap.h | 49 +++++++++++++++++++++++++++++++++ src/minisynth.cpp | 14 +++------- src/patch.cpp | 19 +++++++++---- src/patch.h | 4 ++- src/synthconfig.cpp | 16 +++++++++-- src/synthconfig.h | 5 +++- 10 files changed, 187 insertions(+), 24 deletions(-) create mode 100644 config/midi-cc.txt create mode 100644 src/midiccmap.cpp create mode 100644 src/midiccmap.h diff --git a/README.md b/README.md index ea8657f..f006efd 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Furthermore you need the Raspberry Pi firmware. You can get it as follows: You have to copy the three files *bootcode.bin*, *start.elf* and *fixup.dat* from the *circle/boot/* subdirectory to the FAT partition on the SD card. The Raspberry Pi 4 requires different firmware files. Please read the file *circle/boot/README* for details! -Finally you have to copy the configuration files *cmdline.txt*, *patchN.txt* (example patches) and *velocity-???.txt* (keyboard velocity curve) from the *config/* subdirectory to the SD card. The appropriate velocity curve file has to be renamed to *velocity.txt* to be used. You can optionally create a subdirectory */patches* and copy the example patches there, if you do not want to have them in the root directory of your SD card. +Finally you have to copy the configuration files *cmdline.txt*, *patchN.txt* (example patches), *velocity-???.txt* (keyboard velocity curve) and *midi-cc.txt* (MIDI CC mapping) from the *config/* subdirectory to the SD card. The appropriate velocity curve file has to be renamed to *velocity.txt* to be used. You can optionally create a subdirectory */patches* and copy the example patches there, if you do not want to have them in the root directory of your SD card. Put the SD card into the card reader of your Raspberry Pi. @@ -129,7 +129,7 @@ One patch of MiniSynth Pi has the following parameters: | Section | Module | Parameter | Unit | Range | Default | Description | MIDI CC | | ---------- | -------- | --------- | ---- | --------- | ------- | -------------------- | ------- | | OSCILLATOR | VCO | Wave | | | Square | Waveform (*) | | -| OSCILLATOR | VCO (2) | Detune | % | 0-200 | 100 | Semitone -/+ | | +| OSCILLATOR | VCO (2) | Detune | % | 0-200 | 100 | Semitone -/+ | 94 (**) | | OSCILLATOR | LFO | Wave | | | Sine | Waveform (*) | | | OSCILLATOR | LFO | Rate | Hz | 1-35 | 20 | Modulation frequency | | | OSCILLATOR | LFO | Volume | % | 0-100 | 0 | Modulation volume | | @@ -151,10 +151,12 @@ One patch of MiniSynth Pi has the following parameters: | AMPLIFIER | ENVELOPE | Sustain | % | 0-100 | 100 | Sustain level | | | AMPLIFIER | ENVELOPE | Release | ms | 0-5000 | 100 | Release delay | | | EFFECTS | REVERB | Decay | % | 0-50 | 20 | Rate of decay | | -| EFFECTS | REVERB | Volume | % | 0-30 | 0 | Wet/dry ratio | | +| EFFECTS | REVERB | Volume | % | 0-30 | 0 | Wet/dry ratio | 91 | (*) Waveform can be: Sine, Square, Sawtooth, Triangle, Pulse 12.5%, Pulse 25% or Noise (Noise not for LFO) +(\*\*) The MIDI CC mapping can be modified in the file *midi-cc.txt*. This is the default mapping. + MiniSynth Pi provides two VCOs, one runs at the pitch frequency, the other at pitch frequency detuned by a configurable value (max. one semitone - or +, default 100% = Detune off). MiniSynth Pi allows to use a specific keyboard velocity curve, which fits best to your keyboard and your playing style. It has to be provided in the file *velocity.txt* on the SD card. The default velocity curve is linear. Have a look into the example files in the *config/* subdirectory. If you want to use one of these files, it has to be renamed to *velocity.txt* on the SD card. It should be easy to modify one example file to adjust the velocity curve to your own needs. diff --git a/config/midi-cc.txt b/config/midi-cc.txt new file mode 100644 index 0000000..9a543ae --- /dev/null +++ b/config/midi-cc.txt @@ -0,0 +1,27 @@ +# +# MIDI CC Mapping +# +LFOVCOWaveform= +LFOVCOFrequency= +VCOWaveform= +VCOModulationVolume= +VCODetune=94 +LFOVCFWaveform= +LFOVCFFrequency= +VCFCutoffFrequency=74 +VCFResonance=71 +EGVCFAttack= +EGVCFDecay= +EGVCFSustain= +EGVCFRelease= +VCFModulationVolume= +LFOVCAWaveform= +LFOVCAFrequency= +EGVCAAttack= +EGVCADecay= +EGVCASustain= +EGVCARelease= +VCAModulationVolume= +ReverbDecay= +ReverbVolume=91 +SynthVolume=7 diff --git a/src/Makefile b/src/Makefile index 9e2f9a3..6740d23 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ CIRCLEHOME ?= ../circle OBJS = main.o kernel.o minisynth.o mididevice.o \ midikeyboard.o pckeyboard.o serialmididevice.o voicemanager.o \ voice.o oscillator.o mixer.o filter.o amplifier.o envelopegenerator.o \ - reverbmodule.o synthconfig.o patch.o parameter.o velocitycurve.o \ + reverbmodule.o synthconfig.o patch.o parameter.o velocitycurve.o midiccmap.o \ mainwindow.o guiparameter.o guistringproperty.o LIBS = $(CIRCLEHOME)/addon/lvgl/liblvgl.a \ diff --git a/src/midiccmap.cpp b/src/midiccmap.cpp new file mode 100644 index 0000000..c8cab9d --- /dev/null +++ b/src/midiccmap.cpp @@ -0,0 +1,67 @@ +// +// midiccmap.h +// +// MiniSynth Pi - A virtual analogue synthesizer for Raspberry Pi +// Copyright (C) 2021 R. Stange +// +// 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, see . +// +#include "midiccmap.h" +#include "config.h" +#include + +CMIDICCMap::CMIDICCMap (FATFS *pFileSystem) +: m_Properties (DRIVE "/midi-cc.txt", pFileSystem) +{ + for (unsigned i = MIDICC_MIN; i <= MIDICC_MAX; i++) + { + m_Map[i] = SynthParameterUnknown; + } +} + +CMIDICCMap::~CMIDICCMap (void) +{ +} + +boolean CMIDICCMap::Load (void) +{ + boolean bResult = m_Properties.Load (); + if (!bResult) + { + m_Properties.RemoveAll (); + } + + for (unsigned i = 0; i < SynthParameterUnknown; i++) + { + unsigned nMIDICC = + m_Properties.GetNumber (CPatch::GetParameterName ((TSynthParameter) i), 0); + + if (MIDICC_MIN <= nMIDICC && nMIDICC <= MIDICC_MAX) + { + m_Map[nMIDICC] = (TSynthParameter) i; + } + } + + return bResult; +} + +TSynthParameter CMIDICCMap::Map (u8 ucMIDICC) const +{ + if (MIDICC_MIN <= ucMIDICC && ucMIDICC <= MIDICC_MAX) + { + return m_Map[ucMIDICC]; + } + + return SynthParameterUnknown; +} diff --git a/src/midiccmap.h b/src/midiccmap.h new file mode 100644 index 0000000..cebb355 --- /dev/null +++ b/src/midiccmap.h @@ -0,0 +1,49 @@ +// +// midiccmap.h +// +// Maps MIDI CC numbers to TSynthParameter +// +// MiniSynth Pi - A virtual analogue synthesizer for Raspberry Pi +// Copyright (C) 2021 R. Stange +// +// 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, see . +// +#ifndef _midiccmap_h +#define _midiccmap_h + +#include +#include +#include +#include "patch.h" + +#define MIDICC_MIN 1 +#define MIDICC_MAX 127 + +class CMIDICCMap +{ +public: + CMIDICCMap (FATFS *pFileSystem); + ~CMIDICCMap (void); + + boolean Load (void); + + TSynthParameter Map (u8 ucMIDICC) const; + +private: + CPropertiesFatFsFile m_Properties; + + TSynthParameter m_Map[MIDICC_MAX+1]; +}; + +#endif diff --git a/src/minisynth.cpp b/src/minisynth.cpp index 51e1e29..ba8f7bb 100644 --- a/src/minisynth.cpp +++ b/src/minisynth.cpp @@ -2,7 +2,7 @@ // minisynth.cpp // // MiniSynth Pi - A virtual analogue synthesizer for Raspberry Pi -// Copyright (C) 2017-2020 R. Stange +// Copyright (C) 2017-2021 R. Stange // // 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 @@ -133,19 +133,13 @@ boolean CMiniSynthesizer::ConfigUpdated (void) void CMiniSynthesizer::ControlChange (u8 ucFunction, u8 ucValue) { - TSynthParameter Parameter; - - switch (ucFunction) + assert (m_pConfig != 0); + TSynthParameter Parameter = m_pConfig->MapMIDICC (ucFunction); + if (Parameter >= SynthParameterUnknown) { - case 7: Parameter = SynthVolume; break; - case 71: Parameter = VCFResonance; break; - case 74: Parameter = VCFCutoffFrequency; break; - - default: return; } - assert (m_pConfig != 0); CPatch *pPatch = m_pConfig->GetActivePatch (); assert (pPatch != 0); diff --git a/src/patch.cpp b/src/patch.cpp index b7d412d..ef4af79 100644 --- a/src/patch.cpp +++ b/src/patch.cpp @@ -2,7 +2,7 @@ // patch.cpp // // MiniSynth Pi - A virtual analogue synthesizer for Raspberry Pi -// Copyright (C) 2017-2020 R. Stange +// Copyright (C) 2017-2021 R. Stange // // 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 @@ -21,7 +21,7 @@ #include "oscillator.h" #include -static struct +static const struct { const char *pName; TParameterType Type; @@ -74,7 +74,7 @@ ParameterList[] = // must match TSynthParameter {"SynthVolume", ParameterPercent, 0, 100, 10, 50, "Volume"} }; -static struct +static const struct { const char *pName; unsigned nMaxLength; @@ -188,9 +188,12 @@ void CPatch::SetParameter (TSynthParameter Parameter, unsigned nValue) void CPatch::SetMIDIParameter (TSynthParameter Parameter, u8 ucValue) { assert (Parameter < SynthParameterUnknown); - assert (ParameterList[Parameter].Type == ParameterPercent); - unsigned nValue = (ucValue*100 + 63) / 127; + unsigned nValue = ucValue; + nValue *= ParameterList[Parameter].nMaximum - ParameterList[Parameter].nMinimum; + nValue = (nValue + 63) / 127; + nValue += ParameterList[Parameter].nMinimum; + nValue = (nValue + ParameterList[Parameter].nStep/2) / ParameterList[Parameter].nStep * ParameterList[Parameter].nStep; @@ -262,3 +265,9 @@ const char *CPatch::GetPropertyHelp (TPatchProperty Property) assert (Property < PatchPropertyUnknown); return PropertyList[Property].pHelp; } + +const char *CPatch::GetParameterName (TSynthParameter Parameter) +{ + assert (Parameter < SynthParameterUnknown); + return ParameterList[Parameter].pName; +} diff --git a/src/patch.h b/src/patch.h index 72dcd3b..a2a0d7b 100644 --- a/src/patch.h +++ b/src/patch.h @@ -4,7 +4,7 @@ // Container for patch settings, loadable from properties file // // MiniSynth Pi - A virtual analogue synthesizer for Raspberry Pi -// Copyright (C) 2017-2020 R. Stange +// Copyright (C) 2017-2021 R. Stange // // 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 @@ -108,6 +108,8 @@ class CPatch static boolean GetPropertyUppercase (TPatchProperty Property); static const char *GetPropertyHelp (TPatchProperty Property); + static const char *GetParameterName (TSynthParameter Parameter); + private: CPropertiesFatFsFile m_Properties; diff --git a/src/synthconfig.cpp b/src/synthconfig.cpp index 705c16f..4eac437 100644 --- a/src/synthconfig.cpp +++ b/src/synthconfig.cpp @@ -2,7 +2,7 @@ // synthconfig.cpp // // MiniSynth Pi - A virtual analogue synthesizer for Raspberry Pi -// Copyright (C) 2017-2020 R. Stange +// Copyright (C) 2017-2021 R. Stange // // 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 @@ -25,7 +25,8 @@ CSynthConfig::CSynthConfig (FATFS *pFileSystem) : m_pFileSystem (pFileSystem), m_nActivePatch (0), - m_VelocityCurve (pFileSystem) + m_VelocityCurve (pFileSystem), + m_MIDICCMap (pFileSystem) { for (unsigned i = 0; i < PATCHES; i++) { @@ -62,7 +63,11 @@ boolean CSynthConfig::Load (void) assert (m_pPatch[i] != 0); } - return m_VelocityCurve.Load (); + boolean bOK = m_VelocityCurve.Load (); + + bOK = m_MIDICCMap.Load () && bOK; + + return bOK; } unsigned CSynthConfig::GetActivePatchNumber (void) const @@ -94,3 +99,8 @@ u8 CSynthConfig::MapVelocity (u8 ucVelocity) const { return m_VelocityCurve.MapVelocity (ucVelocity); } + +TSynthParameter CSynthConfig::MapMIDICC (u8 ucMIDICC) const +{ + return m_MIDICCMap.Map (ucMIDICC); +} diff --git a/src/synthconfig.h b/src/synthconfig.h index 3efee24..1611fbe 100644 --- a/src/synthconfig.h +++ b/src/synthconfig.h @@ -4,7 +4,7 @@ // Container for global configuration and all patches // // MiniSynth Pi - A virtual analogue synthesizer for Raspberry Pi -// Copyright (C) 2017-2020 R. Stange +// Copyright (C) 2017-2021 R. Stange // // 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 @@ -25,6 +25,7 @@ #include #include "patch.h" #include "velocitycurve.h" +#include "midiccmap.h" #include "config.h" class CSynthConfig @@ -47,6 +48,7 @@ class CSynthConfig CPatch *GetPatch (unsigned nPatch); u8 MapVelocity (u8 ucVelocity) const; + TSynthParameter MapMIDICC (u8 ucMIDICC) const; private: FATFS *m_pFileSystem; @@ -55,6 +57,7 @@ class CSynthConfig unsigned m_nActivePatch; CVelocityCurve m_VelocityCurve; + CMIDICCMap m_MIDICCMap; }; #endif