1 /*! 2 * @file midilfo_lv2.cpp 3 * @brief Implements an LV2 plugin inheriting from MidiLfo 4 * 5 * 6 * Copyright 2009 - 2017 <qmidiarp-devel@lists.sourceforge.net> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 21 * MA 02110-1301, USA. 22 * 23 */ 24 25 26 #include <cstdio> 27 #include "midilfo_lv2.h" 28 29 MidiLfoLV2::MidiLfoLV2 ( 30 double sample_rate, const LV2_Feature *const *host_features ) 31 :MidiLfo() 32 { 33 MidiEventID = 0; 34 sampleRate = sample_rate; getpeereid(int sock,uid_t * uid,gid_t * gid)35 curFrame = 0; 36 inLfoFrame = 0; 37 inEventBuffer = NULL; 38 outEventBuffer = NULL; 39 getNextFrame(0); 40 mouseXCur = 0; 41 mouseYCur = 0; 42 mouseEvCur = 0; 43 tempo = 120.0f; 44 internalTempo = 120.0f; 45 lastMouseIndex = 0; 46 47 transportBpm = 120.0f; 48 transportFramesDelta = 0; 49 curTick = 0; 50 tempoChangeTick = 0; 51 hostTransport = true; 52 transportSpeed = 0; 53 transportAtomReceived = false; 54 55 dataChanged = true; 56 ui_up = false; 57 58 getNextFrame(0); 59 60 LV2_URID_Map *urid_map; 61 62 /* Scan host features for URID map */ 63 64 for (int i = 0; host_features[i]; ++i) { 65 if (::strcmp(host_features[i]->URI, LV2_URID_URI "#map") == 0) { 66 urid_map = (LV2_URID_Map *) host_features[i]->data; 67 if (urid_map) { 68 MidiEventID = urid_map->map(urid_map->handle, LV2_MIDI_EVENT_URI); 69 break; 70 } 71 } 72 } 73 if (!urid_map) { 74 printf("Host does not support urid:map.\n"); 75 return; 76 } 77 78 lv2_atom_forge_init(&forge, urid_map); 79 80 /* Map URIS */ 81 QMidiArpURIs* const uris = &m_uris; 82 map_uris(urid_map, uris); 83 uridMap = urid_map; 84 } 85 86 87 MidiLfoLV2::~MidiLfoLV2 (void) 88 { 89 } 90 91 void MidiLfoLV2::connect_port ( uint32_t port, void *seqdata ) 92 { 93 switch(port) { 94 case 0: 95 inEventBuffer = (LV2_Atom_Sequence*)seqdata; 96 break; 97 case 1: 98 outEventBuffer = (const LV2_Atom_Sequence*)seqdata; 99 break; 100 default: 101 val[port - 2] = (float *) seqdata; 102 break; 103 } 104 } 105 106 void MidiLfoLV2::updatePosAtom(const LV2_Atom_Object* obj) 107 { 108 if (!hostTransport) return; 109 110 QMidiArpURIs* const uris = &m_uris; 111 112 uint64_t pos1 = transportFramesDelta; 113 float bpm1 = tempo; 114 int speed1 = transportSpeed; 115 116 // flag that the host sends transport information via atom port and 117 // that we will no longer process designated port events 118 transportAtomReceived = true; 119 120 LV2_Atom *bpm = NULL, *speed = NULL, *pos = NULL; 121 lv2_atom_object_get(obj, 122 uris->time_frame, &pos, 123 uris->time_beatsPerMinute, &bpm, 124 uris->time_speed, &speed, 125 NULL); 126 127 if (bpm && bpm->type == uris->atom_Float) bpm1 = ((LV2_Atom_Float*)bpm)->body; 128 if (pos && pos->type == uris->atom_Long) pos1 = ((LV2_Atom_Long*)pos)->body; 129 if (speed && speed->type == uris->atom_Float) speed1 = ((LV2_Atom_Float*)speed)->body; 130 131 updatePos(pos1, bpm1, speed1); 132 } 133 134 void MidiLfoLV2::updatePos(uint64_t pos, float bpm, int speed, bool ignore_pos) 135 { 136 if (transportBpm != bpm) { 137 /* Tempo changed */ 138 transportBpm = bpm; 139 tempo = transportBpm; 140 transportSpeed = 0; 141 } 142 143 if (!ignore_pos) { 144 const float frames_per_beat = 60.0f / transportBpm * sampleRate; 145 transportFramesDelta = pos; 146 tempoChangeTick = pos * TPQN / frames_per_beat; 147 } 148 if (transportSpeed != speed) { 149 /* Speed changed, e.g. 0 (stop) to 1 (play) */ 150 transportSpeed = speed; 151 curFrame = transportFramesDelta; 152 inLfoFrame = 0; 153 if (transportSpeed) { 154 setNextTick(tempoChangeTick); 155 getNextFrame(tempoChangeTick); 156 } 157 } 158 //printf("transportBpm %f, transportFramesDelta %d\n", transportBpm, transportFramesDelta); 159 } 160 161 void MidiLfoLV2::run ( uint32_t nframes ) 162 { 163 const uint32_t capacity = outEventBuffer->atom.size; 164 const QMidiArpURIs* uris = &m_uris; 165 166 lv2_atom_forge_set_buffer(&forge, (uint8_t*)outEventBuffer, capacity); 167 lv2_atom_forge_sequence_head(&forge, &m_lv2frame, 0); 168 169 updateParams(); 170 if (isRecording) { 171 getData(&data); 172 } 173 sendWave(); 174 175 if (inEventBuffer) { 176 LV2_ATOM_SEQUENCE_FOREACH(inEventBuffer, event) { 177 // Control Atom Input 178 if (event && (event->body.type == uris->atom_Object 179 || event->body.type == uris->atom_Blank)) { 180 const LV2_Atom_Object* obj = (LV2_Atom_Object*)&event->body; 181 if (obj->body.otype == uris->time_Position) { 182 /* Received position information, update */ 183 if (hostTransport) updatePosAtom(obj); 184 } 185 else if (obj->body.otype == uris->ui_up) { 186 /* UI was activated */ 187 ui_up = true; 188 dataChanged = true; 189 } 190 else if (obj->body.otype == uris->ui_down) { 191 /* UI was closed */ 192 ui_up = false; 193 } 194 else if (obj->body.otype == uris->flip_wave) { 195 /* LFO wave was vertically flipped */ 196 flipWaveVertical(); 197 getData(&data); 198 updateWaveForm(5); 199 dataChanged = true; 200 } 201 } 202 // MIDI Input 203 else if (event && event->body.type == MidiEventID) { 204 uint8_t *di = (uint8_t *) LV2_ATOM_BODY(&event->body); 205 MidiEvent inEv = {0, 0, 0, 0}; 206 if ( (di[0] & 0xf0) == 0x90 ) { 207 inEv.type = EV_NOTEON; 208 inEv.value = di[2]; 209 } 210 else if ( (di[0] & 0xf0) == 0x80 ) { 211 inEv.type = EV_NOTEON; 212 inEv.value = 0; 213 } 214 else if ( (di[0] & 0xf0) == 0xb0 ) { 215 inEv.type = EV_CONTROLLER; 216 inEv.value = di[2]; 217 } 218 else inEv.type = EV_NONE; 219 220 inEv.channel = di[0] & 0x0f; 221 inEv.data=di[1]; 222 int tick = ((uint64_t)(curFrame - transportFramesDelta) * nframes 223 +(uint64_t)(&event->time.frames) % nframes) 224 *TPQN*tempo/nframes/60/sampleRate + tempoChangeTick; 225 if (handleEvent(inEv, tick)) //if event is unmatched, forward it 226 forgeMidiEvent((int)((uint64_t)(&event->time.frames) % nframes), di, 3); 227 } 228 } 229 } 230 231 232 // MIDI and Wave Control Output 233 234 for (uint f = 0 ; f < nframes; f++) { 235 curTick = (uint64_t)(curFrame - transportFramesDelta) 236 *TPQN*tempo/60/sampleRate + tempoChangeTick; 237 if ((curTick >= frame.at(inLfoFrame).tick) 238 && (transportSpeed)) { 239 if (!frame.at(inLfoFrame).muted && !isMuted) { 240 unsigned char d[3]; 241 d[0] = 0xb0 + channelOut; 242 d[1] = ccnumber; 243 d[2] = frame.at(inLfoFrame).value; 244 forgeMidiEvent(f, d, 3); 245 *val[WaveOut] = (float)d[2] / 128; 246 } 247 inLfoFrame++; 248 inLfoFrame%=frameSize; 249 if (!inLfoFrame) { 250 framePtr = getFramePtr(); 251 float pos = (float)framePtr; 252 *val[CURSOR_POS] = pos; 253 getNextFrame(curTick); 254 } 255 } 256 curFrame++; 257 } 258 } 259 260 void MidiLfoLV2::forgeMidiEvent(uint32_t f, const uint8_t* const buffer, uint32_t size) 261 { 262 QMidiArpURIs* const uris = &m_uris; 263 LV2_Atom midiatom; 264 midiatom.type = uris->midi_MidiEvent; 265 midiatom.size = size; 266 lv2_atom_forge_frame_time(&forge, f); 267 lv2_atom_forge_raw(&forge, &midiatom, sizeof(LV2_Atom)); 268 lv2_atom_forge_raw(&forge, buffer, size); 269 lv2_atom_forge_pad(&forge, sizeof(LV2_Atom) + size); 270 } 271 272 void MidiLfoLV2::updateParams() 273 { 274 bool changed = false; 275 276 277 if (amp != *val[AMPLITUDE]) { 278 changed = true; 279 updateAmplitude(*val[AMPLITUDE]); 280 } 281 282 if (offs != *val[OFFSET]) { 283 changed = true; 284 updateOffset(*val[OFFSET]); 285 *val[OFFSET] = offs; 286 } 287 288 if (mouseXCur != *val[MOUSEX] || mouseYCur != *val[MOUSEY] 289 || mouseEvCur != *val[MOUSEPRESSED]) { 290 int ix = 1; 291 int evtype = 0; 292 changed = true; 293 mouseXCur = *val[MOUSEX]; 294 mouseYCur = *val[MOUSEY]; 295 if ((mouseEvCur == 2) && (*val[MOUSEPRESSED] != 2) ) 296 evtype = 1; 297 else if (*val[MOUSEPRESSED] != -1) 298 evtype = *val[MOUSEPRESSED]; 299 300 mouseEvCur = *val[MOUSEPRESSED]; 301 302 if (mouseEvCur == 2) return; // mouse was released 303 ix = mouseEvent(mouseXCur, mouseYCur, *val[MOUSEBUTTON], evtype); 304 if (evtype == 1) lastMouseIndex = ix; // if we have a new press event set last point index here 305 } 306 307 if (res != lfoResValues[(int)*val[RESOLUTION]]) { 308 changed = true; 309 updateResolution(lfoResValues[(int)*val[RESOLUTION]]); 310 } 311 312 if (size != lfoSizeValues[(int)*val[SIZE]]) { 313 changed = true; 314 updateSize(lfoSizeValues[(int)*val[SIZE]]); 315 } 316 317 if (freq != lfoFreqValues[(int)*val[FREQUENCY]]) { 318 changed = true; 319 updateFrequency(lfoFreqValues[(int)*val[FREQUENCY]]); 320 } 321 322 if (waveFormIndex != (int)*val[WAVEFORM]) { 323 changed = true; 324 updateWaveForm(*val[WAVEFORM]); 325 } 326 327 if (curLoopMode != (*val[LOOPMODE])) updateLoop(*val[LOOPMODE]); 328 if (recordMode != ((bool)*val[RECORD])) { 329 setRecordMode((bool)*val[RECORD]); 330 } 331 if (deferChanges != ((bool)*val[DEFER])) deferChanges = ((bool)*val[DEFER]); 332 if (isMuted != (bool)*val[MUTE] && !parChangesPending) { 333 setMuted((bool)(*val[MUTE])); 334 changed = true; 335 } 336 337 ccnumber = (int)*val[CC_OUT]; 338 ccnumberIn = (int)*val[CC_IN]; 339 enableNoteOff = (bool)*val[ENABLE_NOTEOFF]; 340 restartByKbd = (bool)*val[ENABLE_RESTARTBYKBD]; 341 trigByKbd = (bool)*val[ENABLE_TRIGBYKBD]; 342 trigLegato = (bool)*val[ENABLE_TRIGLEGATO]; 343 344 channelOut = (int)*val[CH_OUT]; 345 chIn = (int)*val[CH_IN]; 346 indexIn[0] = (int)*val[INDEX_IN1]; 347 indexIn[1] = (int)*val[INDEX_IN2]; 348 rangeIn[0] = (int)*val[RANGE_IN1]; 349 rangeIn[1] = (int)*val[RANGE_IN2]; 350 351 if (internalTempo != *val[TEMPO]) { 352 internalTempo = *val[TEMPO]; 353 initTransport(); 354 } 355 356 if (hostTransport != (bool)(*val[TRANSPORT_MODE])) { 357 hostTransport = (bool)(*val[TRANSPORT_MODE]); 358 initTransport(); 359 } 360 361 if (hostTransport && !transportAtomReceived) { 362 updatePos( (uint64_t)*val[HOST_POSITION], 363 (float)*val[HOST_TEMPO], 364 (int)*val[HOST_SPEED], 365 false); 366 } 367 368 if (changed) { 369 getData(&data); 370 dataChanged = true; 371 } 372 } 373 374 void MidiLfoLV2::initTransport() 375 { 376 if (!hostTransport) { 377 transportFramesDelta = curFrame; 378 if (curTick > 0) tempoChangeTick = curTick; 379 transportBpm = internalTempo; 380 tempo = internalTempo; 381 transportSpeed = 1; 382 } 383 else transportSpeed = 0; 384 385 setNextTick(tempoChangeTick); 386 getNextFrame(tempoChangeTick); 387 inLfoFrame = 0; 388 } 389 390 void MidiLfoLV2::sendWave() 391 { 392 if (!(dataChanged && ui_up)) return; 393 dataChanged = false; 394 395 const QMidiArpURIs* uris = &m_uris; 396 int ct = res * size + 1; // last element in wave is an end tag 397 int tempArray[ct]; 398 399 for (int l1 = 0; l1 < ct; l1++) { 400 tempArray[l1]=data.at(l1).value*((data.at(l1).muted) ? -1 : 1); 401 } 402 403 /* forge container object of type 'hex_customwave' */ 404 LV2_Atom_Forge_Frame lv2frame; 405 lv2_atom_forge_frame_time(&forge, 0); 406 lv2_atom_forge_object(&forge, &lv2frame, 1, uris->hex_customwave); 407 408 /* Send customWave to UI */ 409 lv2_atom_forge_property_head(&forge, uris->hex_customwave, 0); 410 lv2_atom_forge_vector(&forge, sizeof(int), uris->atom_Int, 411 ct, tempArray); 412 413 /* close-off frame */ 414 lv2_atom_forge_pop(&forge, &lv2frame); 415 } 416 417 static LV2_State_Status MidiLfoLV2_state_restore ( LV2_Handle instance, 418 LV2_State_Retrieve_Function retrieve, LV2_State_Handle handle, 419 uint32_t flags, const LV2_Feature *const * ) 420 { 421 MidiLfoLV2 *pPlugin = static_cast<MidiLfoLV2 *> (instance); 422 423 if (pPlugin == NULL) return LV2_STATE_ERR_UNKNOWN; 424 425 QMidiArpURIs* const uris = &pPlugin->m_uris; 426 427 uint32_t type = uris->atom_String; 428 429 if (type == 0) return LV2_STATE_ERR_BAD_TYPE; 430 431 size_t size = 0; 432 int l1; 433 uint32_t key = uris->hex_mutemask; 434 if (!key) return LV2_STATE_ERR_NO_PROPERTY; 435 436 const char *value1 437 = (const char *) (*retrieve)(handle, key, &size, &type, &flags); 438 439 if (size < 2) return LV2_STATE_ERR_UNKNOWN; 440 441 pPlugin->setFramePtr(0); 442 pPlugin->maxNPoints = (size - 1 ) / 2; 443 444 for (l1 = 0; l1 < pPlugin->maxNPoints; l1++) { 445 pPlugin->muteMask[l1] = (value1[2 * l1 + 1] == '1'); 446 } 447 448 key = uris->hex_customwave; 449 if (!key) return LV2_STATE_ERR_NO_PROPERTY; 450 451 const char *value 452 = (const char *) (*retrieve)(handle, key, &size, &type, &flags); 453 454 if (size < 2) return LV2_STATE_ERR_UNKNOWN; 455 456 Sample sample; 457 int step = TPQN / pPlugin->res; 458 int lt = 0; 459 int min = 127; 460 for (l1 = 0; l1 < pPlugin->maxNPoints; l1++) { 461 int hi = 0; 462 int lo = 0; 463 if (value[2*l1] <= '9' && value[2*l1] >= '0') hi = value[2*l1] - '0'; 464 if (value[2*l1] <= 'f' && value[2*l1] >= 'a') hi = value[2*l1] - 'a' + 10; 465 466 if (value[2*l1 + 1] <= '9' && value[2*l1 + 1] >= '0') lo = value[2*l1 + 1] - '0'; 467 if (value[2*l1 + 1] <= 'f' && value[2*l1 + 1] >= 'a') lo = value[2*l1 + 1] - 'a' + 10; 468 469 sample.value = hi * 16 + lo; 470 sample.tick = lt; 471 sample.muted = pPlugin->muteMask[l1]; 472 pPlugin->customWave[l1] = sample; 473 if (sample.value < min) min = sample.value; 474 lt+=step; 475 } 476 pPlugin->cwmin = min; 477 pPlugin->getData(&pPlugin->data); 478 pPlugin->sendWave(); 479 480 return LV2_STATE_SUCCESS; 481 } 482 483 static LV2_State_Status MidiLfoLV2_state_save ( LV2_Handle instance, 484 LV2_State_Store_Function store, LV2_State_Handle handle, 485 uint32_t flags, const LV2_Feature *const * ) 486 { 487 MidiLfoLV2 *pPlugin = static_cast<MidiLfoLV2 *> (instance); 488 489 if (pPlugin == NULL) return LV2_STATE_ERR_UNKNOWN; 490 491 QMidiArpURIs* const uris = &pPlugin->m_uris; 492 493 uint32_t type = uris->atom_String; 494 495 if (type == 0) return LV2_STATE_ERR_BAD_TYPE; 496 497 flags |= (LV2_STATE_IS_POD | LV2_STATE_IS_PORTABLE); 498 499 const char hexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7', 500 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; 501 int l1; 502 char bt[pPlugin->maxNPoints * 2 + 1]; 503 504 for (l1 = 0; l1 < pPlugin->maxNPoints; l1++) { 505 bt[2*l1] = hexmap[(pPlugin->customWave[l1].value & 0xF0) >> 4]; 506 bt[2*l1 + 1] = hexmap[pPlugin->customWave[l1].value & 0x0F]; 507 } 508 bt[pPlugin->maxNPoints * 2] = '\0'; 509 510 const char *value = bt; 511 512 size_t size = strlen(value) + 1; 513 514 uint32_t key = uris->hex_customwave; 515 if (!key) return LV2_STATE_ERR_NO_PROPERTY; 516 517 store(handle, key, value, size, type, flags); 518 519 for (l1 = 0; l1 < pPlugin->maxNPoints; l1++) { 520 bt[2*l1] = '0'; 521 bt[2*l1 + 1] = hexmap[pPlugin->muteMask[l1]]; 522 } 523 524 const char *value1 = bt; 525 526 size = strlen(value1) + 1; 527 key = uris->hex_mutemask; 528 if (!key) return LV2_STATE_ERR_NO_PROPERTY; 529 530 LV2_State_Status result = (*store)(handle, key, value1, size, type, flags); 531 532 return result; 533 } 534 535 static const LV2_State_Interface MidiLfoLV2_state_interface = 536 { 537 MidiLfoLV2_state_save, 538 MidiLfoLV2_state_restore 539 }; 540 541 void MidiLfoLV2::activate (void) 542 { 543 initTransport(); 544 } 545 546 void MidiLfoLV2::deactivate (void) 547 { 548 transportSpeed = 0; 549 } 550 551 static LV2_Handle MidiLfoLV2_instantiate ( 552 const LV2_Descriptor *, double sample_rate, const char *, 553 const LV2_Feature *const *host_features ) 554 { 555 return new MidiLfoLV2(sample_rate, host_features); 556 } 557 558 static void MidiLfoLV2_connect_port ( 559 LV2_Handle instance, uint32_t port, void *data ) 560 { 561 MidiLfoLV2 *pPlugin = static_cast<MidiLfoLV2 *> (instance); 562 if (pPlugin) 563 pPlugin->connect_port(port, data); 564 } 565 566 static void MidiLfoLV2_run ( LV2_Handle instance, uint32_t nframes ) 567 { 568 MidiLfoLV2 *pPlugin = static_cast<MidiLfoLV2 *> (instance); 569 if (pPlugin) 570 pPlugin->run(nframes); 571 } 572 573 static void MidiLfoLV2_activate ( LV2_Handle instance ) 574 { 575 MidiLfoLV2 *pPlugin = static_cast<MidiLfoLV2 *> (instance); 576 if (pPlugin) 577 pPlugin->activate(); 578 } 579 580 static void MidiLfoLV2_deactivate ( LV2_Handle instance ) 581 { 582 MidiLfoLV2 *pPlugin = static_cast<MidiLfoLV2 *> (instance); 583 if (pPlugin) 584 pPlugin->deactivate(); 585 } 586 587 static void MidiLfoLV2_cleanup ( LV2_Handle instance ) 588 { 589 MidiLfoLV2 *pPlugin = static_cast<MidiLfoLV2 *> (instance); 590 if (pPlugin) 591 delete pPlugin; 592 } 593 594 static const void *MidiLfoLV2_extension_data ( const char * uri) 595 { 596 static const LV2_State_Interface state_iface = 597 { MidiLfoLV2_state_save, MidiLfoLV2_state_restore }; 598 if (!strcmp(uri, LV2_STATE__interface)) { 599 return &state_iface; 600 } 601 else return NULL; 602 } 603 604 static const LV2_Descriptor MidiLfoLV2_descriptor = 605 { 606 QMIDIARP_LFO_LV2_URI, 607 MidiLfoLV2_instantiate, 608 MidiLfoLV2_connect_port, 609 MidiLfoLV2_activate, 610 MidiLfoLV2_run, 611 MidiLfoLV2_deactivate, 612 MidiLfoLV2_cleanup, 613 MidiLfoLV2_extension_data 614 }; 615 616 LV2_SYMBOL_EXPORT const LV2_Descriptor *lv2_descriptor ( uint32_t index ) 617 { 618 return (index == 0 ? &MidiLfoLV2_descriptor : NULL); 619 } 620 621