Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

474 lines
15KB

  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2012-2015 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #ifndef MIDI_BASE_HPP_INCLUDED
  18. #define MIDI_BASE_HPP_INCLUDED
  19. #include "CarlaMIDI.h"
  20. #include "CarlaMutex.hpp"
  21. #include "LinkedList.hpp"
  22. #include "CarlaJuceUtils.hpp"
  23. #include "CarlaMathUtils.hpp"
  24. // -----------------------------------------------------------------------
  25. #define MAX_EVENT_DATA_SIZE 4
  26. #define MIN_PREALLOCATED_EVENT_COUNT 100
  27. #define MAX_PREALLOCATED_EVENT_COUNT 1000
  28. // -----------------------------------------------------------------------
  29. struct RawMidiEvent {
  30. uint64_t time;
  31. uint8_t size;
  32. uint8_t data[MAX_EVENT_DATA_SIZE];
  33. };
  34. // -----------------------------------------------------------------------
  35. class AbstractMidiPlayer
  36. {
  37. public:
  38. virtual ~AbstractMidiPlayer() {}
  39. virtual void writeMidiEvent(const uint8_t port, const long double timePosFrame, const RawMidiEvent* const event) = 0;
  40. };
  41. // -----------------------------------------------------------------------
  42. class MidiPattern
  43. {
  44. public:
  45. MidiPattern(AbstractMidiPlayer* const player) noexcept
  46. : kPlayer(player),
  47. fMidiPort(0),
  48. fStartTime(0),
  49. fMutex(),
  50. fData()
  51. {
  52. CARLA_SAFE_ASSERT(kPlayer != nullptr);
  53. }
  54. ~MidiPattern() noexcept
  55. {
  56. clear();
  57. }
  58. // -------------------------------------------------------------------
  59. // add data, time always counts from 0
  60. void addControl(const uint64_t time, const uint8_t channel, const uint8_t control, const uint8_t value)
  61. {
  62. RawMidiEvent* const ctrlEvent(new RawMidiEvent());
  63. ctrlEvent->time = time;
  64. ctrlEvent->size = 3;
  65. ctrlEvent->data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT));
  66. ctrlEvent->data[1] = control;
  67. ctrlEvent->data[2] = value;
  68. appendSorted(ctrlEvent);
  69. }
  70. void addChannelPressure(const uint64_t time, const uint8_t channel, const uint8_t pressure)
  71. {
  72. RawMidiEvent* const pressureEvent(new RawMidiEvent());
  73. pressureEvent->time = time;
  74. pressureEvent->size = 2;
  75. pressureEvent->data[0] = uint8_t(MIDI_STATUS_CHANNEL_PRESSURE | (channel & MIDI_CHANNEL_BIT));
  76. pressureEvent->data[1] = pressure;
  77. appendSorted(pressureEvent);
  78. }
  79. void addNote(const uint64_t time, const uint8_t channel, const uint8_t pitch, const uint8_t velocity, const uint32_t duration)
  80. {
  81. addNoteOn(time, channel, pitch, velocity);
  82. addNoteOff(time+duration, channel, pitch, velocity);
  83. }
  84. void addNoteOn(const uint64_t time, const uint8_t channel, const uint8_t pitch, const uint8_t velocity)
  85. {
  86. RawMidiEvent* const noteOnEvent(new RawMidiEvent());
  87. noteOnEvent->time = time;
  88. noteOnEvent->size = 3;
  89. noteOnEvent->data[0] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT));
  90. noteOnEvent->data[1] = pitch;
  91. noteOnEvent->data[2] = velocity;
  92. appendSorted(noteOnEvent);
  93. }
  94. void addNoteOff(const uint64_t time, const uint8_t channel, const uint8_t pitch, const uint8_t velocity = 0)
  95. {
  96. RawMidiEvent* const noteOffEvent(new RawMidiEvent());
  97. noteOffEvent->time = time;
  98. noteOffEvent->size = 3;
  99. noteOffEvent->data[0] = uint8_t(MIDI_STATUS_NOTE_OFF | (channel & MIDI_CHANNEL_BIT));
  100. noteOffEvent->data[1] = pitch;
  101. noteOffEvent->data[2] = velocity;
  102. appendSorted(noteOffEvent);
  103. }
  104. void addNoteAftertouch(const uint64_t time, const uint8_t channel, const uint8_t pitch, const uint8_t pressure)
  105. {
  106. RawMidiEvent* const noteAfterEvent(new RawMidiEvent());
  107. noteAfterEvent->time = time;
  108. noteAfterEvent->size = 3;
  109. noteAfterEvent->data[0] = uint8_t(MIDI_STATUS_POLYPHONIC_AFTERTOUCH | (channel & MIDI_CHANNEL_BIT));
  110. noteAfterEvent->data[1] = pitch;
  111. noteAfterEvent->data[2] = pressure;
  112. appendSorted(noteAfterEvent);
  113. }
  114. void addProgram(const uint64_t time, const uint8_t channel, const uint8_t bank, const uint8_t program)
  115. {
  116. RawMidiEvent* const bankEvent(new RawMidiEvent());
  117. bankEvent->time = time;
  118. bankEvent->size = 3;
  119. bankEvent->data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT));
  120. bankEvent->data[1] = MIDI_CONTROL_BANK_SELECT;
  121. bankEvent->data[2] = bank;
  122. RawMidiEvent* const programEvent(new RawMidiEvent());
  123. programEvent->time = time;
  124. programEvent->size = 2;
  125. programEvent->data[0] = uint8_t(MIDI_STATUS_PROGRAM_CHANGE | (channel & MIDI_CHANNEL_BIT));
  126. programEvent->data[1] = program;
  127. appendSorted(bankEvent);
  128. appendSorted(programEvent);
  129. }
  130. void addPitchbend(const uint64_t time, const uint8_t channel, const uint8_t lsb, const uint8_t msb)
  131. {
  132. RawMidiEvent* const pressureEvent(new RawMidiEvent());
  133. pressureEvent->time = time;
  134. pressureEvent->size = 3;
  135. pressureEvent->data[0] = uint8_t(MIDI_STATUS_PITCH_WHEEL_CONTROL | (channel & MIDI_CHANNEL_BIT));
  136. pressureEvent->data[1] = lsb;
  137. pressureEvent->data[2] = msb;
  138. appendSorted(pressureEvent);
  139. }
  140. void addRaw(const uint64_t time, const uint8_t* const data, const uint8_t size)
  141. {
  142. RawMidiEvent* const rawEvent(new RawMidiEvent());
  143. rawEvent->time = time;
  144. rawEvent->size = size;
  145. carla_copy<uint8_t>(rawEvent->data, data, size);
  146. // Fix zero-velocity note-ons
  147. if (MIDI_IS_STATUS_NOTE_ON(data[0]) && data[2] == 0)
  148. rawEvent->data[0] = uint8_t(MIDI_STATUS_NOTE_OFF | (data[0] & MIDI_CHANNEL_BIT));
  149. appendSorted(rawEvent);
  150. }
  151. // -------------------------------------------------------------------
  152. // remove data
  153. void removeRaw(const uint64_t time, const uint8_t* const data, const uint8_t size)
  154. {
  155. const CarlaMutexLocker sl(fMutex);
  156. for (LinkedList<const RawMidiEvent*>::Itenerator it = fData.begin2(); it.valid(); it.next())
  157. {
  158. const RawMidiEvent* const rawMidiEvent(it.getValue(nullptr));
  159. CARLA_SAFE_ASSERT_CONTINUE(rawMidiEvent != nullptr);
  160. if (rawMidiEvent->time != time)
  161. continue;
  162. if (rawMidiEvent->size != size)
  163. continue;
  164. if (std::memcmp(rawMidiEvent->data, data, size) != 0)
  165. continue;
  166. delete rawMidiEvent;
  167. fData.remove(it);
  168. return;
  169. }
  170. carla_stderr("MidiPattern::removeRaw(" P_INT64 ", %p, %i) - unable to find event to remove", time, data, size);
  171. }
  172. // -------------------------------------------------------------------
  173. // clear
  174. void clear() noexcept
  175. {
  176. const CarlaMutexLocker sl(fMutex);
  177. for (LinkedList<const RawMidiEvent*>::Itenerator it = fData.begin2(); it.valid(); it.next())
  178. delete it.getValue(nullptr);
  179. fData.clear();
  180. }
  181. // -------------------------------------------------------------------
  182. // play on time
  183. void play(const uint64_t timePosFrame, const uint32_t frames)
  184. {
  185. play(static_cast<long double>(timePosFrame), static_cast<double>(frames));
  186. }
  187. void play(long double timePosFrame, const double frames)
  188. {
  189. if (! fMutex.tryLock())
  190. return;
  191. if (fStartTime != 0)
  192. timePosFrame += static_cast<long double>(fStartTime);
  193. for (LinkedList<const RawMidiEvent*>::Itenerator it = fData.begin2(); it.valid(); it.next())
  194. {
  195. const RawMidiEvent* const rawMidiEvent(it.getValue(nullptr));
  196. CARLA_SAFE_ASSERT_CONTINUE(rawMidiEvent != nullptr);
  197. if (timePosFrame > rawMidiEvent->time)
  198. continue;
  199. if (timePosFrame + frames <= rawMidiEvent->time)
  200. continue;
  201. kPlayer->writeMidiEvent(fMidiPort, static_cast<long double>(rawMidiEvent->time)-timePosFrame, rawMidiEvent);
  202. }
  203. fMutex.unlock();
  204. }
  205. // -------------------------------------------------------------------
  206. // configure
  207. void setMidiPort(const uint8_t port) noexcept
  208. {
  209. fMidiPort = port;
  210. }
  211. void setStartTime(const uint64_t time) noexcept
  212. {
  213. fStartTime = time;
  214. }
  215. // -------------------------------------------------------------------
  216. // special
  217. const CarlaMutex& getLock() const noexcept
  218. {
  219. return fMutex;
  220. }
  221. LinkedList<const RawMidiEvent*>::Itenerator iteneratorBegin() const noexcept
  222. {
  223. return fData.begin2();
  224. }
  225. // -------------------------------------------------------------------
  226. // state
  227. char* getState() const
  228. {
  229. static const std::size_t maxTimeSize = 20; // std::strlen("18446744073709551615");
  230. static const std::size_t maxDataSize = 4 + 4*MAX_EVENT_DATA_SIZE; // std::strlen("0xFF:127:127:127");
  231. static const std::size_t maxMsgSize = maxTimeSize + 3 /* sep + size + sep */ + maxDataSize + 1 /* newline */;
  232. const CarlaMutexLocker sl(fMutex);
  233. if (fData.count() == 0)
  234. return nullptr;
  235. char* const data((char*)std::calloc(1, fData.count()*maxMsgSize+1));
  236. CARLA_SAFE_ASSERT_RETURN(data != nullptr, nullptr);
  237. char* dataWrtn = data;
  238. int wrtn;
  239. for (LinkedList<const RawMidiEvent*>::Itenerator it = fData.begin2(); it.valid(); it.next())
  240. {
  241. const RawMidiEvent* const rawMidiEvent(it.getValue(nullptr));
  242. CARLA_SAFE_ASSERT_CONTINUE(rawMidiEvent != nullptr);
  243. wrtn = std::snprintf(dataWrtn, maxTimeSize+6, P_UINT64 ":%u:", rawMidiEvent->time, rawMidiEvent->size);
  244. CARLA_SAFE_ASSERT_BREAK(wrtn > 0);
  245. dataWrtn += wrtn;
  246. wrtn = std::snprintf(dataWrtn, 5, "0x%02X", rawMidiEvent->data[0]);
  247. CARLA_SAFE_ASSERT_BREAK(wrtn > 0);
  248. dataWrtn += wrtn;
  249. for (uint8_t i=1, size=rawMidiEvent->size; i<size; ++i)
  250. {
  251. wrtn = std::snprintf(dataWrtn, 5, ":%03u", rawMidiEvent->data[i]);
  252. CARLA_SAFE_ASSERT_BREAK(wrtn > 0);
  253. dataWrtn += wrtn;
  254. }
  255. *dataWrtn++ = '\n';
  256. }
  257. *dataWrtn = '\0';
  258. return data;
  259. }
  260. void setState(const char* const data)
  261. {
  262. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  263. const size_t dataLen = std::strlen(data);
  264. const char* dataRead = data;
  265. const char* needle;
  266. RawMidiEvent midiEvent;
  267. char tmpBuf[24];
  268. ssize_t tmpSize;
  269. clear();
  270. const CarlaMutexLocker sl(fMutex);
  271. for (size_t dataPos=0; dataPos < dataLen && *dataRead != '\0';)
  272. {
  273. // get time
  274. needle = std::strchr(dataRead, ':');
  275. if (needle == nullptr)
  276. return;
  277. carla_zeroStruct(midiEvent);
  278. tmpSize = needle - dataRead;
  279. CARLA_SAFE_ASSERT_RETURN(tmpSize > 0,);
  280. CARLA_SAFE_ASSERT_RETURN(tmpSize < 24,);
  281. {
  282. const size_t uSize = static_cast<size_t>(tmpSize);
  283. std::strncpy(tmpBuf, dataRead, uSize);
  284. tmpBuf[tmpSize] = '\0';
  285. dataRead += uSize+1U;
  286. dataPos += uSize+1U;
  287. }
  288. const long long time = std::atoll(tmpBuf);
  289. CARLA_SAFE_ASSERT_RETURN(time >= 0,);
  290. midiEvent.time = static_cast<uint64_t>(time);
  291. // get size
  292. needle = std::strchr(dataRead, ':');
  293. CARLA_SAFE_ASSERT_RETURN(needle != nullptr,);
  294. tmpSize = needle - dataRead;
  295. CARLA_SAFE_ASSERT_RETURN(tmpSize > 0 && tmpSize < 24,);
  296. {
  297. const size_t uSize = static_cast<size_t>(tmpSize);
  298. std::strncpy(tmpBuf, dataRead, uSize);
  299. tmpBuf[tmpSize] = '\0';
  300. dataRead += uSize+1U;
  301. dataPos += uSize+1U;
  302. }
  303. const int midiDataSize = std::atoi(tmpBuf);
  304. CARLA_SAFE_ASSERT_RETURN(midiDataSize > 0 && midiDataSize <= MAX_EVENT_DATA_SIZE,);
  305. midiEvent.size = static_cast<uint8_t>(midiDataSize);
  306. // get events
  307. for (int i=0; i<midiDataSize; ++i)
  308. {
  309. CARLA_SAFE_ASSERT_RETURN(dataRead-data >= 4,);
  310. tmpSize = i==0 ? 4 : 3;
  311. const size_t uSize = static_cast<size_t>(tmpSize);
  312. std::strncpy(tmpBuf, dataRead, uSize);
  313. tmpBuf[tmpSize] = '\0';
  314. dataRead += uSize+1U;
  315. dataPos += uSize+1U;
  316. long mdata;
  317. if (i == 0)
  318. {
  319. mdata = std::strtol(tmpBuf, nullptr, 16);
  320. CARLA_SAFE_ASSERT_RETURN(mdata >= 0x80 && mdata <= 0xFF,);
  321. }
  322. else
  323. {
  324. mdata = std::atoi(tmpBuf);
  325. CARLA_SAFE_ASSERT_RETURN(mdata >= 0 && mdata < MAX_MIDI_VALUE,);
  326. }
  327. midiEvent.data[i] = static_cast<uint8_t>(mdata);
  328. }
  329. for (int i=midiDataSize; i<MAX_EVENT_DATA_SIZE; ++i)
  330. midiEvent.data[i] = 0;
  331. RawMidiEvent* const event(new RawMidiEvent());
  332. carla_copyStruct(*event, midiEvent);
  333. fData.append(event);
  334. }
  335. }
  336. // -------------------------------------------------------------------
  337. private:
  338. AbstractMidiPlayer* const kPlayer;
  339. uint8_t fMidiPort;
  340. uint64_t fStartTime;
  341. CarlaMutex fMutex;
  342. LinkedList<const RawMidiEvent*> fData;
  343. void appendSorted(const RawMidiEvent* const event)
  344. {
  345. const CarlaMutexLocker sl(fMutex);
  346. if (fData.isEmpty())
  347. {
  348. fData.append(event);
  349. return;
  350. }
  351. for (LinkedList<const RawMidiEvent*>::Itenerator it = fData.begin2(); it.valid(); it.next())
  352. {
  353. const RawMidiEvent* const oldEvent(it.getValue(nullptr));
  354. CARLA_SAFE_ASSERT_CONTINUE(oldEvent != nullptr);
  355. if (event->time >= oldEvent->time)
  356. continue;
  357. fData.insertAt(event, it);
  358. return;
  359. }
  360. fData.append(event);
  361. }
  362. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MidiPattern)
  363. };
  364. // -----------------------------------------------------------------------
  365. #endif // MIDI_BASE_HPP_INCLUDED