| 
							- /*
 -  * Carla Native Plugins
 -  * Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com>
 -  *
 -  * This program is free software; you can redistribute it and/or
 -  * modify it under the terms of the GNU General Public License as
 -  * published by the Free Software Foundation; either version 2 of
 -  * the License, or any later version.
 -  *
 -  * This program is distributed in the hope that it will be useful,
 -  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 -  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 -  * GNU General Public License for more details.
 -  *
 -  * For a full copy of the GNU General Public License see the doc/GPL.txt file.
 -  */
 - 
 - #include "CarlaNativeExtUI.hpp"
 - #include "RtLinkedList.hpp"
 - 
 - #include "midi-base.hpp"
 - 
 - // -----------------------------------------------------------------------
 - 
 - class MidiSequencerPlugin : public NativePluginAndUiClass,
 -                             public AbstractMidiPlayer
 - {
 - public:
 -     MidiSequencerPlugin(const NativeHostDescriptor* const host)
 -         : NativePluginAndUiClass(host, CARLA_OS_SEP_STR "midiseq-ui"),
 -           fWantInEvents(false),
 -           fWasPlayingBefore(false),
 -           fInEvents(),
 -           fMidiOut(this),
 -           fTimeInfo(),
 -           leakDetector_MidiSequencerPlugin()
 -     {
 -         // TEST SONG (unsorted to test RtList API)
 - 
 -         uint32_t m = 44;
 - 
 -         fMidiOut.addControl(0*m, 0,  7, 99);
 -         fMidiOut.addControl(0*m, 0, 10, 63);
 -         fMidiOut.addProgram(0*m, 0,  0, 0);
 - 
 -         // 6912 On ch=1 n=60 v=90
 -         // 7237 Off ch=1 n=60 v=90
 -         // 7296 On ch=1 n=62 v=90
 -         // 7621 Off ch=1 n=62 v=90
 -         // 7680 On ch=1 n=64 v=90
 -         // 8005 Off ch=1 n=64 v=90
 -         fMidiOut.addNote(6912*m, 0, 60, 90, 325*m);
 -         fMidiOut.addNote(7680*m, 0, 64, 90, 325*m);
 -         fMidiOut.addNote(7296*m, 0, 62, 90, 325*m);
 - 
 -         // 1152 On ch=1 n=62 v=90
 -         // 1477 Off ch=1 n=62 v=90
 -         // 1536 On ch=1 n=64 v=90
 -         // 1861 Off ch=1 n=64 v=90
 -         // 1920 On ch=1 n=64 v=90
 -         // 2245 Off ch=1 n=64 v=90
 -         fMidiOut.addNote(1152*m, 0, 62, 90, 325*m);
 -         fMidiOut.addNote(1920*m, 0, 64, 90, 325*m);
 -         fMidiOut.addNote(1536*m, 0, 64, 90, 325*m);
 - 
 -         // 3840 On ch=1 n=62 v=90
 -         // 4491 Off ch=1 n=62 v=90
 -         // 4608 On ch=1 n=64 v=90
 -         // 4933 Off ch=1 n=64 v=90
 -         // 4992 On ch=1 n=67 v=90
 -         // 5317 Off ch=1 n=67 v=90
 -         fMidiOut.addNote(3840*m, 0, 62, 90, 650*m);
 -         fMidiOut.addNote(4992*m, 0, 67, 90, 325*m);
 -         fMidiOut.addNote(4608*m, 0, 64, 90, 325*m);
 - 
 -         // 0 On ch=1 n=64 v=90
 -         // 325 Off ch=1 n=64 v=90
 -         // 384 On ch=1 n=62 v=90
 -         // 709 Off ch=1 n=62 v=90
 -         // 768 On ch=1 n=60 v=90
 -         //1093 Off ch=1 n=60 v=90
 -         fMidiOut.addNote(  0*m, 0, 64, 90, 325*m);
 -         fMidiOut.addNote(768*m, 0, 60, 90, 325*m);
 -         fMidiOut.addNote(384*m, 0, 62, 90, 325*m);
 - 
 -         // 10752 On ch=1 n=60 v=90
 -         // 12056 Off ch=1 n=60 v=90
 -         fMidiOut.addNote(10752*m, 0, 60, 90, 650*m);
 - 
 -         // 5376 On ch=1 n=67 v=90
 -         // 6027 Off ch=1 n=67 v=90
 -         // 6144 On ch=1 n=64 v=90
 -         // 6469 Off ch=1 n=64 v=90
 -         // 6528 On ch=1 n=62 v=90
 -         // 6853 Off ch=1 n=62 v=90
 -         fMidiOut.addNote(5376*m, 0, 67, 90, 650*m);
 -         fMidiOut.addNote(6144*m, 0, 64, 90, 325*m);
 -         fMidiOut.addNote(6528*m, 0, 62, 90, 325*m);
 - 
 -         // 8064 On ch=1 n=64 v=90
 -         // 8389 Off ch=1 n=64 v=90
 -         // 8448 On ch=1 n=64 v=90
 -         // 9099 Off ch=1 n=64 v=90
 -         // 9216 On ch=1 n=62 v=90
 -         // 9541 Off ch=1 n=62 v=90
 -         fMidiOut.addNote(8064*m, 0, 64, 90, 325*m);
 -         fMidiOut.addNote(8448*m, 0, 64, 90, 650*m);
 -         fMidiOut.addNote(9216*m, 0, 62, 90, 325*m);
 - 
 -         // 9600 On ch=1 n=62 v=90
 -         // 9925 Off ch=1 n=62 v=90
 -         // 9984 On ch=1 n=64 v=90
 -         // 10309 Off ch=1 n=64 v=90
 -         // 10368 On ch=1 n=62 v=90
 -         // 10693 Off ch=1 n=62 v=90
 -         fMidiOut.addNote(9600*m, 0, 62, 90, 325*m);
 -         fMidiOut.addNote(9984*m, 0, 64, 90, 325*m);
 -         fMidiOut.addNote(10368*m, 0, 62, 90, 325*m);
 - 
 -         // 2304 On ch=1 n=64 v=90
 -         // 2955 Off ch=1 n=64 v=90
 -         // 3072 On ch=1 n=62 v=90
 -         // 3397 Off ch=1 n=62 v=90
 -         // 3456 On ch=1 n=62 v=90
 -         // 3781 Off ch=1 n=62 v=90
 -         fMidiOut.addNote(2304*m, 0, 64, 90, 650*m);
 -         fMidiOut.addNote(3072*m, 0, 62, 90, 325*m);
 -         fMidiOut.addNote(3456*m, 0, 62, 90, 325*m);
 - 
 -         carla_zeroStruct(fTimeInfo);
 -     }
 - 
 - protected:
 -     // -------------------------------------------------------------------
 -     // Plugin process calls
 - 
 -     void process(float**, float**, const uint32_t frames, const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
 -     {
 -         const NativeTimeInfo* const timePos = getTimeInfo();
 - 
 -         if (fWantInEvents)
 -         {
 -             if (midiEventCount > 0)
 -             {
 -                 RawMidiEvent rawMidiEvent;
 - 
 -                 for (uint32_t i=0; i < midiEventCount; ++i)
 -                 {
 -                     const NativeMidiEvent* const midiEvent = &midiEvents[i];
 - 
 -                     rawMidiEvent.data[0] = midiEvent->data[0];
 -                     rawMidiEvent.data[1] = midiEvent->data[1];
 -                     rawMidiEvent.data[2] = midiEvent->data[2];
 -                     rawMidiEvent.data[3] = midiEvent->data[3];
 -                     rawMidiEvent.size    = midiEvent->size;
 -                     rawMidiEvent.time    = timePos->playing ? timePos->frame + midiEvent->time : 0;
 - 
 -                     fInEvents.appendRT(rawMidiEvent);
 -                 }
 -             }
 - 
 -             fInEvents.trySplice();
 -         }
 - 
 -         if (const NativeTimeInfo* const timeInfo = getTimeInfo())
 -             fTimeInfo = *timeInfo;
 - 
 -         if (timePos->playing)
 -         {
 -             fMidiOut.play(timePos->frame, frames);
 -         }
 -         else if (fWasPlayingBefore)
 -         {
 -             NativeMidiEvent midiEvent;
 - 
 -             midiEvent.port    = 0;
 -             midiEvent.time    = 0;
 -             midiEvent.data[0] = MIDI_STATUS_CONTROL_CHANGE;
 -             midiEvent.data[1] = MIDI_CONTROL_ALL_NOTES_OFF;
 -             midiEvent.data[2] = 0;
 -             midiEvent.data[3] = 0;
 -             midiEvent.size    = 3;
 - 
 -             for (int i=0; i < MAX_MIDI_CHANNELS; ++i)
 -             {
 -                 midiEvent.data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE+i);
 -                 NativePluginAndUiClass::writeMidiEvent(&midiEvent);
 -             }
 - 
 -             carla_stdout("WAS PLAYING BEFORE, NOW STOPPED");
 -         }
 - 
 -         fWasPlayingBefore = timePos->playing;
 -     }
 - 
 -     // -------------------------------------------------------------------
 -     // Plugin UI calls
 - 
 -     void uiShow(const bool show) override
 -     {
 -         NativePluginAndUiClass::uiShow(show);
 - 
 -         if (show)
 -             _sendEventsToUI();
 -     }
 - 
 -     void uiIdle() override
 -     {
 -         NativePluginAndUiClass::uiIdle();
 - 
 -         // send transport
 -         if (isPipeRunning())
 -         {
 -             char strBuf[0xff+1];
 -             strBuf[0xff] = '\0';
 - 
 -             const CarlaMutexLocker cml(getPipeLock());
 -             const ScopedLocale csl;
 - 
 -             writeAndFixMessage("transport");
 -             writeMessage(fTimeInfo.playing ? "true\n" : "false\n");
 - 
 -             if (fTimeInfo.bbt.valid)
 -             {
 -                 std::sprintf(strBuf, P_UINT64 ":%i:%i:%i\n", fTimeInfo.frame, fTimeInfo.bbt.bar, fTimeInfo.bbt.beat, fTimeInfo.bbt.tick);
 -                 writeMessage(strBuf);
 -                 std::sprintf(strBuf, "%f:%f:%f\n", fTimeInfo.bbt.beatsPerMinute, fTimeInfo.bbt.beatsPerBar, fTimeInfo.bbt.beatType);
 -                 writeMessage(strBuf);
 -             }
 -             else
 -             {
 -                 std::sprintf(strBuf, P_UINT64 ":0:0:0\n", fTimeInfo.frame);
 -                 writeMessage(strBuf);
 -                 writeMessage("120.0:4.0:4.0\n");
 -             }
 - 
 -             flushMessages();
 -         }
 -     }
 - 
 -     // -------------------------------------------------------------------
 -     // Plugin state calls
 - 
 -     char* getState() const override
 -     {
 -         // TODO: malloc list of events
 - 
 -         return nullptr;
 -     }
 - 
 -     void setState(const char* const data) override
 -     {
 -         CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
 - 
 -         return;
 - 
 -         fMidiOut.clear();
 - 
 -         // TODO: set events according to data
 - 
 -         _sendEventsToUI();
 -     }
 - 
 -     // -------------------------------------------------------------------
 -     // AbstractMidiPlayer calls
 - 
 -     void writeMidiEvent(const uint8_t port, const uint64_t timePosFrame, const RawMidiEvent* const event) override
 -     {
 -         NativeMidiEvent midiEvent;
 - 
 -         midiEvent.port    = port;
 -         midiEvent.time    = uint32_t(event->time-timePosFrame);
 -         midiEvent.data[0] = event->data[0];
 -         midiEvent.data[1] = event->data[1];
 -         midiEvent.data[2] = event->data[2];
 -         midiEvent.data[3] = event->data[3];
 -         midiEvent.size    = event->size;
 - 
 -         NativePluginAndUiClass::writeMidiEvent(&midiEvent);
 -     }
 - 
 -     // -------------------------------------------------------------------
 -     // Pipe Server calls
 - 
 -     bool msgReceived(const char* const msg) noexcept override
 -     {
 -         if (NativePluginAndUiClass::msgReceived(msg))
 -             return true;
 - 
 -         if (std::strcmp(msg, "midi-clear-all") == 0)
 -         {
 -             fMidiOut.clear();
 -             return true;
 -         }
 - 
 -         if (std::strcmp(msg, "midievent-add") == 0)
 -         {
 -             uint64_t time;
 -             uint8_t size;
 - 
 -             CARLA_SAFE_ASSERT_RETURN(readNextLineAsULong(time), true);
 -             CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(size), true);
 - 
 -             uint8_t data[size], dvalue;
 - 
 -             for (uint8_t i=0; i<size; ++i)
 -             {
 -                 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(dvalue), true);
 -                 data[i] = dvalue;
 -             }
 - 
 -             fMidiOut.addRaw(time, data, size);
 - 
 -             return true;
 -         }
 - 
 -         if (std::strcmp(msg, "midievent-remove") == 0)
 -         {
 -             uint64_t time;
 -             uint8_t size;
 - 
 -             CARLA_SAFE_ASSERT_RETURN(readNextLineAsULong(time), true);
 -             CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(size), true);
 - 
 -             uint8_t data[size], dvalue;
 - 
 -             for (uint8_t i=0; i<size; ++i)
 -             {
 -                 CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(dvalue), true);
 -                 data[i] = dvalue;
 -             }
 - 
 -             fMidiOut.removeRaw(time, data, size);
 - 
 -             return true;
 -         }
 - 
 -         return false;
 -     }
 - 
 -     // -------------------------------------------------------------------
 - 
 - private:
 -     bool fWantInEvents;
 -     bool fWasPlayingBefore;
 - 
 -     struct InRtEvents {
 -         CarlaMutex mutex;
 -         RtLinkedList<RawMidiEvent>::Pool dataPool;
 -         RtLinkedList<RawMidiEvent> data;
 -         RtLinkedList<RawMidiEvent> dataPendingRT;
 - 
 -         InRtEvents() noexcept
 -             : mutex(),
 -               dataPool(MIN_PREALLOCATED_EVENT_COUNT, MAX_PREALLOCATED_EVENT_COUNT),
 -               data(dataPool),
 -               dataPendingRT(dataPool) {}
 - 
 -         ~InRtEvents() noexcept
 -         {
 -             clear();
 -         }
 - 
 -         void appendRT(const RawMidiEvent& event) noexcept
 -         {
 -             dataPendingRT.append(event);
 -         }
 - 
 -         void clear() noexcept
 -         {
 -             mutex.lock();
 -             data.clear();
 -             dataPendingRT.clear();
 -             mutex.unlock();
 -         }
 - 
 -         void trySplice() noexcept
 -         {
 -             if (mutex.tryLock())
 -             {
 -                 if (dataPendingRT.count() > 0)
 -                     dataPendingRT.moveTo(data, true);
 -                 mutex.unlock();
 -             }
 -         }
 - 
 -         CARLA_DECLARE_NON_COPY_STRUCT(InRtEvents);
 - 
 -     } fInEvents;
 - 
 -     MidiPattern    fMidiOut;
 -     NativeTimeInfo fTimeInfo;
 - 
 -     void _sendEventsToUI() const noexcept
 -     {
 -         char strBuf[0xff+1];
 -         strBuf[0xff] = '\0';
 - 
 -         const CarlaMutexLocker cml1(getPipeLock());
 -         const CarlaMutexLocker cml2(fMidiOut.getLock());
 - 
 -         writeMessage("midi-clear-all\n", 15);
 - 
 -         for (LinkedList<const RawMidiEvent*>::Itenerator it = fMidiOut.iteneratorBegin(); it.valid(); it.next())
 -         {
 -             const RawMidiEvent* const rawMidiEvent(it.getValue(nullptr));
 -             CARLA_SAFE_ASSERT_CONTINUE(rawMidiEvent != nullptr);
 - 
 -             writeMessage("midievent-add\n", 14);
 - 
 -             std::snprintf(strBuf, 0xff, P_INT64 "\n", rawMidiEvent->time);
 -             writeMessage(strBuf);
 - 
 -             std::snprintf(strBuf, 0xff, "%i\n", rawMidiEvent->size);
 -             writeMessage(strBuf);
 - 
 -             for (uint8_t i=0, size=rawMidiEvent->size; i<size; ++i)
 -             {
 -                 std::snprintf(strBuf, 0xff, "%i\n", rawMidiEvent->data[i]);
 -                 writeMessage(strBuf);
 -             }
 -         }
 -     }
 - 
 -     PluginClassEND(MidiSequencerPlugin)
 -     CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MidiSequencerPlugin)
 - };
 - 
 - // -----------------------------------------------------------------------
 - 
 - static const NativePluginDescriptor midisequencerDesc = {
 -     /* category  */ NATIVE_PLUGIN_CATEGORY_UTILITY,
 -     /* hints     */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE
 -                                                   |NATIVE_PLUGIN_HAS_UI
 -                                                   |NATIVE_PLUGIN_USES_STATE
 -                                                   |NATIVE_PLUGIN_USES_TIME),
 -     /* supports  */ NATIVE_PLUGIN_SUPPORTS_EVERYTHING,
 -     /* audioIns  */ 0,
 -     /* audioOuts */ 0,
 -     /* midiIns   */ 1,
 -     /* midiOuts  */ 1,
 -     /* paramIns  */ 0,
 -     /* paramOuts */ 0,
 -     /* name      */ "MIDI Sequencer",
 -     /* label     */ "midisequencer",
 -     /* maker     */ "falkTX, tatch",
 -     /* copyright */ "GNU GPL v2+",
 -     PluginDescriptorFILL(MidiSequencerPlugin)
 - };
 - 
 - // -----------------------------------------------------------------------
 - 
 - CARLA_EXPORT
 - void carla_register_native_plugin_midisequencer();
 - 
 - CARLA_EXPORT
 - void carla_register_native_plugin_midisequencer()
 - {
 -     carla_register_native_plugin(&midisequencerDesc);
 - }
 - 
 - // -----------------------------------------------------------------------
 
 
  |