| @@ -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 | ||||