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.

702 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 (handlePtr->midiOutCount > 0 && transportState == JackTransportRolling)
  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. // note off
  327. if (rawEventPtr->dataSize == 3 && (rawEventPtr->data[0] & 0xF0) == 0x80)
  328. {
  329. midiEvent.type = MIDI_EVENT_TYPE_NOTE_OFF;
  330. midiEvent.channel = rawEventPtr->data[0] & 0x0F;
  331. midiEvent.data.note.note = rawEventPtr->data[1];
  332. midiEvent.data.note.velocity = rawEventPtr->data[2];
  333. }
  334. // note on
  335. else if (rawEventPtr->dataSize == 3 && (rawEventPtr->data[0] & 0xF0) == 0x90)
  336. {
  337. midiEvent.type = MIDI_EVENT_TYPE_NOTE_ON;
  338. midiEvent.channel = rawEventPtr->data[0] & 0x0F;
  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) == 0xA0)
  344. {
  345. midiEvent.type = MIDI_EVENT_TYPE_AFTER_TOUCH;
  346. midiEvent.channel = rawEventPtr->data[0] & 0x0F;
  347. midiEvent.data.note.note = rawEventPtr->data[1];
  348. midiEvent.data.note.velocity = rawEventPtr->data[2];
  349. }
  350. // control
  351. else if (rawEventPtr->dataSize == 3 && (rawEventPtr->data[0] & 0xF0) == 0xB0)
  352. {
  353. midiEvent.type = MIDI_EVENT_TYPE_CONTROL;
  354. midiEvent.channel = rawEventPtr->data[0] & 0x0F;
  355. midiEvent.data.control.controller = rawEventPtr->data[1];
  356. midiEvent.data.control.value = rawEventPtr->data[2];
  357. }
  358. // program
  359. else if (rawEventPtr->dataSize == 2 && (rawEventPtr->data[0] & 0xF0) == 0xC0)
  360. {
  361. midiEvent.type = MIDI_EVENT_TYPE_PROGRAM;
  362. midiEvent.channel = rawEventPtr->data[0] & 0x0F;
  363. midiEvent.data.program.value = rawEventPtr->data[1];
  364. }
  365. // channel pressure
  366. else if (rawEventPtr->dataSize == 2 && (rawEventPtr->data[0] & 0xF0) == 0xD0)
  367. {
  368. midiEvent.type = MIDI_EVENT_TYPE_CHANNEL_PRESSURE;
  369. midiEvent.channel = rawEventPtr->data[0] & 0x0F;
  370. midiEvent.data.pressure.value = rawEventPtr->data[1];
  371. }
  372. // pitch wheel
  373. else if (rawEventPtr->dataSize == 3 && (rawEventPtr->data[0] & 0xF0) == 0xE0)
  374. {
  375. midiEvent.type = MIDI_EVENT_TYPE_PITCH_WHEEL;
  376. midiEvent.channel = rawEventPtr->data[0] & 0x0F;
  377. midiEvent.data.pitchwheel.value = ((rawEventPtr->data[2] << 7) | rawEventPtr->data[1]) - 8192;
  378. }
  379. else
  380. {
  381. return NULL;
  382. }
  383. rtsafe_memory_pool_deallocate(handlePtr->mempool, rawEventPtr);
  384. return &midiEvent;
  385. }
  386. // ------------------------------------------------------------------------------------------
  387. // Output (utils)
  388. void caitlib_midi_encode_control(RawMidiEvent* eventPtr, uint8_t channel, uint8_t control, uint8_t value)
  389. {
  390. eventPtr->data[0] = MIDI_EVENT_TYPE_CONTROL | (channel & 0x0F);
  391. eventPtr->data[1] = control;
  392. eventPtr->data[2] = value;
  393. eventPtr->dataSize = 3;
  394. }
  395. void caitlib_midi_encode_note_on(RawMidiEvent* eventPtr, uint8_t channel, uint8_t note, uint8_t velocity)
  396. {
  397. eventPtr->data[0] = MIDI_EVENT_TYPE_NOTE_ON | (channel & 0x0F);
  398. eventPtr->data[1] = note;
  399. eventPtr->data[2] = velocity;
  400. eventPtr->dataSize = 3;
  401. }
  402. void caitlib_midi_encode_note_off(RawMidiEvent* eventPtr, uint8_t channel, uint8_t note, uint8_t velocity)
  403. {
  404. eventPtr->data[0] = MIDI_EVENT_TYPE_NOTE_OFF | (channel & 0x0F);
  405. eventPtr->data[1] = note;
  406. eventPtr->data[2] = velocity;
  407. eventPtr->dataSize = 3;
  408. }
  409. void caitlib_midi_encode_aftertouch(RawMidiEvent* eventPtr, uint8_t channel, uint8_t note, uint8_t pressure)
  410. {
  411. eventPtr->data[0] = MIDI_EVENT_TYPE_AFTER_TOUCH | (channel & 0x0F);
  412. eventPtr->data[1] = note;
  413. eventPtr->data[2] = pressure;
  414. eventPtr->dataSize = 3;
  415. }
  416. void caitlib_midi_encode_channel_pressure(RawMidiEvent* eventPtr, uint8_t channel, uint8_t pressure)
  417. {
  418. eventPtr->data[0] = MIDI_EVENT_TYPE_CHANNEL_PRESSURE | (channel & 0x0F);
  419. eventPtr->data[1] = pressure;
  420. eventPtr->dataSize = 2;
  421. }
  422. void caitlib_midi_encode_program(RawMidiEvent* eventPtr, uint8_t channel, uint8_t program)
  423. {
  424. eventPtr->data[0] = MIDI_EVENT_TYPE_PROGRAM | (channel & 0x0F);
  425. eventPtr->data[1] = program;
  426. eventPtr->dataSize = 2;
  427. }
  428. void caitlib_midi_encode_pitchwheel(RawMidiEvent* eventPtr, uint8_t channel, int16_t pitchwheel)
  429. {
  430. pitchwheel += 8192;
  431. eventPtr->data[0] = MIDI_EVENT_TYPE_PITCH_WHEEL | (channel & 0x0F);
  432. eventPtr->data[1] = pitchwheel & 0x7F;
  433. eventPtr->data[2] = pitchwheel >> 7;
  434. eventPtr->dataSize = 3;
  435. }
  436. // ------------------------------------------------------------------------------------------
  437. // Output
  438. void caitlib_put_event(CaitlibHandle handle, uint32_t port, const MidiEvent* event)
  439. {
  440. #ifdef USE_LIST_HEAD_OUTS
  441. ListHead* entryPtr;
  442. #endif
  443. RawMidiEvent* eventPtr;
  444. CaitlibOutPort* outPortPtr;
  445. bool portFound = false;
  446. eventPtr = rtsafe_memory_pool_allocate_sleepy(handlePtr->mempool);
  447. eventPtr->time = event->time;
  448. switch (event->type)
  449. {
  450. case MIDI_EVENT_TYPE_CONTROL:
  451. caitlib_midi_encode_control(eventPtr, event->channel, event->data.control.controller, event->data.control.value);
  452. break;
  453. case MIDI_EVENT_TYPE_NOTE_ON:
  454. caitlib_midi_encode_note_on(eventPtr, event->channel, event->data.note.note, event->data.note.velocity);
  455. break;
  456. case MIDI_EVENT_TYPE_NOTE_OFF:
  457. caitlib_midi_encode_note_off(eventPtr, event->channel, event->data.note.note, event->data.note.velocity);
  458. break;
  459. case MIDI_EVENT_TYPE_AFTER_TOUCH:
  460. caitlib_midi_encode_aftertouch(eventPtr, event->channel, event->data.note.note, event->data.note.velocity);
  461. break;
  462. case MIDI_EVENT_TYPE_CHANNEL_PRESSURE:
  463. caitlib_midi_encode_channel_pressure(eventPtr, event->channel, event->data.pressure.value);
  464. break;
  465. case MIDI_EVENT_TYPE_PROGRAM:
  466. caitlib_midi_encode_program(eventPtr, event->channel, event->data.program.value);
  467. break;
  468. case MIDI_EVENT_TYPE_PITCH_WHEEL:
  469. caitlib_midi_encode_pitchwheel(eventPtr, event->channel, event->data.pitchwheel.value);
  470. break;
  471. default:
  472. return;
  473. }
  474. pthread_mutex_lock(&handlePtr->mutex);
  475. #ifdef USE_LIST_HEAD_OUTS
  476. list_for_each(entryPtr, &handlePtr->outPorts)
  477. {
  478. outPortPtr = list_entry(entryPtr, CaitlibOutPort, siblings);
  479. if (outPortPtr->id == port)
  480. {
  481. list_add_tail(&eventPtr->siblings, &outPortPtr->queue);
  482. break;
  483. }
  484. }
  485. #else
  486. for (uint32_t i = 0; i < handlePtr->midiOutCount; i++)
  487. {
  488. outPortPtr = handlePtr->midiOuts[i];
  489. if (outPortPtr->id == port)
  490. {
  491. portFound = true;
  492. list_add_tail(&eventPtr->siblings, &outPortPtr->queue);
  493. break;
  494. }
  495. }
  496. #endif
  497. if (! portFound)
  498. printf("caitlib_put_event(%p, %i, %p) - failed to find port", handle, port, event);
  499. pthread_mutex_unlock(&handlePtr->mutex);
  500. }
  501. void caitlib_put_control(CaitlibHandle handle, uint32_t port, uint32_t time, uint8_t channel, uint8_t control, uint8_t value)
  502. {
  503. MidiEvent event;
  504. event.type = MIDI_EVENT_TYPE_CONTROL;
  505. event.channel = channel;
  506. event.time = time;
  507. event.data.control.controller = control;
  508. event.data.control.value = value;
  509. caitlib_put_event(handle, port, &event);
  510. }
  511. void caitlib_put_note_on(CaitlibHandle handle, uint32_t port, uint32_t time, uint8_t channel, uint8_t note, uint8_t velocity)
  512. {
  513. MidiEvent event;
  514. event.type = MIDI_EVENT_TYPE_NOTE_ON;
  515. event.channel = channel;
  516. event.time = time;
  517. event.data.note.note = note;
  518. event.data.note.velocity = velocity;
  519. caitlib_put_event(handle, port, &event);
  520. }
  521. void caitlib_put_note_off(CaitlibHandle handle, uint32_t port, uint32_t time, uint8_t channel, uint8_t note, uint8_t velocity)
  522. {
  523. MidiEvent event;
  524. event.type = MIDI_EVENT_TYPE_NOTE_OFF;
  525. event.channel = channel;
  526. event.time = time;
  527. event.data.note.note = note;
  528. event.data.note.velocity = velocity;
  529. caitlib_put_event(handle, port, &event);
  530. }
  531. void caitlib_put_aftertouch(CaitlibHandle handle, uint32_t port, uint32_t time, uint8_t channel, uint8_t note, uint8_t pressure)
  532. {
  533. MidiEvent event;
  534. event.type = MIDI_EVENT_TYPE_AFTER_TOUCH;
  535. event.channel = channel;
  536. event.time = time;
  537. event.data.note.note = note;
  538. event.data.note.velocity = pressure;
  539. caitlib_put_event(handle, port, &event);
  540. }
  541. void caitlib_put_channel_pressure(CaitlibHandle handle, uint32_t port, uint32_t time, uint8_t channel, uint8_t pressure)
  542. {
  543. MidiEvent event;
  544. event.type = MIDI_EVENT_TYPE_CHANNEL_PRESSURE;
  545. event.channel = channel;
  546. event.time = time;
  547. event.data.pressure.value = pressure;
  548. caitlib_put_event(handle, port, &event);
  549. }
  550. void caitlib_put_program(CaitlibHandle handle, uint32_t port, uint32_t time, uint8_t channel, uint8_t program)
  551. {
  552. MidiEvent event;
  553. event.type = MIDI_EVENT_TYPE_PROGRAM;
  554. event.channel = channel;
  555. event.time = time;
  556. event.data.program.value = program;
  557. caitlib_put_event(handle, port, &event);
  558. }
  559. void caitlib_put_pitchwheel(CaitlibHandle handle, uint32_t port, uint32_t time, uint8_t channel, int16_t value)
  560. {
  561. MidiEvent event;
  562. event.type = MIDI_EVENT_TYPE_PITCH_WHEEL;
  563. event.channel = channel;
  564. event.time = time;
  565. event.data.pitchwheel.value = value;
  566. caitlib_put_event(handle, port, &event);
  567. }