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.

464 lines
14KB

  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. RawMidiEvent() noexcept
  34. : time(0),
  35. size(0)
  36. {
  37. carla_zeroBytes(data, MAX_EVENT_DATA_SIZE);
  38. }
  39. };
  40. // -----------------------------------------------------------------------
  41. class AbstractMidiPlayer
  42. {
  43. public:
  44. virtual ~AbstractMidiPlayer() {}
  45. virtual void writeMidiEvent(const uint8_t port, const long double timePosFrame, const RawMidiEvent* const event) = 0;
  46. };
  47. // -----------------------------------------------------------------------
  48. class MidiPattern
  49. {
  50. public:
  51. MidiPattern(AbstractMidiPlayer* const player) noexcept
  52. : kPlayer(player),
  53. fMidiPort(0),
  54. fStartTime(0),
  55. fMutex(),
  56. fData(),
  57. leakDetector_MidiPattern()
  58. {
  59. CARLA_SAFE_ASSERT(kPlayer != nullptr);
  60. }
  61. ~MidiPattern() noexcept
  62. {
  63. clear();
  64. }
  65. // -------------------------------------------------------------------
  66. // add data, time always counts from 0
  67. void addControl(const uint64_t time, const uint8_t channel, const uint8_t control, const uint8_t value)
  68. {
  69. RawMidiEvent* const ctrlEvent(new RawMidiEvent());
  70. ctrlEvent->time = time;
  71. ctrlEvent->size = 3;
  72. ctrlEvent->data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT));
  73. ctrlEvent->data[1] = control;
  74. ctrlEvent->data[2] = value;
  75. appendSorted(ctrlEvent);
  76. }
  77. void addChannelPressure(const uint64_t time, const uint8_t channel, const uint8_t pressure)
  78. {
  79. RawMidiEvent* const pressureEvent(new RawMidiEvent());
  80. pressureEvent->time = time;
  81. pressureEvent->size = 2;
  82. pressureEvent->data[0] = uint8_t(MIDI_STATUS_CHANNEL_PRESSURE | (channel & MIDI_CHANNEL_BIT));
  83. pressureEvent->data[1] = pressure;
  84. appendSorted(pressureEvent);
  85. }
  86. void addNote(const uint64_t time, const uint8_t channel, const uint8_t pitch, const uint8_t velocity, const uint32_t duration)
  87. {
  88. addNoteOn(time, channel, pitch, velocity);
  89. addNoteOff(time+duration, channel, pitch, velocity);
  90. }
  91. void addNoteOn(const uint64_t time, const uint8_t channel, const uint8_t pitch, const uint8_t velocity)
  92. {
  93. RawMidiEvent* const noteOnEvent(new RawMidiEvent());
  94. noteOnEvent->time = time;
  95. noteOnEvent->size = 3;
  96. noteOnEvent->data[0] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT));
  97. noteOnEvent->data[1] = pitch;
  98. noteOnEvent->data[2] = velocity;
  99. appendSorted(noteOnEvent);
  100. }
  101. void addNoteOff(const uint64_t time, const uint8_t channel, const uint8_t pitch, const uint8_t velocity = 0)
  102. {
  103. RawMidiEvent* const noteOffEvent(new RawMidiEvent());
  104. noteOffEvent->time = time;
  105. noteOffEvent->size = 3;
  106. noteOffEvent->data[0] = uint8_t(MIDI_STATUS_NOTE_OFF | (channel & MIDI_CHANNEL_BIT));
  107. noteOffEvent->data[1] = pitch;
  108. noteOffEvent->data[2] = velocity;
  109. appendSorted(noteOffEvent);
  110. }
  111. void addNoteAftertouch(const uint64_t time, const uint8_t channel, const uint8_t pitch, const uint8_t pressure)
  112. {
  113. RawMidiEvent* const noteAfterEvent(new RawMidiEvent());
  114. noteAfterEvent->time = time;
  115. noteAfterEvent->size = 3;
  116. noteAfterEvent->data[0] = uint8_t(MIDI_STATUS_POLYPHONIC_AFTERTOUCH | (channel & MIDI_CHANNEL_BIT));
  117. noteAfterEvent->data[1] = pitch;
  118. noteAfterEvent->data[2] = pressure;
  119. appendSorted(noteAfterEvent);
  120. }
  121. void addProgram(const uint64_t time, const uint8_t channel, const uint8_t bank, const uint8_t program)
  122. {
  123. RawMidiEvent* const bankEvent(new RawMidiEvent());
  124. bankEvent->time = time;
  125. bankEvent->size = 3;
  126. bankEvent->data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (channel & MIDI_CHANNEL_BIT));
  127. bankEvent->data[1] = MIDI_CONTROL_BANK_SELECT;
  128. bankEvent->data[2] = bank;
  129. RawMidiEvent* const programEvent(new RawMidiEvent());
  130. programEvent->time = time;
  131. programEvent->size = 2;
  132. programEvent->data[0] = uint8_t(MIDI_STATUS_PROGRAM_CHANGE | (channel & MIDI_CHANNEL_BIT));
  133. programEvent->data[1] = program;
  134. appendSorted(bankEvent);
  135. appendSorted(programEvent);
  136. }
  137. void addPitchbend(const uint64_t time, const uint8_t channel, const uint8_t lsb, const uint8_t msb)
  138. {
  139. RawMidiEvent* const pressureEvent(new RawMidiEvent());
  140. pressureEvent->time = time;
  141. pressureEvent->size = 3;
  142. pressureEvent->data[0] = uint8_t(MIDI_STATUS_PITCH_WHEEL_CONTROL | (channel & MIDI_CHANNEL_BIT));
  143. pressureEvent->data[1] = lsb;
  144. pressureEvent->data[2] = msb;
  145. appendSorted(pressureEvent);
  146. }
  147. void addRaw(const uint64_t time, const uint8_t* const data, const uint8_t size)
  148. {
  149. RawMidiEvent* const rawEvent(new RawMidiEvent());
  150. rawEvent->time = time;
  151. rawEvent->size = size;
  152. carla_copy<uint8_t>(rawEvent->data, data, size);
  153. appendSorted(rawEvent);
  154. }
  155. // -------------------------------------------------------------------
  156. // remove data
  157. void removeRaw(const uint64_t time, const uint8_t* const data, const uint8_t size)
  158. {
  159. const CarlaMutexLocker sl(fMutex);
  160. for (LinkedList<const RawMidiEvent*>::Itenerator it = fData.begin(); it.valid(); it.next())
  161. {
  162. const RawMidiEvent* const rawMidiEvent(it.getValue(nullptr));
  163. CARLA_SAFE_ASSERT_CONTINUE(rawMidiEvent != nullptr);
  164. if (rawMidiEvent->time != time)
  165. continue;
  166. if (rawMidiEvent->size != size)
  167. continue;
  168. if (std::memcmp(rawMidiEvent->data, data, size) != 0)
  169. continue;
  170. delete rawMidiEvent;
  171. fData.remove(it);
  172. return;
  173. }
  174. carla_stderr("MidiPattern::removeRaw(" P_INT64 ", %p, %i) - unable to find event to remove", time, data, size);
  175. }
  176. // -------------------------------------------------------------------
  177. // clear
  178. void clear() noexcept
  179. {
  180. const CarlaMutexLocker sl(fMutex);
  181. for (LinkedList<const RawMidiEvent*>::Itenerator it = fData.begin(); it.valid(); it.next())
  182. delete it.getValue(nullptr);
  183. fData.clear();
  184. }
  185. // -------------------------------------------------------------------
  186. // play on time
  187. void play(const uint64_t timePosFrame, const uint32_t frames)
  188. {
  189. play(static_cast<long double>(timePosFrame), static_cast<double>(frames));
  190. }
  191. void play(long double timePosFrame, const double frames)
  192. {
  193. if (! fMutex.tryLock())
  194. return;
  195. if (fStartTime != 0)
  196. timePosFrame += static_cast<long double>(fStartTime);
  197. for (LinkedList<const RawMidiEvent*>::Itenerator it = fData.begin(); it.valid(); it.next())
  198. {
  199. const RawMidiEvent* const rawMidiEvent(it.getValue(nullptr));
  200. CARLA_SAFE_ASSERT_CONTINUE(rawMidiEvent != nullptr);
  201. if (timePosFrame > rawMidiEvent->time)
  202. continue;
  203. if (timePosFrame + frames <= rawMidiEvent->time)
  204. continue;
  205. kPlayer->writeMidiEvent(fMidiPort, static_cast<long double>(rawMidiEvent->time)-timePosFrame, rawMidiEvent);
  206. }
  207. fMutex.unlock();
  208. }
  209. // -------------------------------------------------------------------
  210. // configure
  211. void setMidiPort(const uint8_t port) noexcept
  212. {
  213. fMidiPort = port;
  214. }
  215. void setStartTime(const uint64_t time) noexcept
  216. {
  217. fStartTime = time;
  218. }
  219. // -------------------------------------------------------------------
  220. // special
  221. const CarlaMutex& getLock() const noexcept
  222. {
  223. return fMutex;
  224. }
  225. LinkedList<const RawMidiEvent*>::Itenerator iteneratorBegin() const noexcept
  226. {
  227. return fData.begin();
  228. }
  229. // -------------------------------------------------------------------
  230. // state
  231. char* getState() const
  232. {
  233. static const std::size_t maxTimeSize = 20; // std::strlen("18446744073709551615");
  234. static const std::size_t maxDataSize = 4 + 4*MAX_EVENT_DATA_SIZE; // std::strlen("0xFF:127:127:127");
  235. static const std::size_t maxMsgSize = maxTimeSize + 3 /* sep + size + sep */ + maxDataSize + 1 /* newline */;
  236. const CarlaMutexLocker sl(fMutex);
  237. if (fData.count() == 0)
  238. return nullptr;
  239. char* const data((char*)std::calloc(1, fData.count()*maxMsgSize));
  240. CARLA_SAFE_ASSERT_RETURN(data != nullptr, nullptr);
  241. char* dataWrtn = data;
  242. int wrtn;
  243. for (LinkedList<const RawMidiEvent*>::Itenerator it = fData.begin(); it.valid(); it.next())
  244. {
  245. const RawMidiEvent* const rawMidiEvent(it.getValue(nullptr));
  246. CARLA_SAFE_ASSERT_CONTINUE(rawMidiEvent != nullptr);
  247. wrtn = std::snprintf(dataWrtn, maxTimeSize+4, P_INT64 ":%i:", rawMidiEvent->time, rawMidiEvent->size);
  248. CARLA_SAFE_ASSERT_BREAK(wrtn > 0);
  249. dataWrtn += wrtn;
  250. wrtn = std::snprintf(dataWrtn, 5, "0x%02X", rawMidiEvent->data[0]);
  251. CARLA_SAFE_ASSERT_BREAK(wrtn > 0);
  252. dataWrtn += wrtn;
  253. for (uint8_t i=1, size=rawMidiEvent->size; i<size; ++i)
  254. {
  255. wrtn = std::snprintf(dataWrtn, 5, ":%03u", rawMidiEvent->data[i]);
  256. CARLA_SAFE_ASSERT_BREAK(wrtn > 0);
  257. dataWrtn += wrtn;
  258. }
  259. *dataWrtn++ = '\n';
  260. }
  261. *dataWrtn = '\0';
  262. return data;
  263. }
  264. void setState(const char* const data)
  265. {
  266. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  267. const char* dataRead = data;
  268. const char* needle;
  269. RawMidiEvent midiEvent;
  270. char tmpBuf[24];
  271. ssize_t tmpSize;
  272. clear();
  273. const CarlaMutexLocker sl(fMutex);
  274. for (; *dataRead != '\0';)
  275. {
  276. // get time
  277. needle = std::strchr(dataRead, ':');
  278. if (needle == nullptr)
  279. return;
  280. tmpSize = needle - dataRead;
  281. CARLA_SAFE_ASSERT_RETURN(tmpSize > 0 && tmpSize < 24,);
  282. std::strncpy(tmpBuf, dataRead, static_cast<size_t>(tmpSize));
  283. tmpBuf[tmpSize] = '\0';
  284. dataRead += tmpSize+1;
  285. const long long time = std::atoll(tmpBuf);
  286. CARLA_SAFE_ASSERT_RETURN(time >= 0,);
  287. midiEvent.time = static_cast<uint64_t>(time);
  288. // get size
  289. needle = std::strchr(dataRead, ':');
  290. CARLA_SAFE_ASSERT_RETURN(needle != nullptr,);
  291. tmpSize = needle - dataRead;
  292. CARLA_SAFE_ASSERT_RETURN(tmpSize > 0 && tmpSize < 24,);
  293. std::strncpy(tmpBuf, dataRead, static_cast<size_t>(tmpSize));
  294. tmpBuf[tmpSize] = '\0';
  295. dataRead += tmpSize+1;
  296. const int size = std::atoi(tmpBuf);
  297. CARLA_SAFE_ASSERT_RETURN(size > 0 && size <= MAX_EVENT_DATA_SIZE,);
  298. midiEvent.size = static_cast<uint8_t>(size);
  299. // get events
  300. for (int i=0; i<size; ++i)
  301. {
  302. CARLA_SAFE_ASSERT_RETURN(dataRead-data >= 4,);
  303. tmpSize = i==0 ? 4 : 3;
  304. std::strncpy(tmpBuf, dataRead, static_cast<size_t>(tmpSize));
  305. tmpBuf[tmpSize] = '\0';
  306. dataRead += tmpSize+1;
  307. long mdata;
  308. if (i == 0)
  309. {
  310. mdata = std::strtol(tmpBuf, nullptr, 16);
  311. CARLA_SAFE_ASSERT_RETURN(mdata >= 0x80 && mdata <= 0xFF,);
  312. }
  313. else
  314. {
  315. mdata = std::atoi(tmpBuf);
  316. CARLA_SAFE_ASSERT_RETURN(mdata >= 0 && mdata < MAX_MIDI_VALUE,);
  317. }
  318. midiEvent.data[i] = static_cast<uint8_t>(mdata);
  319. }
  320. for (int i=size; i<MAX_EVENT_DATA_SIZE; ++i)
  321. midiEvent.data[i] = 0;
  322. RawMidiEvent* const event(new RawMidiEvent());
  323. carla_copyStruct(*event, midiEvent);
  324. fData.append(event);
  325. }
  326. }
  327. // -------------------------------------------------------------------
  328. private:
  329. AbstractMidiPlayer* const kPlayer;
  330. uint8_t fMidiPort;
  331. uint64_t fStartTime;
  332. CarlaMutex fMutex;
  333. LinkedList<const RawMidiEvent*> fData;
  334. void appendSorted(const RawMidiEvent* const event)
  335. {
  336. const CarlaMutexLocker sl(fMutex);
  337. if (fData.isEmpty())
  338. {
  339. fData.append(event);
  340. return;
  341. }
  342. for (LinkedList<const RawMidiEvent*>::Itenerator it = fData.begin(); it.valid(); it.next())
  343. {
  344. const RawMidiEvent* const oldEvent(it.getValue(nullptr));
  345. CARLA_SAFE_ASSERT_CONTINUE(oldEvent != nullptr);
  346. if (event->time >= oldEvent->time)
  347. continue;
  348. fData.insertAt(event, it);
  349. return;
  350. }
  351. fData.append(event);
  352. }
  353. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MidiPattern)
  354. };
  355. // -----------------------------------------------------------------------
  356. #endif // MIDI_BASE_HPP_INCLUDED