3 * Copyright (C) 2011-2020 Filipe Coelho <falktx@falktx.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
18 #include "CarlaEnginePorts.hpp"
19 #include "CarlaEngineUtils.hpp"
20 #include "CarlaMathUtils.hpp"
21 #include "CarlaMIDI.h"
23 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
24 #include "CarlaEngineGraph.hpp"
29 CARLA_BACKEND_START_NAMESPACE
31 // -----------------------------------------------------------------------
34 static EngineEvent kFallbackEngineEvent
= {
35 kEngineEventTypeNull
, 0, 0, {{ kEngineControlEventTypeNull
, 0, -1, 0.0f
, true }}
38 // -----------------------------------------------------------------------
39 // Carla Engine port (Abstract)
41 CarlaEnginePort::CarlaEnginePort(const CarlaEngineClient
& client
, const bool isInputPort
, const uint32_t indexOffset
) noexcept
43 kIsInput(isInputPort
),
44 kIndexOffset(indexOffset
)
46 carla_debug("CarlaEnginePort::CarlaEnginePort(%s)", bool2str(isInputPort
));
49 CarlaEnginePort::~CarlaEnginePort() noexcept
51 carla_debug("CarlaEnginePort::~CarlaEnginePort()");
54 void CarlaEnginePort::setMetaData(const char*, const char*, const char*)
58 // -----------------------------------------------------------------------
59 // Carla Engine Audio port
61 CarlaEngineAudioPort::CarlaEngineAudioPort(const CarlaEngineClient
& client
, const bool isInputPort
, const uint32_t indexOffset
) noexcept
62 : CarlaEnginePort(client
, isInputPort
, indexOffset
),
65 carla_debug("CarlaEngineAudioPort::CarlaEngineAudioPort(%s)", bool2str(isInputPort
));
68 CarlaEngineAudioPort::~CarlaEngineAudioPort() noexcept
70 carla_debug("CarlaEngineAudioPort::~CarlaEngineAudioPort()");
73 void CarlaEngineAudioPort::initBuffer() noexcept
77 // -----------------------------------------------------------------------
78 // Carla Engine CV port
80 CarlaEngineCVPort::CarlaEngineCVPort(const CarlaEngineClient
& client
, const bool isInputPort
, const uint32_t indexOffset
) noexcept
81 : CarlaEnginePort(client
, isInputPort
, indexOffset
),
86 carla_debug("CarlaEngineCVPort::CarlaEngineCVPort(%s)", bool2str(isInputPort
));
89 CarlaEngineCVPort::~CarlaEngineCVPort() noexcept
91 carla_debug("CarlaEngineCVPort::~CarlaEngineCVPort()");
94 void CarlaEngineCVPort::initBuffer() noexcept
98 void CarlaEngineCVPort::setRange(const float min
, const float max
) noexcept
103 char strBufMin
[STR_MAX
];
104 char strBufMax
[STR_MAX
];
105 carla_zeroChars(strBufMin
, STR_MAX
);
106 carla_zeroChars(strBufMax
, STR_MAX
);
109 const CarlaScopedLocale csl
;
110 std::snprintf(strBufMin
, STR_MAX
-1, "%.12g", static_cast<double>(min
));
111 std::snprintf(strBufMax
, STR_MAX
-1, "%.12g", static_cast<double>(max
));
114 setMetaData(LV2_CORE__minimum
, strBufMin
, "");
115 setMetaData(LV2_CORE__maximum
, strBufMax
, "");
118 // -----------------------------------------------------------------------
119 // Carla Engine Event port
121 CarlaEngineEventPort::CarlaEngineEventPort(const CarlaEngineClient
& client
, const bool isInputPort
, const uint32_t indexOffset
) noexcept
122 : CarlaEnginePort(client
, isInputPort
, indexOffset
),
123 kProcessMode(client
.getEngine().getProccessMode()),
126 carla_debug("CarlaEngineEventPort::CarlaEngineEventPort(%s)", bool2str(isInputPort
));
128 if (kProcessMode
== ENGINE_PROCESS_MODE_PATCHBAY
)
130 fBuffer
= new EngineEvent
[kMaxEngineEventInternalCount
];
131 carla_zeroStructs(fBuffer
, kMaxEngineEventInternalCount
);
135 CarlaEngineEventPort::~CarlaEngineEventPort() noexcept
137 carla_debug("CarlaEngineEventPort::~CarlaEngineEventPort()");
139 if (kProcessMode
== ENGINE_PROCESS_MODE_PATCHBAY
)
141 CARLA_SAFE_ASSERT_RETURN(fBuffer
!= nullptr,);
148 void CarlaEngineEventPort::initBuffer() noexcept
150 if (kProcessMode
== ENGINE_PROCESS_MODE_CONTINUOUS_RACK
|| kProcessMode
== ENGINE_PROCESS_MODE_BRIDGE
)
151 fBuffer
= kClient
.getEngine().getInternalEventBuffer(kIsInput
);
152 else if (kProcessMode
== ENGINE_PROCESS_MODE_PATCHBAY
&& ! kIsInput
)
153 carla_zeroStructs(fBuffer
, kMaxEngineEventInternalCount
);
156 uint32_t CarlaEngineEventPort::getEventCount() const noexcept
158 CARLA_SAFE_ASSERT_RETURN(kIsInput
, 0);
159 CARLA_SAFE_ASSERT_RETURN(fBuffer
!= nullptr, 0);
160 CARLA_SAFE_ASSERT_RETURN(kProcessMode
!= ENGINE_PROCESS_MODE_SINGLE_CLIENT
&& kProcessMode
!= ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
, 0);
164 for (; i
< kMaxEngineEventInternalCount
; ++i
)
166 if (fBuffer
[i
].type
== kEngineEventTypeNull
)
173 EngineEvent
& CarlaEngineEventPort::getEvent(const uint32_t index
) const noexcept
175 CARLA_SAFE_ASSERT_RETURN(kIsInput
, kFallbackEngineEvent
);
176 CARLA_SAFE_ASSERT_RETURN(fBuffer
!= nullptr, kFallbackEngineEvent
);
177 CARLA_SAFE_ASSERT_RETURN(kProcessMode
!= ENGINE_PROCESS_MODE_SINGLE_CLIENT
&& kProcessMode
!= ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
, kFallbackEngineEvent
);
178 CARLA_SAFE_ASSERT_RETURN(index
< kMaxEngineEventInternalCount
, kFallbackEngineEvent
);
180 return fBuffer
[index
];
183 EngineEvent
& CarlaEngineEventPort::getEventUnchecked(const uint32_t index
) const noexcept
185 return fBuffer
[index
];
188 bool CarlaEngineEventPort::writeControlEvent(const uint32_t time
, const uint8_t channel
, const EngineControlEvent
& ctrl
) noexcept
190 return writeControlEvent(time
, channel
, ctrl
.type
, ctrl
.param
, ctrl
.midiValue
, ctrl
.normalizedValue
);
193 bool CarlaEngineEventPort::writeControlEvent(const uint32_t time
, const uint8_t channel
,
194 const EngineControlEventType type
,
195 const uint16_t param
,
196 const int8_t midiValue
,
197 const float normalizedValue
) noexcept
199 CARLA_SAFE_ASSERT_RETURN(! kIsInput
, false);
200 CARLA_SAFE_ASSERT_RETURN(fBuffer
!= nullptr, false);
201 CARLA_SAFE_ASSERT_RETURN(kProcessMode
!= ENGINE_PROCESS_MODE_SINGLE_CLIENT
&& kProcessMode
!= ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
, false);
202 CARLA_SAFE_ASSERT_RETURN(type
!= kEngineControlEventTypeNull
, false);
203 CARLA_SAFE_ASSERT_RETURN(channel
< MAX_MIDI_CHANNELS
, false);
204 CARLA_SAFE_ASSERT(normalizedValue
>= 0.0f
&& normalizedValue
<= 1.0f
);
206 if (type
== kEngineControlEventTypeParameter
) {
207 CARLA_SAFE_ASSERT(! MIDI_IS_CONTROL_BANK_SELECT(param
));
210 for (uint32_t i
=0; i
< kMaxEngineEventInternalCount
; ++i
)
212 EngineEvent
& event(fBuffer
[i
]);
214 if (event
.type
!= kEngineEventTypeNull
)
217 event
.type
= kEngineEventTypeControl
;
219 event
.channel
= channel
;
221 event
.ctrl
.type
= type
;
222 event
.ctrl
.param
= param
;
223 event
.ctrl
.midiValue
= midiValue
;
224 event
.ctrl
.normalizedValue
= carla_fixedValue
<float>(0.0f
, 1.0f
, normalizedValue
);
229 carla_stderr2("CarlaEngineEventPort::writeControlEvent() - buffer full");
233 bool CarlaEngineEventPort::writeMidiEvent(const uint32_t time
, const uint8_t size
, const uint8_t* const data
) noexcept
235 return writeMidiEvent(time
, uint8_t(MIDI_GET_CHANNEL_FROM_DATA(data
)), size
, data
);
238 bool CarlaEngineEventPort::writeMidiEvent(const uint32_t time
, const uint8_t channel
, const EngineMidiEvent
& midi
) noexcept
240 CARLA_SAFE_ASSERT(midi
.port
== kIndexOffset
);
241 return writeMidiEvent(time
, channel
, midi
.size
, midi
.data
);
244 bool CarlaEngineEventPort::writeMidiEvent(const uint32_t time
, const uint8_t channel
, const uint8_t size
, const uint8_t* const data
) noexcept
246 CARLA_SAFE_ASSERT_RETURN(! kIsInput
, false);
247 CARLA_SAFE_ASSERT_RETURN(fBuffer
!= nullptr, false);
248 CARLA_SAFE_ASSERT_RETURN(kProcessMode
!= ENGINE_PROCESS_MODE_SINGLE_CLIENT
&& kProcessMode
!= ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
, false);
249 CARLA_SAFE_ASSERT_RETURN(channel
< MAX_MIDI_CHANNELS
, false);
250 CARLA_SAFE_ASSERT_RETURN(size
> 0 && size
<= EngineMidiEvent::kDataSize
, false);
251 CARLA_SAFE_ASSERT_RETURN(data
!= nullptr, false);
253 for (uint32_t i
=0; i
< kMaxEngineEventInternalCount
; ++i
)
255 EngineEvent
& event(fBuffer
[i
]);
257 if (event
.type
!= kEngineEventTypeNull
)
261 event
.channel
= channel
;
263 const uint8_t status(uint8_t(MIDI_GET_STATUS_FROM_DATA(data
)));
265 if (status
== MIDI_STATUS_CONTROL_CHANGE
)
267 CARLA_SAFE_ASSERT_RETURN(size
>= 2, true);
271 case MIDI_CONTROL_BANK_SELECT
:
272 case MIDI_CONTROL_BANK_SELECT__LSB
:
273 CARLA_SAFE_ASSERT_RETURN(size
>= 3, true);
274 event
.type
= kEngineEventTypeControl
;
275 event
.ctrl
.type
= kEngineControlEventTypeMidiBank
;
276 event
.ctrl
.param
= data
[2];
277 event
.ctrl
.midiValue
= -1;
278 event
.ctrl
.normalizedValue
= 0.0f
;
279 event
.ctrl
.handled
= true;
282 case MIDI_CONTROL_ALL_SOUND_OFF
:
283 event
.type
= kEngineEventTypeControl
;
284 event
.ctrl
.type
= kEngineControlEventTypeAllSoundOff
;
285 event
.ctrl
.param
= 0;
286 event
.ctrl
.midiValue
= -1;
287 event
.ctrl
.normalizedValue
= 0.0f
;
288 event
.ctrl
.handled
= true;
291 case MIDI_CONTROL_ALL_NOTES_OFF
:
292 event
.type
= kEngineEventTypeControl
;
293 event
.ctrl
.type
= kEngineControlEventTypeAllNotesOff
;
294 event
.ctrl
.param
= 0;
295 event
.ctrl
.midiValue
= -1;
296 event
.ctrl
.normalizedValue
= 0.0f
;
297 event
.ctrl
.handled
= true;
302 if (status
== MIDI_STATUS_PROGRAM_CHANGE
)
304 CARLA_SAFE_ASSERT_RETURN(size
>= 2, true);
306 event
.type
= kEngineEventTypeControl
;
307 event
.ctrl
.type
= kEngineControlEventTypeMidiProgram
;
308 event
.ctrl
.param
= data
[1];
309 event
.ctrl
.midiValue
= -1;
310 event
.ctrl
.normalizedValue
= 0.0f
;
311 event
.ctrl
.handled
= true;
315 event
.type
= kEngineEventTypeMidi
;
316 event
.midi
.size
= size
;
318 if (kIndexOffset
< 0xFF /* uint8_t max */)
320 event
.midi
.port
= static_cast<uint8_t>(kIndexOffset
);
325 carla_safe_assert_uint("kIndexOffset < 0xFF", __FILE__
, __LINE__
, kIndexOffset
);
328 event
.midi
.data
[0] = status
;
331 for (; j
< size
; ++j
)
332 event
.midi
.data
[j
] = data
[j
];
333 for (; j
< EngineMidiEvent::kDataSize
; ++j
)
334 event
.midi
.data
[j
] = 0;
339 carla_stderr2("CarlaEngineEventPort::writeMidiEvent() - buffer full");
343 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
344 // -----------------------------------------------------------------------
345 // Carla Engine Meta CV port
347 CarlaEngineCVSourcePorts::CarlaEngineCVSourcePorts()
348 : pData(new ProtectedData())
350 carla_debug("CarlaEngineCVSourcePorts::CarlaEngineCVSourcePorts()");
353 CarlaEngineCVSourcePorts::~CarlaEngineCVSourcePorts()
355 carla_debug("CarlaEngineCVSourcePorts::~CarlaEngineCVSourcePorts()");
359 bool CarlaEngineCVSourcePorts::addCVSource(CarlaEngineCVPort
* const port
,
360 const uint32_t portIndexOffset
,
361 const bool reconfigureNow
)
363 CARLA_SAFE_ASSERT_RETURN(port
!= nullptr, false);
364 CARLA_SAFE_ASSERT_RETURN(port
->isInput(), false);
365 carla_debug("CarlaEngineCVSourcePorts::addCVSource(%p, %u)", port
, portIndexOffset
);
368 const CarlaRecursiveMutexLocker
crml(pData
->rmutex
);
370 const CarlaEngineEventCV ecv
= { port
, portIndexOffset
, 0.0f
};
371 if (! pData
->cvs
.add(ecv
))
374 if (reconfigureNow
&& pData
->graph
!= nullptr && pData
->plugin
.get() != nullptr)
375 pData
->graph
->reconfigureForCV(pData
->plugin
, static_cast<uint
>(pData
->cvs
.size()-1), true);
381 bool CarlaEngineCVSourcePorts::removeCVSource(const uint32_t portIndexOffset
)
383 carla_debug("CarlaEngineCVSourcePorts::removeCVSource(%u)", portIndexOffset
);
386 const CarlaRecursiveMutexLocker
crml(pData
->rmutex
);
388 for (int i
= pData
->cvs
.size(); --i
>= 0;)
390 const CarlaEngineEventCV
& ecv(pData
->cvs
[i
]);
392 if (ecv
.indexOffset
== portIndexOffset
)
395 pData
->cvs
.remove(i
);
397 if (pData
->graph
!= nullptr && pData
->plugin
.get() != nullptr)
398 pData
->graph
->reconfigureForCV(pData
->plugin
, static_cast<uint
>(i
), false);
400 carla_stdout("found cv source to remove %u", portIndexOffset
);
407 carla_stdout("did NOT found cv source to remove %u", portIndexOffset
);
411 void CarlaEngineCVSourcePorts::initPortBuffers(const float* const* const buffers
,
412 const uint32_t frames
,
413 const bool sampleAccurate
,
414 CarlaEngineEventPort
* const eventPort
)
416 CARLA_SAFE_ASSERT_RETURN(buffers
!= nullptr,);
417 CARLA_SAFE_ASSERT_RETURN(eventPort
!= nullptr,);
419 const CarlaRecursiveMutexTryLocker
crmtl(pData
->rmutex
);
421 if (! crmtl
.wasLocked())
424 const int numCVs
= pData
->cvs
.size();
429 EngineEvent
* const buffer
= eventPort
->fBuffer
;
430 CARLA_SAFE_ASSERT_RETURN(buffer
!= nullptr,);
432 uint32_t eventCount
= 0;
435 for (; eventCount
< kMaxEngineEventInternalCount
; ++eventCount
)
437 if (buffer
[eventCount
].type
== kEngineEventTypeNull
)
441 if (eventCount
== kMaxEngineEventInternalCount
)
444 // TODO be sample accurate
446 if (true || ! sampleAccurate
)
448 const uint32_t eventFrame
= eventCount
== 0 ? 0 : std::min(buffer
[eventCount
-1].time
, frames
-1U);
450 for (int i
= 0; i
< numCVs
&& eventCount
< kMaxEngineEventInternalCount
; ++i
)
452 CarlaEngineEventCV
& ecv(pData
->cvs
.getReference(i
));
453 CARLA_SAFE_ASSERT_CONTINUE(ecv
.cvPort
!= nullptr);
454 CARLA_SAFE_ASSERT_CONTINUE(buffers
[i
] != nullptr);
456 float previousValue
= ecv
.previousValue
;
457 ecv
.cvPort
->getRange(min
, max
);
459 v
= buffers
[i
][eventFrame
];
461 if (carla_isNotEqual(v
, previousValue
))
465 EngineEvent
& event(buffer
[eventCount
++]);
467 event
.type
= kEngineEventTypeControl
;
468 event
.time
= eventFrame
;
469 event
.channel
= kEngineEventNonMidiChannel
;
471 event
.ctrl
.type
= kEngineControlEventTypeParameter
;
472 event
.ctrl
.param
= static_cast<uint16_t>(ecv
.indexOffset
);
473 event
.ctrl
.midiValue
= -1;
474 event
.ctrl
.normalizedValue
= carla_fixedValue(0.0f
, 1.0f
, (v
- min
) / (max
- min
));
477 ecv
.previousValue
= previousValue
;
482 bool CarlaEngineCVSourcePorts::setCVSourceRange(const uint32_t portIndexOffset
, const float minimum
, const float maximum
)
484 const CarlaRecursiveMutexLocker
crml(pData
->rmutex
);
486 for (int i
= pData
->cvs
.size(); --i
>= 0;)
488 CarlaEngineEventCV
& ecv(pData
->cvs
.getReference(i
));
490 if (ecv
.indexOffset
== portIndexOffset
)
492 CARLA_SAFE_ASSERT_RETURN(ecv
.cvPort
!= nullptr, false);
493 ecv
.cvPort
->setRange(minimum
, maximum
);
501 void CarlaEngineCVSourcePorts::cleanup()
507 void CarlaEngineCVSourcePorts::mixWithCvBuffer(const float* const buffer,
508 const uint32_t frames,
509 const uint32_t indexOffset) noexcept
511 for (LinkedList<CarlaEngineEventCV>::Itenerator it = pData->cvs.begin2(); it.valid(); it.next())
513 CarlaEngineEventCV& ecv(it.getValue(kFallbackEngineEventCV));
515 if (ecv.indexOffset != indexOffset)
517 CARLA_SAFE_ASSERT_RETURN(ecv.cvPort != nullptr,);
519 float previousValue = ecv.previousValue;
520 ecv.cvPort->getRange(min, max);
522 for (uint32_t i=0; i<frames; i+=32)
526 if (carla_isNotEqual(v, previousValue))
530 EngineEvent& event(pData->buffer[eventIndex++]);
532 event.type = kEngineEventTypeControl;
534 event.channel = kEngineEventNonMidiChannel;
536 event.ctrl.type = kEngineControlEventTypeParameter;
537 event.ctrl.param = static_cast<uint16_t>(indexOffset);
538 event.ctrl.value = carla_fixedValue(0.0f, 1.0f, (v - min) / (max - min));
542 ecv.previousValue = previousValue;
549 // -----------------------------------------------------------------------
551 CARLA_BACKEND_END_NAMESPACE