- prepared Midiclock sync of voices
- buttonLed has flash() has brightness git-svn-id: http://moon:8086/svn/software/trunk/projects/JaySynth@716 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
@@ -197,7 +197,7 @@ void ButtonLED::paintButton (Graphics& g, bool /*isMouseOverButton*/, bool /*isB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ButtonLED::flash(uint32_t duration_ms)
|
void ButtonLED::flash(uint32_t duration_ms, uint32_t brighness)
|
||||||
{
|
{
|
||||||
setToggleState(true, juce::NotificationType::dontSendNotification);
|
setToggleState(true, juce::NotificationType::dontSendNotification);
|
||||||
startTimer((uint32_t)duration_ms);
|
startTimer((uint32_t)duration_ms);
|
||||||
|
|||||||
+1
-1
@@ -49,7 +49,7 @@ public:
|
|||||||
void clicked(const ModifierKeys &modifiers);
|
void clicked(const ModifierKeys &modifiers);
|
||||||
void mouseWheelMove(const MouseEvent &event, const MouseWheelDetails &wheel);
|
void mouseWheelMove(const MouseEvent &event, const MouseWheelDetails &wheel);
|
||||||
void timerCallback();
|
void timerCallback();
|
||||||
void flash(uint32_t duration_ms);
|
void flash(uint32_t duration_ms, uint32_t brightness);
|
||||||
void setTriggeredOnMouseDown (bool triggeredOnMouseDown);
|
void setTriggeredOnMouseDown (bool triggeredOnMouseDown);
|
||||||
bool getClickingTogglesState (void);
|
bool getClickingTogglesState (void);
|
||||||
void setClickingTogglesState (bool clickingTogglesState);
|
void setClickingTogglesState (bool clickingTogglesState);
|
||||||
|
|||||||
+102
-49
@@ -123,11 +123,10 @@ JaySynth::JaySynth (int num_voices, String pathToWaves)
|
|||||||
m_ppAudioThread[i]->startThread (12);
|
m_ppAudioThread[i]->startThread (12);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_clockdiv = 0;
|
m_clock_cnt_bar = 0;
|
||||||
m_lastTime_ms = 0;
|
m_lastTime_ms = 0;
|
||||||
m_lastTimeError_ms = 0;
|
|
||||||
m_estimatedTime_ms = 0;
|
m_estimatedTime_ms = 0;
|
||||||
|
m_isMidiClockStarted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
JaySynth::~JaySynth()
|
JaySynth::~JaySynth()
|
||||||
@@ -1022,26 +1021,39 @@ void JaySynth::renderNextBlock (AudioSampleBuffer& outputBuffer,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JaySynth::updateMidiTiming(const MidiMessage& m)
|
||||||
|
{
|
||||||
|
// Quarter clock generation
|
||||||
|
int nom;
|
||||||
|
int denom;
|
||||||
|
m.getTimeSignatureInfo(nom, denom);
|
||||||
|
|
||||||
|
m_numMidiClocksPerBeat = m_numMidiclocksPerFourQuarterBeats/denom;
|
||||||
|
m_numMidiClocksPerBar = nom*m_numMidiClocksPerBeat;
|
||||||
|
}
|
||||||
|
|
||||||
void JaySynth::handleMidiEvent (const MidiMessage& m)
|
void JaySynth::handleMidiEvent (const MidiMessage& m)
|
||||||
{
|
{
|
||||||
|
updateMidiTiming(m);
|
||||||
|
|
||||||
if (m.isNoteOn())
|
if (m.isNoteOn())
|
||||||
{
|
{
|
||||||
noteOn (m.getChannel(),
|
noteOn (m.getChannel(),
|
||||||
m.getNoteNumber(),
|
m.getNoteNumber(),
|
||||||
m.getFloatVelocity());
|
m.getFloatVelocity());
|
||||||
}
|
}
|
||||||
else if (m.isNoteOff())
|
if (m.isNoteOff())
|
||||||
{
|
{
|
||||||
noteOff (m.getChannel(),
|
noteOff (m.getChannel(),
|
||||||
m.getNoteNumber(),
|
m.getNoteNumber(),
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
else if (m.isAllNotesOff() || m.isAllSoundOff())
|
if (m.isAllNotesOff() || m.isAllSoundOff())
|
||||||
{
|
{
|
||||||
allNotesOff (m.getChannel(), true);
|
allNotesOff (m.getChannel(), true);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (m.isPitchWheel())
|
if (m.isPitchWheel())
|
||||||
{
|
{
|
||||||
const int channel = m.getChannel();
|
const int channel = m.getChannel();
|
||||||
const int wheelPos = m.getPitchWheelValue();
|
const int wheelPos = m.getPitchWheelValue();
|
||||||
@@ -1049,80 +1061,121 @@ void JaySynth::handleMidiEvent (const MidiMessage& m)
|
|||||||
|
|
||||||
handlePitchWheel (channel, wheelPos);
|
handlePitchWheel (channel, wheelPos);
|
||||||
}
|
}
|
||||||
else if (m.isController())
|
if (m.isController())
|
||||||
{
|
{
|
||||||
handleController (m.getChannel(),
|
handleController (m.getChannel(),
|
||||||
m.getControllerNumber(),
|
m.getControllerNumber(),
|
||||||
m.getControllerValue());
|
m.getControllerValue());
|
||||||
}
|
}
|
||||||
else if (m.isMidiMachineControlMessage())
|
if (m.isMidiMachineControlMessage())
|
||||||
{
|
{
|
||||||
SynthDebug("MidiMachineControlMessage(%08X)\n", m.getMidiMachineControlCommand());
|
SynthDebug("MidiMachineControlMessage(%08X)\n", m.getMidiMachineControlCommand());
|
||||||
}
|
}
|
||||||
else if (m.isTempoMetaEvent())
|
if (m.isTempoMetaEvent())
|
||||||
{
|
{
|
||||||
SynthDebug("TempoMetaEvent\n");
|
SynthDebug("TempoMetaEvent\n");
|
||||||
}
|
}
|
||||||
else if (m.isMidiStart())
|
if (m.isTimeSignatureMetaEvent())
|
||||||
|
{
|
||||||
|
int nom;
|
||||||
|
int denom;
|
||||||
|
|
||||||
|
m.getTimeSignatureInfo(nom, denom);
|
||||||
|
|
||||||
|
SynthDebug("isTimeSignatureMetaEvent\n");
|
||||||
|
SynthDebug("Time signature %d/%d\n", nom, denom);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (m.isMidiStart())
|
||||||
{
|
{
|
||||||
SynthDebug("MidiStart\n");
|
SynthDebug("MidiStart\n");
|
||||||
|
m_isMidiClockStarted = true;
|
||||||
}
|
}
|
||||||
else if (m.isMidiContinue())
|
if (m.isMidiContinue())
|
||||||
{
|
{
|
||||||
SynthDebug("MidiContinue\n");
|
SynthDebug("MidiContinue\n");
|
||||||
|
m_isMidiClockStarted = true;
|
||||||
}
|
}
|
||||||
else if (m.isMidiStop())
|
if (m.isMidiStop())
|
||||||
{
|
{
|
||||||
SynthDebug("MidiStop\n");
|
SynthDebug("MidiStop\n");
|
||||||
|
m_isMidiClockStarted = false;
|
||||||
}
|
}
|
||||||
else if (m.isMidiClock())
|
if (m.isSongPositionPointer())
|
||||||
{
|
|
||||||
const double alpha_1 = 1.0;
|
|
||||||
const double alpha_2 = 1.0/48;
|
|
||||||
const double currTime_ms = juce::Time::getMillisecondCounterHiRes();
|
|
||||||
|
|
||||||
double deltaTime_ms = currTime_ms - m_lastTime_ms;
|
|
||||||
|
|
||||||
if (m_lastTime_ms)
|
|
||||||
{
|
|
||||||
double timeError_ms = deltaTime_ms - m_estimatedTime_ms;
|
|
||||||
m_lastTimeError_ms = (1-alpha_1)*m_lastTimeError_ms + alpha_1*timeError_ms;
|
|
||||||
|
|
||||||
if (std::abs(timeError_ms) > 5.0)
|
|
||||||
{
|
|
||||||
m_estimatedTime_ms = deltaTime_ms;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_estimatedTime_ms = m_estimatedTime_ms + alpha_2*(m_lastTimeError_ms);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_lastTime_ms = currTime_ms;
|
|
||||||
if (!m_clockdiv)
|
|
||||||
{
|
|
||||||
uint32_t dT = (uint32_t)(24*m_estimatedTime_ms + 0.5);
|
|
||||||
listeners.call (&JaySynthListener::synthChanged, SYNTH_CHANGED_MIDICLOCK, &dT);
|
|
||||||
m_clockdiv = 24;
|
|
||||||
}
|
|
||||||
m_clockdiv--;
|
|
||||||
}
|
|
||||||
else if (m.isSongPositionPointer())
|
|
||||||
{
|
{
|
||||||
SynthDebug("SongPositionPointer\n");
|
SynthDebug("SongPositionPointer\n");
|
||||||
m_clockdiv = (6 * m.getSongPositionPointerMidiBeat()) % 24;
|
m_clock_cnt_bar = (6 * m.getSongPositionPointerMidiBeat()) % m_numMidiClocksPerBar;
|
||||||
|
SynthDebug("getSongPositionPointerMidiBeat(): %u -> %u clocks\n", m.getSongPositionPointerMidiBeat(), m_clock_cnt_bar);
|
||||||
|
m_lastTime_ms = 0;
|
||||||
}
|
}
|
||||||
else if (m.isQuarterFrame())
|
if (m.isQuarterFrame())
|
||||||
{
|
{
|
||||||
SynthDebug("QuarterFrame\n");
|
SynthDebug("QuarterFrame\n");
|
||||||
}
|
}
|
||||||
else if (m.isFullFrame())
|
if (m.isFullFrame())
|
||||||
{
|
{
|
||||||
SynthDebug("FullFrame\n");
|
SynthDebug("FullFrame\n");
|
||||||
}
|
}
|
||||||
else
|
if (m.isTempoMetaEvent())
|
||||||
{
|
{
|
||||||
SynthDebug("Unknown\n");
|
SynthDebug("TempoMetaEvent = %f\n", m.getTempoSecondsPerQuarterNote());
|
||||||
|
SynthDebug("TimeStamp = %f\n", m.getTimeStamp());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (m.isMidiClock())
|
||||||
|
{
|
||||||
|
const double alpha_1 = 2.0/m_numMidiclocksPerQuarterNote;
|
||||||
|
const double currTime_ms = juce::Time::getMillisecondCounterHiRes();
|
||||||
|
|
||||||
|
// BPM Estimation
|
||||||
|
double deltaTime_ms = currTime_ms - m_lastTime_ms;
|
||||||
|
if (m_lastTime_ms)
|
||||||
|
{
|
||||||
|
m_estimatedTime_ms = (1.0-alpha_1)*m_estimatedTime_ms + alpha_1*deltaTime_ms;
|
||||||
|
voiceSetMidiBpm(m_lastTime_ms*m_numMidiclocksPerQuarterNote);
|
||||||
|
}
|
||||||
|
m_lastTime_ms = currTime_ms;
|
||||||
|
|
||||||
|
// Quarter clock generation
|
||||||
|
m_clock_cnt_bar = m_clock_cnt_bar % m_numMidiClocksPerBar;
|
||||||
|
if (m_clock_cnt_bar % m_numMidiClocksPerBeat == 0)
|
||||||
|
{
|
||||||
|
// Send quarter pulse with current BPM estimation
|
||||||
|
midi_quarter_clock_info_t info;
|
||||||
|
|
||||||
|
info.bpm = (uint32_t)(m_numMidiclocksPerQuarterNote*m_estimatedTime_ms + 0.5);
|
||||||
|
info.type = 1;
|
||||||
|
if (m_clock_cnt_bar == 0)
|
||||||
|
{
|
||||||
|
info.type = 2;
|
||||||
|
}
|
||||||
|
if (m_isMidiClockStarted)
|
||||||
|
{
|
||||||
|
listeners.call (&JaySynthListener::synthChanged, SYNTH_CHANGED_MIDICLOCK, &info);
|
||||||
|
}
|
||||||
|
voiceSetMidiBeat(m_clock_cnt_bar);
|
||||||
|
}
|
||||||
|
m_clock_cnt_bar++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JaySynth::voiceSetMidiBpm(synth_float_t bpm)
|
||||||
|
{
|
||||||
|
for (int i=0; i < max_num_voices; i++)
|
||||||
|
{
|
||||||
|
JaySynthVoice* const voice = voices.getUnchecked (i);
|
||||||
|
voice->setMidiBpm(bpm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void JaySynth::voiceSetMidiBeat(int beatcount)
|
||||||
|
{
|
||||||
|
for (int i=0; i < max_num_voices; i++)
|
||||||
|
{
|
||||||
|
JaySynthVoice* const voice = voices.getUnchecked (i);
|
||||||
|
voice->setMidiBeat(beatcount);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|||||||
+15
-3
@@ -87,6 +87,8 @@ public:
|
|||||||
const float velocity, bool doTrigger);
|
const float velocity, bool doTrigger);
|
||||||
|
|
||||||
void Voicestop (JaySynthVoice* voice, const bool allowTailOff);
|
void Voicestop (JaySynthVoice* voice, const bool allowTailOff);
|
||||||
|
void voiceSetMidiBpm(synth_float_t bpm);
|
||||||
|
void voiceSetMidiBeat(int beatcount);
|
||||||
int getNumVoicesPlaying (SynthesiserSound* soundToPlay);
|
int getNumVoicesPlaying (SynthesiserSound* soundToPlay);
|
||||||
|
|
||||||
void clearKeysPressed(void);
|
void clearKeysPressed(void);
|
||||||
@@ -175,6 +177,12 @@ public:
|
|||||||
|
|
||||||
} midi_note_info_t;
|
} 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)
|
midiCC_info_t* getLastMidiCC_infos(void)
|
||||||
{
|
{
|
||||||
return last_midiCC_info;
|
return last_midiCC_info;
|
||||||
@@ -246,11 +254,15 @@ private:
|
|||||||
JaySynthThread **m_ppAudioThread;
|
JaySynthThread **m_ppAudioThread;
|
||||||
WaitableEvent **m_ppEventAudioThreadRdy;
|
WaitableEvent **m_ppEventAudioThreadRdy;
|
||||||
JaySynthMonophonicMGR m_monoMGR;
|
JaySynthMonophonicMGR m_monoMGR;
|
||||||
uint32_t m_clockdiv;
|
const int m_numMidiclocksPerQuarterNote = 24;
|
||||||
|
const int m_numMidiclocksPerFourQuarterBeats = 4*m_numMidiclocksPerQuarterNote;
|
||||||
|
int m_clock_cnt_bar;
|
||||||
|
int m_numMidiClocksPerBeat;
|
||||||
|
int m_numMidiClocksPerBar;
|
||||||
double m_lastTime_ms;
|
double m_lastTime_ms;
|
||||||
double m_lastTimeError_ms;
|
|
||||||
double m_estimatedTime_ms;
|
double m_estimatedTime_ms;
|
||||||
|
bool m_isMidiClockStarted;
|
||||||
|
void updateMidiTiming(const MidiMessage& m);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5111,9 +5111,9 @@ void JaySynthAudioProcessorEditor::actionListenerCallback (const String &message
|
|||||||
|
|
||||||
case JaySynthActionListener::JAYSYNTH_CHANGED_MIDICLOCK:
|
case JaySynthActionListener::JAYSYNTH_CHANGED_MIDICLOCK:
|
||||||
{
|
{
|
||||||
uint32_t deltaTime_ms;
|
uint32_t deltaTime_ms = spa.getValue("deltatime", "-1").getIntValue();
|
||||||
deltaTime_ms = spa.getValue("value", "-1").getIntValue();
|
uint32_t brightness = spa.getValue("brightness", "-1").getIntValue();
|
||||||
m_btn_midiClockLed->flash(100);
|
m_btn_midiClockLed->flash(brightness*50, brightness);
|
||||||
uint32_t bpm = (uint32_t)(60*1000.0/deltaTime_ms + 0.5);
|
uint32_t bpm = (uint32_t)(60*1000.0/deltaTime_ms + 0.5);
|
||||||
m_labelDebug->setText(String("BPM = ") + String(bpm), juce::NotificationType::dontSendNotification);
|
m_labelDebug->setText(String("BPM = ") + String(bpm), juce::NotificationType::dontSendNotification);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,19 @@ public:
|
|||||||
currentlyPlayingSound = nullptr;
|
currentlyPlayingSound = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setMidiBpm(synth_float_t bpm)
|
||||||
|
{
|
||||||
|
LFO_Param2Set(&m_pVoice->lfo[0], LFO_PARAM2_FREQ, 1.0/bpm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMidiBeat(int beatCounter)
|
||||||
|
{
|
||||||
|
if (beatCounter == 0)
|
||||||
|
{
|
||||||
|
LFO_Reset(&m_pVoice->lfo[0], 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class JaySynth;
|
friend class JaySynth;
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ void JaySynthAudioProcessor::synthChanged(int type, void *pData)
|
|||||||
{
|
{
|
||||||
JaySynth::midiCC_info_t *pMidiCC_info;
|
JaySynth::midiCC_info_t *pMidiCC_info;
|
||||||
JaySynth::midi_note_info_t *pMidi_note_info;
|
JaySynth::midi_note_info_t *pMidi_note_info;
|
||||||
|
JaySynth::midi_quarter_clock_info_t *pMidi_quarter_info;
|
||||||
|
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
@@ -167,8 +168,9 @@ void JaySynthAudioProcessor::synthChanged(int type, void *pData)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case JaySynth::SYNTH_CHANGED_MIDICLOCK:
|
case JaySynth::SYNTH_CHANGED_MIDICLOCK:
|
||||||
|
pMidi_quarter_info = (JaySynth::midi_quarter_clock_info_t*)pData;
|
||||||
if (getEditor(this) != NULL)
|
if (getEditor(this) != NULL)
|
||||||
actionListener.callMidiClock(*((uint32_t*)pData));
|
actionListener.callMidiClock(pMidi_quarter_info->bpm, pMidi_quarter_info->type);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -113,12 +113,14 @@ public:
|
|||||||
sendActionMessage(s);
|
sendActionMessage(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void callMidiClock (uint32_t deltaTime_ms)
|
void callMidiClock (uint32_t deltaTime_ms, uint32_t type)
|
||||||
{
|
{
|
||||||
String s;
|
String s;
|
||||||
s = String("type=") + String(JAYSYNTH_CHANGED_MIDICLOCK);
|
s = String("type=") + String(JAYSYNTH_CHANGED_MIDICLOCK);
|
||||||
s = s + String(" ");
|
s = s + String(" ");
|
||||||
s = s + String("value=") + String(deltaTime_ms);
|
s = s + String("deltatime=") + String(deltaTime_ms);
|
||||||
|
s = s + String(" ");
|
||||||
|
s = s + String("brightness=") + String(type);
|
||||||
s = s + String(" ");
|
s = s + String(" ");
|
||||||
sendActionMessage(s);
|
sendActionMessage(s);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user