11namespace tracktion {
inline namespace engine
14TrackOutput::TrackOutput (Track& t)
17 auto um = &t.edit.getUndoManager();
18 state = t.state.getOrCreateChildWithName (IDs::OUTPUTDEVICES, um);
19 auto devicesTree = state.getOrCreateChildWithName (IDs::DEVICE, um);
20 outputDevice.referTo (devicesTree, IDs::name, um);
22 state.addListener (
this);
25TrackOutput::~TrackOutput()
27 state.removeListener (
this);
31void TrackOutput::initialise()
35 if (outputDevice.get().isEmpty() && getDestinationTrack() ==
nullptr)
36 setOutputToDefaultDevice (
false);
39void TrackOutput::flushStateToValueTree()
41 if (! destTrackID.isValid())
44 if (
auto at = findAudioTrackForID (owner.edit, destTrackID))
45 setOutputToTrack (at);
48void TrackOutput::updateOutput()
51 for (
auto t = getDestinationTrack(); t !=
nullptr; t = t->getOutput().getDestinationTrack())
52 t->setFrozen (
false, Track::groupFreeze);
54 auto oldTrackID = destTrackID;
57 if (outputDevice.get().startsWith (
"track "))
59 auto trackNum = outputDevice.get().upToFirstOccurrenceOf (
"(",
false,
false).trim().getTrailingIntValue();
63 if (at->getAudioTrackNumber() == trackNum)
65 if (! at->getOutput().feedsInto (&owner))
66 destTrackID = at->itemID;
72 if (oldTrackID == destTrackID)
76 owner.edit.restartPlayback();
78 owner.setFrozen (
false, Track::groupFreeze);
82bool TrackOutput::outputsToDevice (
const juce::String& deviceName,
bool compareDefaultDevices)
const
84 if (
auto destTrack = getDestinationTrack())
87 == destTrack->getAudioTrackNumber());
89 if (outputDevice.get().equalsIgnoreCase (deviceName))
92 if (compareDefaultDevices)
94 auto& dm = owner.edit.engine.getDeviceManager();
96 if (
auto defaultWave = dm.getDefaultWaveOutDevice())
98 if (defaultWave->isEnabled())
100 auto defWaveName = defaultWave->getName();
102 bool b1 = deviceName.
equalsIgnoreCase (DeviceManager::getDefaultAudioOutDeviceName (
false))
103 && outputDevice.get().equalsIgnoreCase (defWaveName);
106 && outputDevice.get().equalsIgnoreCase (DeviceManager::getDefaultAudioOutDeviceName (
false));
113 if (
auto defaultMIDI = dm.getDefaultMidiOutDevice())
115 if (defaultMIDI->isEnabled())
117 auto defMidiName = defaultMIDI->getName();
119 if ((deviceName.
equalsIgnoreCase (DeviceManager::getDefaultMidiOutDeviceName (
false))
120 && outputDevice.get().equalsIgnoreCase (defMidiName))
122 && outputDevice.get().equalsIgnoreCase (DeviceManager::getDefaultMidiOutDeviceName (
false))))
133 if (destTrackID.isValid())
146 return t.itemID == destTrackID;
149OutputDevice* TrackOutput::getOutputDevice (
bool traceThroughDestTracks)
const
151 auto dev = owner.edit.engine.
getDeviceManager().findOutputDeviceWithName (outputDevice);
153 if ((dev ==
nullptr || ! dev->isEnabled()) && traceThroughDestTracks)
154 if (
auto t = getDestinationTrack())
155 dev = t->getOutput().getOutputDevice (
true);
162 if (
auto t = getDestinationTrack())
163 return t->getNameAsTrackNumber();
170 if (
auto t = getDestinationTrack())
172 if (! t->getName().startsWithIgnoreCase (
TRANS(
"Track") +
" "))
173 return TRANS(
"Feeds into track 123 (XZZX)")
174 .replace (
"123",
juce::String (t->getAudioTrackNumber()))
175 .replace (
"XZZX",
"(" + t->getName() +
")");
177 return TRANS(
"Feeds into track 123")
178 .replace (
"123",
juce::String (t->getAudioTrackNumber()));
181 if (
auto dev = owner.edit.engine.getDeviceManager().findOutputDeviceWithName (outputDevice))
182 return dev->getAlias();
187void TrackOutput::setOutputByName (
const juce::String& name)
189 if (name.startsWith (
TRANS(
"Track") +
" "))
190 outputDevice =
juce::String (
"track ") +
juce::String (name.upToFirstOccurrenceOf (
"(",
false,
false).trim().getTrailingIntValue());
195bool TrackOutput::canPlayAudio()
const
197 if (
auto out = getOutputDevice (
false))
201 if (
auto t = getDestinationTrack())
202 return t->canPlayAudio();
207bool TrackOutput::canPlayMidi()
const
209 if (
auto out = getOutputDevice (
false))
213 if (
auto t = getDestinationTrack())
214 return t->canPlayMidi();
219void TrackOutput::setOutputToTrack (
AudioTrack* track)
225void TrackOutput::setOutputToDefaultDevice (
bool isMidi)
227 outputDevice = isMidi ? DeviceManager::getDefaultMidiOutDeviceName (
false)
236 auto& output = t->getOutput();
238 for (
auto track : tracks)
239 if (output.feedsInto (track))
253 s.
add (DeviceManager::getDefaultAudioOutDeviceName (
false));
254 a.
add (DeviceManager::getDefaultAudioOutDeviceName (
true));
257 s.
add (DeviceManager::getDefaultMidiOutDeviceName (
false));
258 a.
add (DeviceManager::getDefaultMidiOutDeviceName (
true));
261 auto& dm = tracks.
getFirst()->edit.engine.getDeviceManager();
263 for (
int i = 0; i < dm.getNumOutputDevices(); ++i)
265 if (
auto out = dm.getOutputDeviceAt (i))
267 if (out->isEnabled())
269 if (
auto m =
dynamic_cast<MidiOutputDevice*
> (out))
271 if (m->isConnectedToExternalController())
281 s.
add (out->getName());
282 a.
add (out->getAlias());
296 getPossibleOutputDeviceNames (tracks, s, a, hasAudio, hasMidi);
298 auto& edit = tracks[0]->edit;
302 if (t->createsOutput() && ! feedsIntoAnyOf (t, tracks))
304 auto trackName = t->getNameAsTrackNumberWithDescription();
311bool TrackOutput::feedsInto (
const Track* dest)
const
313 if (
auto t = getDestinationTrack())
314 return t == dest || t->getOutput().feedsInto (dest);
321 auto dev = owner.edit.engine.getDeviceManager().findOutputDeviceWithName (outputDevice);
323 if (dev !=
nullptr && dev->isMidi() && dev->isEnabled())
327 midiDev->fireMessage (message);
333 if (
auto t = getDestinationTrack())
335 t->getOutput().injectLiveMidiMessage (message);
345 if (v.hasType (IDs::DEVICE) && ident == IDs::name)
347 outputDevice.forceUpdateOfCachedValue();
bool isEmpty() const noexcept
ElementType getFirst() const noexcept
bool contains(ParameterType elementToLookFor) const
BigInteger & setBit(int bitNumber)
int size() const noexcept
void add(String stringToAdd)
bool equalsIgnoreCase(const String &other) const noexcept
String upToFirstOccurrenceOf(StringRef substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const
bool startsWithIgnoreCase(StringRef text) const noexcept
int getTrailingIntValue() const noexcept
DeviceManager & getDeviceManager() const
Returns the DeviceManager instance for handling audio / MIDI devices.
Base class for audio or midi output devices, to which a track's output can be sent.
Base class for tracks which contain clips and plugins and can be added to Edit[s].
#define TRANS(stringLiteral)
juce::Array< AudioTrack * > getAudioTracks(const Edit &edit)
Returns all the AudioTracks in an Edit.
Track * findTrackForID(const Edit &edit, EditItemID id)
Returns the Track with a given ID if contained in the Edit.