added Midi NRPN

This commit is contained in:
2026-05-09 20:37:17 +02:00
parent 6be1b4a911
commit 8ce2db511b
5 changed files with 243 additions and 86 deletions
+33 -18
View File
@@ -896,22 +896,16 @@ void JaySynth::handlePitchWheel (const int midiChannel, const int wheelValue)
} }
void JaySynth::handleController (const int midiChannel, void JaySynth::handleController (const midiCC_info_t &midiCC_info)
const int controllerNumber,
const int controllerValue)
{ {
midiCC_info.channel = midiChannel; last_midiCC_info[midiCC_info.ID] = midiCC_info;
midiCC_info.ID = controllerNumber; listeners.call (&JaySynthListener::synthChanged, SYNTH_CHANGED_MIDICC, (midiCC_info_t*)&midiCC_info);
midiCC_info.value = (synth_float_t)controllerValue/127;
last_midiCC_info[controllerNumber] = midiCC_info;
listeners.call (&JaySynthListener::synthChanged, SYNTH_CHANGED_MIDICC, &midiCC_info);
switch (controllerNumber) switch (midiCC_info.ID)
{ {
case 0x40: handleSustainPedal (midiChannel, controllerValue >= 64); break; case 0x40: handleSustainPedal (midiCC_info.channel, midiCC_info.value_raw >= 64); break;
case 0x42: handleSostenutoPedal (midiChannel, controllerValue >= 64); break; case 0x42: handleSostenutoPedal (midiCC_info.channel, midiCC_info.value_raw >= 64); break;
case 0x43: handleSoftPedal (midiChannel, controllerValue >= 64); break; case 0x43: handleSoftPedal (midiCC_info.channel, midiCC_info.value_raw >= 64); break;
default: break; default: break;
} }
@@ -921,8 +915,8 @@ void JaySynth::handleController (const int midiChannel,
{ {
JaySynthVoice* const voice = voices.getUnchecked (i); JaySynthVoice* const voice = voices.getUnchecked (i);
if (midiChannel <= 0 || voice->isPlayingChannel (midiChannel)) if (midiCC_info.channel <= 0 || voice->isPlayingChannel (midiCC_info.channel))
voice->controllerMoved (controllerNumber, controllerValue); voice->controllerMoved (midiCC_info.ID, midiCC_info.value_raw);
} }
} }
@@ -1096,9 +1090,30 @@ void JaySynth::handleMidiEvent (const MidiMessage& m)
} }
if (m.isController()) if (m.isController())
{ {
handleController (m.getChannel(), midiCC_info_t midiCC_info;
m.getControllerNumber(), midiCC_info.channel = m.getChannel();
m.getControllerValue()); midiCC_info.ID = m.getControllerNumber();
midiCC_info.type = MIDI_CONTROLLER_TYPE_CC;
midiCC_info.value_raw = m.getControllerValue();
midiCC_info.value = (synth_float_t)midiCC_info.value_raw/127;
SynthDebug("CC: controllerNumber=%d, controllerValue=%d", midiCC_info.ID, midiCC_info.value_raw);
bool isNrpnProcessing = mMidiNrpn.process(midiCC_info.ID, midiCC_info.value_raw);
if (mMidiNrpn.isValue())
{
midiCC_info.ID = mMidiNrpn.getCommand();
midiCC_info.type = MIDI_CONTROLLER_TYPE_NRPN;
midiCC_info.value_raw = mMidiNrpn.consumeValue();
midiCC_info.value = (synth_float_t)midiCC_info.value_raw/1000;
SynthDebug("NRPN: controllerNumber=%d, controllerValue=%d", midiCC_info.ID, midiCC_info.value_raw);
}
if (!isNrpnProcessing)
{
handleController (midiCC_info);
}
} }
if (m.isMidiMachineControlMessage()) if (m.isMidiMachineControlMessage())
{ {
+81 -68
View File
@@ -16,6 +16,7 @@
#include "JaySynthVoice.h" #include "JaySynthVoice.h"
#include "JaySynthMonophonicMGR.h" #include "JaySynthMonophonicMGR.h"
#include "JaySynthMidiCC.h" #include "JaySynthMidiCC.h"
#include "MidiNrpn.h"
#define GET_NUM_VOICES max_num_voices #define GET_NUM_VOICES max_num_voices
@@ -46,7 +47,83 @@ private:
class JaySynth : public Synthesiser class JaySynth : public Synthesiser
{ {
public: public:
JaySynth(int num_voices, String pathToWaves); enum
{
SYNTH_PER_VOICE_CONTROL_VELKEY = 0,
SYNTH_PER_VOICE_CONTROL_SIZE
};
enum
{
SYNTH_CHANGED_PARAM = 0,
SYNTH_CHANGED_MIDICC,
SYNTH_CHANGED_NUM_VOICES_PLAYING,
SYNTH_CHANGED_NOTE_PRESSED,
SYNTH_CHANGED_NOTE_RELEASED,
SYNTH_CHANGED_MIDICLOCK,
SYNTH_CHANGED_SIZE
};
enum
{
MIDI_CONTROLLER_TYPE_CC = 0,
MIDI_CONTROLLER_TYPE_NRPN,
MIDI_CONTROLLER_TYPE_RPN,
MIDI_CONTROLLER_TYPE_SIZE
};
typedef struct _smidiCC_info_t
{
int type;
int channel;
int ID;
int value_raw;
synth_float_t value;
} midiCC_info_t;
typedef struct _smidi_note_info_t
{
int note;
synth_float_t velocity;
} midi_note_info_t;
typedef struct _smidi_quarter_clock_info_t
{
uint32_t type;
uint32_t bpm;
} midi_quarter_clock_info_t;
midiCC_info_t* getLastMidiCC_infos(void)
{
return last_midiCC_info;
}
midiCC_info_t* getLastMidiCC_info(int controllerID)
{
if (controllerID < NUM_MIDI_CONTROLLERS)
return &last_midiCC_info[controllerID];
return NULL;
}
midi_note_info_t* getLastMidiNote_infos()
{
return &last_midi_note_info;
}
void setMidiCC_editBuffer(JaySynthMidiCC *pMidiCC)
{
pMidCC_editBuffer = pMidiCC;
}
typedef struct _sper_voice_control_t
{
synth_float_t ctrl[SYNTH_PER_VOICE_CONTROL_SIZE][SYNTH_NUM_PARAMS];
} per_voice_control_t;
JaySynth(int num_voices, String pathToWaves);
~JaySynth(); ~JaySynth();
void setSampleRate (synth_float_t sampleRate); void setSampleRate (synth_float_t sampleRate);
void setBufsize (int bufsize); void setBufsize (int bufsize);
@@ -59,7 +136,8 @@ public:
synth_float_t getVolume(void); synth_float_t getVolume(void);
int lastPitchWheelValue, lastmidiChannel; int lastPitchWheelValue, lastmidiChannel;
void handlePitchWheel (int midiChannel, int wheelValue); void handlePitchWheel (int midiChannel, int wheelValue);
void handleController (int midiChannel, int controllerNumber, int controllerValue); void handleController (int midiChannel, int controllerNumber, int controllerValue) {}
void handleController (const midiCC_info_t &midiCC_info);
void updateParameters(void); void updateParameters(void);
void updateParameter(int paramID); void updateParameter(int paramID);
void humanizeModeChanged(void); void humanizeModeChanged(void);
@@ -147,72 +225,6 @@ public:
listeners.add (listener); listeners.add (listener);
} }
enum
{
SYNTH_PER_VOICE_CONTROL_VELKEY = 0,
SYNTH_PER_VOICE_CONTROL_SIZE
};
enum
{
SYNTH_CHANGED_PARAM = 0,
SYNTH_CHANGED_MIDICC,
SYNTH_CHANGED_NUM_VOICES_PLAYING,
SYNTH_CHANGED_NOTE_PRESSED,
SYNTH_CHANGED_NOTE_RELEASED,
SYNTH_CHANGED_MIDICLOCK,
SYNTH_CHANGED_SIZE
};
typedef struct _smidiCC_info_t
{
int channel;
int ID;
synth_float_t value;
} midiCC_info_t;
typedef struct _smidi_note_info_t
{
int note;
synth_float_t velocity;
} midi_note_info_t;
typedef struct _smidi_quarter_clock_info_t
{
uint32_t type;
uint32_t bpm;
} midi_quarter_clock_info_t;
midiCC_info_t* getLastMidiCC_infos(void)
{
return last_midiCC_info;
}
midiCC_info_t* getLastMidiCC_info(int controllerID)
{
if (controllerID < NUM_MIDI_CONTROLLERS)
return &last_midiCC_info[controllerID];
return NULL;
}
midi_note_info_t* getLastMidiNote_infos()
{
return &last_midi_note_info;
}
void setMidiCC_editBuffer(JaySynthMidiCC *pMidiCC)
{
pMidCC_editBuffer = pMidiCC;
}
typedef struct _sper_voice_control_t
{
synth_float_t ctrl[SYNTH_PER_VOICE_CONTROL_SIZE][SYNTH_NUM_PARAMS];
} per_voice_control_t;
//============================================================================== //==============================================================================
private: private:
@@ -263,6 +275,7 @@ private:
bool m_isMidiClockStarted; bool m_isMidiClockStarted;
void updateMidiTiming(const MidiMessage& m); void updateMidiTiming(const MidiMessage& m);
MidiNrpn mMidiNrpn;
}; };
+98
View File
@@ -0,0 +1,98 @@
#include "MidiNrpn.h"
#include "synth/synth_types.h"
MidiNrpn::MidiNrpn()
: mState(0)
, mCommand(0)
, mValue(0)
{
}
MidiNrpn::~MidiNrpn()
{
}
void MidiNrpn::reset()
{
mState = 0;
}
bool MidiNrpn::isCommand()
{
return mState >= 2;
}
int MidiNrpn::getCommand()
{
if (!isCommand())
{
return -1;
}
return mCommand;
}
bool MidiNrpn::isValue()
{
return mState == 4;
}
int MidiNrpn::consumeValue()
{
if (!isValue())
{
return -1;
}
mState = 2;
return mValue;
}
bool MidiNrpn::process(uint8_t controllerNumber, uint8_t controllerValue)
{
bool isNrpnProcessing = false;
int state_nxt = mState;
switch (mState)
{
case 1:
if (controllerNumber == 98)
{
state_nxt = 2;
mCommand |= (uint16_t)controllerValue & 0x00FF;
isNrpnProcessing = true;
}
break;
case 2:
if (controllerNumber == 6)
{
state_nxt = 3;
mValue = (uint16_t)controllerValue << 8 & 0xFF00;
isNrpnProcessing = true;
}
break;
case 3:
if (controllerNumber == 38)
{
state_nxt = 4;
mValue |= (uint16_t)controllerValue & 0x00FF;
}
break;
default:
break;
}
if (controllerNumber == 99)
{
state_nxt = 1;
mCommand = (uint16_t)controllerValue << 8 & 0xFF00;
isNrpnProcessing = true;
}
mState = state_nxt;
return isNrpnProcessing;
}
+30
View File
@@ -0,0 +1,30 @@
// MidiNrpn.h
#ifndef _MIDI_NRPN_H_
#define _MIDI_NRPN_H_
#include <stdint.h>
class MidiNrpn
{
public:
MidiNrpn();
~MidiNrpn();
void reset();
bool isCommand();
int getCommand();
bool isValue();
int consumeValue();
bool process(uint8_t controllerNumber, uint8_t controllerValue);
private:
int mState;
int mCommand;
int mValue;
};
#endif //_MIDI_NRPN_H_
+1
View File
@@ -13,3 +13,4 @@ CXX_SRCS += PluginProcessor.cpp
CXX_SRCS += VelKey_PopUp.cpp CXX_SRCS += VelKey_PopUp.cpp
CXX_SRCS += JaySynth.cpp CXX_SRCS += JaySynth.cpp
CXX_SRCS += JK_MidiClock.cpp CXX_SRCS += JK_MidiClock.cpp
CXX_SRCS += MidiNrpn.cpp