Integration finalized and stable

pull/293/head
abscisys 2 years ago
parent 4e7a6842dd
commit 1ebcd28ed7
  1. 23
      .vscode/c_cpp_properties.json
  2. 53
      build.sh
  3. 2
      make-all.sh
  4. 46
      make.sh
  5. 3
      setup.sh
  6. 26
      src/Makefile
  7. 438
      src/mididevice.cpp
  8. 593
      src/minidexed.cpp
  9. 64
      src/minidexed.h
  10. 30
      src/userinterface.cpp
  11. 5
      src/userinterface.h

@ -0,0 +1,23 @@
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE",
"ARM_ALLOW_MULTI_CORE"
],
"windowsSdkVersion": "10.0.19041.0",
"compilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.31.31103/bin/Hostx64/x64/cl.exe",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "windows-msvc-x64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}

@ -1,36 +1,47 @@
#!/bin/bash
set +x
usage()
{
# Display Help
echo "This script launch the build of the code."
echo
echo "options:"
echo "-h Print this Help."
echo "-RPI <version> Set Raspberry PI version"
echo "-clean Run clean before building"
echo "-full Run full build"
echo "-all Run the entire build"
echo " -h Print this Help."
echo " -d|--debug Set the debug mode"
echo " -RPI <version> Set Raspberry PI version"
echo " -clean Run clean before building"
echo " -full Run full build"
echo " -all Run the entire build"
}
export clean=0;
export minimal=1
export PATH=$(readlink -f ./gcc-*/bin/):$PATH
export CLEAN=0;
export INCREMENTAL_BUILD=1
while true
do
case "$1" in
-h|--help) usage ; exit 0;;
-RPI) export RPI=$2 ; shift;;
-clean) export clean=1 ; shift;;
-all) export minimal=0 ; shift;;
-h|--help) usage ; shift ; exit 0;;
-d|--debug) set -x ; shift;;
-RPI) export RPI=$2 ; shift 2;;
-clean) export CLEAN=1 ; shift;;
-all) export INCREMENTAL_BUILD=0 ; shift;;
--) shift ; break;;
*) break;;
*) if [ $1 ]
then
echo "Error processing param #$1#"
exit 1
else
break
fi;;
esac
done
if [ -z "${RPI}" ] ; then
echo "\$RPI missing, exting"
echo "\$RPI missing, exiting"
exit 1
fi
@ -46,12 +57,12 @@ if [ "${RPI}" -gt "1" ]; then
OPTIONS="${OPTIONS} -o ARM_ALLOW_MULTI_CORE"
fi
if [ ${minimal} -eq 1 ]
if [ ${INCREMENTAL_BUILD} -eq 0 ]
then
# Build circle-stdlib library
cd circle-stdlib/
if [ ${clean} -eq 1 ]
if [ ${CLEAN} -eq 1 ]
then
make mrproper || true
fi
@ -61,21 +72,21 @@ then
# Build additional libraries
cd libs/circle/addon/display/
if [ ${clean} -eq 1 ]
if [ ${CLEAN} -eq 1 ]
then
make clean || true
fi
make -j
cd ../sensor/
if [ ${clean} -eq 1 ]
if [ ${CLEAN} -eq 1 ]
then
make clean || true
fi
make -j
cd ../Properties/
if [ ${clean} -eq 1 ]
if [ ${CLEAN} -eq 1 ]
then
make clean || true
fi
@ -86,9 +97,9 @@ then
cd ..
fi
# Build MiniDexed
# Build MaxiDexed
cd src
if [ ${clean} -eq 1 ]
if [ ${CLEAN} -eq 1 ]
then
make clean || true
fi

@ -1,3 +1,3 @@
#!/bin/bash
./make.sh -RPI 4 -prepenv -sysex -zip $*
./make.sh -RPI 4 -build -boot -sysex -zip $*

@ -1,5 +1,6 @@
#!/bin/bash
set -e
set +x
# this script install the dev environment and assume that the repository is alreadw cloned
@ -16,7 +17,8 @@ usage()
echo " Set Raspberry PI version"
echo " -prepenv Prepare the development environment"
echo " -build Run build"
echo " -FETCH_SYSEX Fetch all FETCH_SYSEX"
echo " -boot Fetch boot files"
echo " -sysex Fetch all System Exclusive cartridge"
echo " -zip Create the resulting zip file"
echo " -opt Run RUN_OPTIONALITIES"
echo
@ -25,6 +27,7 @@ usage()
export RPI=4
export SETUP_ENV=0
export BUILD=0
export FETCH_BOOT=0
export CREATE_ZIP=0
export FETCH_SYSEX=0
export RUN_OPTIONALITIES=0
@ -36,12 +39,18 @@ while true ; do
-r|-RPI|--raspberrypi) export RPI=$2 ; shift 2;;
-prepenv) export SETUP_ENV=1 ; shift;;
-build) export BUILD=1 ; shift;;
-FETCH_SYSEX) export FETCH_SYSEX=1 ; shift;;
-boot) export FETCH_BOOT=1 ; shift;;
-sysex) export FETCH_SYSEX=1 ; shift;;
-zip) export CREATE_ZIP=1 ; shift;;
-opt) export RUN_OPTIONALITIES=1 ; shift;;
--) shift ; break ;;
*) break ;;
# *) echo "Internal error! Remaining params: #$*#" ; exit 1;;
*) if [ $1 ]
then
echo "Error processing param #$1#"
exit 1
else
break
fi;;
esac
done
@ -59,6 +68,10 @@ then
# Recursively pull git submodules
git submodule update --init --recursive
cd circle-stdlib/libs/circle
git checkout develop # move to develop branch
cd -
# Install toolchain
if [ "${RPI}" -gt 2 ]
then
@ -76,28 +89,27 @@ then
wget https://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-arm-none-eabi.tar.xz
fi
tar xvf gcc-arm-*-*.tar.xz
echo "Unpacking"
tar xf --checkpoint gcc-arm-*-*.tar.xz
fi
if [ ${BUILD} -eq 1 ]
then
export PATH=$(readlink -f ./gcc-*/bin/):$PATH
# Build dependencies and MiniDexed
./build.sh -clean -all
./build.sh -RPI ${RPI} -clean -all
cp ./src/kernel*.img ./kernels/
fi
if [ ${SETUP_ENV} -eq 1 ]
if [ ${FETCH_BOOT} -eq 1 ]
then
# Get Raspberry Pi boot files
cd ./circle-stdlib/libs/circle/boot
make
if [ "${RPI}" -gt 2 ]
then
# Get Raspberry Pi boot files
cd ./circle-stdlib/libs/circle/boot
make
if [ "${RPI}" -gt 2 ]
then
make armstub64
fi
cd -
make armstub64
fi
cd -
fi
if [ ${CREATE_ZIP} -eq 1 ]

@ -0,0 +1,3 @@
#!/bin/bash
./make.sh -RPI 4 -prepenv -build -boot -sysex -zip $*

@ -9,20 +9,26 @@ SYNTH_DEXED_DIR = ../Synth_Dexed/src
CMSIS_DIR = ../CMSIS_5/CMSIS
U8G2_DIR = ../u8g2
BUILD_DIR = ../build
# BUILD_DIR = ../build
MAXIDEXED_BUILD_DIR = $(BUILD_DIR)/maxi-dexed
# MAXIDEXED_BUILD_DIR = $(BUILD_DIR)/maxi-dexed
CIRCLE_STDLIB_BUILD_DIR = $(BUILD_DIR)/circle-stdlib
SYNTH_DEXED_BUILD_DIR = $(BUILD_DIR)/Synth_Dexed/src
CMSIS_BUILD_DIR = $(BUILD_DIR)/CMSIS_5/CMSIS
U8G2_BUILD_DIR = $(BUILD_DIR)/u8g2
# CIRCLE_STDLIB_BUILD_DIR = $(BUILD_DIR)/circle-stdlib
# SYNTH_DEXED_BUILD_DIR = $(BUILD_DIR)/Synth_Dexed/src
# CMSIS_BUILD_DIR = $(BUILD_DIR)/CMSIS_5/CMSIS
# U8G2_BUILD_DIR = $(BUILD_DIR)/u8g2
SOURCES = $(wildcard $(MAXIDEXED_SRC_DIR)/*.cpp)
OBJECTS = $(patsubst $(MAXIDEXED_SRC_DIR)/%.cpp,$(MAXIDEXED_BUILD_DIR)/%.o,$(SOURCES))
# SOURCES = $(wildcard $(MAXIDEXED_SRC_DIR)/*.cpp)
# OBJECTS = $(patsubst $(MAXIDEXED_SRC_DIR)/%.cpp,$(MAXIDEXED_BUILD_DIR)/%.o,$(SOURCES))
dir:
mkdir -p $(MAXIDEXED_BUILD_DIR)
# dir:
# mkdir -p $(MAXIDEXED_BUILD_DIR)
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_compressor.o effect_platervbstereo.o
# ui.o screens.o userinterfaceext.o
OPTIMIZE = -O3

@ -20,27 +20,42 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include <circle/logger.h>
#include "mididevice.h"
#include "minidexed.h"
#include "config.h"
#include <stdio.h>
#include <assert.h>
LOGMODULE ("mididevice");
#define MIDI_NOTE_OFF 0b1000
#define MIDI_NOTE_ON 0b1001
#define MIDI_AFTERTOUCH 0b1010 // TODO
#define MIDI_CONTROL_CHANGE 0b1011
#define MIDI_CC_BANK_SELECT_MSB 0 // TODO
#define MIDI_CC_MODULATION 1
#define MIDI_CC_VOLUME 7
#define MIDI_CC_BANK_SELECT_MSB 0
#define MIDI_CC_MODULATION 1
#define MIDI_CC_VOLUME 7
#define MIDI_CC_PAN_POSITION 10
#define MIDI_CC_BANK_SELECT_LSB 32
#define MIDI_CC_BANK_SUSTAIN 64
#define MIDI_CC_RESONANCE 71
#define MIDI_CC_FREQUENCY_CUTOFF 74
#define MIDI_CC_REVERB_LEVEL 91
#define MIDI_CC_DETUNE_LEVEL 94
#define MIDI_CC_ALL_SOUND_OFF 120
#define MIDI_CC_ALL_NOTES_OFF 123
#define MIDI_PROGRAM_CHANGE 0b1100
#define MIDI_PITCH_BEND 0b1110
#define MIDI_SYSTEM_EXCLUSIVE_BEGIN 0xF0
#define MIDI_SYSTEM_EXCLUSIVE_END 0xF7
#define MIDI_TIMING_CLOCK 0xF8
#define MIDI_ACTIVE_SENSING 0xFE
CMIDIDevice::TDeviceMap CMIDIDevice::s_DeviceMap;
CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig)
: m_pSynthesizer (pSynthesizer),
m_pConfig (pConfig)
@ -70,8 +85,6 @@ u8 CMIDIDevice::GetChannel (unsigned nTG) const
void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable)
{
assert (m_pSynthesizer != 0);
// The packet contents are just normal MIDI data - see
// https://www.midi.org/specifications/item/table-1-summary-of-midi-message
@ -97,113 +110,380 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
(unsigned) pMessage[0], (unsigned) pMessage[1],
(unsigned) pMessage[2]);
break;
default:
switch(pMessage[0])
{
case MIDI_SYSTEM_EXCLUSIVE_BEGIN:
printf("MIDI%u: SysEx data length: [%d]:",nCable, uint16_t(nLength));
for (uint16_t i = 0; i < nLength; i++)
{
if((i % 16) == 0)
printf("\n%04d:",i);
printf(" 0x%02x",pMessage[i]);
}
printf("\n");
break;
default:
printf("MIDI%u: Unhandled MIDI event type %0x02x\n",nCable,pMessage[0]);
}
break;
}
}
// Only for debugging:
/*
if(pMessage[0]==MIDI_SYSTEM_EXCLUSIVE_BEGIN)
{
printf("MIDI%u: SysEx data length: [%d]:",nCable, uint16_t(nLength));
for (uint16_t i = 0; i < nLength; i++)
{
if((i % 16) == 0)
printf("\n%04d:",i);
printf(" 0x%02x",pMessage[i]);
}
printf("\n");
}
*/
// Handle MIDI Thru
if (m_DeviceName.compare (m_pConfig->GetMIDIThruIn ()) == 0)
{
TDeviceMap::const_iterator Iterator;
Iterator = s_DeviceMap.find (m_pConfig->GetMIDIThruOut ());
if (Iterator != s_DeviceMap.end ())
{
Iterator->second->Send (pMessage, nLength, nCable);
}
}
if (nLength < 2)
{
LOGERR("MIDI message is shorter than 2 bytes!");
return;
}
m_MIDISpinLock.Acquire ();
u8 ucStatus = pMessage[0];
u8 ucChannel = ucStatus & 0x0F;
u8 ucType = ucStatus >> 4;
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
// GLOBAL MIDI SYSEX
if (pMessage[0] == MIDI_SYSTEM_EXCLUSIVE_BEGIN && pMessage[3] == 0x04 && pMessage[4] == 0x01 && pMessage[nLength-1] == MIDI_SYSTEM_EXCLUSIVE_END) // MASTER VOLUME
{
float32_t nMasterVolume=((pMessage[5] & 0x7c) & ((pMessage[6] & 0x7c) <<7))/(1<<14);
LOGNOTE("Master volume: %f",nMasterVolume);
m_pSynthesizer->setMasterVolume(nMasterVolume);
}
else
{
if ( m_ChannelMap[nTG] == ucChannel
|| m_ChannelMap[nTG] == OmniMode)
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
{
switch (ucType)
if (ucStatus == MIDI_SYSTEM_EXCLUSIVE_BEGIN)
{
case MIDI_NOTE_ON:
if (nLength < 3)
// MIDI SYSEX per MIDI channel
uint8_t ucSysExChannel = (pMessage[2] & 0x07);
if (m_ChannelMap[nTG] == ucSysExChannel || m_ChannelMap[nTG] == OmniMode)
{
break;
LOGNOTE("MIDI-SYSEX: channel: %u, len: %u, TG: %u",m_ChannelMap[nTG],nLength,nTG);
HandleSystemExclusive(pMessage, nLength, nCable, nTG);
}
if (pMessage[2] > 0)
}
else
{
if ( m_ChannelMap[nTG] == ucChannel
|| m_ChannelMap[nTG] == OmniMode)
{
if (pMessage[2] <= 127)
switch (ucType)
{
m_pSynthesizer->keydown (pMessage[1],
pMessage[2], nTG);
}
}
else
{
m_pSynthesizer->keyup (pMessage[1], nTG);
}
break;
case MIDI_NOTE_ON:
if (nLength < 3)
{
break;
}
case MIDI_NOTE_OFF:
if (nLength < 3)
{
break;
}
if (pMessage[2] > 0)
{
if (pMessage[2] <= 127)
{
m_pSynthesizer->keydown (pMessage[1],
pMessage[2], nTG);
}
}
else
{
m_pSynthesizer->keyup (pMessage[1], nTG);
}
break;
m_pSynthesizer->keyup (pMessage[1], nTG);
break;
case MIDI_NOTE_OFF:
if (nLength < 3)
{
break;
}
case MIDI_CONTROL_CHANGE:
if (nLength < 3)
{
break;
}
m_pSynthesizer->keyup (pMessage[1], nTG);
break;
switch (pMessage[1])
{
case MIDI_CC_MODULATION:
m_pSynthesizer->setModWheel (pMessage[2], nTG);
m_pSynthesizer->ControllersRefresh (nTG);
break;
case MIDI_CONTROL_CHANGE:
if (nLength < 3)
{
break;
}
case MIDI_CC_VOLUME:
m_pSynthesizer->SetVolume (pMessage[2], nTG);
break;
switch (pMessage[1])
{
case MIDI_CC_MODULATION:
m_pSynthesizer->setModWheel (pMessage[2], nTG);
m_pSynthesizer->ControllersRefresh (nTG);
break;
case MIDI_CC_BANK_SELECT_MSB:
{
int bank = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterVoiceBank, nTG);
bank = (pMessage[2] << 7) + (bank & 0b01111111);
m_pSynthesizer->BankSelect (bank, nTG);
}
break;
case MIDI_CC_VOLUME:
m_pSynthesizer->SetVolume (pMessage[2], nTG);
break;
case MIDI_CC_BANK_SELECT_LSB:
{
int bank = m_pSynthesizer->GetTGParameter (CMiniDexed::TGParameterVoiceBank, nTG);
bank = (bank & 0b011111110000000) + pMessage[2];
m_pSynthesizer->BankSelect (bank, nTG);
}
break;
case MIDI_CC_PAN_POSITION:
m_pSynthesizer->SetPan (pMessage[2], nTG);
break;
case MIDI_CC_BANK_SUSTAIN:
m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG);
break;
}
break;
case MIDI_CC_BANK_SELECT_MSB:
{
int nBank = m_pSynthesizer->GetTGParameter(CMiniDexed::TGParameterVoiceBank, nTG);
nBank &= 0b00000001111111; // keep the LSB and zeroes the MSB
nBank += pMessage[2] << 7;
m_pSynthesizer->BankSelect (nBank, nTG);
}
break;
case MIDI_PROGRAM_CHANGE:
m_pSynthesizer->ProgramChange (pMessage[1], nTG);
break;
case MIDI_CC_BANK_SELECT_LSB:
{
int nBank = m_pSynthesizer->GetTGParameter(CMiniDexed::TGParameterVoiceBank, nTG);
nBank &= 0b11111110000000; // keep the MSB and zeroes the LSB
nBank += pMessage[2];
m_pSynthesizer->BankSelect (nBank, nTG);
}
break;
case MIDI_PITCH_BEND: {
if (nLength < 3)
{
break;
}
case MIDI_CC_BANK_SUSTAIN:
m_pSynthesizer->setSustain (pMessage[2] >= 64, nTG);
break;
case MIDI_CC_RESONANCE:
m_pSynthesizer->SetResonance (maplong (pMessage[2], 0, 127, 0, 99), nTG);
break;
case MIDI_CC_FREQUENCY_CUTOFF:
m_pSynthesizer->SetCutoff (maplong (pMessage[2], 0, 127, 0, 99), nTG);
break;
case MIDI_CC_REVERB_LEVEL:
m_pSynthesizer->SetReverbSend (maplong (pMessage[2], 0, 127, 0, 99), nTG);
break;
case MIDI_CC_DETUNE_LEVEL:
if (pMessage[2] == 0)
{
// "0 to 127, with 0 being no celeste (detune) effect applied at all."
m_pSynthesizer->SetMasterTune (0, nTG);
}
else
{
m_pSynthesizer->SetMasterTune (maplong (pMessage[2], 1, 127, -99, 99), nTG);
}
break;
case MIDI_CC_ALL_SOUND_OFF:
m_pSynthesizer->panic (pMessage[2], nTG);
break;
case MIDI_CC_ALL_NOTES_OFF:
m_pSynthesizer->notesOff (pMessage[2], nTG);
break;
}
break;
case MIDI_PROGRAM_CHANGE:
// do program change only if enabled in config
if( m_pConfig->GetMIDIRXProgramChange() )
m_pSynthesizer->ProgramChange (pMessage[1], nTG);
break;
s16 nValue = pMessage[1];
nValue |= (s16) pMessage[2] << 7;
nValue -= 0x2000;
case MIDI_PITCH_BEND: {
if (nLength < 3)
{
break;
}
m_pSynthesizer->setPitchbend (nValue, nTG);
} break;
s16 nValue = pMessage[1];
nValue |= (s16) pMessage[2] << 7;
nValue -= 0x2000;
default:
break;
m_pSynthesizer->setPitchbend (nValue, nTG);
} break;
default:
break;
}
}
}
}
}
m_MIDISpinLock.Release ();
}
void CMIDIDevice::AddDevice (const char *pDeviceName)
{
assert (pDeviceName);
assert (m_DeviceName.empty ());
m_DeviceName = pDeviceName;
assert (!m_DeviceName.empty ());
s_DeviceMap.insert (std::pair<std::string, CMIDIDevice *> (pDeviceName, this));
}
void CMIDIDevice::HandleSystemExclusive(const uint8_t* pMessage, const size_t nLength, const unsigned nCable, const uint8_t nTG)
{
int16_t sysex_return;
sysex_return = m_pSynthesizer->checkSystemExclusive(pMessage, nLength, nTG);
LOGDBG("SYSEX handler return value: %d", sysex_return);
switch (sysex_return)
{
case -1:
LOGERR("SysEx end status byte not detected.");
break;
case -2:
LOGERR("SysEx vendor not Yamaha.");
break;
case -3:
LOGERR("Unknown SysEx parameter change.");
break;
case -4:
LOGERR("Unknown SysEx voice or function.");
break;
case -5:
LOGERR("Not a SysEx voice bulk upload.");
break;
case -6:
LOGERR("Wrong length for SysEx voice bulk upload (not 155).");
break;
case -7:
LOGERR("Checksum error for one voice.");
break;
case -8:
LOGERR("Not a SysEx bank bulk upload.");
break;
case -9:
LOGERR("Wrong length for SysEx bank bulk upload (not 4096).");
case -10:
LOGERR("Checksum error for bank.");
break;
case -11:
LOGERR("Unknown SysEx message.");
break;
case 64:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
m_pSynthesizer->setMonoMode(pMessage[5],nTG);
break;
case 65:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
m_pSynthesizer->setPitchbendRange(pMessage[5],nTG);
break;
case 66:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
m_pSynthesizer->setPitchbendStep(pMessage[5],nTG);
break;
case 67:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
m_pSynthesizer->setPortamentoMode(pMessage[5],nTG);
break;
case 68:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
m_pSynthesizer->setPortamentoGlissando(pMessage[5],nTG);
break;
case 69:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
m_pSynthesizer->setPortamentoTime(pMessage[5],nTG);
break;
case 70:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
m_pSynthesizer->setModWheelRange(pMessage[5],nTG);
break;
case 71:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
m_pSynthesizer->setModWheelTarget(pMessage[5],nTG);
break;
case 72:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
m_pSynthesizer->setFootControllerRange(pMessage[5],nTG);
break;
case 73:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
m_pSynthesizer->setFootControllerTarget(pMessage[5],nTG);
break;
case 74:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
m_pSynthesizer->setBreathControllerRange(pMessage[5],nTG);
break;
case 75:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
m_pSynthesizer->setBreathControllerTarget(pMessage[5],nTG);
break;
case 76:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
m_pSynthesizer->setAftertouchRange(pMessage[5],nTG);
break;
case 77:
LOGDBG("SysEx Function parameter change: %d Value %d",pMessage[4],pMessage[5]);
m_pSynthesizer->setAftertouchTarget(pMessage[5],nTG);
break;
case 100:
// load sysex-data into voice memory
LOGDBG("One Voice bulk upload");
m_pSynthesizer->loadVoiceParameters(pMessage,nTG);
break;
case 200:
LOGDBG("Bank bulk upload.");
//TODO: add code for storing a bank bulk upload
LOGNOTE("Currently code for storing a bulk bank upload is missing!");
break;
default:
if(sysex_return >= 300 && sysex_return < 500)
{
LOGDBG("SysEx voice parameter change: Parameter %d value: %d",pMessage[4] + ((pMessage[3] & 0x03) * 128), pMessage[5]);
m_pSynthesizer->setVoiceDataElement(pMessage[4] + ((pMessage[3] & 0x03) * 128), pMessage[5],nTG);
switch(pMessage[4] + ((pMessage[3] & 0x03) * 128))
{
case 134:
m_pSynthesizer->notesOff(0,nTG);
break;
}
}
else if(sysex_return >= 500 && sysex_return < 600)
{
LOGDBG("SysEx send voice %u request",sysex_return-500);
SendSystemExclusiveVoice(sysex_return-500, nCable, nTG);
}
break;
}
}
void CMIDIDevice::SendSystemExclusiveVoice(uint8_t nVoice, const unsigned nCable, uint8_t nTG)
{
uint8_t voicedump[163];
// Get voice sysex dump from TG
m_pSynthesizer->getSysExVoiceDump(voicedump, nTG);
TDeviceMap::const_iterator Iterator;
// send voice dump to all MIDI interfaces
for(Iterator = s_DeviceMap.begin(); Iterator != s_DeviceMap.end(); ++Iterator)
{
Iterator->second->Send (voicedump, sizeof(voicedump)*sizeof(uint8_t));
LOGDBG("Send SYSEX voice dump %u to \"%s\"",nVoice,Iterator->first.c_str());
}
}

@ -23,6 +23,7 @@
#include <circle/pwmsoundbasedevice.h>
#include <circle/i2ssoundbasedevice.h>
#include <circle/hdmisoundbasedevice.h>
#include <circle/gpiopin.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
@ -36,7 +37,9 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
CMultiCoreSupport (CMemorySystem::Get ()),
#endif
m_pConfig (pConfig),
m_UI (this, pGPIOManager, pConfig),
m_bSavePerformanceNewFile (false),
m_bSetNewPerformance (false),
m_UI (this, pGPIOManager, pI2CMaster, pConfig),
m_PerformanceConfig (pFileSystem),
m_PCKeyboard (this, pConfig),
m_SerialMIDI (this, pInterrupt, pConfig),
@ -46,9 +49,9 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
#ifdef ARM_ALLOW_MULTI_CORE
m_nActiveTGsLog2 (0),
#endif
m_GetChunkTimer ("GetChunk",
1000000U * pConfig->GetChunkSize ()/2 / pConfig->GetSampleRate ()),
m_bProfileEnabled (m_pConfig->GetProfileEnabled ())
m_GetChunkTimer ("GetChunk", 1000000U * pConfig->GetChunkSize ()/2 / pConfig->GetSampleRate ()),
m_bProfileEnabled (m_pConfig->GetProfileEnabled ()),
m_bSavePerformance (false)
{
assert (m_pConfig);
@ -62,12 +65,18 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
m_nCutoff[i] = 99;
m_nResonance[i] = 0;
m_nMIDIChannel[i] = CMIDIDevice::Disabled;
m_nPitchBendRange[i] = 2;
m_nPitchBendStep[i] = 0;
m_nPortamentoMode[i] = 0;
m_nPortamentoGlissando[i] = 0;
m_nPortamentoTime[i] = 0;
m_nNoteLimitLow[i] = 0;
m_nNoteLimitHigh[i] = 127;
m_nNoteShift[i] = 0;
m_nReverbSend[i] = 0;
m_uchOPMask[i] = 0b111111; // All operators on
m_pTG[i] = new CDexedAdapter (CConfig::MaxNotes, pConfig->GetSampleRate ());
assert (m_pTG[i]);
@ -117,6 +126,8 @@ CMiniDexed::CMiniDexed (CConfig *pConfig, CInterruptSystem *pInterrupt,
}
#endif
setMasterVolume(1.0);
// BEGIN setup tg_mixer
tg_mixer = new AudioStereoMixer<CConfig::ToneGenerators>(pConfig->GetChunkSize()/2);
// END setup tgmixer
@ -165,7 +176,7 @@ bool CMiniDexed::Initialize (void)
m_pTG[i]->setTranspose (24);
m_pTG[i]->setPBController (12, 1);
m_pTG[i]->setPBController (2, 0);
m_pTG[i]->setMWController (99, 7, 0);
tg_mixer->pan(i,mapfloat(m_nPan[i],0,127,0.0f,1.0f));
@ -176,39 +187,19 @@ bool CMiniDexed::Initialize (void)
if (m_PerformanceConfig.Load ())
{
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
{
BankSelect (m_PerformanceConfig.GetBankNumber (nTG), nTG);
ProgramChange (m_PerformanceConfig.GetVoiceNumber (nTG), nTG);
SetMIDIChannel (m_PerformanceConfig.GetMIDIChannel (nTG), nTG);
SetVolume (m_PerformanceConfig.GetVolume (nTG), nTG);
SetPan (m_PerformanceConfig.GetPan (nTG), nTG);
SetMasterTune (m_PerformanceConfig.GetDetune (nTG), nTG);
SetCutoff (m_PerformanceConfig.GetCutoff (nTG), nTG);
SetResonance (m_PerformanceConfig.GetResonance (nTG), nTG);
m_nNoteLimitLow[nTG] = m_PerformanceConfig.GetNoteLimitLow (nTG);
m_nNoteLimitHigh[nTG] = m_PerformanceConfig.GetNoteLimitHigh (nTG);
m_nNoteShift[nTG] = m_PerformanceConfig.GetNoteShift (nTG);
SetReverbSend (m_PerformanceConfig.GetReverbSend (nTG), nTG);
}
// Effects
SetParameter (ParameterCompressorEnable, m_PerformanceConfig.GetCompressorEnable () ? 1 : 0);
SetParameter (ParameterReverbEnable, m_PerformanceConfig.GetReverbEnable () ? 1 : 0);
SetParameter (ParameterReverbSize, m_PerformanceConfig.GetReverbSize ());
SetParameter (ParameterReverbHighDamp, m_PerformanceConfig.GetReverbHighDamp ());
SetParameter (ParameterReverbLowDamp, m_PerformanceConfig.GetReverbLowDamp ());
SetParameter (ParameterReverbLowPass, m_PerformanceConfig.GetReverbLowPass ());
SetParameter (ParameterReverbDiffusion, m_PerformanceConfig.GetReverbDiffusion ());
SetParameter (ParameterReverbLevel, m_PerformanceConfig.GetReverbLevel ());
LoadPerformanceParameters();
}
else
{
SetMIDIChannel (CMIDIDevice::OmniMode, 0);
}
// load performances file list, and attempt to create the performance folder
if (!m_PerformanceConfig.ListPerformances())
{
LOGERR ("Cannot create internal Performance folder, new performances can't be created");
}
// setup and start the sound device
if (!m_pSoundDevice->AllocateQueueFrames (m_pConfig->GetChunkSize ()))
{
@ -259,6 +250,25 @@ void CMiniDexed::Process (bool bPlugAndPlayUpdated)
m_UI.Process ();
if (m_bSavePerformance)
{
DoSavePerformance ();
m_bSavePerformance = false;
}
if (m_bSavePerformanceNewFile)
{
DoSavePerformanceNewFile ();
m_bSavePerformanceNewFile = false;
}
if (m_bSetNewPerformance)
{
DoSetNewPerformance ();
m_bSetNewPerformance = false;
}
if (m_bProfileEnabled)
{
m_GetChunkTimer.Dump ();
@ -352,6 +362,7 @@ void CMiniDexed::ProgramChange (unsigned nProgram, unsigned nTG)
assert (m_pTG[nTG]);
m_pTG[nTG]->loadVoiceParameters (Buffer);
m_SerialMIDI.SendSystemExclusiveVoice(nProgram,0,nTG);
m_UI.ParameterChanged ();
}
@ -433,6 +444,8 @@ void CMiniDexed::SetResonance (int nResonance, unsigned nTG)
m_UI.ParameterChanged ();
}
void CMiniDexed::SetMIDIChannel (uint8_t uchChannel, unsigned nTG)
{
assert (nTG < CConfig::ToneGenerators);
@ -521,6 +534,24 @@ void CMiniDexed::setSustain(bool sustain, unsigned nTG)
m_pTG[nTG]->setSustain (sustain);
}
void CMiniDexed::panic(uint8_t value, unsigned nTG)
{
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
if (value == 0) {
m_pTG[nTG]->panic ();
}
}
void CMiniDexed::notesOff(uint8_t value, unsigned nTG)
{
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
if (value == 0) {
m_pTG[nTG]->notesOff ();
}
}
void CMiniDexed::setModWheel (uint8_t value, unsigned nTG)
{
assert (nTG < CConfig::ToneGenerators);
@ -633,6 +664,11 @@ void CMiniDexed::SetTGParameter (TTGParameter Parameter, int nValue, unsigned nT
case TGParameterMasterTune: SetMasterTune (nValue, nTG); break;
case TGParameterCutoff: SetCutoff (nValue, nTG); break;
case TGParameterResonance: SetResonance (nValue, nTG); break;
case TGParameterPitchBendRange: setPitchbendRange (nValue, nTG); break;
case TGParameterPitchBendStep: setPitchbendStep (nValue, nTG); break;
case TGParameterPortamentoMode: setPortamentoMode (nValue, nTG); break;
case TGParameterPortamentoGlissando: setPortamentoGlissando (nValue, nTG); break;
case TGParameterPortamentoTime: setPortamentoTime (nValue, nTG); break;
case TGParameterMIDIChannel:
assert (0 <= nValue && nValue <= 255);
@ -662,6 +698,11 @@ 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 TGParameterPitchBendRange: return m_nPitchBendRange[nTG];
case TGParameterPitchBendStep: return m_nPitchBendStep[nTG];
case TGParameterPortamentoMode: return m_nPortamentoMode[nTG];
case TGParameterPortamentoGlissando: return m_nPortamentoGlissando[nTG];
case TGParameterPortamentoTime: return m_nPortamentoTime[nTG];
default:
assert (0);
@ -677,6 +718,22 @@ void CMiniDexed::SetVoiceParameter (uint8_t uchOffset, uint8_t uchValue, unsigne
if (nOP < 6)
{
if (uchOffset == DEXED_OP_ENABLE)
{
if (uchValue)
{
m_uchOPMask[nTG] |= 1 << nOP;
}
else
{
m_uchOPMask[nTG] &= ~(1 << nOP);
}
m_pTG[nTG]->setOPAll (m_uchOPMask[nTG]);
return;
}
nOP = 5 - nOP; // OPs are in reverse order
}
@ -694,6 +751,11 @@ uint8_t CMiniDexed::GetVoiceParameter (uint8_t uchOffset, unsigned nOP, unsigned
if (nOP < 6)
{
if (uchOffset == DEXED_OP_ENABLE)
{
return !!(m_uchOPMask[nTG] & (1 << nOP));
}
nOP = 5 - nOP; // OPs are in reverse order
}
@ -805,56 +867,70 @@ void CMiniDexed::ProcessSound (void)
}
// BEGIN TG mixing
for (uint8_t i = 0; i < CConfig::ToneGenerators; i++)
float32_t tmp_float[nFrames*2];
int16_t tmp_int[nFrames*2];
if(nMasterVolume > 0.0)
{
tg_mixer->doAddMix(i,m_OutputLevel[i]);
reverb_send_mixer->doAddMix(i,m_OutputLevel[i]);
}
// END TG mixing
for (uint8_t i = 0; i < CConfig::ToneGenerators; i++)
{
tg_mixer->doAddMix(i,m_OutputLevel[i]);
reverb_send_mixer->doAddMix(i,m_OutputLevel[i]);
}
// END TG mixing
// BEGIN create SampleBuffer for holding audio data
float32_t SampleBuffer[2][nFrames];
// END create SampleBuffer for holding audio data
// BEGIN create SampleBuffer for holding audio data
float32_t SampleBuffer[2][nFrames];
// END create SampleBuffer for holding audio data
// get the mix of all TGs
tg_mixer->getMix(SampleBuffer[indexL], SampleBuffer[indexR]);
// get the mix of all TGs
tg_mixer->getMix(SampleBuffer[indexL], SampleBuffer[indexR]);
// BEGIN adding reverb
if (m_nParameter[ParameterReverbEnable])
{
float32_t ReverbBuffer[2][nFrames];
float32_t ReverbSendBuffer[2][nFrames];
// BEGIN adding reverb
if (m_nParameter[ParameterReverbEnable])
{
float32_t ReverbBuffer[2][nFrames];
float32_t ReverbSendBuffer[2][nFrames];
arm_fill_f32(0.0f, ReverbBuffer[indexL], nFrames);
arm_fill_f32(0.0f, ReverbBuffer[indexR], nFrames);
arm_fill_f32(0.0f, ReverbSendBuffer[indexR], nFrames);
arm_fill_f32(0.0f, ReverbSendBuffer[indexL], nFrames);
arm_fill_f32(0.0f, ReverbBuffer[indexL], nFrames);
arm_fill_f32(0.0f, ReverbBuffer[indexR], nFrames);
arm_fill_f32(0.0f, ReverbSendBuffer[indexR], nFrames);
arm_fill_f32(0.0f, ReverbSendBuffer[indexL], nFrames);
m_ReverbSpinLock.Acquire ();
m_ReverbSpinLock.Acquire ();
reverb_send_mixer->getMix(ReverbSendBuffer[indexL], ReverbSendBuffer[indexR]);
reverb->doReverb(ReverbSendBuffer[indexL],ReverbSendBuffer[indexR],ReverbBuffer[indexL], ReverbBuffer[indexR],nFrames);
reverb_send_mixer->getMix(ReverbSendBuffer[indexL], ReverbSendBuffer[indexR]);
reverb->doReverb(ReverbSendBuffer[indexL],ReverbSendBuffer[indexR],ReverbBuffer[indexL], ReverbBuffer[indexR],nFrames);
// scale down and add left reverb buffer by reverb level
arm_scale_f32(ReverbBuffer[indexL], reverb->get_level(), ReverbBuffer[indexL], nFrames);
arm_add_f32(SampleBuffer[indexL], ReverbBuffer[indexL], SampleBuffer[indexL], nFrames);
// scale down and add right reverb buffer by reverb level
arm_scale_f32(ReverbBuffer[indexR], reverb->get_level(), ReverbBuffer[indexR], nFrames);
arm_add_f32(SampleBuffer[indexR], ReverbBuffer[indexR], SampleBuffer[indexR], nFrames);
// scale down and add left reverb buffer by reverb level
arm_scale_f32(ReverbBuffer[indexL], reverb->get_level(), ReverbBuffer[indexL], nFrames);
arm_add_f32(SampleBuffer[indexL], ReverbBuffer[indexL], SampleBuffer[indexL], nFrames);
// scale down and add right reverb buffer by reverb level
arm_scale_f32(ReverbBuffer[indexR], reverb->get_level(), ReverbBuffer[indexR], nFrames);
arm_add_f32(SampleBuffer[indexR], ReverbBuffer[indexR], SampleBuffer[indexR], nFrames);
m_ReverbSpinLock.Release ();
}
// END adding reverb
m_ReverbSpinLock.Release ();
}
// END adding reverb
// Convert dual float array (left, right) to single int16 array (left/right)
float32_t tmp_float[nFrames*2];
int16_t tmp_int[nFrames*2];
for(uint16_t i=0; i<nFrames;i++)
{
tmp_float[i*2]=SampleBuffer[indexL][i];
tmp_float[(i*2)+1]=SampleBuffer[indexR][i];
// Convert dual float array (left, right) to single int16 array (left/right)
for(uint16_t i=0; i<nFrames;i++)
{
if(nMasterVolume >0.0 && nMasterVolume <1.0)
{
tmp_float[i*2]=SampleBuffer[indexL][i] * nMasterVolume;
tmp_float[(i*2)+1]=SampleBuffer[indexR][i] * nMasterVolume;
}
else if(nMasterVolume == 1.0)
{
tmp_float[i*2]=SampleBuffer[indexL][i];
tmp_float[(i*2)+1]=SampleBuffer[indexR][i];
}
}
arm_float_to_q15(tmp_float,tmp_int,nFrames*2);
}
arm_float_to_q15(tmp_float,tmp_int,nFrames*2);
else
arm_fill_q15(0, tmp_int, nFrames * 2);
if (m_pSoundDevice->Write (tmp_int, sizeof(tmp_int)) != (int) sizeof(tmp_int))
{
@ -871,6 +947,13 @@ void CMiniDexed::ProcessSound (void)
#endif
bool CMiniDexed::SavePerformance (void)
{
m_bSavePerformance = true;
return true;
}
bool CMiniDexed::DoSavePerformance (void)
{
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
{
@ -882,10 +965,17 @@ bool CMiniDexed::SavePerformance (void)
m_PerformanceConfig.SetDetune (m_nMasterTune[nTG], nTG);
m_PerformanceConfig.SetCutoff (m_nCutoff[nTG], nTG);
m_PerformanceConfig.SetResonance (m_nResonance[nTG], nTG);
m_PerformanceConfig.SetPitchBendRange (m_nPitchBendRange[nTG], nTG);
m_PerformanceConfig.SetPitchBendStep (m_nPitchBendStep[nTG], nTG);
m_PerformanceConfig.SetPortamentoMode (m_nPortamentoMode[nTG], nTG);
m_PerformanceConfig.SetPortamentoGlissando (m_nPortamentoGlissando[nTG], nTG);
m_PerformanceConfig.SetPortamentoTime (m_nPortamentoTime[nTG], nTG);
m_PerformanceConfig.SetNoteLimitLow (m_nNoteLimitLow[nTG], nTG);
m_PerformanceConfig.SetNoteLimitHigh (m_nNoteLimitHigh[nTG], nTG);
m_PerformanceConfig.SetNoteShift (m_nNoteShift[nTG], nTG);
m_pTG[nTG]->getVoiceData(m_nRawVoiceData);
m_PerformanceConfig.SetVoiceDataToTxt (m_nRawVoiceData, nTG);
m_PerformanceConfig.SetReverbSend (m_nReverbSend[nTG], nTG);
}
@ -901,3 +991,364 @@ bool CMiniDexed::SavePerformance (void)
return m_PerformanceConfig.Save ();
}
void CMiniDexed::setMonoMode(uint8_t mono, uint8_t nTG)
{
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_pTG[nTG]->setMonoMode(constrain(mono, 0, 1));
m_pTG[nTG]->doRefreshVoice();
m_UI.ParameterChanged ();
}
void CMiniDexed::setPitchbendRange(uint8_t range, uint8_t nTG)
{
range = constrain (range, 0, 12);
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_nPitchBendRange[nTG] = range;
m_pTG[nTG]->setPitchbendRange(range);
m_pTG[nTG]->ControllersRefresh();
m_UI.ParameterChanged ();
}
void CMiniDexed::setPitchbendStep(uint8_t step, uint8_t nTG)
{
step= constrain (step, 0, 12);
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_nPitchBendStep[nTG] = step;
m_pTG[nTG]->setPitchbendStep(step);
m_pTG[nTG]->ControllersRefresh();
m_UI.ParameterChanged ();
}
void CMiniDexed::setPortamentoMode(uint8_t mode, uint8_t nTG)
{
mode= constrain (mode, 0, 1);
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_nPortamentoMode[nTG] = mode;
m_pTG[nTG]->setPortamentoMode(mode);
m_pTG[nTG]->ControllersRefresh();
m_UI.ParameterChanged ();
}
void CMiniDexed::setPortamentoGlissando(uint8_t glissando, uint8_t nTG)
{
glissando = constrain (glissando, 0, 1);
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_nPortamentoGlissando[nTG] = glissando;
m_pTG[nTG]->setPortamentoGlissando(glissando);
m_pTG[nTG]->ControllersRefresh();
m_UI.ParameterChanged ();
}
void CMiniDexed::setPortamentoTime(uint8_t time, uint8_t nTG)
{
time = constrain (time, 0, 99);
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_nPortamentoTime[nTG] = time;
m_pTG[nTG]->setPortamentoTime(time);
m_pTG[nTG]->ControllersRefresh();
m_UI.ParameterChanged ();
}
void CMiniDexed::setModWheelRange(uint8_t range, uint8_t nTG)
{
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_pTG[nTG]->setModWheelRange(constrain(range, 0, 99));
m_pTG[nTG]->ControllersRefresh();
m_UI.ParameterChanged ();
}
void CMiniDexed::setModWheelTarget(uint8_t target, uint8_t nTG)
{
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_pTG[nTG]->setModWheelTarget(constrain(target, 0, 7));
m_pTG[nTG]->ControllersRefresh();
m_UI.ParameterChanged ();
}
void CMiniDexed::setFootControllerRange(uint8_t range, uint8_t nTG)
{
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_pTG[nTG]->setFootControllerRange(constrain(range, 0, 99));
m_pTG[nTG]->ControllersRefresh();
m_UI.ParameterChanged ();
}
void CMiniDexed::setFootControllerTarget(uint8_t target, uint8_t nTG)
{
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_pTG[nTG]->setFootControllerTarget(constrain(target, 0, 7));
m_pTG[nTG]->ControllersRefresh();
m_UI.ParameterChanged ();
}
void CMiniDexed::setBreathControllerRange(uint8_t range, uint8_t nTG)
{
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_pTG[nTG]->setBreathControllerRange(constrain(range, 0, 99));
m_pTG[nTG]->ControllersRefresh();
m_UI.ParameterChanged ();
}
void CMiniDexed::setBreathControllerTarget(uint8_t target, uint8_t nTG)
{
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_pTG[nTG]->setBreathControllerTarget(constrain(target, 0, 7));
m_pTG[nTG]->ControllersRefresh();
m_UI.ParameterChanged ();
}
void CMiniDexed::setAftertouchRange(uint8_t range, uint8_t nTG)
{
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_pTG[nTG]->setAftertouchRange(constrain(range, 0, 99));
m_pTG[nTG]->ControllersRefresh();
m_UI.ParameterChanged ();
}
void CMiniDexed::setAftertouchTarget(uint8_t target, uint8_t nTG)
{
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_pTG[nTG]->setAftertouchTarget(constrain(target, 0, 7));
m_pTG[nTG]->ControllersRefresh();
m_UI.ParameterChanged ();
}
void CMiniDexed::loadVoiceParameters(const uint8_t* data, uint8_t nTG)
{
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
uint8_t voice[161];
memcpy(voice, data, sizeof(uint8_t)*161);
// fix voice name
for (uint8_t i = 0; i < 10; i++)
{
if (voice[151 + i] > 126) // filter characters
voice[151 + i] = 32;
}
m_pTG[nTG]->loadVoiceParameters(&voice[6]);
m_pTG[nTG]->doRefreshVoice();
m_UI.ParameterChanged ();
}
void CMiniDexed::setVoiceDataElement(uint8_t data, uint8_t number, uint8_t nTG)
{
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_pTG[nTG]->setVoiceDataElement(constrain(data, 0, 155),constrain(number, 0, 99));
//m_pTG[nTG]->doRefreshVoice();
m_UI.ParameterChanged ();
}
int16_t CMiniDexed::checkSystemExclusive(const uint8_t* pMessage,const uint16_t nLength, uint8_t nTG)
{
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
return(m_pTG[nTG]->checkSystemExclusive(pMessage, nLength));
}
void CMiniDexed::getSysExVoiceDump(uint8_t* dest, uint8_t nTG)
{
uint8_t checksum = 0;
uint8_t data[155];
assert (nTG < CConfig::ToneGenerators);
assert (m_pTG[nTG]);
m_pTG[nTG]->getVoiceData(data);
dest[0] = 0xF0; // SysEx start
dest[1] = 0x43; // ID=Yamaha
dest[2] = GetTGParameter(TGParameterMIDIChannel, nTG); // Sub-status and MIDI channel
dest[3] = 0x00; // Format number (0=1 voice)
dest[4] = 0x01; // Byte count MSB
dest[5] = 0x1B; // Byte count LSB
for (uint8_t n = 0; n < 155; n++)
{
checksum -= data[n];
dest[6 + n] = data[n];
}
dest[161] = checksum & 0x7f; // Checksum
dest[162] = 0xF7; // SysEx end
}
void CMiniDexed::setMasterVolume (float32_t vol)
{
if(vol < 0.0)
vol = 0.0;
else if(vol > 1.0)
vol = 1.0;
nMasterVolume=vol;
}
std::string CMiniDexed::GetPerformanceFileName(unsigned nID)
{
return m_PerformanceConfig.GetPerformanceFileName(nID);
}
std::string CMiniDexed::GetPerformanceName(unsigned nID)
{
return m_PerformanceConfig.GetPerformanceName(nID);
}
unsigned CMiniDexed::GetLastPerformance()
{
return m_PerformanceConfig.GetLastPerformance();
}
unsigned CMiniDexed::GetActualPerformanceID()
{
return m_PerformanceConfig.GetActualPerformanceID();
}
void CMiniDexed::SetActualPerformanceID(unsigned nID)
{
m_PerformanceConfig.SetActualPerformanceID(nID);
}
unsigned CMiniDexed::GetMenuSelectedPerformanceID()
{
return m_PerformanceConfig.GetMenuSelectedPerformanceID();
}
void CMiniDexed::SetMenuSelectedPerformanceID(unsigned nID)
{
m_PerformanceConfig.SetMenuSelectedPerformanceID(nID);
}
bool CMiniDexed::SetNewPerformance(unsigned nID)
{
m_bSetNewPerformance = true;
m_nSetNewPerformanceID = nID;
return true;
}
bool CMiniDexed::DoSetNewPerformance (void)
{
unsigned nID = m_nSetNewPerformanceID;
m_PerformanceConfig.SetNewPerformance(nID);
if (m_PerformanceConfig.Load ())
{
LoadPerformanceParameters();
return true;
}
else
{
SetMIDIChannel (CMIDIDevice::OmniMode, 0);
return false;
}
}
bool CMiniDexed::SavePerformanceNewFile ()
{
m_bSavePerformanceNewFile = m_PerformanceConfig.GetInternalFolderOk();
return m_bSavePerformanceNewFile;
}
bool CMiniDexed::DoSavePerformanceNewFile (void)
{
std::string nPerformanceName=""; // for future enhacements: capability to write performance name
if (m_PerformanceConfig.CreateNewPerformanceFile(nPerformanceName))
{
if(SavePerformance())
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
void CMiniDexed::LoadPerformanceParameters(void)
{
for (unsigned nTG = 0; nTG < CConfig::ToneGenerators; nTG++)
{
BankSelect (m_PerformanceConfig.GetBankNumber (nTG), nTG);
ProgramChange (m_PerformanceConfig.GetVoiceNumber (nTG), nTG);
SetMIDIChannel (m_PerformanceConfig.GetMIDIChannel (nTG), nTG);
SetVolume (m_PerformanceConfig.GetVolume (nTG), nTG);
SetPan (m_PerformanceConfig.GetPan (nTG), nTG);
SetMasterTune (m_PerformanceConfig.GetDetune (nTG), nTG);
SetCutoff (m_PerformanceConfig.GetCutoff (nTG), nTG);
SetResonance (m_PerformanceConfig.GetResonance (nTG), nTG);
setPitchbendRange (m_PerformanceConfig.GetPitchBendRange (nTG), nTG);
setPitchbendStep (m_PerformanceConfig.GetPitchBendStep (nTG), nTG);
setPortamentoMode (m_PerformanceConfig.GetPortamentoMode (nTG), nTG);
setPortamentoGlissando (m_PerformanceConfig.GetPortamentoGlissando (nTG), nTG);
setPortamentoTime (m_PerformanceConfig.GetPortamentoTime (nTG), nTG);
m_nNoteLimitLow[nTG] = m_PerformanceConfig.GetNoteLimitLow (nTG);
m_nNoteLimitHigh[nTG] = m_PerformanceConfig.GetNoteLimitHigh (nTG);
m_nNoteShift[nTG] = m_PerformanceConfig.GetNoteShift (nTG);
if(m_PerformanceConfig.VoiceDataFilled(nTG))
{
uint8_t* tVoiceData = m_PerformanceConfig.GetVoiceDataFromTxt(nTG);
m_pTG[nTG]->loadVoiceParameters(tVoiceData);
}
SetReverbSend (m_PerformanceConfig.GetReverbSend (nTG), nTG);
}
// Effects
SetParameter (ParameterCompressorEnable, m_PerformanceConfig.GetCompressorEnable () ? 1 : 0);
SetParameter (ParameterReverbEnable, m_PerformanceConfig.GetReverbEnable () ? 1 : 0);
SetParameter (ParameterReverbSize, m_PerformanceConfig.GetReverbSize ());
SetParameter (ParameterReverbHighDamp, m_PerformanceConfig.GetReverbHighDamp ());
SetParameter (ParameterReverbLowDamp, m_PerformanceConfig.GetReverbLowDamp ());
SetParameter (ParameterReverbLowPass, m_PerformanceConfig.GetReverbLowPass ());
SetParameter (ParameterReverbDiffusion, m_PerformanceConfig.GetReverbDiffusion ());
SetParameter (ParameterReverbLevel, m_PerformanceConfig.GetReverbLevel ());
}

@ -76,12 +76,47 @@ public:
void keydown (int16_t pitch, uint8_t velocity, unsigned nTG);
void setSustain (bool sustain, unsigned nTG);
void panic (uint8_t value, unsigned nTG);
void notesOff (uint8_t value, unsigned nTG);
void setModWheel (uint8_t value, unsigned nTG);
void setPitchbend (int16_t value, unsigned nTG);
void ControllersRefresh (unsigned nTG);
void SetReverbSend (unsigned nReverbSend, unsigned nTG); // 0 .. 127
void setMonoMode(uint8_t mono, uint8_t nTG);
void setPitchbendRange(uint8_t range, uint8_t nTG);
void setPitchbendStep(uint8_t step, uint8_t nTG);
void setPortamentoMode(uint8_t mode, uint8_t nTG);
void setPortamentoGlissando(uint8_t glissando, uint8_t nTG);
void setPortamentoTime(uint8_t time, uint8_t nTG);
void setModWheelRange(uint8_t range, uint8_t nTG);
void setModWheelTarget(uint8_t target, uint8_t nTG);
void setFootControllerRange(uint8_t range, uint8_t nTG);
void setFootControllerTarget(uint8_t target, uint8_t nTG);
void setBreathControllerRange(uint8_t range, uint8_t nTG);
void setBreathControllerTarget(uint8_t target, uint8_t nTG);
void setAftertouchRange(uint8_t range, uint8_t nTG);
void setAftertouchTarget(uint8_t target, uint8_t nTG);
void loadVoiceParameters(const uint8_t* data, uint8_t nTG);
void setVoiceDataElement(uint8_t data, uint8_t number, uint8_t nTG);
void getSysExVoiceDump(uint8_t* dest, uint8_t nTG);
int16_t checkSystemExclusive(const uint8_t* pMessage, const uint16_t nLength, uint8_t nTG);
std::string GetPerformanceFileName(unsigned nID);
std::string GetPerformanceName(unsigned nID);
unsigned GetLastPerformance();
unsigned GetActualPerformanceID();
void SetActualPerformanceID(unsigned nID);
bool SetNewPerformance(unsigned nID);
bool SavePerformanceNewFile ();
unsigned GetMenuSelectedPerformanceID();
void SetMenuSelectedPerformanceID(unsigned nID);
bool DoSavePerformanceNewFile (void);
bool DoSetNewPerformance (void);
enum TParameter
{
ParameterCompressorEnable,
@ -109,6 +144,11 @@ public:
TGParameterResonance,
TGParameterMIDIChannel,
TGParameterReverbSend,
TGParameterPitchBendRange,
TGParameterPitchBendStep,
TGParameterPortamentoMode,
TGParameterPortamentoGlissando,
TGParameterPortamentoTime,
TGParameterUnknown
};
@ -123,10 +163,14 @@ public:
std::string GetVoiceName (unsigned nTG);
bool SavePerformance (void);
bool DoSavePerformance (void);
void setMasterVolume (float32_t vol);
private:
int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG); // returns < 0 to ignore note
uint8_t m_uchOPMask[CConfig::ToneGenerators];
void LoadPerformanceParameters(void);
void ProcessSound (void);
#ifdef ARM_ALLOW_MULTI_CORE
@ -155,6 +199,11 @@ private:
int m_nCutoff[CConfig::ToneGenerators];
int m_nResonance[CConfig::ToneGenerators];
unsigned m_nMIDIChannel[CConfig::ToneGenerators];
unsigned m_nPitchBendRange[CConfig::ToneGenerators];
unsigned m_nPitchBendStep[CConfig::ToneGenerators];
unsigned m_nPortamentoMode[CConfig::ToneGenerators];
unsigned m_nPortamentoGlissando[CConfig::ToneGenerators];
unsigned m_nPortamentoTime[CConfig::ToneGenerators];
unsigned m_nNoteLimitLow[CConfig::ToneGenerators];
unsigned m_nNoteLimitHigh[CConfig::ToneGenerators];
@ -162,6 +211,17 @@ private:
unsigned m_nReverbSend[CConfig::ToneGenerators];
uint8_t m_nRawVoiceData[156];
bool m_bSavePerformanceNewFile;
bool m_bSetNewPerformance;
unsigned m_nSetNewPerformanceID;
float32_t nMasterVolume;
CUserInterface m_UI;
CSysExFileLoader m_SysExFileLoader;
CPerformanceConfig m_PerformanceConfig;
@ -190,6 +250,8 @@ private:
AudioStereoMixer<CConfig::ToneGenerators>* reverb_send_mixer;
CSpinLock m_ReverbSpinLock;
bool m_bSavePerformance;
};
#endif

@ -27,9 +27,10 @@
LOGMODULE ("ui");
CUserInterface::CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CConfig *pConfig)
CUserInterface::CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster, CConfig *pConfig)
: m_pMiniDexed (pMiniDexed),
m_pGPIOManager (pGPIOManager),
m_pI2CMaster (pI2CMaster),
m_pConfig (pConfig),
m_pLCD (0),
m_pLCDBuffered (0),
@ -52,14 +53,23 @@ bool CUserInterface::Initialize (void)
if (m_pConfig->GetLCDEnabled ())
{
m_pLCD = new CHD44780Device (CConfig::LCDColumns, CConfig::LCDRows,
m_pConfig->GetLCDPinData4 (),
m_pConfig->GetLCDPinData5 (),
m_pConfig->GetLCDPinData6 (),
m_pConfig->GetLCDPinData7 (),
m_pConfig->GetLCDPinEnable (),
m_pConfig->GetLCDPinRegisterSelect (),
m_pConfig->GetLCDPinReadWrite ());
unsigned i2caddr = m_pConfig->GetLCDI2CAddress ();
if (i2caddr == 0)
{
m_pLCD = new CHD44780Device (CConfig::LCDColumns, CConfig::LCDRows,
m_pConfig->GetLCDPinData4 (),
m_pConfig->GetLCDPinData5 (),
m_pConfig->GetLCDPinData6 (),
m_pConfig->GetLCDPinData7 (),
m_pConfig->GetLCDPinEnable (),
m_pConfig->GetLCDPinRegisterSelect (),
m_pConfig->GetLCDPinReadWrite ());
}
else
{
m_pLCD = new CHD44780Device (m_pI2CMaster, i2caddr,
CConfig::LCDColumns, CConfig::LCDRows);
}
assert (m_pLCD);
if (!m_pLCD->Initialize ())
@ -215,7 +225,7 @@ void CUserInterface::EncoderEventHandler (CKY040::TEvent Event)
break;
case CKY040::EventSwitchHold:
if (m_pRotaryEncoder->GetHoldSeconds () >= 10)
if (m_pRotaryEncoder->GetHoldSeconds () >= 120)
{
delete m_pLCD; // reset LCD

@ -26,13 +26,14 @@
#include <display/hd44780device.h>
#include <circle/gpiomanager.h>
#include <circle/writebuffer.h>
#include <circle/i2cmaster.h>
class CMiniDexed;
class CUserInterface
{
public:
CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CConfig *pConfig);
CUserInterface (CMiniDexed *pMiniDexed, CGPIOManager *pGPIOManager, CI2CMaster *pI2CMaster, CConfig *pConfig);
~CUserInterface (void);
bool Initialize (void);
@ -53,12 +54,14 @@ public:
private:
void LCDWrite (const char *pString); // Print to optional HD44780 display
void EncoderEventHandler (CKY040::TEvent Event);
static void EncoderEventStub (CKY040::TEvent Event, void *pParam);
private:
CMiniDexed *m_pMiniDexed;
CGPIOManager *m_pGPIOManager;
CI2CMaster *m_pI2CMaster;
CConfig *m_pConfig;
CHD44780Device *m_pLCD;

Loading…
Cancel
Save