Closes #207tags/1.9.6
@@ -29,6 +29,7 @@ public: | |||||
MidiFilePlugin(const NativeHostDescriptor* const host) | MidiFilePlugin(const NativeHostDescriptor* const host) | ||||
: NativePluginClass(host), | : NativePluginClass(host), | ||||
fMidiOut(this), | fMidiOut(this), | ||||
fNeedsAllNotesOff(false), | |||||
fWasPlayingBefore(false), | fWasPlayingBefore(false), | ||||
leakDetector_MidiFilePlugin() {} | leakDetector_MidiFilePlugin() {} | ||||
@@ -54,32 +55,35 @@ protected: | |||||
{ | { | ||||
const NativeTimeInfo* const timePos(getTimeInfo()); | const NativeTimeInfo* const timePos(getTimeInfo()); | ||||
if (timePos->playing) | |||||
if (fWasPlayingBefore != timePos->playing) | |||||
{ | { | ||||
fMidiOut.play(timePos->frame, frames); | |||||
fNeedsAllNotesOff = true; | |||||
fWasPlayingBefore = timePos->playing; | |||||
} | } | ||||
else if (fWasPlayingBefore) | |||||
if (fNeedsAllNotesOff) | |||||
{ | { | ||||
NativeMidiEvent midiEvent; | NativeMidiEvent midiEvent; | ||||
midiEvent.port = 0; | midiEvent.port = 0; | ||||
midiEvent.time = 0; | midiEvent.time = 0; | ||||
midiEvent.data[0] = MIDI_STATUS_CONTROL_CHANGE; | |||||
midiEvent.data[0] = 0; | |||||
midiEvent.data[1] = MIDI_CONTROL_ALL_NOTES_OFF; | midiEvent.data[1] = MIDI_CONTROL_ALL_NOTES_OFF; | ||||
midiEvent.data[2] = 0; | midiEvent.data[2] = 0; | ||||
midiEvent.data[3] = 0; | midiEvent.data[3] = 0; | ||||
midiEvent.size = 3; | midiEvent.size = 3; | ||||
for (int i=0; i < MAX_MIDI_CHANNELS; ++i) | |||||
for (int channel=MAX_MIDI_CHANNELS; --channel >= 0;) | |||||
{ | { | ||||
midiEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE+i); | |||||
midiEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT)); | |||||
NativePluginClass::writeMidiEvent(&midiEvent); | NativePluginClass::writeMidiEvent(&midiEvent); | ||||
} | } | ||||
carla_stdout("WAS PLAYING BEFORE, NOW STOPPED"); | |||||
fNeedsAllNotesOff = false; | |||||
} | } | ||||
fWasPlayingBefore = timePos->playing; | |||||
if (fWasPlayingBefore) | |||||
fMidiOut.play(timePos->frame, frames); | |||||
} | } | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -131,6 +135,7 @@ protected: | |||||
private: | private: | ||||
MidiPattern fMidiOut; | MidiPattern fMidiOut; | ||||
bool fNeedsAllNotesOff; | |||||
bool fWasPlayingBefore; | bool fWasPlayingBefore; | ||||
void _loadMidiFile(const char* const filename) | void _loadMidiFile(const char* const filename) | ||||
@@ -200,6 +205,8 @@ private: | |||||
fMidiOut.addRaw(static_cast<uint64_t>(time), midiMessage.getRawData(), static_cast<uint8_t>(dataSize)); | fMidiOut.addRaw(static_cast<uint64_t>(time), midiMessage.getRawData(), static_cast<uint8_t>(dataSize)); | ||||
} | } | ||||
} | } | ||||
fNeedsAllNotesOff = true; | |||||
} | } | ||||
PluginClassEND(MidiFilePlugin) | PluginClassEND(MidiFilePlugin) | ||||
@@ -32,6 +32,7 @@ public: | |||||
MidiSequencerPlugin(const NativeHostDescriptor* const host) | MidiSequencerPlugin(const NativeHostDescriptor* const host) | ||||
: NativePluginAndUiClass(host, CARLA_OS_SEP_STR "midiseq-ui"), | : NativePluginAndUiClass(host, CARLA_OS_SEP_STR "midiseq-ui"), | ||||
fNeedsAllNotesOff(false), | |||||
fWantInEvents(false), | fWantInEvents(false), | ||||
fWasPlayingBefore(false), | fWasPlayingBefore(false), | ||||
fTicksPerFrame(0.0), | fTicksPerFrame(0.0), | ||||
@@ -76,17 +77,13 @@ protected: | |||||
fInEvents.trySplice(); | fInEvents.trySplice(); | ||||
} | } | ||||
if (fTimeInfo.playing) | |||||
if (fWasPlayingBefore != fTimeInfo.playing) | |||||
{ | { | ||||
if (! fTimeInfo.bbt.valid) | |||||
fTimeInfo.bbt.beatsPerMinute = 120.0; | |||||
fTicksPerFrame = 48.0 / (60.0 / fTimeInfo.bbt.beatsPerMinute * getSampleRate()); | |||||
fMidiOut.play(fTicksPerFrame*static_cast<long double>(fTimeInfo.frame), | |||||
fTicksPerFrame*static_cast<double>(frames)); | |||||
fNeedsAllNotesOff = true; | |||||
fWasPlayingBefore = fTimeInfo.playing; | |||||
} | } | ||||
else if (fWasPlayingBefore) | |||||
if (fNeedsAllNotesOff) | |||||
{ | { | ||||
NativeMidiEvent midiEvent; | NativeMidiEvent midiEvent; | ||||
@@ -104,10 +101,19 @@ protected: | |||||
NativePluginAndUiClass::writeMidiEvent(&midiEvent); | NativePluginAndUiClass::writeMidiEvent(&midiEvent); | ||||
} | } | ||||
carla_stdout("WAS PLAYING BEFORE, NOW STOPPED"); | |||||
fNeedsAllNotesOff = false; | |||||
} | } | ||||
fWasPlayingBefore = fTimeInfo.playing; | |||||
if (fTimeInfo.playing) | |||||
{ | |||||
if (! fTimeInfo.bbt.valid) | |||||
fTimeInfo.bbt.beatsPerMinute = 120.0; | |||||
fTicksPerFrame = 48.0 / (60.0 / fTimeInfo.bbt.beatsPerMinute * getSampleRate()); | |||||
fMidiOut.play(fTicksPerFrame*static_cast<long double>(fTimeInfo.frame), | |||||
fTicksPerFrame*static_cast<double>(frames)); | |||||
} | |||||
} | } | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -208,6 +214,7 @@ protected: | |||||
if (std::strcmp(msg, "midi-clear-all") == 0) | if (std::strcmp(msg, "midi-clear-all") == 0) | ||||
{ | { | ||||
fMidiOut.clear(); | fMidiOut.clear(); | ||||
fNeedsAllNotesOff = true; | |||||
return true; | return true; | ||||
} | } | ||||
@@ -259,6 +266,7 @@ protected: | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
private: | private: | ||||
bool fNeedsAllNotesOff; | |||||
bool fWantInEvents; | bool fWantInEvents; | ||||
bool fWasPlayingBefore; | bool fWasPlayingBefore; | ||||
@@ -366,7 +366,9 @@ private: | |||||
bool _add(const T& value, const bool inTail, ListHead* const queue) noexcept | bool _add(const T& value, const bool inTail, ListHead* const queue) noexcept | ||||
{ | { | ||||
return _add_internal(_allocate(), value, inTail, queue); | |||||
if (Data* const data = _allocate()) | |||||
return _add_internal(data, value, inTail, queue); | |||||
return false; | |||||
} | } | ||||
bool _add_internal(Data* const data, const T& value, const bool inTail, ListHead* const queue) noexcept | bool _add_internal(Data* const data, const T& value, const bool inTail, ListHead* const queue) noexcept | ||||