1 /* 2 * Copyright (C) 2020 Linux Studio Plugins Project <https://lsp-plug.in/> 3 * (C) 2020 Vladimir Sadovnikov <sadko4u@gmail.com> 4 * 5 * This file is part of lsp-plugins 6 * Created on: 13 мая 2016 г. 7 * 8 * lsp-plugins is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Lesser General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * any later version. 12 * 13 * lsp-plugins 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 Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public License 19 * along with lsp-plugins. If not, see <https://www.gnu.org/licenses/>. 20 */ 21 22 #ifndef COINTAINER_JACK_PORTS_H_ 23 #define COINTAINER_JACK_PORTS_H_ 24 25 namespace lsp 26 { 27 class JACKPort: public IPort 28 { 29 protected: 30 JACKWrapper *pWrapper; 31 32 public: JACKPort(const port_t * meta,JACKWrapper * w)33 explicit JACKPort(const port_t *meta, JACKWrapper *w): IPort(meta) 34 { 35 pWrapper = w; 36 } 37 ~JACKPort()38 virtual ~JACKPort() 39 { 40 pWrapper = NULL; 41 } 42 43 public: init()44 virtual int init() 45 { 46 return STATUS_OK; 47 } 48 destroy()49 virtual void destroy() 50 { 51 } 52 }; 53 54 class JACKPortGroup: public JACKPort 55 { 56 private: 57 float nCurrRow; 58 size_t nCols; 59 size_t nRows; 60 61 public: JACKPortGroup(const port_t * meta,JACKWrapper * w)62 explicit JACKPortGroup(const port_t *meta, JACKWrapper *w) : JACKPort(meta, w) 63 { 64 nCurrRow = meta->start; 65 nCols = port_list_size(meta->members); 66 nRows = list_size(meta->items); 67 } 68 ~JACKPortGroup()69 virtual ~JACKPortGroup() 70 { 71 nCurrRow = 0; 72 nCols = 0; 73 nRows = 0; 74 } 75 76 public: setValue(float value)77 virtual void setValue(float value) 78 { 79 int32_t v = value; 80 if ((v >= 0) && (v < ssize_t(nRows))) 81 nCurrRow = v; 82 } 83 getValue()84 virtual float getValue() 85 { 86 return nCurrRow; 87 } 88 89 public: rows()90 inline size_t rows() const { return nRows; } cols()91 inline size_t cols() const { return nCols; } curr_row()92 inline size_t curr_row() const { return nCurrRow; } 93 }; 94 95 class JACKDataPort: public JACKPort 96 { 97 private: 98 jack_port_t *pPort; // JACK port descriptor 99 void *pDataBuffer; // Real data buffer passed from JACK 100 void *pBuffer; // Data buffer 101 midi_t *pMidi; // Midi buffer for operating MIDI messages 102 float *pSanitized; // Input float data for sanitized buffers 103 size_t nBufSize; // Size of sanitized buffer in samples 104 105 public: JACKDataPort(const port_t * meta,JACKWrapper * w)106 explicit JACKDataPort(const port_t *meta, JACKWrapper *w) : JACKPort(meta, w) 107 { 108 pPort = NULL; 109 pDataBuffer = NULL; 110 pBuffer = NULL; 111 pMidi = NULL; 112 pSanitized = NULL; 113 nBufSize = 0; 114 } 115 ~JACKDataPort()116 virtual ~JACKDataPort() 117 { 118 pPort = NULL; 119 pDataBuffer = NULL; 120 pBuffer = NULL; 121 pMidi = NULL; 122 pSanitized = NULL; 123 nBufSize = 0; 124 }; 125 126 public: getBuffer()127 virtual void *getBuffer() 128 { 129 return pBuffer; 130 }; 131 init()132 virtual int init() 133 { 134 return connect(); 135 } 136 disconnect()137 int disconnect() 138 { 139 if (pPort == NULL) 140 return STATUS_OK; 141 142 jack_client_t *cl = pWrapper->client(); 143 if (cl != NULL) 144 jack_port_unregister(cl, pPort); 145 146 if (pSanitized != NULL) 147 { 148 ::free(pSanitized); 149 pSanitized = NULL; 150 } 151 152 if (pMidi != NULL) 153 { 154 delete pMidi; 155 pMidi = NULL; 156 } 157 158 pPort = NULL; 159 nBufSize = 0; 160 161 return STATUS_OK; 162 } 163 connect()164 int connect() 165 { 166 // Determine port type 167 const char *port_type = NULL; 168 if (pMetadata->role == R_AUDIO) 169 port_type = JACK_DEFAULT_AUDIO_TYPE; 170 else if (pMetadata->role == R_MIDI) 171 { 172 port_type = JACK_DEFAULT_MIDI_TYPE; 173 pMidi = new midi_t; 174 if (pMidi == NULL) 175 return STATUS_NO_MEM; 176 pMidi->clear(); 177 } 178 else 179 return STATUS_BAD_FORMAT; 180 181 // Determine flags 182 size_t flags = (IS_OUT_PORT(pMetadata)) ? JackPortIsOutput : JackPortIsInput; 183 184 // Get client 185 jack_client_t *cl = pWrapper->client(); 186 if (cl == NULL) 187 { 188 if (pMidi != NULL) 189 { 190 delete pMidi; 191 pMidi = NULL; 192 } 193 return STATUS_DISCONNECTED; 194 } 195 196 // Register port 197 pPort = jack_port_register(cl, pMetadata->id, port_type, flags, 0); 198 199 return (pPort != NULL) ? STATUS_OK : STATUS_UNKNOWN_ERR; 200 } 201 set_buffer_size(size_t size)202 void set_buffer_size(size_t size) 203 { 204 // set_buffer_size should affect only input audio ports currently 205 if ((!IS_IN_PORT(pMetadata)) || (pMidi != NULL)) 206 return; 207 208 // Buffer size has changed? 209 if (nBufSize == size) 210 return; 211 212 float *buf = reinterpret_cast<float *>(::realloc(pSanitized, sizeof(float) * size)); 213 if (buf == NULL) 214 { 215 ::free(pSanitized); 216 pSanitized = NULL; 217 return; 218 } 219 220 nBufSize = size; 221 pSanitized = buf; 222 dsp::fill_zero(pSanitized, nBufSize); 223 } 224 report_latency(ssize_t latency)225 void report_latency(ssize_t latency) 226 { 227 // Only output ports should report latency 228 if ((pMetadata == NULL) || (!IS_OUT_PORT(pMetadata))) 229 return; 230 231 // Report latency 232 jack_latency_range_t range; 233 jack_port_get_latency_range(pPort, JackCaptureLatency, &range); 234 range.min += latency; 235 range.max += latency; 236 jack_port_set_latency_range (pPort, JackCaptureLatency, &range); 237 } 238 destroy()239 virtual void destroy() 240 { 241 disconnect(); 242 } 243 pre_process(size_t samples)244 virtual bool pre_process(size_t samples) 245 { 246 if (pPort == NULL) 247 { 248 pBuffer = NULL; 249 return false; 250 } 251 252 pDataBuffer = jack_port_get_buffer(pPort, samples); 253 pBuffer = pDataBuffer; 254 255 if (pMidi != NULL) 256 { 257 if ((pBuffer != NULL) && IS_IN_PORT(pMetadata)) 258 { 259 // Clear our buffer 260 pMidi->clear(); 261 262 // Read MIDI events 263 jack_midi_event_t midi_event; 264 midi::event_t ev; 265 266 jack_nframes_t event_count = jack_midi_get_event_count(pBuffer); 267 for (jack_nframes_t i=0; i<event_count; i++) 268 { 269 // Read MIDI event 270 if (jack_midi_event_get(&midi_event, pBuffer, i) != 0) 271 { 272 lsp_warn("Could not fetch MIDI event #%d from JACK port", int(i)); 273 continue; 274 } 275 276 // Convert MIDI event 277 lsp_dumpb("in midi event", midi_event.buffer, midi_event.size); 278 if (midi::decode(&ev, midi_event.buffer) <= 0) 279 { 280 lsp_warn("Could not decode MIDI event #%d at timestamp %d from JACK port", int(i), int(midi_event.time)); 281 continue; 282 } 283 284 // Update timestamp and store event 285 ev.timestamp = midi_event.time; 286 if (!pMidi->push(ev)) 287 lsp_warn("Could not append MIDI event #%d at timestamp %d due to buffer overflow", int(i), int(midi_event.time)); 288 } 289 290 // All MIDI events ARE ordered chronologically, we do not need to perform sort 291 #ifdef LSP_TRACE 292 if (event_count > 0) 293 lsp_trace("Decoded %d MIDI events", int(event_count)); 294 #endif 295 } 296 297 // Replace pBuffer with pMidi 298 pBuffer = pMidi; 299 } 300 else if (pSanitized != NULL) // Need to sanitize? 301 { 302 // Perform sanitize() if possible 303 if (samples <= nBufSize) 304 { 305 dsp::sanitize2(pSanitized, reinterpret_cast<float *>(pDataBuffer), samples); 306 pBuffer = pSanitized; 307 } 308 else 309 { 310 lsp_warn("Could not sanitize buffer data for port %s, not enough buffer size (required: %d, actual: %d)", 311 pMetadata->id, int(samples), int(nBufSize)); 312 } 313 } 314 315 return false; 316 } 317 post_process(size_t samples)318 virtual void post_process(size_t samples) 319 { 320 if ((pMidi != NULL) && (pDataBuffer != NULL) && IS_OUT_PORT(pMetadata)) 321 { 322 // Reset buffer 323 jack_midi_clear_buffer(pDataBuffer); 324 325 // Transfer MIDI events 326 pMidi->sort(); // All events SHOULD be ordered chonologically 327 328 // Transmit all events 329 for (size_t i=0, events=pMidi->nEvents; i<events; ++i) 330 { 331 // Determine size of the message 332 midi::event_t *ev = &pMidi->vEvents[i]; 333 ssize_t size = midi::size_of(ev); 334 lsp_trace("Output event: type=0x%02x, timestamp=%d", int(ev->type), int(ev->timestamp)); 335 336 if (size <= 0) 337 { 338 lsp_warn("Could not encode output MIDI message of type 0x%02x, timestamp=%d", int(ev->type), int(ev->timestamp)); 339 continue; 340 } 341 342 // Allocate MIDI event 343 jack_midi_data_t *midi_data = jack_midi_event_reserve(pDataBuffer, ev->timestamp, size); 344 if (midi_data == NULL) 345 { 346 lsp_warn("Could not write MIDI message of type 0x%02x, size=%d, timestamp=%d to JACK output port buffer=%p", 347 int(ev->type), int(size), int(ev->timestamp), pBuffer); 348 continue; 349 } 350 351 // Encode MIDI event 352 midi::encode(midi_data, ev); 353 lsp_dumpb("out midi event", midi_data, size); 354 } 355 356 // Cleanup the output buffer 357 pMidi->clear(); 358 } 359 360 pBuffer = NULL; 361 } 362 }; 363 364 class JACKControlPort: public JACKPort 365 { 366 private: 367 float fNewValue; 368 float fCurrValue; 369 370 public: JACKControlPort(const port_t * meta,JACKWrapper * w)371 explicit JACKControlPort(const port_t *meta, JACKWrapper *w) : JACKPort(meta, w) 372 { 373 fNewValue = meta->start; 374 fCurrValue = meta->start; 375 } 376 ~JACKControlPort()377 virtual ~JACKControlPort() 378 { 379 fNewValue = pMetadata->start; 380 fCurrValue = pMetadata->start; 381 }; 382 383 public: pre_process(size_t samples)384 virtual bool pre_process(size_t samples) 385 { 386 if (fNewValue == fCurrValue) 387 return false; 388 389 fCurrValue = fNewValue; 390 return true; 391 } 392 getValue()393 virtual float getValue() 394 { 395 return fCurrValue; 396 } 397 updateValue(float value)398 void updateValue(float value) 399 { 400 fNewValue = limit_value(pMetadata, value); 401 } 402 }; 403 404 class JACKMeterPort: public JACKPort 405 { 406 private: 407 float fValue; 408 bool bForce; 409 410 public: JACKMeterPort(const port_t * meta,JACKWrapper * w)411 explicit JACKMeterPort(const port_t *meta, JACKWrapper *w) : JACKPort(meta, w) 412 { 413 fValue = meta->start; 414 bForce = true; 415 } 416 ~JACKMeterPort()417 virtual ~JACKMeterPort() 418 { 419 fValue = pMetadata->start; 420 }; 421 422 public: getValue()423 virtual float getValue() 424 { 425 return fValue; 426 } 427 setValue(float value)428 virtual void setValue(float value) 429 { 430 value = limit_value(pMetadata, value); 431 432 if (pMetadata->flags & F_PEAK) 433 { 434 if ((bForce) || (fabs(fValue) < fabs(value))) 435 { 436 fValue = value; 437 bForce = false; 438 } 439 } 440 else 441 fValue = value; 442 } 443 syncValue()444 float syncValue() 445 { 446 float value = fValue; 447 bForce = true; 448 return value; 449 } 450 }; 451 452 class JACKMeshPort: public JACKPort 453 { 454 private: 455 mesh_t *pMesh; 456 457 public: JACKMeshPort(const port_t * meta,JACKWrapper * w)458 explicit JACKMeshPort(const port_t *meta, JACKWrapper *w) : JACKPort(meta, w) 459 { 460 pMesh = NULL; 461 } 462 ~JACKMeshPort()463 virtual ~JACKMeshPort() 464 { 465 pMesh = NULL; 466 } 467 468 public: getBuffer()469 virtual void *getBuffer() 470 { 471 return pMesh; 472 } 473 init()474 virtual int init() 475 { 476 pMesh = jack_create_mesh(pMetadata); 477 return (pMesh == NULL) ? STATUS_NO_MEM : STATUS_OK; 478 } 479 destroy()480 virtual void destroy() 481 { 482 if (pMesh != NULL) 483 { 484 jack_destroy_mesh(pMesh); 485 pMesh = NULL; 486 } 487 } 488 }; 489 490 class JACKStreamPort: public JACKPort 491 { 492 private: 493 stream_t *pStream; 494 495 public: JACKStreamPort(const port_t * meta,JACKWrapper * w)496 explicit JACKStreamPort(const port_t *meta, JACKWrapper *w): JACKPort(meta, w) 497 { 498 pStream = NULL; 499 } 500 ~JACKStreamPort()501 virtual ~JACKStreamPort() 502 { 503 pStream = NULL; 504 } 505 506 public: getBuffer()507 virtual void *getBuffer() 508 { 509 return pStream; 510 } 511 init()512 virtual int init() 513 { 514 pStream = stream_t::create(pMetadata->min, pMetadata->max, pMetadata->start); 515 return (pStream == NULL) ? STATUS_NO_MEM : STATUS_OK; 516 } 517 destroy()518 virtual void destroy() 519 { 520 stream_t::destroy(pStream); 521 pStream = NULL; 522 } 523 }; 524 525 class JACKFrameBufferPort: public JACKPort 526 { 527 private: 528 frame_buffer_t sFB; 529 530 public: JACKFrameBufferPort(const port_t * meta,JACKWrapper * w)531 explicit JACKFrameBufferPort(const port_t *meta, JACKWrapper *w) : JACKPort(meta, w) 532 { 533 } 534 ~JACKFrameBufferPort()535 virtual ~JACKFrameBufferPort() 536 { 537 } 538 539 public: getBuffer()540 virtual void *getBuffer() 541 { 542 return &sFB; 543 } 544 init()545 virtual int init() 546 { 547 return sFB.init(pMetadata->start, pMetadata->step); 548 } 549 destroy()550 virtual void destroy() 551 { 552 sFB.destroy(); 553 } 554 }; 555 556 class JACKOscPort: public JACKPort 557 { 558 private: 559 osc_buffer_t *pFB; 560 561 public: JACKOscPort(const port_t * meta,JACKWrapper * w)562 explicit JACKOscPort(const port_t *meta, JACKWrapper *w) : JACKPort(meta, w) 563 { 564 pFB = NULL; 565 } 566 ~JACKOscPort()567 virtual ~JACKOscPort() 568 { 569 } 570 571 public: getBuffer()572 virtual void *getBuffer() 573 { 574 return pFB; 575 } 576 init()577 virtual int init() 578 { 579 pFB = osc_buffer_t::create(OSC_BUFFER_MAX); 580 return (pFB == NULL) ? STATUS_NO_MEM : STATUS_OK; 581 } 582 destroy()583 virtual void destroy() 584 { 585 if (pFB != NULL) 586 { 587 osc_buffer_t::destroy(pFB); 588 pFB = NULL; 589 } 590 } 591 }; 592 593 class JACKPathPort: public JACKPort 594 { 595 private: 596 jack_path_t sPath; 597 598 public: JACKPathPort(const port_t * meta,JACKWrapper * w)599 explicit JACKPathPort(const port_t *meta, JACKWrapper *w) : JACKPort(meta, w) 600 { 601 sPath.init(); 602 } 603 ~JACKPathPort()604 virtual ~JACKPathPort() 605 { 606 } 607 608 public: getBuffer()609 virtual void *getBuffer() 610 { 611 return static_cast<path_t *>(&sPath); 612 } 613 pre_process(size_t samples)614 virtual bool pre_process(size_t samples) 615 { 616 return sPath.pending(); 617 } 618 }; 619 620 } 621 622 623 #endif /* COINTAINER_JACK_PORTS_H_ */ 624