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.

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