Collection of tools useful for audio production
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.

701 lines
20KB

  1. /*
  2. * Caitlib
  3. * Copyright (C) 2007 Nedko Arnaudov <nedko@arnaudov.name>
  4. * Copyright (C) 2012 Filipe Coelho <falktx@falktx.com>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * For a full copy of the GNU General Public License see the COPYING file
  17. */
  18. #include <math.h>
  19. #include <stdbool.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <pthread.h>
  24. #include <jack/jack.h>
  25. #include <jack/midiport.h>
  26. #include "caitlib.h"
  27. #include "list.h"
  28. #include "memory_atomic.h"
  29. #define MAX_EVENT_DATA_SIZE 100
  30. #define MIN_PREALLOCATED_EVENT_COUNT 100
  31. #define MAX_PREALLOCATED_EVENT_COUNT 1000
  32. //#define USE_LIST_HEAD_OUTS // incomplete
  33. // ------------------------------------------------------------------------------------------
  34. typedef struct list_head ListHead;
  35. typedef pthread_mutex_t Mutex;
  36. typedef struct _RawMidiEvent {
  37. ListHead siblings;
  38. jack_midi_data_t data[MAX_EVENT_DATA_SIZE];
  39. size_t dataSize;
  40. jack_nframes_t time;
  41. } RawMidiEvent;
  42. typedef struct _CaitlibOutPort {
  43. #ifdef USE_LIST_HEAD_OUTS
  44. ListHead siblings;
  45. #endif
  46. uint32_t id;
  47. ListHead queue;
  48. jack_port_t* port;
  49. } CaitlibOutPort;
  50. typedef struct _CaitlibInstance {
  51. bool doProcess, wantEvents;
  52. jack_client_t* client;
  53. jack_port_t* midiIn;
  54. #ifdef USE_LIST_HEAD_OUTS
  55. ListHead outPorts;
  56. #else
  57. uint32_t midiOutCount;
  58. CaitlibOutPort** midiOuts;
  59. #endif
  60. ListHead inQueue;
  61. ListHead inQueuePendingRT;
  62. Mutex mutex;
  63. rtsafe_memory_pool_handle mempool;
  64. } CaitlibInstance;
  65. // ------------------------------------------------------------------------------------------
  66. #define handlePtr ((CaitlibInstance*)ptr)
  67. static
  68. int jack_process(jack_nframes_t nframes, void* ptr)
  69. {
  70. if (! handlePtr->doProcess)
  71. return 0;
  72. void* portBuffer;
  73. RawMidiEvent* eventPtr;
  74. jack_position_t transportPos;
  75. jack_transport_state_t transportState = jack_transport_query(handlePtr->client, &transportPos);
  76. if (transportPos.unique_1 != transportPos.unique_2)
  77. transportPos.frame = 0;
  78. // MIDI In
  79. if (handlePtr->wantEvents)
  80. {
  81. jack_midi_event_t inEvent;
  82. jack_nframes_t inEventCount;
  83. portBuffer = jack_port_get_buffer(handlePtr->midiIn, nframes);
  84. inEventCount = jack_midi_get_event_count(portBuffer);
  85. for (jack_nframes_t i = 0 ; i < inEventCount; i++)
  86. {
  87. if (jack_midi_event_get(&inEvent, portBuffer, i) != 0)
  88. break;
  89. if (inEvent.size > MAX_EVENT_DATA_SIZE)
  90. continue;
  91. /* allocate memory for buffer copy */
  92. eventPtr = rtsafe_memory_pool_allocate(handlePtr->mempool);
  93. if (eventPtr == NULL)
  94. {
  95. //LOG_ERROR("Ignored midi event with size %u because memory allocation failed.", (unsigned int)inEvent.size);
  96. continue;
  97. }
  98. /* copy buffer data */
  99. memcpy(eventPtr->data, inEvent.buffer, inEvent.size);
  100. eventPtr->dataSize = inEvent.size;
  101. eventPtr->time = transportPos.frame + inEvent.time;
  102. /* Add event buffer to inQueuePendingRT list */
  103. list_add(&eventPtr->siblings, &handlePtr->inQueuePendingRT);
  104. }
  105. }
  106. if (pthread_mutex_trylock(&handlePtr->mutex) != 0)
  107. return 0;
  108. if (handlePtr->wantEvents)
  109. list_splice_init(&handlePtr->inQueuePendingRT, &handlePtr->inQueue);
  110. #ifdef USE_LIST_HEAD_OUTS
  111. if (transportState == JackTransportRolling)
  112. {
  113. }
  114. #else
  115. // MIDI Out
  116. if (handlePtr->midiOutCount > 0 && transportState == JackTransportRolling)
  117. {
  118. ListHead* entryPtr;
  119. CaitlibOutPort* outPortPtr;
  120. for (uint32_t i = 0; i < handlePtr->midiOutCount; i++)
  121. {
  122. outPortPtr = handlePtr->midiOuts[i];
  123. portBuffer = jack_port_get_buffer(outPortPtr->port, nframes);
  124. jack_midi_clear_buffer(portBuffer);
  125. list_for_each(entryPtr, &outPortPtr->queue)
  126. {
  127. eventPtr = list_entry(entryPtr, RawMidiEvent, siblings);
  128. if (transportPos.frame > eventPtr->time || transportPos.frame + nframes <= eventPtr->time)
  129. continue;
  130. if (jack_midi_event_write(portBuffer, eventPtr->time - transportPos.frame, eventPtr->data, eventPtr->dataSize) != 0)
  131. break;
  132. }
  133. }
  134. }
  135. #endif
  136. pthread_mutex_unlock(&handlePtr->mutex);
  137. return 0;
  138. }
  139. #undef handlePtr
  140. // ------------------------------------------------------------------------------------------
  141. // Initialization
  142. CaitlibHandle caitlib_init(const char* instanceName)
  143. {
  144. CaitlibInstance* handlePtr = (CaitlibInstance*)malloc(sizeof(CaitlibInstance));
  145. if (handlePtr == NULL)
  146. goto fail;
  147. handlePtr->doProcess = true;
  148. handlePtr->wantEvents = false;
  149. #ifdef USE_LIST_HEAD_OUTS
  150. INIT_LIST_HEAD(&handlePtr->outPorts);
  151. #else
  152. handlePtr->midiOuts = NULL;
  153. handlePtr->midiOutCount = 0;
  154. #endif
  155. INIT_LIST_HEAD(&handlePtr->inQueue);
  156. INIT_LIST_HEAD(&handlePtr->inQueuePendingRT);
  157. if (! rtsafe_memory_pool_create(sizeof(RawMidiEvent), MIN_PREALLOCATED_EVENT_COUNT, MAX_PREALLOCATED_EVENT_COUNT, &handlePtr->mempool))
  158. goto fail_free;
  159. pthread_mutex_init(&handlePtr->mutex, NULL);
  160. handlePtr->client = jack_client_open(instanceName, JackNullOption, 0);
  161. if (handlePtr->client == NULL)
  162. goto fail_destroyMutex;
  163. handlePtr->midiIn = jack_port_register(handlePtr->client, "midi-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
  164. if (handlePtr->midiIn == NULL)
  165. goto fail_closeJack;
  166. if (jack_set_process_callback(handlePtr->client, jack_process, handlePtr) != 0)
  167. goto fail_closeJack;
  168. if (jack_activate(handlePtr->client) != 0)
  169. goto fail_closeJack;
  170. return handlePtr;
  171. fail_closeJack:
  172. jack_client_close(handlePtr->client);
  173. fail_destroyMutex:
  174. pthread_mutex_destroy(&handlePtr->mutex);
  175. //fail_destroy_pool:
  176. rtsafe_memory_pool_destroy(handlePtr->mempool);
  177. fail_free:
  178. free(handlePtr);
  179. fail:
  180. return NULL;
  181. }
  182. #define handlePtr ((CaitlibInstance*)handle)
  183. void caitlib_close(CaitlibHandle handle)
  184. {
  185. // wait for jack processing to end
  186. handlePtr->doProcess = false;
  187. pthread_mutex_lock(&handlePtr->mutex);
  188. if (handlePtr->client)
  189. {
  190. #ifdef USE_LIST_HEAD_OUTS
  191. ListHead* entryPtr;
  192. CaitlibOutPort* outPortPtr;
  193. #endif
  194. jack_deactivate(handlePtr->client);
  195. jack_port_unregister(handlePtr->client, handlePtr->midiIn);
  196. #ifdef USE_LIST_HEAD_OUTS
  197. list_for_each(entryPtr, &handlePtr->outPorts)
  198. {
  199. outPortPtr = list_entry(entryPtr, CaitlibOutPort, siblings);
  200. jack_port_unregister(handlePtr->client, outPortPtr->port);
  201. }
  202. #else
  203. for (uint32_t i = 0; i < handlePtr->midiOutCount; i++)
  204. {
  205. jack_port_unregister(handlePtr->client, handlePtr->midiOuts[i]->port);
  206. free(handlePtr->midiOuts[i]);
  207. }
  208. #endif
  209. jack_client_close(handlePtr->client);
  210. }
  211. pthread_mutex_unlock(&handlePtr->mutex);
  212. pthread_mutex_destroy(&handlePtr->mutex);
  213. rtsafe_memory_pool_destroy(handlePtr->mempool);
  214. free(handlePtr);
  215. }
  216. uint32_t caitlib_create_port(CaitlibHandle handle, const char* portName)
  217. {
  218. uint32_t nextId = 0;
  219. // wait for jack processing to end
  220. handlePtr->doProcess = false;
  221. pthread_mutex_lock(&handlePtr->mutex);
  222. // re-allocate pointers (midiOutCount + 1) and find next available ID
  223. {
  224. #ifdef USE_LIST_HEAD_OUTS
  225. ListHead* entryPtr;
  226. CaitlibOutPort* outPortPtr;
  227. list_for_each(entryPtr, &handlePtr->outPorts)
  228. {
  229. outPortPtr = list_entry(entryPtr, CaitlibOutPort, siblings);
  230. if (outPortPtr->id == nextId)
  231. {
  232. nextId++;
  233. continue;
  234. }
  235. }
  236. #else
  237. CaitlibOutPort* oldMidiOuts[handlePtr->midiOutCount];
  238. for (uint32_t i = 0; i < handlePtr->midiOutCount; i++)
  239. {
  240. oldMidiOuts[i] = handlePtr->midiOuts[i];
  241. if (handlePtr->midiOuts[i]->id == nextId)
  242. nextId++;
  243. }
  244. if (handlePtr->midiOuts)
  245. free(handlePtr->midiOuts);
  246. handlePtr->midiOuts = (CaitlibOutPort**)malloc(sizeof(CaitlibOutPort*) * (handlePtr->midiOutCount+1));
  247. for (uint32_t i = 0; i < handlePtr->midiOutCount; i++)
  248. handlePtr->midiOuts[i] = oldMidiOuts[i];
  249. #endif
  250. }
  251. // we can continue normal operation now
  252. pthread_mutex_unlock(&handlePtr->mutex);
  253. handlePtr->doProcess = true;
  254. #ifdef USE_LIST_HEAD_OUTS
  255. #else
  256. // create new port
  257. {
  258. CaitlibOutPort* newPort = (CaitlibOutPort*)malloc(sizeof(CaitlibOutPort));
  259. newPort->id = nextId;
  260. newPort->port = jack_port_register(handlePtr->client, portName, JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
  261. INIT_LIST_HEAD(&newPort->queue);
  262. handlePtr->midiOuts[handlePtr->midiOutCount++] = newPort;
  263. }
  264. #endif
  265. return nextId;
  266. }
  267. void caitlib_destroy_port(CaitlibHandle handle, uint32_t port)
  268. {
  269. // wait for jack processing to end
  270. handlePtr->doProcess = false;
  271. pthread_mutex_lock(&handlePtr->mutex);
  272. #ifdef USE_LIST_HEAD_OUTS
  273. #else
  274. // re-allocate pointers (midiOutCount - 1)
  275. {
  276. CaitlibOutPort* oldMidiOuts[handlePtr->midiOutCount];
  277. for (uint32_t i = 0; i < handlePtr->midiOutCount; i++)
  278. oldMidiOuts[i] = handlePtr->midiOuts[i];
  279. if (handlePtr->midiOuts)
  280. free(handlePtr->midiOuts);
  281. if (handlePtr->midiOutCount == 1)
  282. {
  283. handlePtr->midiOuts = NULL;
  284. }
  285. else
  286. {
  287. handlePtr->midiOuts = (CaitlibOutPort**)malloc(sizeof(CaitlibOutPort*) * (handlePtr->midiOutCount-1));
  288. for (uint32_t i = 0, j = 0; i < handlePtr->midiOutCount; i++)
  289. {
  290. if (oldMidiOuts[i]->id != port)
  291. handlePtr->midiOuts[j++] = oldMidiOuts[i];
  292. }
  293. }
  294. handlePtr->midiOutCount--;
  295. }
  296. #endif
  297. pthread_mutex_unlock(&handlePtr->mutex);
  298. handlePtr->doProcess = true;
  299. return;
  300. (void)port;
  301. }
  302. // ------------------------------------------------------------------------------------------
  303. // Input
  304. void caitlib_want_events(CaitlibHandle handle, bool yesNo)
  305. {
  306. pthread_mutex_lock(&handlePtr->mutex);
  307. handlePtr->wantEvents = yesNo;
  308. pthread_mutex_unlock(&handlePtr->mutex);
  309. }
  310. MidiEvent* caitlib_get_event(CaitlibHandle handle)
  311. {
  312. static MidiEvent midiEvent;
  313. ListHead* nodePtr;
  314. RawMidiEvent* rawEventPtr;
  315. pthread_mutex_lock(&handlePtr->mutex);
  316. if (list_empty(&handlePtr->inQueue))
  317. {
  318. pthread_mutex_unlock(&handlePtr->mutex);
  319. return NULL;
  320. }
  321. nodePtr = handlePtr->inQueue.prev;
  322. list_del(nodePtr);
  323. rawEventPtr = list_entry(nodePtr, RawMidiEvent, siblings);
  324. pthread_mutex_unlock(&handlePtr->mutex);
  325. // note off
  326. if (rawEventPtr->dataSize == 3 && (rawEventPtr->data[0] & 0xF0) == 0x80)
  327. {
  328. midiEvent.type = MIDI_EVENT_TYPE_NOTE_OFF;
  329. midiEvent.channel = rawEventPtr->data[0] & 0x0F;
  330. midiEvent.data.note.note = rawEventPtr->data[1];
  331. midiEvent.data.note.velocity = rawEventPtr->data[2];
  332. }
  333. // note on
  334. else if (rawEventPtr->dataSize == 3 && (rawEventPtr->data[0] & 0xF0) == 0x90)
  335. {
  336. midiEvent.type = MIDI_EVENT_TYPE_NOTE_ON;
  337. midiEvent.channel = rawEventPtr->data[0] & 0x0F;
  338. midiEvent.data.note.note = rawEventPtr->data[1];
  339. midiEvent.data.note.velocity = rawEventPtr->data[2];
  340. }
  341. // aftertouch
  342. else if (rawEventPtr->dataSize == 3 && (rawEventPtr->data[0] & 0xF0) == 0xA0)
  343. {
  344. midiEvent.type = MIDI_EVENT_TYPE_AFTER_TOUCH;
  345. midiEvent.channel = rawEventPtr->data[0] & 0x0F;
  346. midiEvent.data.note.note = rawEventPtr->data[1];
  347. midiEvent.data.note.velocity = rawEventPtr->data[2];
  348. }
  349. // control
  350. else if (rawEventPtr->dataSize == 3 && (rawEventPtr->data[0] & 0xF0) == 0xB0)
  351. {
  352. midiEvent.type = MIDI_EVENT_TYPE_CONTROL;
  353. midiEvent.channel = rawEventPtr->data[0] & 0x0F;
  354. midiEvent.data.control.controller = rawEventPtr->data[1];
  355. midiEvent.data.control.value = rawEventPtr->data[2];
  356. }
  357. // program
  358. else if (rawEventPtr->dataSize == 2 && (rawEventPtr->data[0] & 0xF0) == 0xC0)
  359. {
  360. midiEvent.type = MIDI_EVENT_TYPE_PROGRAM;
  361. midiEvent.channel = rawEventPtr->data[0] & 0x0F;
  362. midiEvent.data.program.value = rawEventPtr->data[1];
  363. }
  364. // channel pressure
  365. else if (rawEventPtr->dataSize == 2 && (rawEventPtr->data[0] & 0xF0) == 0xD0)
  366. {
  367. midiEvent.type = MIDI_EVENT_TYPE_CHANNEL_PRESSURE;
  368. midiEvent.channel = rawEventPtr->data[0] & 0x0F;
  369. midiEvent.data.pressure.value = rawEventPtr->data[1];
  370. }
  371. // pitch wheel
  372. else if (rawEventPtr->dataSize == 3 && (rawEventPtr->data[0] & 0xF0) == 0xE0)
  373. {
  374. midiEvent.type = MIDI_EVENT_TYPE_PITCH_WHEEL;
  375. midiEvent.channel = rawEventPtr->data[0] & 0x0F;
  376. midiEvent.data.pitchwheel.value = ((rawEventPtr->data[2] << 7) | rawEventPtr->data[1]) - 8192;
  377. }
  378. else
  379. {
  380. return NULL;
  381. }
  382. rtsafe_memory_pool_deallocate(handlePtr->mempool, rawEventPtr);
  383. return &midiEvent;
  384. }
  385. // ------------------------------------------------------------------------------------------
  386. // Output (utils)
  387. void caitlib_midi_encode_control(RawMidiEvent* eventPtr, uint8_t channel, uint8_t control, uint8_t value)
  388. {
  389. eventPtr->data[0] = MIDI_EVENT_TYPE_CONTROL | (channel & 0x0F);
  390. eventPtr->data[1] = control;
  391. eventPtr->data[2] = value;
  392. eventPtr->dataSize = 3;
  393. }
  394. void caitlib_midi_encode_note_on(RawMidiEvent* eventPtr, uint8_t channel, uint8_t note, uint8_t velocity)
  395. {
  396. eventPtr->data[0] = MIDI_EVENT_TYPE_NOTE_ON | (channel & 0x0F);
  397. eventPtr->data[1] = note;
  398. eventPtr->data[2] = velocity;
  399. eventPtr->dataSize = 3;
  400. }
  401. void caitlib_midi_encode_note_off(RawMidiEvent* eventPtr, uint8_t channel, uint8_t note, uint8_t velocity)
  402. {
  403. eventPtr->data[0] = MIDI_EVENT_TYPE_NOTE_OFF | (channel & 0x0F);
  404. eventPtr->data[1] = note;
  405. eventPtr->data[2] = velocity;
  406. eventPtr->dataSize = 3;
  407. }
  408. void caitlib_midi_encode_aftertouch(RawMidiEvent* eventPtr, uint8_t channel, uint8_t note, uint8_t pressure)
  409. {
  410. eventPtr->data[0] = MIDI_EVENT_TYPE_AFTER_TOUCH | (channel & 0x0F);
  411. eventPtr->data[1] = note;
  412. eventPtr->data[2] = pressure;
  413. eventPtr->dataSize = 3;
  414. }
  415. void caitlib_midi_encode_channel_pressure(RawMidiEvent* eventPtr, uint8_t channel, uint8_t pressure)
  416. {
  417. eventPtr->data[0] = MIDI_EVENT_TYPE_CHANNEL_PRESSURE | (channel & 0x0F);
  418. eventPtr->data[1] = pressure;
  419. eventPtr->dataSize = 2;
  420. }
  421. void caitlib_midi_encode_program(RawMidiEvent* eventPtr, uint8_t channel, uint8_t program)
  422. {
  423. eventPtr->data[0] = MIDI_EVENT_TYPE_PROGRAM | (channel & 0x0F);
  424. eventPtr->data[1] = program;
  425. eventPtr->dataSize = 2;
  426. }
  427. void caitlib_midi_encode_pitchwheel(RawMidiEvent* eventPtr, uint8_t channel, int16_t pitchwheel)
  428. {
  429. pitchwheel += 8192;
  430. eventPtr->data[0] = MIDI_EVENT_TYPE_PITCH_WHEEL | (channel & 0x0F);
  431. eventPtr->data[1] = pitchwheel & 0x7F;
  432. eventPtr->data[2] = pitchwheel >> 7;
  433. eventPtr->dataSize = 3;
  434. }
  435. // ------------------------------------------------------------------------------------------
  436. // Output
  437. void caitlib_put_event(CaitlibHandle handle, uint32_t port, const MidiEvent* event)
  438. {
  439. #ifdef USE_LIST_HEAD_OUTS
  440. ListHead* entryPtr;
  441. #endif
  442. RawMidiEvent* eventPtr;
  443. CaitlibOutPort* outPortPtr;
  444. bool portFound = false;
  445. eventPtr = rtsafe_memory_pool_allocate_sleepy(handlePtr->mempool);
  446. eventPtr->time = event->time;
  447. switch (event->type)
  448. {
  449. case MIDI_EVENT_TYPE_CONTROL:
  450. caitlib_midi_encode_control(eventPtr, event->channel, event->data.control.controller, event->data.control.value);
  451. break;
  452. case MIDI_EVENT_TYPE_NOTE_ON:
  453. caitlib_midi_encode_note_on(eventPtr, event->channel, event->data.note.note, event->data.note.velocity);
  454. break;
  455. case MIDI_EVENT_TYPE_NOTE_OFF:
  456. caitlib_midi_encode_note_off(eventPtr, event->channel, event->data.note.note, event->data.note.velocity);
  457. break;
  458. case MIDI_EVENT_TYPE_AFTER_TOUCH:
  459. caitlib_midi_encode_aftertouch(eventPtr, event->channel, event->data.note.note, event->data.note.velocity);
  460. break;
  461. case MIDI_EVENT_TYPE_CHANNEL_PRESSURE:
  462. caitlib_midi_encode_channel_pressure(eventPtr, event->channel, event->data.pressure.value);
  463. break;
  464. case MIDI_EVENT_TYPE_PROGRAM:
  465. caitlib_midi_encode_program(eventPtr, event->channel, event->data.program.value);
  466. break;
  467. case MIDI_EVENT_TYPE_PITCH_WHEEL:
  468. caitlib_midi_encode_pitchwheel(eventPtr, event->channel, event->data.pitchwheel.value);
  469. break;
  470. default:
  471. return;
  472. }
  473. pthread_mutex_lock(&handlePtr->mutex);
  474. #ifdef USE_LIST_HEAD_OUTS
  475. list_for_each(entryPtr, &handlePtr->outPorts)
  476. {
  477. outPortPtr = list_entry(entryPtr, CaitlibOutPort, siblings);
  478. if (outPortPtr->id == port)
  479. {
  480. list_add_tail(&eventPtr->siblings, &outPortPtr->queue);
  481. break;
  482. }
  483. }
  484. #else
  485. for (uint32_t i = 0; i < handlePtr->midiOutCount; i++)
  486. {
  487. outPortPtr = handlePtr->midiOuts[i];
  488. if (outPortPtr->id == port)
  489. {
  490. portFound = true;
  491. list_add_tail(&eventPtr->siblings, &outPortPtr->queue);
  492. break;
  493. }
  494. }
  495. #endif
  496. if (! portFound)
  497. printf("caitlib_put_event(%p, %i, %p) - failed to find port", handle, port, event);
  498. pthread_mutex_unlock(&handlePtr->mutex);
  499. }
  500. void caitlib_put_control(CaitlibHandle handle, uint32_t port, uint32_t time, uint8_t channel, uint8_t control, uint8_t value)
  501. {
  502. MidiEvent event;
  503. event.type = MIDI_EVENT_TYPE_CONTROL;
  504. event.channel = channel;
  505. event.time = time;
  506. event.data.control.controller = control;
  507. event.data.control.value = value;
  508. caitlib_put_event(handle, port, &event);
  509. }
  510. void caitlib_put_note_on(CaitlibHandle handle, uint32_t port, uint32_t time, uint8_t channel, uint8_t note, uint8_t velocity)
  511. {
  512. MidiEvent event;
  513. event.type = MIDI_EVENT_TYPE_NOTE_ON;
  514. event.channel = channel;
  515. event.time = time;
  516. event.data.note.note = note;
  517. event.data.note.velocity = velocity;
  518. caitlib_put_event(handle, port, &event);
  519. }
  520. void caitlib_put_note_off(CaitlibHandle handle, uint32_t port, uint32_t time, uint8_t channel, uint8_t note, uint8_t velocity)
  521. {
  522. MidiEvent event;
  523. event.type = MIDI_EVENT_TYPE_NOTE_OFF;
  524. event.channel = channel;
  525. event.time = time;
  526. event.data.note.note = note;
  527. event.data.note.velocity = velocity;
  528. caitlib_put_event(handle, port, &event);
  529. }
  530. void caitlib_put_aftertouch(CaitlibHandle handle, uint32_t port, uint32_t time, uint8_t channel, uint8_t note, uint8_t pressure)
  531. {
  532. MidiEvent event;
  533. event.type = MIDI_EVENT_TYPE_AFTER_TOUCH;
  534. event.channel = channel;
  535. event.time = time;
  536. event.data.note.note = note;
  537. event.data.note.velocity = pressure;
  538. caitlib_put_event(handle, port, &event);
  539. }
  540. void caitlib_put_channel_pressure(CaitlibHandle handle, uint32_t port, uint32_t time, uint8_t channel, uint8_t pressure)
  541. {
  542. MidiEvent event;
  543. event.type = MIDI_EVENT_TYPE_CHANNEL_PRESSURE;
  544. event.channel = channel;
  545. event.time = time;
  546. event.data.pressure.value = pressure;
  547. caitlib_put_event(handle, port, &event);
  548. }
  549. void caitlib_put_program(CaitlibHandle handle, uint32_t port, uint32_t time, uint8_t channel, uint8_t program)
  550. {
  551. MidiEvent event;
  552. event.type = MIDI_EVENT_TYPE_PROGRAM;
  553. event.channel = channel;
  554. event.time = time;
  555. event.data.program.value = program;
  556. caitlib_put_event(handle, port, &event);
  557. }
  558. void caitlib_put_pitchwheel(CaitlibHandle handle, uint32_t port, uint32_t time, uint8_t channel, int16_t value)
  559. {
  560. MidiEvent event;
  561. event.type = MIDI_EVENT_TYPE_PITCH_WHEEL;
  562. event.channel = channel;
  563. event.time = time;
  564. event.data.pitchwheel.value = value;
  565. caitlib_put_event(handle, port, &event);
  566. }