Skip to content

Commit b37b25d

Browse files
committed
Refactored the way that audio channel groupings are handled and stored by the DeviceManager so that groupings with any number of channels are possible.
1 parent 3cc98f9 commit b37b25d

11 files changed

+787
-354
lines changed

modules/tracktion_engine/playback/devices/tracktion_WaveDeviceDescription.cpp

Lines changed: 583 additions & 7 deletions
Large diffs are not rendered by default.

modules/tracktion_engine/playback/devices/tracktion_WaveDeviceDescription.h

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ struct ChannelIndex
2424
/** Creates a ChannelIndex for a given index and a channel type. */
2525
ChannelIndex (int indexInDevice, juce::AudioChannelSet::ChannelType);
2626

27+
static ChannelIndex createMono (int indexInDevice);
28+
2729
bool operator== (const ChannelIndex&) const;
2830
bool operator!= (const ChannelIndex&) const;
2931

30-
int indexInDevice = -1; // Number of input or output in device
32+
int indexInDevice = -1; // Index of this channel in the device's full channel list
3133
juce::AudioChannelSet::ChannelType channel = juce::AudioChannelSet::unknown;
3234
};
3335

@@ -49,19 +51,30 @@ juce::AudioChannelSet channelSetFromSpeakerArrangementString (const juce::String
4951

5052

5153
//==============================================================================
52-
/** Describes a WaveDevice from which the WaveOutputDevice and
53-
WaveInputDevice lists will be built.
54+
/** Describes a group of audio channels from a physical device, which are to be
55+
treated as a WaveInputDevice or WaveOutputDevice.
5456
*/
5557
struct WaveDeviceDescription
5658
{
57-
/** Creates an invalid device description. */
59+
/// Creates an invalid device description.
5860
WaveDeviceDescription();
5961

60-
/** Creates a WaveDevieDescription from left and right channel indicies. */
61-
WaveDeviceDescription (const juce::String& name, int leftChanIndex, int rightChanIndex, bool isEnabled);
62+
/// Creates a WaveDeviceDescription for a given set of channels.
63+
WaveDeviceDescription (const juce::String& name, std::vector<ChannelIndex>, bool isEnabled);
64+
65+
/// Creates a canonical WaveDeviceDescription for a number of channels
66+
static WaveDeviceDescription withNumChannels (const juce::String& name, uint32_t firstChannelIndexInDevice,
67+
uint32_t numChannels, bool enabled);
6268

63-
/** Creates a WaveDeviceDescription for a given set of channels. */
64-
WaveDeviceDescription (const juce::String& nm, const ChannelIndex* channels, int numChannels, bool isEnabled);
69+
choc::value::Value toJSON() const;
70+
static WaveDeviceDescription fromJSON (const choc::value::ValueView&);
71+
std::string toString() const;
72+
static WaveDeviceDescription fromString (const std::string&);
73+
74+
void setNumChannels (uint32_t firstChannelIndexInDevice, uint32_t newNumChannels);
75+
void setNumChannels (uint32_t newNumChannels);
76+
uint32_t getNumChannels() const;
77+
std::pair<uint32_t, uint32_t> getDeviceChannelRange() const;
6578

6679
bool operator== (const WaveDeviceDescription&) const;
6780
bool operator!= (const WaveDeviceDescription&) const;
@@ -71,4 +84,43 @@ struct WaveDeviceDescription
7184
bool enabled = true;
7285
};
7386

87+
//==============================================================================
88+
struct WaveDeviceDescriptionList
89+
{
90+
WaveDeviceDescriptionList();
91+
92+
void initialise (Engine&, juce::AudioIODevice&, const juce::XmlElement*);
93+
bool updateForDevice (juce::AudioIODevice&);
94+
95+
juce::XmlElement toXML() const;
96+
choc::value::Value toJSON() const;
97+
98+
uint32_t getTotalInputChannelCount() const;
99+
uint32_t getTotalOutputChannelCount() const;
100+
101+
bool setChannelCountInDevice (const WaveDeviceDescription&, bool isInput, uint32_t newNumChannels);
102+
void setDeviceEnabled (const WaveDeviceDescription&, bool isInput, bool enabled);
103+
bool setAllInputsToNumChannels (uint32_t numChannels);
104+
bool setAllOutputsToNumChannels (uint32_t numChannels);
105+
juce::StringArray getPossibleChannelGroupsForDevice (const WaveDeviceDescription&, uint32_t maxNumChannels, bool isInput) const;
106+
107+
bool operator== (const WaveDeviceDescriptionList& other) const noexcept { return deviceName == other.deviceName && inputs == other.inputs && outputs == other.outputs; }
108+
bool operator!= (const WaveDeviceDescriptionList& other) const noexcept { return ! operator== (other); }
109+
110+
juce::String deviceName;
111+
std::vector<WaveDeviceDescription> inputs, outputs;
112+
113+
private:
114+
juce::StringArray deviceInputChannelNames, deviceOutputChannelNames;
115+
116+
bool initialiseFromCustomBehaviour (juce::AudioIODevice&, EngineBehaviour&);
117+
void initialiseFromDeviceDefault();
118+
bool initialiseFromState (const juce::XmlElement&);
119+
bool initialiseFromLegacyState (const juce::XmlElement&);
120+
bool setAllToNumChannels (std::vector<WaveDeviceDescription>&, uint32_t numChannels, bool isInput);
121+
void sanityCheckList();
122+
WaveDeviceDescription* findMatchingDevice (const WaveDeviceDescription&, bool isInput);
123+
};
124+
125+
74126
}} // namespace tracktion { inline namespace engine

modules/tracktion_engine/playback/devices/tracktion_WaveInputDevice.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,7 +1367,7 @@ class WaveInputDeviceInstance : public InputDeviceInstance
13671367
//==============================================================================
13681368
WaveInputDevice::WaveInputDevice (Engine& e, const WaveDeviceDescription& desc, DeviceType t)
13691369
: InputDevice (e, desc.name, "wavein_" + juce::String::toHexString (desc.name.hashCode())),
1370-
deviceChannels (desc.channels),
1370+
deviceDescription (desc),
13711371
deviceType (t),
13721372
channelSet (createChannelSet (desc.channels))
13731373
{
@@ -1435,7 +1435,7 @@ void WaveInputDevice::setEnabled (bool b)
14351435

14361436
if (! isTrackDevice())
14371437
{
1438-
engine.getDeviceManager().setWaveInChannelsEnabled (deviceChannels, b);
1438+
engine.getDeviceManager().setDeviceEnabled (*this, b);
14391439
}
14401440
else
14411441
{
@@ -1528,7 +1528,7 @@ juce::String WaveInputDevice::getSelectableDescription()
15281528

15291529
bool WaveInputDevice::isStereoPair() const
15301530
{
1531-
return deviceChannels.size() == 2;
1531+
return deviceDescription.getNumChannels() == 2;
15321532
}
15331533

15341534
void WaveInputDevice::setStereoPair (bool stereo)
@@ -1539,12 +1539,23 @@ void WaveInputDevice::setStereoPair (bool stereo)
15391539
return;
15401540
}
15411541

1542+
engine.getDeviceManager().setDeviceNumChannels (*this, stereo ? 2 : 1);
1543+
}
1544+
1545+
juce::PopupMenu WaveInputDevice::createChannelGroupMenu()
1546+
{
1547+
juce::PopupMenu m;
15421548
auto& dm = engine.getDeviceManager();
1549+
uint32_t channelNum = 0;
1550+
1551+
for (auto& option : dm.getPossibleChannelGroupsForDevice (*this, DeviceManager::maxNumChannelsPerDevice))
1552+
m.addItem (option, [this, &dm, num = ++channelNum] { dm.setDeviceNumChannels (*this, num); });
1553+
1554+
m.addSeparator();
1555+
m.addItem ("Set all to mono channels", [&dm] { dm.setAllWaveInputsToNumChannels (1); });
1556+
m.addItem ("Set all to stereo pairs", [&dm] { dm.setAllWaveInputsToNumChannels (2); });
15431557

1544-
if (deviceChannels.size() == 2)
1545-
dm.setDeviceInChannelStereo (std::max (deviceChannels[0].indexInDevice, deviceChannels[1].indexInDevice), stereo);
1546-
else if (deviceChannels.size() == 1)
1547-
dm.setDeviceInChannelStereo (deviceChannels[0].indexInDevice, stereo);
1558+
return m;
15481559
}
15491560

15501561
void WaveInputDevice::setRecordAdjustment (TimeDuration d)

modules/tracktion_engine/playback/devices/tracktion_WaveInputDevice.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ namespace tracktion { inline namespace engine
1313

1414
/** A (virtual) audio input device.
1515
16-
There'll be multiple instances of these, representing mono or stereo pairs of
17-
input channels.
16+
There'll be one or more instances of these, each one representing a group of
17+
channels from a physical device.
1818
*/
1919
class WaveInputDevice : public InputDevice
2020
{
@@ -41,6 +41,7 @@ class WaveInputDevice : public InputDevice
4141
double getRecordAdjustmentMs() const { return recordAdjustMs; }
4242
bool isStereoPair() const;
4343
void setStereoPair (bool);
44+
juce::PopupMenu createChannelGroupMenu();
4445
juce::Array<int> getAvailableBitDepths() const;
4546
void setBitDepth (int);
4647
int getBitDepth() const { return bitDepth; }
@@ -59,7 +60,7 @@ class WaveInputDevice : public InputDevice
5960
void setMergeMode (const juce::String&);
6061
juce::String getMergeMode() const;
6162

62-
const std::vector<ChannelIndex>& getChannels() const noexcept { return deviceChannels; }
63+
const std::vector<ChannelIndex>& getChannels() const noexcept { return deviceDescription.channels; }
6364
const juce::AudioChannelSet& getChannelSet() const noexcept { return channelSet; }
6465

6566
//==============================================================================
@@ -72,6 +73,8 @@ class WaveInputDevice : public InputDevice
7273
//==============================================================================
7374
juce::String getSelectableDescription() override;
7475

76+
const WaveDeviceDescription deviceDescription;
77+
7578
protected:
7679
juce::String openDevice();
7780
void closeDevice();
@@ -80,7 +83,6 @@ class WaveInputDevice : public InputDevice
8083
friend class DeviceManager;
8184
friend class WaveInputDeviceInstance;
8285

83-
const std::vector<ChannelIndex> deviceChannels;
8486
const DeviceType deviceType;
8587
const juce::AudioChannelSet channelSet;
8688

modules/tracktion_engine/playback/devices/tracktion_WaveInputDevice.test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,8 +363,8 @@ namespace tracktion::inline engine
363363

364364
// Add an InsertPlugin on track 1 and asign the second set of mono channels to it
365365
auto& dm = engine.getDeviceManager();
366-
dm.setDeviceInChannelStereo (0, false);
367-
dm.setDeviceOutChannelStereo (0, false);
366+
dm.setAllWaveInputsToNumChannels (1);
367+
dm.setAllWaveOutputsToNumChannels (1);
368368
auto waveOutput = dm.getWaveOutputDevices();
369369
auto waveInputs = dm.getWaveInputDevices();
370370
auto insertPlugin = insertNewPlugin<InsertPlugin> (sourceTrack, 0);

modules/tracktion_engine/playback/devices/tracktion_WaveOutputDevice.cpp

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace tracktion { inline namespace engine
1313

1414
WaveOutputDevice::WaveOutputDevice (Engine& e, const WaveDeviceDescription& desc)
1515
: OutputDevice (e, desc.name, "waveout_" + juce::String::toHexString (desc.name.hashCode())),
16-
deviceChannels (desc.channels),
16+
deviceDescription (desc),
1717
channelSet (createChannelSet (desc.channels)),
1818
ditheringEnabled (false),
1919
leftRightReversed (false)
@@ -40,7 +40,7 @@ void WaveOutputDevice::setEnabled (bool b)
4040
{
4141
enabled = b;
4242
changed();
43-
engine.getDeviceManager().setWaveOutChannelsEnabled (deviceChannels, b);
43+
engine.getDeviceManager().setDeviceEnabled (*this, b);
4444
// do nothing now! this object is probably deleted..
4545
}
4646
}
@@ -125,27 +125,38 @@ void WaveOutputDeviceInstance::prepareToPlay (double, int blockSize)
125125
//==============================================================================
126126
int WaveOutputDevice::getLeftChannel() const
127127
{
128-
return deviceChannels.size() >= 1 ? deviceChannels[0].indexInDevice : -1;
128+
return deviceDescription.getNumChannels() >= 1 ? deviceDescription.channels[0].indexInDevice : -1;
129129
}
130130

131131
int WaveOutputDevice::getRightChannel() const
132132
{
133-
return deviceChannels.size() >= 2 ? deviceChannels[1].indexInDevice : -1;
133+
return deviceDescription.getNumChannels() >= 2 ? deviceDescription.channels[1].indexInDevice : -1;
134134
}
135135

136136
bool WaveOutputDevice::isStereoPair() const
137137
{
138-
return deviceChannels.size() == 2;
138+
return deviceDescription.getNumChannels() == 2;
139139
}
140140

141141
void WaveOutputDevice::setStereoPair (bool stereo)
142142
{
143+
engine.getDeviceManager().setDeviceNumChannels (*this, stereo ? 2 : 1);
144+
}
145+
146+
juce::PopupMenu WaveOutputDevice::createChannelGroupMenu()
147+
{
148+
juce::PopupMenu m;
143149
auto& dm = engine.getDeviceManager();
150+
uint32_t channelNum = 0;
151+
152+
for (auto& option : dm.getPossibleChannelGroupsForDevice (*this, DeviceManager::maxNumChannelsPerDevice))
153+
m.addItem (option, [this, &dm, num = ++channelNum] { dm.setDeviceNumChannels (*this, num); });
154+
155+
m.addSeparator();
156+
m.addItem ("Set all to mono channels", [&dm] { dm.setAllWaveOutputsToNumChannels (1); });
157+
m.addItem ("Set all to stereo pairs", [&dm] { dm.setAllWaveOutputsToNumChannels (2); });
144158

145-
if (deviceChannels.size() == 2)
146-
dm.setDeviceOutChannelStereo (std::max (getLeftChannel(), getRightChannel()), stereo);
147-
else if (deviceChannels.size() == 1)
148-
dm.setDeviceOutChannelStereo (getLeftChannel(), stereo);
159+
return m;
149160
}
150161

151162
}} // namespace tracktion { inline namespace engine

modules/tracktion_engine/playback/devices/tracktion_WaveOutputDevice.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ namespace tracktion { inline namespace engine
1313

1414
/** A (virtual) audio output device.
1515
16-
There'll be multiple instances of these, representing mono or stereo pairs of
17-
output channels.
16+
There'll be one or more instances of these, each one representing a group of
17+
channels from a physical device.
1818
*/
1919
class WaveOutputDevice : public OutputDevice
2020
{
@@ -25,7 +25,7 @@ class WaveOutputDevice : public OutputDevice
2525
void resetToDefault();
2626
juce::String getDeviceTypeDescription() const override { return NEEDS_TRANS("Wave Audio Output"); }
2727
void setEnabled (bool) override;
28-
const std::vector<ChannelIndex>& getChannels() const noexcept { return deviceChannels; }
28+
const std::vector<ChannelIndex>& getChannels() const noexcept { return deviceDescription.channels; }
2929
const juce::AudioChannelSet& getChannelSet() const noexcept { return channelSet; }
3030

3131
void reverseChannels (bool);
@@ -46,13 +46,14 @@ class WaveOutputDevice : public OutputDevice
4646
*/
4747
int getRightChannel() const;
4848

49-
/** Returns true if the output is a stereo pair. I.e. has two channels. */
5049
bool isStereoPair() const;
51-
5250
void setStereoPair (bool);
51+
juce::PopupMenu createChannelGroupMenu();
5352

5453
WaveOutputDeviceInstance* createInstance (EditPlaybackContext&);
5554

55+
const WaveDeviceDescription deviceDescription;
56+
5657
protected:
5758
juce::String openDevice() override;
5859
void closeDevice() override;
@@ -61,7 +62,6 @@ class WaveOutputDevice : public OutputDevice
6162
friend class DeviceManager;
6263
friend class WaveOutputDeviceInstance;
6364

64-
const std::vector<ChannelIndex> deviceChannels;
6565
const juce::AudioChannelSet channelSet;
6666
bool ditheringEnabled, leftRightReversed;
6767

0 commit comments

Comments
 (0)