11namespace tracktion {
inline namespace engine
14#if TRACKTION_ENABLE_REWIRE
16#include "ReWire/ReWireSDK/ReWire.h"
17#include "ReWire/ReWireSDK/ReWireAPI.h"
18#include "ReWire/ReWireSDK/ReWireMixerAPI.h"
21 #pragma comment(lib, "version.lib")
24using namespace ReWire;
27static juce::String getReWireErrorMessage (ReWireError err)
29 const char* e =
"Unknown error";
33 case kReWireError_AccessDenied: e =
"Access Denied";
break;
34 case kReWireError_ReWireOpenByOtherApplication: e =
"ReWire in use by another application";
break;
35 case kReWireError_DLLNotFound: e =
"ReWire DLL not found";
break;
36 case kReWireError_DLLTooOld: e =
"ReWire DLL too old";
break;
37 case kReWireError_UnableToLoadDLL: e =
"Unable to load ReWire DLL";
break;
38 case kReWireError_NotEnoughMemoryForDLL: e =
"Not enough memory for ReWire DLL";
break;
39 case kReWireError_OutOfMemory: e =
"Out of memory";
break;
40 case kReWireError_UnableToOpenDevice: e =
"Unable to open device";
break;
41 case kReWireError_AlreadyExists: e =
"Already exists";
break;
42 case kReWireError_NotFound: e =
"Not found";
break;
43 case kReWireError_Busy: e =
"Busy";
break;
44 case kReWireError_BufferFull: e =
"Buffer full";
break;
45 case kReWireError_PortNotConnected: e =
"Port not connected";
break;
46 case kReWireError_PortConnected: e =
"Port connected";
break;
47 case kReWireError_PortStale: e =
"Port stale";
break;
48 case kReWireError_ReadError: e =
"Read error";
break;
49 case kReWireError_NoMoreMessages: e =
"No more messages";
break;
50 case kReWireImplError_ReWireNotOpen: e =
"ReWire not open";
break;
51 case kReWireImplError_ReWireAlreadyOpen: e =
"ReWire already open";
break;
52 case kReWireImplError_DeviceNotOpen: e =
"Device not open";
break;
53 case kReWireImplError_DeviceAlreadyOpen: e =
"Device already open";
break;
54 case kReWireImplError_AudioInfoInvalid: e =
"Audio info invalid";
break;
55 case kReWireImplError_InvalidParameter: e =
"Invalid Parameter";
break;
56 case kReWireImplError_InvalidSignature: e =
"Invalid Signature";
break;
57 case kReWireError_Undefined: e =
"Undefined error";
break;
58 case kReWireError_NoError: e =
"No Error";
break;
65static void logRewireError (ReWireError res)
67 if (res != kReWireError_NoError)
68 TRACKTION_LOG_ERROR (getReWireErrorMessage (res));
71const uint32_t inputEventBufferSize = 200;
81class ReWireSystem::Device :
private Timer
92 jassert (isReWireEnabled (engine));
94 std::memset (reWireToLocalChanMap, 0,
sizeof (reWireToLocalChanMap));
96 ReWireDeviceInfo devInfo;
97 ReWirePrepareDeviceInfo (&devInfo);
98 auto res = RWMGetDeviceInfo (index, &devInfo);
100 if (res == kReWireError_NoError)
102 for (
int i = 0; i < devInfo.fChannelCount; ++i)
107 logRewireError (res);
112 ReWireDriveAudioInputParams& in = inputToDeviceParams;
113 ReWireDriveAudioOutputParams& out = outputFromDeviceParams;
115 ReWirePrepareDriveAudioInputParams (&in, inputEventBufferSize, inputToDeviceBuffer);
117 ReWireClearBitField (in.fRequestedChannelsBitField, kReWireAudioChannelCount);
119 outputEventBufferSize = (
uint32_t)
std::max (32, (
int) devInfo.fMaxEventOutputBufferSize);
120 outputFromDeviceBuffer.calloc (outputEventBufferSize);
122 ReWirePrepareDriveAudioOutputParams (&out, (ReWire_uint32_t) outputEventBufferSize, outputFromDeviceBuffer);
124 in.fFramesToRender = 128;
125 in.fTempo = 1000 * 120;
126 in.fSignatureNumerator = 4;
127 in.fSignatureDenominator = 4;
128 in.fLoopStartPPQ15360Pos = rewireLoopStart;
129 in.fLoopEndPPQ15360Pos = rewireLoopEnd;
130 in.fLoopOn = rewireLooping;
132 ReWirePrepareEventTarget (&eventTarget, 0, 0);
137 bool closeIfPossible()
141 if (handle ==
nullptr)
146 if (RWMIsCloseDeviceOK (handle, &okFlag) == kReWireError_NoError && okFlag != 0)
148 if (RWMCloseDevice (handle) == kReWireError_NoError)
160 jassert (isReWireEnabled (engine));
164 void removeReference()
170 void prepareToPlay (
double sr,
int blockSize,
int leftChanIndex,
int rightChanIndex, Edit* edit)
173 jassert (isReWireEnabled (engine));
179 storedMessages.clear();
184 bufferSourceChannels.setBit (leftChanIndex);
185 bufferSourceChannels.setBit (rightChanIndex);
186 buffer.setSize (bufferSourceChannels.countNumberOfSetBits(), blockSize);
188 std::memset (reWireToLocalChanMap, 0,
sizeof (reWireToLocalChanMap));
191 for (
int i = 0; i < kReWireAudioChannelCount; ++i)
192 if (bufferSourceChannels[i])
193 reWireToLocalChanMap[i] = (
short) localChan++;
195 ReWireDeviceInfo devInfo;
196 ReWirePrepareDeviceInfo (&devInfo);
197 auto res = RWMGetDeviceInfo (deviceIndex, &devInfo);
198 logRewireError (res);
200 ReWireAudioInfo info;
201 ReWirePrepareAudioInfo (&info, (ReWire_int32_t) sr, blockSize + 512);
202 res = RWMSetAudioInfo (&info);
204 if (res != kReWireError_NoError)
206 logRewireError (res);
207 engine.getUIBehaviour().showWarningMessage (
TRANS(
"Couldn't start ReWire plugin")
208 +
": " + getReWireErrorMessage (res));
212 auto& in = inputToDeviceParams;
213 auto& out = outputFromDeviceParams;
216 ReWirePrepareDriveAudioInputParams (&in,
217 inputEventBufferSize,
218 inputToDeviceBuffer);
220 ReWireClearBitField (in.fRequestedChannelsBitField, kReWireAudioChannelCount);
222 for (
int i = kReWireAudioChannelCount; --i >= 0;)
224 if (bufferSourceChannels[i])
226 ReWireSetBitInBitField (in.fRequestedChannelsBitField, (
unsigned short)i);
227 in.fAudioBuffers[i] = buffer.getWritePointer (reWireToLocalChanMap[i], 0);
232 outputEventBufferSize = (
uint32_t)
std::max (32, (
int) devInfo.fMaxEventOutputBufferSize);
233 outputFromDeviceBuffer.calloc (outputEventBufferSize);
235 ReWirePrepareDriveAudioOutputParams (&out, (ReWire_uint32_t) outputEventBufferSize, outputFromDeviceBuffer);
244 const auto loopRange = edit->getTransport().getLoopRange();
246 markPos.set (loopRange.getStart());
249 markPos.set (loopRange.getEnd());
252 rewireLooping = edit->getTransport().looping;
256 timePerBlock = TimeDuration::fromSamples (0.060 + blockSize, sampleRate);
258 ReWirePrepareEventTarget (&eventTarget, 0, 0);
260 timeSigRequest =
false;
261 requestTempo =
false;
263 requestedReposition =
false;
264 requestedPlay =
false;
265 requestedStop =
false;
272 bufferSourceChannels.clear();
273 storedMessages.clear();
276 void updateTempoInfo (
const tempo::Sequence::Position& position)
278 const auto bpm = position.getTempo();
279 const auto [numerator, denominator] = position.getTimeSignature();
281 inputToDeviceParams.fTempo = (bpm < 10) ? 120000 : (ReWire_uint32_t) (1000 * bpm);
282 inputToDeviceParams.fSignatureNumerator = (numerator <= 0) ? 4 : (ReWire_uint32_t) numerator;
283 inputToDeviceParams.fSignatureDenominator = (denominator == 0) ? 4 : (ReWire_uint32_t) denominator;
285 inputToDeviceParams.fPPQ15360TickOfBatchStart =
juce::roundToInt (position.getPPQTime() * kReWirePPQ);
287 pluginsServedThisFrame = 0;
290 void getAudioOutput (
const PluginRenderContext& fc,
291 int leftChannelIndex,
int rightChannelIndex,
292 int bus,
int channel)
296 auto& in = inputToDeviceParams;
297 auto& out = outputFromDeviceParams;
299 if (fc.bufferForMidiMessages !=
nullptr && references <= 1)
301 fc.bufferForMidiMessages->sortByTimestamp();
303 auto num =
std::min ((
int) fc.bufferForMidiMessages->size(),
304 (
int) inputEventBufferSize);
306 auto*
event = &in.fEventInBuffer.fEventBuffer [in.fEventInBuffer.fCount];
308 for (
int i = 0; i < num; ++i)
310 auto& m = (*fc.bufferForMidiMessages)[i];
311 const int type = *(m.getRawData());
313 if (type < 0xf0 && type >= 0x80)
315 setupMidiEvent (*ReWireConvertToMIDIEvent (event, &eventTarget),
316 type, m, fc.bufferNumSamples, bus, channel);
319 in.fEventInBuffer.fCount++;
323 fc.bufferForMidiMessages->clear();
326 if (pluginsServedThisFrame == 0)
328 in.fFramesToRender = (ReWire_uint32_t) fc.bufferNumSamples;
329 bool isPlaying = this->isPlaying (fc, in);
331 in.fLoopStartPPQ15360Pos = rewireLoopStart;
332 in.fLoopEndPPQ15360Pos = rewireLoopEnd;
333 in.fLoopOn = rewireLooping && ! fc.isRendering;
335 out.fEventOutBuffer.fCount = 0;
336 ReWireClearBitField (out.fServedChannelsBitField, kReWireAudioChannelCount);
338 if (storedMessages.size() > 0)
340 std::sort (storedMessages.begin(), storedMessages.end(),
341 [] (ReWireMIDIEvent* a, ReWireMIDIEvent* b) { return a->fRelativeSamplePos < b->fRelativeSamplePos; });
343 auto*
event = &in.fEventInBuffer.fEventBuffer [in.fEventInBuffer.fCount];
344 auto num =
std::min (storedMessages.size(), (
int) inputEventBufferSize);
346 for (
int i = 1; i < num; ++i)
348 auto* e1 = storedMessages.getUnchecked (i - 1);
349 auto* e2 = storedMessages.getUnchecked (i);
351 if (e1->fData1 == e2->fData1
352 && e1->fRelativeSamplePos == e2->fRelativeSamplePos
353 && e1->fMIDIEventType == 0x90
354 && e2->fMIDIEventType == 0x80)
356 e1->fMIDIEventType = 0x80;
357 e2->fMIDIEventType = 0x90;
362 for (
int i = 0; i < num; ++i)
364 auto* midiEvent = ReWireConvertToMIDIEvent (event, &eventTarget);
365 *midiEvent = *storedMessages.getUnchecked(i);
367 in.fEventInBuffer.fCount++;
370 storedMessages.clear();
373 if (wasPlaying && ! isPlaying)
374 in.fEventInBuffer.fCount = 0;
376 wasPlaying = isPlaying;
378 if (handle !=
nullptr)
379 RWMDriveAudio (handle, &in, &out);
383 in.fEventInBuffer.fCount = 0;
386 if (references > 1 && fc.bufferForMidiMessages !=
nullptr)
388 for (
auto& m : *fc.bufferForMidiMessages)
390 auto type = *(m.getRawData());
392 if (type < 0xf0 && type >= 0x80)
394 auto midiEvent =
new ReWireMIDIEvent();
396 setupMidiEvent (*ReWireConvertToMIDIEvent ((ReWireEvent*) midiEvent, &eventTarget),
397 type, m, fc.bufferNumSamples, bus, channel);
399 storedMessages.add (midiEvent);
403 fc.bufferForMidiMessages->clear();
406 if (pluginsServedThisFrame++ == 0)
407 handleEvents (out, fc.bufferForMidiMessages);
409 if (fc.destBuffer !=
nullptr)
411 if (ReWireIsBitInBitFieldSet (out.fServedChannelsBitField, (
unsigned short) leftChannelIndex))
412 juce::FloatVectorOperations::copy (fc.destBuffer->getWritePointer (0, fc.bufferStartSample),
413 in.fAudioBuffers[leftChannelIndex],
414 fc.bufferNumSamples);
416 if (ReWireIsBitInBitFieldSet (out.fServedChannelsBitField, (
unsigned short) rightChannelIndex))
417 juce::FloatVectorOperations::copy (fc.destBuffer->getWritePointer (1, fc.bufferStartSample),
418 in.fAudioBuffers[rightChannelIndex],
419 fc.bufferNumSamples);
424 int numSamples,
int bus,
int channel)
const
426 e.fMIDIEventType = (
unsigned short) (0xf0 & type);
427 e.fData1 = m.getRawData()[1];
428 e.fData2 = m.getRawData()[2];
431 if (e.fData2 == 0 && (e.fMIDIEventType & 0xf0) == 0x90)
432 e.fMIDIEventType = 0x80;
435 e.fEventTarget.fMIDIBusIndex = (
unsigned short) bus;
436 e.fEventTarget.fChannel = (
unsigned short) channel;
439 bool isPlaying (
const PluginRenderContext& fc, ReWireDriveAudioInputParams& in)
441 const auto playheadOutputTime = fc.editTime.getStart();
443 if ((fc.isPlaying && playheadOutputTime >= 0s) || fc.isRendering)
445 if (lastTime > playheadOutputTime || lastTime < playheadOutputTime - timePerBlock)
446 in.fPlayMode = kReWirePlayModeChaseAndPlay;
448 in.fPlayMode = kReWirePlayModeKeepPlaying;
450 lastTime = playheadOutputTime;
454 in.fPlayMode = kReWirePlayModeStop;
458 void handleEvents (ReWireDriveAudioOutputParams& out,
459 MidiMessageArray* bufferForMidiMessages)
461 auto numEventsOut = (
int) out.fEventOutBuffer.fCount;
463 for (
int i = 0; i < numEventsOut; ++i)
465 auto event = &out.fEventOutBuffer.fEventBuffer[i];
467 switch (event->fEventType)
469 case kReWireRequestSignatureEvent:
471 auto theEvent = ReWireCastToRequestSignatureEvent (event);
472 requestedTimeSigNum =
std::max (1, (
int) theEvent->fSignatureNumerator);
473 requestedTimeSigDenom =
std::max (1, (
int) theEvent->fSignatureDenominator);
474 timeSigRequest =
true;
478 case kReWireRequestTempoEvent:
480 auto theEvent = ReWireCastToRequestTempoEvent (event);
481 requestedTempo = (
int) theEvent->fTempo;
486 case kReWireRequestLoopEvent:
488 auto theEvent = ReWireCastToRequestLoopEvent (event);
489 rewireLoopStart = theEvent->fLoopStartPPQ15360Pos;
490 rewireLoopEnd = theEvent->fLoopEndPPQ15360Pos;
491 rewireLooping = theEvent->fLoopOn != 0;
496 case kReWireRequestRepositionEvent:
498 auto theEvent = ReWireCastToRequestRepositionEvent (event);
499 requestedPosition = theEvent->fPPQ15360Pos / (
double) kReWirePPQ;
500 requestedReposition =
true;
504 case kReWireRequestPlayEvent:
505 requestedPlay =
true;
508 case kReWireRequestStopEvent:
509 requestedStop =
true;
512 case kReWireMIDIEvent:
513 if (bufferForMidiMessages !=
nullptr)
515 auto m = ReWireCastToMIDIEvent (event);
517 bufferForMidiMessages->addMidiMessage (
juce::MidiMessage (m->fMIDIEventType | (0xf & m->fEventTarget.fChannel),
518 m->fData1, m->fData2),
529 void timerCallback()
override
535 if (
auto edit = editRef.get())
536 if (edit->tempoSequence.getNumTempos() == 1)
537 edit->tempoSequence.getTimeSig(0)->setStringTimeSig (
juce::String (requestedTimeSigNum)
541 timeSigRequest =
false;
548 if (
auto edit = editRef.get())
549 if (edit->tempoSequence.getNumTempos() == 1)
550 edit->tempoSequence.getTempo(0)->setBpm (requestedTempo / 1000.0);
552 requestTempo =
false;
559 if (
auto edit = editRef.get())
561 edit->getTransport().looping = rewireLooping;
565 markPos.setPPQTime (rewireLoopStart / (
double) kReWirePPQ);
566 edit->getTransport().setLoopIn (markPos.getTime());
568 markPos.setPPQTime (rewireLoopEnd / (
double) kReWirePPQ);
569 edit->getTransport().setLoopOut (markPos.getTime());
576 if (
auto edit = editRef.get())
581 const auto loopRange = edit->getTransport().getLoopRange();
582 markPos.set (loopRange.getStart());
585 markPos.set (loopRange.getEnd());
588 rewireLooping = edit->getTransport().looping;
592 if (requestedReposition)
594 if (
auto edit = editRef.get())
599 pos.setPPQTime (requestedPosition);
600 edit->getTransport().setPosition (pos.getTime());
603 requestedReposition =
false;
609 if (
auto edit = editRef.get())
610 edit->getTransport().play (
true);
612 requestedPlay =
false;
618 if (
auto edit = editRef.get())
619 edit->getTransport().stop (
false,
false);
621 requestedStop =
false;
628 ReWireDriveAudioInputParams& in = inputToDeviceParams;
629 ReWireDriveAudioOutputParams& out = outputFromDeviceParams;
638 in.fPlayMode = kReWirePlayModeStop;
639 in.fEventInBuffer.fCount = 0;
641 in.fLoopStartPPQ15360Pos = rewireLoopStart;
642 in.fLoopEndPPQ15360Pos = rewireLoopEnd;
643 in.fLoopOn = rewireLooping;
645 out.fEventOutBuffer.fCount = 0;
646 ReWireClearBitField (out.fServedChannelsBitField, kReWireAudioChannelCount);
649 RWMDriveAudio (handle, &in, &out);
651 const int numEventsOut = (
int) out.fEventOutBuffer.fCount;
653 for (
int i = 0; i < numEventsOut; ++i)
655 auto event = &out.fEventOutBuffer.fEventBuffer[i];
657 switch (event->fEventType)
659 case kReWireRequestSignatureEvent:
661 auto theEvent = ReWireCastToRequestSignatureEvent (event);
662 requestedTimeSigNum =
std::max (1, (
int) theEvent->fSignatureNumerator);
663 requestedTimeSigDenom =
std::max (1, (
int) theEvent->fSignatureDenominator);
664 timeSigRequest =
true;
668 case kReWireRequestTempoEvent:
670 auto theEvent = ReWireCastToRequestTempoEvent (event);
671 requestedTempo = (
int) theEvent->fTempo;
676 case kReWireRequestLoopEvent:
678 auto theEvent = ReWireCastToRequestLoopEvent (event);
679 rewireLoopStart = theEvent->fLoopStartPPQ15360Pos;
680 rewireLoopEnd = theEvent->fLoopEndPPQ15360Pos;
681 rewireLooping = theEvent->fLoopOn != 0;
686 case kReWireRequestRepositionEvent:
688 auto theEvent = ReWireCastToRequestRepositionEvent (event);
689 requestedPosition = theEvent->fPPQ15360Pos / (
double)kReWirePPQ;
690 requestedReposition =
true;
694 case kReWireRequestPlayEvent:
695 requestedPlay =
true;
698 case kReWireRequestStopEvent:
699 requestedStop =
true;
711 TRWMDeviceHandle handle;
716 const int deviceIndex;
717 ReWireDriveAudioInputParams inputToDeviceParams;
718 ReWireDriveAudioOutputParams outputFromDeviceParams;
719 ReWireEvent inputToDeviceBuffer [inputEventBufferSize];
722 ReWireEventTarget eventTarget;
726 short reWireToLocalChanMap[kReWireAudioChannelCount];
730 MidiMessageArray::MPESourceID midiSourceID = MidiMessageArray::createUniqueMPESourceID();
732 int references = 0, pluginsServedThisFrame = 0;
733 double sampleRate = 0;
734 TimePosition lastTime;
735 TimeDuration timePerBlock;
736 bool wasPlaying =
false;
737 SafeSelectable<Edit> editRef;
739 double requestedPosition = 0;
740 int requestedTempo = 0, requestedTimeSigNum = 0, requestedTimeSigDenom = 0;
741 int rewireLoopStart = 0, rewireLoopEnd = 0;
742 bool timeSigRequest =
false;
743 bool requestTempo =
false;
744 bool rewireLooping =
false;
745 bool requestLoop =
false;
746 bool requestedReposition =
false;
747 bool requestedPlay =
false;
748 bool requestedStop =
false;
756static ReWireSystem* rewireSystemInstance =
nullptr;
758ReWireSystem::ReWireSystem (
Engine& e) : engine (e)
761 jassert (rewireSystemInstance ==
nullptr);
762 jassert (isReWireEnabled (engine));
764 TRACKTION_LOG (
"Initialising ReWire...");
766 ReWireOpenInfo openInfo;
767 ReWirePrepareOpenInfo (&openInfo, 44100, 6400);
769 auto res = RWMOpen (&openInfo);
771 if (res != kReWireError_NoError)
773 openError = getReWireErrorMessage (res);
774 logRewireError (res);
780 ReWire_int32_t numDevs = 0;
781 res = RWMGetDeviceCount (&numDevs);
783 if (res == kReWireError_NoError)
785 for (
int i = 0; i < numDevs; ++i)
787 ReWireDeviceInfo devInfo;
788 ReWirePrepareDeviceInfo (&devInfo);
790 res = RWMGetDeviceInfo (i, &devInfo);
792 if (res == kReWireError_NoError)
795 devices.add (
nullptr);
799 logRewireError (res);
808 logRewireError (res);
815ReWireSystem::~ReWireSystem()
817 jassert (rewireSystemInstance ==
this);
819 rewireSystemInstance =
nullptr;
822bool ReWireSystem::isReWireEnabled (
Engine& e,
bool returnCurrentState)
824 if (returnCurrentState)
826 static bool systemEnabled = isReWireEnabled (e,
false);
827 return systemEnabled;
830 return e.getPropertyStorage().getProperty (SettingID::reWireEnabled,
true);
833void ReWireSystem::setReWireEnabled (
Engine& e,
bool b)
835 e.getPropertyStorage().setProperty (SettingID::reWireEnabled, b);
838ReWireSystem* ReWireSystem::getInstanceIfActive() {
return rewireSystemInstance; }
840const char* ReWireSystem::getReWireLibraryName() {
return ReWire::getReWireLibraryName(); }
841const char* ReWireSystem::getReWireFolderName() {
return ReWire::getReWireFolderName(); }
842const char* ReWireSystem::getPropellerheadFolderName() {
return ReWire::getPropellerheadFolderName(); }
843int ReWireSystem::getRequiredVersionNumMajor() {
return ReWire::getRequiredVersionNumMajor(); }
844int ReWireSystem::getRequiredVersionNumMinor() {
return ReWire::getRequiredVersionNumMinor(); }
846void ReWireSystem::initialise (
Engine& e)
850 if (rewireSystemInstance ==
nullptr && isReWireEnabled (e))
852 setReWireEnabled (e,
false);
855 DeadMansPedalMessage dmp (e.getPropertyStorage(),
856 TRANS(
"The ReWire system failed to start up correctly last time "
857 "Tracktion ran - it has now been disabled (see the settings panel to re-enable it)")
858 .replace (
"Tracktion", e.getPropertyStorage().getApplicationName()));
860 rewireSystemInstance =
new ReWireSystem (e);
863 setReWireEnabled (e,
true);
867bool ReWireSystem::shutdown()
871 if (rewireSystemInstance !=
nullptr)
873 if (rewireSystemInstance->tryToCloseAllOpenDevices())
875 delete rewireSystemInstance;
885bool ReWireSystem::closeSystem()
888 jassert (isReWireEnabled (engine));
895 if (RWMIsCloseOK (&okFlag) == kReWireError_NoError && okFlag)
897 auto res = RWMClose();
899 if (res == kReWireError_NoError)
903 logRewireError (res);
904 openError = getReWireErrorMessage (res);
915 jassert (isReWireEnabled (engine));
916 auto index = deviceNames.indexOf (devName);
920 if (
auto dev = devices[index])
926 DeadMansPedalMessage dmp (engine.getPropertyStorage(),
927 "The ReWire device \"" + devName +
"\" crashed while being initialised.\n\n"
928 "You may want to remove this device or disable ReWire (in Tracktion's settings panel).");
930 if (
auto dev = createDevice (index, devName, error))
932 devices.set (index, dev);
939 error =
TRANS(
"Unknown device");
947 TRWMDeviceHandle handle =
nullptr;
948 auto res = RWMOpenDevice (index, &handle);
950 if (res != kReWireError_NoError)
952 logRewireError (res);
953 error = getReWireErrorMessage (res);
957 return new Device (engine, handle, devName, index);
960bool ReWireSystem::tryToCloseAllOpenDevices()
968 bool waitForDevices =
false;
970 for (
auto& dev : devices)
974 char isRunningFlag = 0;
976 if (RWMIsPanelAppLaunched (dev->handle, &isRunningFlag) == kReWireError_NoError
977 && isRunningFlag != 0)
979 auto res = RWMQuitPanelApp (dev->handle);
980 jassert (res == kReWireError_NoError); (void) res;
985 ok = ok && dev->closeIfPossible();
986 waitForDevices =
true;
990 TRACKTION_LOG (
"ReWire - closing system");
992 if (ok && closeSystem())
1000 for (
int j = 20; --j >= 0;)
1008 TRACKTION_LOG (
"ReWire - done");
1012void ReWireSystem::timerCallback()
1015 auto err = RWMIdle();
1016 jassert (err == kReWireError_NoError); (void) err;
1021const char* ReWirePlugin::xmlTypeName =
"ReWire";
1023ReWirePlugin::ReWirePlugin (PluginCreationInfo info) : Plugin (info)
1025 auto* um = getUndoManager();
1027 currentDeviceName.referTo (state, IDs::device, um);
1028 currentChannelNameL.referTo (state, IDs::channelL, um);
1029 currentChannelNameR.referTo (state, IDs::channelR, um);
1030 currentBus.referTo (state, IDs::bus, um);
1031 currentChannel.referTo (state, IDs::channel, um);
1033 if (ReWireSystem::isReWireEnabled (info.edit.engine))
1034 ReWireSystem::initialise (info.edit.engine);
1037ReWirePlugin::~ReWirePlugin()
1039 if (device !=
nullptr)
1040 device->removeReference();
1042 notifyListenersOfDeletion();
1045void ReWirePlugin::initialiseFully()
1047 openDevice (currentDeviceName);
1050void ReWirePlugin::valueTreeChanged()
1052 Plugin::valueTreeChanged();
1053 triggerAsyncUpdate();
1056void ReWirePlugin::handleAsyncUpdate()
1063 if (device !=
nullptr)
1064 return currentDeviceName;
1066 return TRANS(
"ReWire Device");
1072 getLeftRightChannelNames (ins);
1074 if (outs !=
nullptr)
1076 outs->
add (currentChannelNameL);
1077 outs->
add (currentChannelNameR);
1081void ReWirePlugin::initialise (
const PluginInitialisationInfo& info)
1083 if (device !=
nullptr)
1085 channelIndexL =
std::max (0, device->channelNames.indexOf (currentChannelNameL.get()));
1086 channelIndexR =
std::max (0, device->channelNames.indexOf (currentChannelNameR.get()));
1088 device->prepareToPlay (info.sampleRate, info.blockSizeSamples,
1089 channelIndexL, channelIndexR, &edit);
1095void ReWirePlugin::deinitialise()
1097 if (device !=
nullptr)
1098 device->deinitialise();
1101void ReWirePlugin::prepareForNextBlock (TimePosition editTime)
1103 if (currentTempoPosition !=
nullptr && device !=
nullptr)
1105 currentTempoPosition->set (editTime);
1106 device->updateTempoInfo (*currentTempoPosition);
1110void ReWirePlugin::applyToBuffer (
const PluginRenderContext& fc)
1112 if (fc.destBuffer !=
nullptr && device !=
nullptr)
1114 SCOPED_REALTIME_CHECK
1116 fc.destBuffer->setSize (2, fc.destBuffer->getNumSamples(),
true);
1118 device->getAudioOutput (fc, channelIndexL, channelIndexR,
1119 currentBus, currentChannel);
1127 auto error =
TRANS(
"ReWire is disabled");
1129 if (ReWireSystem::isReWireEnabled (engine))
1131 if (rewireSystemInstance !=
nullptr)
1133 error = rewireSystemInstance->openError;
1135 if (device ==
nullptr || newDev != device->deviceName)
1137 edit.getTransport().stop (
false,
true);
1138 edit.getTransport().freePlaybackContext();
1140 if (
auto newDevice = rewireSystemInstance->openDevice (newDev, error))
1142 if (device !=
nullptr)
1143 device->removeReference();
1146 currentDeviceName = newDev;
1148 if (! device->channelNames.contains (currentChannelNameL.get()))
1149 currentChannelNameL = device->channelNames[0];
1151 if (! device->channelNames.contains (currentChannelNameR.get()))
1152 currentChannelNameR = device->channelNames[
std::min (1, device->channelNames.size() - 1)];
1157 if (newDev.
isNotEmpty() && error.isNotEmpty())
1158 engine.getUIBehaviour().showWarningMessage (
TRANS(
"ReWire error - Couldn't open device")
1162 updateBusesAndChannels();
1165 propertiesChanged();
1173bool ReWirePlugin::updateBusesAndChannels()
1176 bool hasChanged =
false;
1178 if (device !=
nullptr)
1180 ReWireEventInfo eventInfo;
1181 ReWirePrepareEventInfo (&eventInfo);
1183 auto err = RWMGetEventInfo (device->handle, &eventInfo);
1185 if (err != kReWireError_NoError)
1187 logRewireError (err);
1191 for (
int i = 0; i < kReWireReservedEventBusIndex; ++i)
1193 if (ReWireIsBitInBitFieldSet (eventInfo.fUsedBusBitField, (
unsigned short)i))
1195 ReWireEventBusInfo eventBusInfo;
1196 ReWirePrepareEventBusInfo (&eventBusInfo);
1198 err = RWMGetEventBusInfo (device->handle, (
unsigned short)i, &eventBusInfo);
1199 jassert (err == kReWireError_NoError);
1201 if (err == kReWireError_NoError)
1205 if (busName.trim().isEmpty())
1206 busName =
"(" +
TRANS(
"Unnamed") +
")";
1214 hasChanged = newBuses != buses;
1217 ReWireEventBusInfo eventBusInfo;
1218 ReWirePrepareEventBusInfo (&eventBusInfo);
1220 err = RWMGetEventBusInfo (device->handle, (
unsigned short)currentBus, &eventBusInfo);
1221 jassert (err == kReWireError_NoError);
1223 if (err == kReWireError_NoError)
1225 for (
int j = 0; j < 16; ++j)
1227 if (ReWireIsBitInBitFieldSet (eventBusInfo.fUsedChannelBitField, (
unsigned short)j))
1229 ReWireEventChannelInfo eventChannelInfo;
1230 ReWirePrepareEventChannelInfo (&eventChannelInfo);
1232 ReWireEventTarget eventTarget;
1233 ReWirePrepareEventTarget (&eventTarget, (
unsigned short)currentBus, (
unsigned short)j);
1235 err = RWMGetEventChannelInfo (device->handle, &eventTarget, &eventChannelInfo);
1237 jassert (err == kReWireError_NoError);
1239 if (err == kReWireError_NoError)
1248 hasChanged = hasChanged || (channels != newChannels);
1249 channels = newChannels;
1251 char isRunningFlag = 0;
1252 err = RWMIsPanelAppLaunched (device->handle, &isRunningFlag);
1253 bool nowRunning = (err == kReWireError_NoError && isRunningFlag != 0);
1254 hasChanged = hasChanged || (uiIsRunning != nowRunning);
1255 uiIsRunning = nowRunning;
1259 uiIsRunning =
false;
1265void ReWirePlugin::openExternalUI()
1267 if (device !=
nullptr)
1269 auto err = RWMLaunchPanelApp (device->handle);
1271 if (err != kReWireError_NoError)
1273 logRewireError (err);
1274 engine.getUIBehaviour().showWarningMessage (
TRANS(
"ReWire error opening interface")
1275 +
": " + getReWireErrorMessage (err));
1278 updateBusesAndChannels();
1282void ReWirePlugin::setLeftChannel (
const juce::String& channelName)
1284 if (currentChannelNameL == channelName)
1287 currentChannelNameL = channelName;
1289 updateBusesAndChannels();
1290 TransportControl::restartAllTransports (engine,
true);
1293void ReWirePlugin::setRightChannel (
const juce::String& channelName)
1295 if (currentChannelNameR == channelName)
1298 currentChannelNameR = channelName;
1300 updateBusesAndChannels();
1301 TransportControl::restartAllTransports (engine,
true);
1304void ReWirePlugin::setMidiBus (
int busNum)
1308 if (currentBus != v)
1312 if (updateBusesAndChannels())
1313 SelectionManager::refreshAllPropertyPanels();
1317void ReWirePlugin::setMidiChannel (
int channel)
1319 unsigned short v = (
unsigned short) (
std::max (0, channel));
1321 if (currentChannel != v)
1328bool ReWirePlugin::hasNameForMidiNoteNumber (
int note,
int ,
juce::String& name)
1330 if (device !=
nullptr)
1332 ReWireEventTarget eventTarget;
1333 ReWirePrepareEventTarget (&eventTarget, (
unsigned short)currentBus, (
unsigned short)currentChannel);
1335 ReWireEventNoteInfo noteInfo;
1336 ReWirePrepareEventNoteInfo (¬eInfo);
1338 if (RWMGetNoteInfo (device->handle, &eventTarget, (
unsigned short)note, ¬eInfo) == kReWireError_NoError
1339 && noteInfo.fType != kReWireEventNoteTypeUnused)
1341 name = noteInfo.fKeyName;
1342 return name.isNotEmpty();
1349void ReWirePlugin::timerCallback()
1351 if (updateBusesAndChannels())
1352 propertiesChanged();
1357 return device->channelNames;
void add(String stringToAdd)
bool isEmpty() const noexcept
bool isNotEmpty() const noexcept
static void JUCE_CALLTYPE sleep(int milliseconds)
static uint32 getApproximateMillisecondCounter() noexcept
#define TRANS(stringLiteral)
Type jlimit(Type lowerLimit, Type upperLimit, Type valueToConstrain) noexcept
void ignoreUnused(Types &&...) noexcept
int roundToInt(const FloatType value) noexcept
tempo::Sequence::Position createPosition(const TempoSequence &s)
Creates a Position to iterate over the given TempoSequence.
#define CRASH_TRACER
This macro adds the current location to a stack which gets logged if a crash happens.