@@ -409,13 +409,18 @@ enum CallbackType { | |||||
*/ | */ | ||||
CALLBACK_PLUGIN_REMOVED = 2, | CALLBACK_PLUGIN_REMOVED = 2, | ||||
/*! | |||||
* A plugin has been renamed. | |||||
*/ | |||||
CALLBACK_PLUGIN_RENAMED = 3, | |||||
/*! | /*! | ||||
* A parameter value has been changed. | * A parameter value has been changed. | ||||
* | * | ||||
* \param value1 Parameter index | * \param value1 Parameter index | ||||
* \param value3 Value | * \param value3 Value | ||||
*/ | */ | ||||
CALLBACK_PARAMETER_VALUE_CHANGED = 3, | |||||
CALLBACK_PARAMETER_VALUE_CHANGED = 4, | |||||
/*! | /*! | ||||
* A parameter default has been changed. | * A parameter default has been changed. | ||||
@@ -423,7 +428,7 @@ enum CallbackType { | |||||
* \param value1 Parameter index | * \param value1 Parameter index | ||||
* \param value3 Default value | * \param value3 Default value | ||||
*/ | */ | ||||
CALLBACK_PARAMETER_DEFAULT_CHANGED = 4, | |||||
CALLBACK_PARAMETER_DEFAULT_CHANGED = 5, | |||||
/*! | /*! | ||||
* A parameter's MIDI channel has been changed. | * A parameter's MIDI channel has been changed. | ||||
@@ -431,7 +436,7 @@ enum CallbackType { | |||||
* \param value1 Parameter index | * \param value1 Parameter index | ||||
* \param value2 MIDI channel | * \param value2 MIDI channel | ||||
*/ | */ | ||||
CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED = 5, | |||||
CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED = 6, | |||||
/*! | /*! | ||||
* A parameter's MIDI CC has been changed. | * A parameter's MIDI CC has been changed. | ||||
@@ -439,14 +444,14 @@ enum CallbackType { | |||||
* \param value1 Parameter index | * \param value1 Parameter index | ||||
* \param value2 MIDI CC | * \param value2 MIDI CC | ||||
*/ | */ | ||||
CALLBACK_PARAMETER_MIDI_CC_CHANGED = 6, | |||||
CALLBACK_PARAMETER_MIDI_CC_CHANGED = 7, | |||||
/*! | /*! | ||||
* The current program has has been changed. | * The current program has has been changed. | ||||
* | * | ||||
* \param value1 Program index | * \param value1 Program index | ||||
*/ | */ | ||||
CALLBACK_PROGRAM_CHANGED = 7, | |||||
CALLBACK_PROGRAM_CHANGED = 8, | |||||
/*! | /*! | ||||
* The current MIDI program has been changed. | * The current MIDI program has been changed. | ||||
@@ -454,7 +459,7 @@ enum CallbackType { | |||||
* \param value1 MIDI bank | * \param value1 MIDI bank | ||||
* \param value2 MIDI program | * \param value2 MIDI program | ||||
*/ | */ | ||||
CALLBACK_MIDI_PROGRAM_CHANGED = 8, | |||||
CALLBACK_MIDI_PROGRAM_CHANGED = 9, | |||||
/*! | /*! | ||||
* A note has been pressed. | * A note has been pressed. | ||||
@@ -463,7 +468,7 @@ enum CallbackType { | |||||
* \param value2 Note | * \param value2 Note | ||||
* \param value3 Velocity | * \param value3 Velocity | ||||
*/ | */ | ||||
CALLBACK_NOTE_ON = 9, | |||||
CALLBACK_NOTE_ON = 10, | |||||
/*! | /*! | ||||
* A note has been released. | * A note has been released. | ||||
@@ -471,7 +476,7 @@ enum CallbackType { | |||||
* \param value1 Channel | * \param value1 Channel | ||||
* \param value2 Note | * \param value2 Note | ||||
*/ | */ | ||||
CALLBACK_NOTE_OFF = 10, | |||||
CALLBACK_NOTE_OFF = 11, | |||||
/*! | /*! | ||||
* The plugin's custom GUI state has changed. | * The plugin's custom GUI state has changed. | ||||
@@ -481,32 +486,32 @@ enum CallbackType { | |||||
* 1: GUI has been shown\n | * 1: GUI has been shown\n | ||||
* -1: GUI has crashed and should not be shown again | * -1: GUI has crashed and should not be shown again | ||||
*/ | */ | ||||
CALLBACK_SHOW_GUI = 11, | |||||
CALLBACK_SHOW_GUI = 12, | |||||
/*! | /*! | ||||
* The plugin needs update. | * The plugin needs update. | ||||
*/ | */ | ||||
CALLBACK_UPDATE = 12, | |||||
CALLBACK_UPDATE = 13, | |||||
/*! | /*! | ||||
* The plugin's data/information has changed. | * The plugin's data/information has changed. | ||||
*/ | */ | ||||
CALLBACK_RELOAD_INFO = 13, | |||||
CALLBACK_RELOAD_INFO = 14, | |||||
/*! | /*! | ||||
* The plugin's parameters have changed. | * The plugin's parameters have changed. | ||||
*/ | */ | ||||
CALLBACK_RELOAD_PARAMETERS = 14, | |||||
CALLBACK_RELOAD_PARAMETERS = 15, | |||||
/*! | /*! | ||||
* The plugin's programs have changed. | * The plugin's programs have changed. | ||||
*/ | */ | ||||
CALLBACK_RELOAD_PROGRAMS = 15, | |||||
CALLBACK_RELOAD_PROGRAMS = 16, | |||||
/*! | /*! | ||||
* The plugin's state has changed. | * The plugin's state has changed. | ||||
*/ | */ | ||||
CALLBACK_RELOAD_ALL = 16, | |||||
CALLBACK_RELOAD_ALL = 17, | |||||
/*! | /*! | ||||
* Canvas client added | * Canvas client added | ||||
@@ -514,14 +519,14 @@ enum CallbackType { | |||||
* \param value1 Client ID | * \param value1 Client ID | ||||
* \param valueStr Client Name | * \param valueStr Client Name | ||||
*/ | */ | ||||
CALLBACK_PATCHBAY_CLIENT_ADDED = 17, | |||||
CALLBACK_PATCHBAY_CLIENT_ADDED = 18, | |||||
/*! | /*! | ||||
* Canvas client removed | * Canvas client removed | ||||
* | * | ||||
* \param value1 Client ID | * \param value1 Client ID | ||||
*/ | */ | ||||
CALLBACK_PATCHBAY_CLIENT_REMOVED = 18, | |||||
CALLBACK_PATCHBAY_CLIENT_REMOVED = 19, | |||||
/*! | /*! | ||||
* Canvas client renamed | * Canvas client renamed | ||||
@@ -529,7 +534,7 @@ enum CallbackType { | |||||
* \param value1 Client ID | * \param value1 Client ID | ||||
* \param valueStr New Client name | * \param valueStr New Client name | ||||
*/ | */ | ||||
CALLBACK_PATCHBAY_CLIENT_RENAMED = 19, | |||||
CALLBACK_PATCHBAY_CLIENT_RENAMED = 20, | |||||
/*! | /*! | ||||
* Canvas port added | * Canvas port added | ||||
@@ -538,14 +543,14 @@ enum CallbackType { | |||||
* \param value2 Port ID | * \param value2 Port ID | ||||
* \param valueStr Port name | * \param valueStr Port name | ||||
*/ | */ | ||||
CALLBACK_PATCHBAY_PORT_ADDED = 20, | |||||
CALLBACK_PATCHBAY_PORT_ADDED = 21, | |||||
/*! | /*! | ||||
* Canvas port remvoed | * Canvas port remvoed | ||||
* | * | ||||
* \param value1 Port ID | * \param value1 Port ID | ||||
*/ | */ | ||||
CALLBACK_PATCHBAY_PORT_REMOVED = 21, | |||||
CALLBACK_PATCHBAY_PORT_REMOVED = 22, | |||||
/*! | /*! | ||||
* Canvas port renamed | * Canvas port renamed | ||||
@@ -553,7 +558,7 @@ enum CallbackType { | |||||
* \param value1 Port ID | * \param value1 Port ID | ||||
* \param valueStr New Port name | * \param valueStr New Port name | ||||
*/ | */ | ||||
CALLBACK_PATCHBAY_PORT_RENAMED = 22, | |||||
CALLBACK_PATCHBAY_PORT_RENAMED = 23, | |||||
/*! | /*! | ||||
* Canvas port connection added | * Canvas port connection added | ||||
@@ -561,7 +566,7 @@ enum CallbackType { | |||||
* \param value1 Output port ID | * \param value1 Output port ID | ||||
* \param value2 Input port ID | * \param value2 Input port ID | ||||
*/ | */ | ||||
CALLBACK_PATCHBAY_CONNECTION_ADDED = 23, | |||||
CALLBACK_PATCHBAY_CONNECTION_ADDED = 24, | |||||
/*! | /*! | ||||
* Canvas port connection removed | * Canvas port connection removed | ||||
@@ -569,37 +574,37 @@ enum CallbackType { | |||||
* \param value1 Output port ID | * \param value1 Output port ID | ||||
* \param value2 Input port ID | * \param value2 Input port ID | ||||
*/ | */ | ||||
CALLBACK_PATCHBAY_CONNECTION_REMOVED = 24, | |||||
CALLBACK_PATCHBAY_CONNECTION_REMOVED = 25, | |||||
/*! | /*! | ||||
* Non-Session-Manager Announce message. | * Non-Session-Manager Announce message. | ||||
*/ | */ | ||||
CALLBACK_NSM_ANNOUNCE = 25, | |||||
CALLBACK_NSM_ANNOUNCE = 26, | |||||
/*! | /*! | ||||
* Non-Session-Manager Open message #1. | * Non-Session-Manager Open message #1. | ||||
*/ | */ | ||||
CALLBACK_NSM_OPEN1 = 26, | |||||
CALLBACK_NSM_OPEN1 = 27, | |||||
/*! | /*! | ||||
* Non-Session-Manager Open message #2. | * Non-Session-Manager Open message #2. | ||||
*/ | */ | ||||
CALLBACK_NSM_OPEN2 = 27, | |||||
CALLBACK_NSM_OPEN2 = 28, | |||||
/*! | /*! | ||||
* Non-Session-Manager Save message. | * Non-Session-Manager Save message. | ||||
*/ | */ | ||||
CALLBACK_NSM_SAVE = 28, | |||||
CALLBACK_NSM_SAVE = 29, | |||||
/*! | /*! | ||||
* An error occurred, show last error to user. | * An error occurred, show last error to user. | ||||
*/ | */ | ||||
CALLBACK_ERROR = 29, | |||||
CALLBACK_ERROR = 30, | |||||
/*! | /*! | ||||
* The engine has crashed or malfunctioned and will no longer work. | * The engine has crashed or malfunctioned and will no longer work. | ||||
*/ | */ | ||||
CALLBACK_QUIT = 30 | |||||
CALLBACK_QUIT = 31 | |||||
}; | }; | ||||
/*! | /*! | ||||
@@ -25,26 +25,33 @@ | |||||
#define MAX_PREALLOCATED_EVENT_COUNT 1000 | #define MAX_PREALLOCATED_EVENT_COUNT 1000 | ||||
struct RawMidiEvent { | struct RawMidiEvent { | ||||
unsigned char data[MAX_EVENT_DATA_SIZE]; | |||||
//size_t dataSize; | |||||
uint32_t time; | |||||
//double value; // used for special events | |||||
uint8_t data[MAX_EVENT_DATA_SIZE]; | |||||
size_t size; | |||||
uint32_t time; | |||||
RawMidiEvent() | |||||
: data{0}, | |||||
size(0), | |||||
time(0) {} | |||||
}; | }; | ||||
class MidiSequencerPlugin : public PluginDescriptorClass | |||||
class MidiPattern | |||||
{ | { | ||||
public: | public: | ||||
MidiSequencerPlugin(const HostDescriptor* const host) | |||||
: PluginDescriptorClass(host), | |||||
fWantInEvents(false) | |||||
MidiPattern(const HostDescriptor* const host) | |||||
: kHost(host), | |||||
fStartTime(0), | |||||
fDuration(0) | |||||
{ | { | ||||
CARLA_ASSERT(host != nullptr); | |||||
// TEST SONG (unsorted to test RtList API) | // TEST SONG (unsorted to test RtList API) | ||||
uint32_t m = 44; | uint32_t m = 44; | ||||
fOutEvents.addControl(0*m, 0, 7, 99); | |||||
fOutEvents.addControl(0*m, 0, 10, 63); | |||||
fOutEvents.addProgram(0*m, 0, 0, 0); | |||||
addControl(0*m, 0, 7, 99); | |||||
addControl(0*m, 0, 10, 63); | |||||
addProgram(0*m, 0, 0, 0); | |||||
// 6912 On ch=1 n=60 v=90 | // 6912 On ch=1 n=60 v=90 | ||||
// 7237 Off ch=1 n=60 v=90 | // 7237 Off ch=1 n=60 v=90 | ||||
@@ -52,9 +59,9 @@ public: | |||||
// 7621 Off ch=1 n=62 v=90 | // 7621 Off ch=1 n=62 v=90 | ||||
// 7680 On ch=1 n=64 v=90 | // 7680 On ch=1 n=64 v=90 | ||||
// 8005 Off ch=1 n=64 v=90 | // 8005 Off ch=1 n=64 v=90 | ||||
fOutEvents.addNote(6912*m, 0, 60, 90, 325*m); | |||||
fOutEvents.addNote(7680*m, 0, 64, 90, 325*m); | |||||
fOutEvents.addNote(7296*m, 0, 62, 90, 325*m); | |||||
addNote(6912*m, 0, 60, 90, 325*m); | |||||
addNote(7680*m, 0, 64, 90, 325*m); | |||||
addNote(7296*m, 0, 62, 90, 325*m); | |||||
// 1152 On ch=1 n=62 v=90 | // 1152 On ch=1 n=62 v=90 | ||||
// 1477 Off ch=1 n=62 v=90 | // 1477 Off ch=1 n=62 v=90 | ||||
@@ -62,9 +69,9 @@ public: | |||||
// 1861 Off ch=1 n=64 v=90 | // 1861 Off ch=1 n=64 v=90 | ||||
// 1920 On ch=1 n=64 v=90 | // 1920 On ch=1 n=64 v=90 | ||||
// 2245 Off ch=1 n=64 v=90 | // 2245 Off ch=1 n=64 v=90 | ||||
fOutEvents.addNote(1152*m, 0, 62, 90, 325*m); | |||||
fOutEvents.addNote(1920*m, 0, 64, 90, 325*m); | |||||
fOutEvents.addNote(1536*m, 0, 64, 90, 325*m); | |||||
addNote(1152*m, 0, 62, 90, 325*m); | |||||
addNote(1920*m, 0, 64, 90, 325*m); | |||||
addNote(1536*m, 0, 64, 90, 325*m); | |||||
// 3840 On ch=1 n=62 v=90 | // 3840 On ch=1 n=62 v=90 | ||||
// 4491 Off ch=1 n=62 v=90 | // 4491 Off ch=1 n=62 v=90 | ||||
@@ -72,9 +79,9 @@ public: | |||||
// 4933 Off ch=1 n=64 v=90 | // 4933 Off ch=1 n=64 v=90 | ||||
// 4992 On ch=1 n=67 v=90 | // 4992 On ch=1 n=67 v=90 | ||||
// 5317 Off ch=1 n=67 v=90 | // 5317 Off ch=1 n=67 v=90 | ||||
fOutEvents.addNote(3840*m, 0, 62, 90, 650*m); | |||||
fOutEvents.addNote(4992*m, 0, 67, 90, 325*m); | |||||
fOutEvents.addNote(4608*m, 0, 64, 90, 325*m); | |||||
addNote(3840*m, 0, 62, 90, 650*m); | |||||
addNote(4992*m, 0, 67, 90, 325*m); | |||||
addNote(4608*m, 0, 64, 90, 325*m); | |||||
// 0 On ch=1 n=64 v=90 | // 0 On ch=1 n=64 v=90 | ||||
// 325 Off ch=1 n=64 v=90 | // 325 Off ch=1 n=64 v=90 | ||||
@@ -82,13 +89,13 @@ public: | |||||
// 709 Off ch=1 n=62 v=90 | // 709 Off ch=1 n=62 v=90 | ||||
// 768 On ch=1 n=60 v=90 | // 768 On ch=1 n=60 v=90 | ||||
//1093 Off ch=1 n=60 v=90 | //1093 Off ch=1 n=60 v=90 | ||||
fOutEvents.addNote( 0*m, 0, 64, 90, 325*m); | |||||
fOutEvents.addNote(768*m, 0, 60, 90, 325*m); | |||||
fOutEvents.addNote(384*m, 0, 62, 90, 325*m); | |||||
addNote( 0*m, 0, 64, 90, 325*m); | |||||
addNote(768*m, 0, 60, 90, 325*m); | |||||
addNote(384*m, 0, 62, 90, 325*m); | |||||
// 10752 On ch=1 n=60 v=90 | // 10752 On ch=1 n=60 v=90 | ||||
// 12056 Off ch=1 n=60 v=90 | // 12056 Off ch=1 n=60 v=90 | ||||
fOutEvents.addNote(10752*m, 0, 60, 90, 650*m); | |||||
addNote(10752*m, 0, 60, 90, 650*m); | |||||
// 5376 On ch=1 n=67 v=90 | // 5376 On ch=1 n=67 v=90 | ||||
// 6027 Off ch=1 n=67 v=90 | // 6027 Off ch=1 n=67 v=90 | ||||
@@ -96,9 +103,9 @@ public: | |||||
// 6469 Off ch=1 n=64 v=90 | // 6469 Off ch=1 n=64 v=90 | ||||
// 6528 On ch=1 n=62 v=90 | // 6528 On ch=1 n=62 v=90 | ||||
// 6853 Off ch=1 n=62 v=90 | // 6853 Off ch=1 n=62 v=90 | ||||
fOutEvents.addNote(5376*m, 0, 67, 90, 650*m); | |||||
fOutEvents.addNote(6144*m, 0, 64, 90, 325*m); | |||||
fOutEvents.addNote(6528*m, 0, 62, 90, 325*m); | |||||
addNote(5376*m, 0, 67, 90, 650*m); | |||||
addNote(6144*m, 0, 64, 90, 325*m); | |||||
addNote(6528*m, 0, 62, 90, 325*m); | |||||
// 8064 On ch=1 n=64 v=90 | // 8064 On ch=1 n=64 v=90 | ||||
// 8389 Off ch=1 n=64 v=90 | // 8389 Off ch=1 n=64 v=90 | ||||
@@ -106,9 +113,9 @@ public: | |||||
// 9099 Off ch=1 n=64 v=90 | // 9099 Off ch=1 n=64 v=90 | ||||
// 9216 On ch=1 n=62 v=90 | // 9216 On ch=1 n=62 v=90 | ||||
// 9541 Off ch=1 n=62 v=90 | // 9541 Off ch=1 n=62 v=90 | ||||
fOutEvents.addNote(8064*m, 0, 64, 90, 325*m); | |||||
fOutEvents.addNote(8448*m, 0, 64, 90, 650*m); | |||||
fOutEvents.addNote(9216*m, 0, 62, 90, 325*m); | |||||
addNote(8064*m, 0, 64, 90, 325*m); | |||||
addNote(8448*m, 0, 64, 90, 650*m); | |||||
addNote(9216*m, 0, 62, 90, 325*m); | |||||
// 9600 On ch=1 n=62 v=90 | // 9600 On ch=1 n=62 v=90 | ||||
// 9925 Off ch=1 n=62 v=90 | // 9925 Off ch=1 n=62 v=90 | ||||
@@ -116,9 +123,9 @@ public: | |||||
// 10309 Off ch=1 n=64 v=90 | // 10309 Off ch=1 n=64 v=90 | ||||
// 10368 On ch=1 n=62 v=90 | // 10368 On ch=1 n=62 v=90 | ||||
// 10693 Off ch=1 n=62 v=90 | // 10693 Off ch=1 n=62 v=90 | ||||
fOutEvents.addNote(9600*m, 0, 62, 90, 325*m); | |||||
fOutEvents.addNote(9984*m, 0, 64, 90, 325*m); | |||||
fOutEvents.addNote(10368*m, 0, 62, 90, 325*m); | |||||
addNote(9600*m, 0, 62, 90, 325*m); | |||||
addNote(9984*m, 0, 64, 90, 325*m); | |||||
addNote(10368*m, 0, 62, 90, 325*m); | |||||
// 2304 On ch=1 n=64 v=90 | // 2304 On ch=1 n=64 v=90 | ||||
// 2955 Off ch=1 n=64 v=90 | // 2955 Off ch=1 n=64 v=90 | ||||
@@ -126,14 +133,166 @@ public: | |||||
// 3397 Off ch=1 n=62 v=90 | // 3397 Off ch=1 n=62 v=90 | ||||
// 3456 On ch=1 n=62 v=90 | // 3456 On ch=1 n=62 v=90 | ||||
// 3781 Off ch=1 n=62 v=90 | // 3781 Off ch=1 n=62 v=90 | ||||
fOutEvents.addNote(2304*m, 0, 64, 90, 650*m); | |||||
fOutEvents.addNote(3072*m, 0, 62, 90, 325*m); | |||||
fOutEvents.addNote(3456*m, 0, 62, 90, 325*m); | |||||
addNote(2304*m, 0, 64, 90, 650*m); | |||||
addNote(3072*m, 0, 62, 90, 325*m); | |||||
addNote(3456*m, 0, 62, 90, 325*m); | |||||
for (auto it = fData.begin(); it.valid(); it.next()) | |||||
{ | |||||
const RawMidiEvent* const rawMidiEvent(*it); | |||||
carla_stdout("Got event %02X @%i", rawMidiEvent->data[0], rawMidiEvent->time); | |||||
} | |||||
} | |||||
~MidiPattern() | |||||
{ | |||||
fData.clear(); | |||||
} | |||||
void addControl(const uint32_t time, const uint8_t channel, const uint8_t control, const uint8_t value) | |||||
{ | |||||
RawMidiEvent* ctrlEvent(new RawMidiEvent()); | |||||
ctrlEvent->data[0] = MIDI_STATUS_CONTROL_CHANGE | (channel & 0x0F); | |||||
ctrlEvent->data[1] = control; | |||||
ctrlEvent->data[2] = value; | |||||
ctrlEvent->size = 3; | |||||
ctrlEvent->time = time; | |||||
appendAt(ctrlEvent, time); | |||||
} | |||||
void addProgram(const uint32_t time, const uint8_t channel, const uint8_t bank, const uint8_t program) | |||||
{ | |||||
RawMidiEvent* bankEvent(new RawMidiEvent()); | |||||
bankEvent->data[0] = MIDI_STATUS_CONTROL_CHANGE | (channel & 0x0F); | |||||
bankEvent->data[1] = MIDI_CONTROL_BANK_SELECT; | |||||
bankEvent->data[2] = bank; | |||||
bankEvent->size = 3; | |||||
bankEvent->time = time; | |||||
RawMidiEvent* programEvent(new RawMidiEvent()); | |||||
programEvent->data[0] = MIDI_STATUS_PROGRAM_CHANGE | (channel & 0x0F); | |||||
programEvent->data[1] = program; | |||||
programEvent->size = 2; | |||||
programEvent->time = time; | |||||
appendAt(bankEvent, time); | |||||
appendAt(programEvent, time); | |||||
} | |||||
void addNote(const uint32_t time, const uint8_t channel, const uint8_t pitch, const uint8_t velocity, const uint32_t duration) | |||||
{ | |||||
RawMidiEvent* noteOnEvent(new RawMidiEvent()); | |||||
noteOnEvent->data[0] = MIDI_STATUS_NOTE_ON | (channel & 0x0F); | |||||
noteOnEvent->data[1] = pitch; | |||||
noteOnEvent->data[2] = velocity; | |||||
noteOnEvent->size = 3; | |||||
noteOnEvent->time = time; | |||||
RawMidiEvent* noteOffEvent(new RawMidiEvent()); | |||||
noteOffEvent->data[0] = MIDI_STATUS_NOTE_OFF | (channel & 0x0F); | |||||
noteOffEvent->data[1] = pitch; | |||||
noteOffEvent->data[2] = velocity; | |||||
noteOffEvent->size = 3; | |||||
noteOffEvent->time = time+duration; | |||||
appendAt(noteOnEvent, time); | |||||
appendAt(noteOffEvent, time+duration); | |||||
} | |||||
void play(uint32_t timePosFrame, uint32_t frames) | |||||
{ | |||||
if (! fMutex.tryLock()) | |||||
return; | |||||
MidiEvent midiEvent; | |||||
for (auto it = fData.begin(); it.valid(); it.next()) | |||||
{ | |||||
const RawMidiEvent* const rawMidiEvent(*it); | |||||
if (timePosFrame > rawMidiEvent->time) | |||||
continue; | |||||
if (timePosFrame + frames <= rawMidiEvent->time) | |||||
continue; | |||||
midiEvent.port = 0; | |||||
midiEvent.time = rawMidiEvent->time-timePosFrame; | |||||
midiEvent.data[0] = rawMidiEvent->data[0]; | |||||
midiEvent.data[1] = rawMidiEvent->data[1]; | |||||
midiEvent.data[2] = rawMidiEvent->data[2]; | |||||
writeMidiEvent(&midiEvent); | |||||
} | |||||
fMutex.unlock(); | |||||
} | |||||
private: | |||||
const HostDescriptor* const kHost; | |||||
uint32_t fStartTime; | |||||
uint32_t fDuration; | |||||
CarlaMutex fMutex; | |||||
NonRtList<const RawMidiEvent*> fData; | |||||
void appendAt(const RawMidiEvent* const event, const uint32_t time) | |||||
{ | |||||
if (fData.isEmpty()) | |||||
{ | |||||
fMutex.lock(); | |||||
fData.append(event); | |||||
fMutex.unlock(); | |||||
return; | |||||
} | |||||
uint32_t lastTime = 0; | |||||
for (auto it = fData.begin(); it.valid(); it.next()) | |||||
{ | |||||
const RawMidiEvent* const oldEvent(*it); | |||||
if (lastTime > time) | |||||
{ | |||||
fMutex.lock(); | |||||
fData.insertAt(event, it); | |||||
fMutex.unlock(); | |||||
return; | |||||
} | |||||
lastTime = oldEvent->time; | |||||
} | |||||
if (time >= lastTime) | |||||
{ | |||||
fMutex.lock(); | |||||
fData.append(event); | |||||
fMutex.unlock(); | |||||
} | |||||
else | |||||
carla_stderr2("MidiPattern::appendAt() failed for time %i", time); | |||||
} | |||||
void writeMidiEvent(const MidiEvent* const event) | |||||
{ | |||||
kHost->write_midi_event(kHost->handle, event); | |||||
} | |||||
}; | |||||
class MidiSequencerPlugin : public PluginDescriptorClass | |||||
{ | |||||
public: | |||||
MidiSequencerPlugin(const HostDescriptor* const host) | |||||
: PluginDescriptorClass(host), | |||||
fWantInEvents(false), | |||||
fMidiOut(host) | |||||
{ | |||||
} | } | ||||
~MidiSequencerPlugin() | ~MidiSequencerPlugin() | ||||
{ | { | ||||
fOutEvents.data.clear(); | |||||
} | } | ||||
protected: | protected: | ||||
@@ -175,32 +334,8 @@ protected: | |||||
} | } | ||||
} | } | ||||
if (! timePos->playing) | |||||
return; | |||||
if (! fOutEvents.mutex.tryLock()) | |||||
return; | |||||
{ | |||||
MidiEvent midiEvent; | |||||
for (auto it = fOutEvents.data.begin(); it.valid(); it.next()) | |||||
{ | |||||
RawMidiEvent* const rawMidiEvent(*it); | |||||
if (timePos->frame > rawMidiEvent->time || timePos->frame + frames <= rawMidiEvent->time) | |||||
continue; | |||||
midiEvent.port = 0; | |||||
midiEvent.time = rawMidiEvent->time-timePos->frame; | |||||
midiEvent.data[0] = rawMidiEvent->data[0]; | |||||
midiEvent.data[1] = rawMidiEvent->data[1]; | |||||
midiEvent.data[2] = rawMidiEvent->data[2]; | |||||
writeMidiEvent(&midiEvent); | |||||
} | |||||
} | |||||
fOutEvents.mutex.unlock(); | |||||
if (timePos->playing) | |||||
fMidiOut.play(timePos->frame, frames); | |||||
} | } | ||||
private: | private: | ||||
@@ -240,95 +375,7 @@ private: | |||||
} fInEvents; | } fInEvents; | ||||
struct OutRtEvents { | |||||
CarlaMutex mutex; | |||||
NonRtList<RawMidiEvent*> data; | |||||
void appendAt(RawMidiEvent* event, uint32_t time) | |||||
{ | |||||
if (data.isEmpty()) | |||||
{ | |||||
mutex.lock(); | |||||
data.append(event); | |||||
mutex.unlock(); | |||||
return; | |||||
} | |||||
uint32_t lastTime = 0; | |||||
for (auto it = data.begin(); it.valid(); it.next()) | |||||
{ | |||||
RawMidiEvent* const oldEvent(*it); | |||||
if (lastTime > time) | |||||
{ | |||||
mutex.lock(); | |||||
data.insertAt(event, it); | |||||
mutex.unlock(); | |||||
return; | |||||
} | |||||
lastTime = oldEvent->time; | |||||
} | |||||
if (time >= lastTime) | |||||
{ | |||||
mutex.lock(); | |||||
data.append(event); | |||||
mutex.unlock(); | |||||
} | |||||
else | |||||
carla_stderr2("MidiSequencerPlugin::appendAt() failed for time %i", time); | |||||
} | |||||
void addControl(uint32_t time, uint8_t channel, uint8_t control, uint8_t value) | |||||
{ | |||||
RawMidiEvent* ctrlEvent(new RawMidiEvent); | |||||
ctrlEvent->data[0] = MIDI_STATUS_CONTROL_CHANGE | (channel & 0x0F); | |||||
ctrlEvent->data[1] = control; | |||||
ctrlEvent->data[2] = value; | |||||
ctrlEvent->time = time; | |||||
appendAt(ctrlEvent, time); | |||||
} | |||||
void addProgram(uint32_t time, uint8_t channel, uint8_t bank, uint8_t program) | |||||
{ | |||||
RawMidiEvent* bankEvent(new RawMidiEvent); | |||||
bankEvent->data[0] = MIDI_STATUS_CONTROL_CHANGE | (channel & 0x0F); | |||||
bankEvent->data[1] = MIDI_CONTROL_BANK_SELECT; | |||||
bankEvent->data[2] = bank; | |||||
bankEvent->time = time; | |||||
RawMidiEvent* programEvent(new RawMidiEvent); | |||||
programEvent->data[0] = MIDI_STATUS_PROGRAM_CHANGE | (channel & 0x0F); | |||||
programEvent->data[1] = program; | |||||
programEvent->data[2] = 0; | |||||
programEvent->time = time; | |||||
appendAt(bankEvent, time); | |||||
appendAt(programEvent, time); | |||||
} | |||||
void addNote(uint32_t time, uint8_t channel, uint8_t pitch, uint8_t velocity, uint32_t duration) | |||||
{ | |||||
RawMidiEvent* noteOnEvent(new RawMidiEvent); | |||||
noteOnEvent->data[0] = MIDI_STATUS_NOTE_ON | (channel & 0x0F); | |||||
noteOnEvent->data[1] = pitch; | |||||
noteOnEvent->data[2] = velocity; | |||||
noteOnEvent->time = time; | |||||
RawMidiEvent* noteOffEvent(new RawMidiEvent); | |||||
noteOffEvent->data[0] = MIDI_STATUS_NOTE_OFF | (channel & 0x0F); | |||||
noteOffEvent->data[1] = pitch; | |||||
noteOffEvent->data[2] = velocity; | |||||
noteOffEvent->time = time+duration; | |||||
appendAt(noteOnEvent, time); | |||||
appendAt(noteOffEvent, time+duration); | |||||
} | |||||
} fOutEvents; | |||||
MidiPattern fMidiOut; | |||||
PluginDescriptorClassEND(MidiSequencerPlugin) | PluginDescriptorClassEND(MidiSequencerPlugin) | ||||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MidiSequencerPlugin) | CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MidiSequencerPlugin) | ||||
@@ -643,6 +643,7 @@ class CarlaMainW(QMainWindow): | |||||
self.connect(self, SIGNAL("DebugCallback(int, int, int, double, QString)"), SLOT("slot_handleDebugCallback(int, int, int, double, QString)")) | self.connect(self, SIGNAL("DebugCallback(int, int, int, double, QString)"), SLOT("slot_handleDebugCallback(int, int, int, double, QString)")) | ||||
self.connect(self, SIGNAL("PluginAddedCallback(int)"), SLOT("slot_handlePluginAddedCallback(int)")) | self.connect(self, SIGNAL("PluginAddedCallback(int)"), SLOT("slot_handlePluginAddedCallback(int)")) | ||||
self.connect(self, SIGNAL("PluginRemovedCallback(int)"), SLOT("slot_handlePluginRemovedCallback(int)")) | self.connect(self, SIGNAL("PluginRemovedCallback(int)"), SLOT("slot_handlePluginRemovedCallback(int)")) | ||||
self.connect(self, SIGNAL("PluginRenamedCallback(int, QString)"), SLOT("slot_handlePluginRenamedCallback(int, QString)")) | |||||
self.connect(self, SIGNAL("ParameterValueChangedCallback(int, int, double)"), SLOT("slot_handleParameterValueChangedCallback(int, int, double)")) | self.connect(self, SIGNAL("ParameterValueChangedCallback(int, int, double)"), SLOT("slot_handleParameterValueChangedCallback(int, int, double)")) | ||||
self.connect(self, SIGNAL("ParameterDefaultChangedCallback(int, int, double)"), SLOT("slot_handleParameterDefaultChangedCallback(int, int, double)")) | self.connect(self, SIGNAL("ParameterDefaultChangedCallback(int, int, double)"), SLOT("slot_handleParameterDefaultChangedCallback(int, int, double)")) | ||||
self.connect(self, SIGNAL("ParameterMidiChannelChangedCallback(int, int, int)"), SLOT("slot_handleParameterMidiChannelChangedCallback(int, int, int)")) | self.connect(self, SIGNAL("ParameterMidiChannelChangedCallback(int, int, int)"), SLOT("slot_handleParameterMidiChannelChangedCallback(int, int, int)")) | ||||
@@ -1060,6 +1061,17 @@ class CarlaMainW(QMainWindow): | |||||
if self.fPluginCount == 0: | if self.fPluginCount == 0: | ||||
self.ui.act_plugin_remove_all.setEnabled(False) | self.ui.act_plugin_remove_all.setEnabled(False) | ||||
@pyqtSlot(int, str) | |||||
def slot_handlePluginRenamedCallback(self, pluginId, newName): | |||||
if pluginId >= self.fPluginCount: | |||||
return | |||||
pwidget = self.fPluginList[pluginId] | |||||
if pwidget is None: | |||||
return | |||||
pwidget.ui.label_name.setText(newName) | |||||
@pyqtSlot(int, int, float) | @pyqtSlot(int, int, float) | ||||
def slot_handleParameterValueChangedCallback(self, pluginId, parameterId, value): | def slot_handleParameterValueChangedCallback(self, pluginId, parameterId, value): | ||||
if pluginId >= self.fPluginCount: | if pluginId >= self.fPluginCount: | ||||
@@ -1471,6 +1483,8 @@ def engineCallback(ptr, action, pluginId, value1, value2, value3, valueStr): | |||||
Carla.gui.emit(SIGNAL("PluginAddedCallback(int)"), pluginId) | Carla.gui.emit(SIGNAL("PluginAddedCallback(int)"), pluginId) | ||||
elif action == CALLBACK_PLUGIN_REMOVED: | elif action == CALLBACK_PLUGIN_REMOVED: | ||||
Carla.gui.emit(SIGNAL("PluginRemovedCallback(int)"), pluginId) | Carla.gui.emit(SIGNAL("PluginRemovedCallback(int)"), pluginId) | ||||
elif action == CALLBACK_PLUGIN_RENAMED: | |||||
Carla.gui.emit(SIGNAL("PluginRenamedCallback(int, QString)"), pluginId, valueStr) | |||||
elif action == CALLBACK_PARAMETER_VALUE_CHANGED: | elif action == CALLBACK_PARAMETER_VALUE_CHANGED: | ||||
Carla.gui.emit(SIGNAL("ParameterValueChangedCallback(int, int, double)"), pluginId, value1, value3) | Carla.gui.emit(SIGNAL("ParameterValueChangedCallback(int, int, double)"), pluginId, value1, value3) | ||||
elif action == CALLBACK_PARAMETER_DEFAULT_CHANGED: | elif action == CALLBACK_PARAMETER_DEFAULT_CHANGED: | ||||
@@ -282,34 +282,35 @@ OPTION_PATH_BRIDGE_VST_X11 = 25 | |||||
CALLBACK_DEBUG = 0 | CALLBACK_DEBUG = 0 | ||||
CALLBACK_PLUGIN_ADDED = 1 | CALLBACK_PLUGIN_ADDED = 1 | ||||
CALLBACK_PLUGIN_REMOVED = 2 | CALLBACK_PLUGIN_REMOVED = 2 | ||||
CALLBACK_PARAMETER_VALUE_CHANGED = 3 | |||||
CALLBACK_PARAMETER_DEFAULT_CHANGED = 4 | |||||
CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED = 5 | |||||
CALLBACK_PARAMETER_MIDI_CC_CHANGED = 6 | |||||
CALLBACK_PROGRAM_CHANGED = 7 | |||||
CALLBACK_MIDI_PROGRAM_CHANGED = 8 | |||||
CALLBACK_NOTE_ON = 9 | |||||
CALLBACK_NOTE_OFF = 10 | |||||
CALLBACK_SHOW_GUI = 11 | |||||
CALLBACK_UPDATE = 12 | |||||
CALLBACK_RELOAD_INFO = 13 | |||||
CALLBACK_RELOAD_PARAMETERS = 14 | |||||
CALLBACK_RELOAD_PROGRAMS = 15 | |||||
CALLBACK_RELOAD_ALL = 16 | |||||
CALLBACK_PATCHBAY_CLIENT_ADDED = 17 | |||||
CALLBACK_PATCHBAY_CLIENT_REMOVED = 18 | |||||
CALLBACK_PATCHBAY_CLIENT_RENAMED = 19 | |||||
CALLBACK_PATCHBAY_PORT_ADDED = 20 | |||||
CALLBACK_PATCHBAY_PORT_REMOVED = 21 | |||||
CALLBACK_PATCHBAY_PORT_RENAMED = 22 | |||||
CALLBACK_PATCHBAY_CONNECTION_ADDED = 23 | |||||
CALLBACK_PATCHBAY_CONNECTION_REMOVED = 24 | |||||
CALLBACK_NSM_ANNOUNCE = 25 | |||||
CALLBACK_NSM_OPEN1 = 26 | |||||
CALLBACK_NSM_OPEN2 = 27 | |||||
CALLBACK_NSM_SAVE = 28 | |||||
CALLBACK_ERROR = 29 | |||||
CALLBACK_QUIT = 30 | |||||
CALLBACK_PLUGIN_RENAMED = 3 | |||||
CALLBACK_PARAMETER_VALUE_CHANGED = 4 | |||||
CALLBACK_PARAMETER_DEFAULT_CHANGED = 5 | |||||
CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED = 6 | |||||
CALLBACK_PARAMETER_MIDI_CC_CHANGED = 7 | |||||
CALLBACK_PROGRAM_CHANGED = 8 | |||||
CALLBACK_MIDI_PROGRAM_CHANGED = 9 | |||||
CALLBACK_NOTE_ON = 10 | |||||
CALLBACK_NOTE_OFF = 11 | |||||
CALLBACK_SHOW_GUI = 12 | |||||
CALLBACK_UPDATE = 13 | |||||
CALLBACK_RELOAD_INFO = 14 | |||||
CALLBACK_RELOAD_PARAMETERS = 15 | |||||
CALLBACK_RELOAD_PROGRAMS = 16 | |||||
CALLBACK_RELOAD_ALL = 17 | |||||
CALLBACK_PATCHBAY_CLIENT_ADDED = 18 | |||||
CALLBACK_PATCHBAY_CLIENT_REMOVED = 19 | |||||
CALLBACK_PATCHBAY_CLIENT_RENAMED = 20 | |||||
CALLBACK_PATCHBAY_PORT_ADDED = 21 | |||||
CALLBACK_PATCHBAY_PORT_REMOVED = 22 | |||||
CALLBACK_PATCHBAY_PORT_RENAMED = 23 | |||||
CALLBACK_PATCHBAY_CONNECTION_ADDED = 24 | |||||
CALLBACK_PATCHBAY_CONNECTION_REMOVED = 25 | |||||
CALLBACK_NSM_ANNOUNCE = 26 | |||||
CALLBACK_NSM_OPEN1 = 27 | |||||
CALLBACK_NSM_OPEN2 = 28 | |||||
CALLBACK_NSM_SAVE = 29 | |||||
CALLBACK_ERROR = 30 | |||||
CALLBACK_QUIT = 31 | |||||
# Process Mode | # Process Mode | ||||
PROCESS_MODE_SINGLE_CLIENT = 0 | PROCESS_MODE_SINGLE_CLIENT = 0 | ||||