Loading...
Searching...
No Matches
WDMKSPortAudioInterface.hpp
1#pragma once
2#include <Audio/AudioInterface.hpp>
3#include <Audio/PortAudioInterface.hpp>
4#include <Audio/Settings/Model.hpp>
5
6namespace Audio
7{
8#if __has_include(<pa_win_wdmks.h>)
9class WDMKSFactory final
10 : public QObject
11 , public AudioFactory
12{
13 SCORE_CONCRETE("d98fca36-4e50-4802-a825-2fa213f95265")
14public:
15 std::vector<PortAudioCard> devices;
16
17 WDMKSFactory() { rescan(); }
18
19 ~WDMKSFactory() override { }
20 bool available() const noexcept override { return true; }
21 void
22 initialize(Audio::Settings::Model& set, const score::ApplicationContext& ctx) override
23 {
24 auto device_in = ossia::find_if(devices, [&](const PortAudioCard& dev) {
25 return dev.raw_name == set.getCardIn() && dev.hostapi != paInDevelopment;
26 });
27 auto device_out = ossia::find_if(devices, [&](const PortAudioCard& dev) {
28 return dev.raw_name == set.getCardOut() && dev.hostapi != paInDevelopment;
29 });
30
31 if(device_in == devices.end() || device_out == devices.end())
32 {
33 set.setCardIn(devices.back().raw_name);
34 set.setCardOut(devices.back().raw_name);
35 set.setDefaultIn(devices.back().inputChan);
36 set.setDefaultOut(devices.back().outputChan);
37 set.setRate(devices.back().rate);
38
39 set.changed();
40 }
41 else
42 {
43 if(device_out != devices.end())
44 {
45 set.setDefaultIn(device_out->inputChan);
46 set.setDefaultOut(device_out->outputChan);
47 set.setRate(device_out->rate);
48
49 set.changed();
50 }
51 }
52 }
53
54 void rescan()
55 {
56 devices.clear();
57 PortAudioScope portaudio;
58
59 devices.push_back(PortAudioCard{{}, {}, QObject::tr("No device"), -1, 0, 0, {}});
60 for(int i = 0; i < Pa_GetHostApiCount(); i++)
61 {
62 auto hostapi = Pa_GetHostApiInfo(i);
63 if(hostapi->type == PaHostApiTypeId::paWDMKS)
64 {
65 for(int card = 0; card < hostapi->deviceCount; card++)
66 {
67 auto dev_idx = Pa_HostApiDeviceIndexToDeviceIndex(i, card);
68 auto dev = Pa_GetDeviceInfo(dev_idx);
69 auto raw_name = QString::fromUtf8(Pa_GetDeviceInfo(dev_idx)->name);
70 if(dev->maxOutputChannels > 0)
71 {
72 devices.push_back(PortAudioCard{
73 "WDMKS", raw_name, raw_name, dev_idx, dev->maxInputChannels,
74 dev->maxOutputChannels, hostapi->type, dev->defaultSampleRate});
75 }
76 }
77 }
78 }
79 }
80
81 QString prettyName() const override { return QObject::tr("WDMKS"); }
82 std::shared_ptr<ossia::audio_engine> make_engine(
83 const Audio::Settings::Model& set, const score::ApplicationContext& ctx) override
84 {
85 return std::make_shared<ossia::portaudio_engine>(
86 "ossia score", set.getCardIn().toStdString(), set.getCardOut().toStdString(),
87 set.getDefaultIn(), set.getDefaultOut(), set.getRate(), set.getBufferSize(),
88 paWDMKS);
89 }
90
91 void setCard(QComboBox* combo, QString val)
92 {
93 auto dev_it = ossia::find_if(
94 devices, [&](const PortAudioCard& d) { return d.raw_name == val; });
95 if(dev_it != devices.end())
96 {
97 combo->setCurrentIndex(dev_it->out_index);
98 }
99 }
100
101 QWidget* make_settings(
103 score::SettingsCommandDispatcher& m_disp, QWidget* parent) override
104 {
105 auto w = new QWidget{parent};
106 auto lay = new QFormLayout{w};
107
108 auto card_list = new QComboBox{w};
109
110 // Disabled case
111 card_list->addItem(devices.front().pretty_name, 0);
112 devices.front().out_index = 0;
113
114 // Normal devices
115 for(std::size_t i = 1; i < devices.size(); i++)
116 {
117 auto& card = devices[i];
118 //qDebug() << card.api << card.raw_name << card.pretty_name << card.inputChan << card.outputChan;
119 card_list->addItem(card.pretty_name, (int)i);
120 card.out_index = card_list->count() - 1;
121 }
122
123 using Model = Audio::Settings::Model;
124
125 {
126 lay->addRow(QObject::tr("Device"), card_list);
127
128 auto update_dev = [=, &m, &m_disp](const PortAudioCard& dev) {
129 if(dev.raw_name != m.getCardOut())
130 {
131 m_disp.submitDeferredCommand<Audio::Settings::SetModelCardIn>(m, dev.raw_name);
132 m_disp.submitDeferredCommand<Audio::Settings::SetModelCardOut>(
133 m, dev.raw_name);
134 m_disp.submitDeferredCommand<Audio::Settings::SetModelDefaultIn>(
135 m, dev.inputChan);
136 m_disp.submitDeferredCommand<Audio::Settings::SetModelDefaultOut>(
137 m, dev.outputChan);
138 }
139 };
140
141 QObject::connect(
142 card_list, SignalUtils::QComboBox_currentIndexChanged_int(), &v, [=](int i) {
143 auto& device = devices[card_list->itemData(i).toInt()];
144 update_dev(device);
145 });
146
147 if(m.getCardOut().isEmpty())
148 {
149 if(!devices.empty())
150 {
151 update_dev(devices.front());
152 }
153 }
154 else
155 {
156 setCard(card_list, m.getCardOut());
157 }
158 }
159
160 addBufferSizeWidget(*w, m, v);
161 addSampleRateWidget(*w, m, v);
162
163 con(m, &Model::changed, w, [=, &m] { setCard(card_list, m.getCardOut()); });
164 return w;
165 }
166};
167#endif
168}
Definition score-plugin-audio/Audio/Settings/Model.hpp:22
Definition score-plugin-audio/Audio/Settings/View.hpp:19
Definition SettingsCommandDispatcher.hpp:10
STL namespace.
Used to access all the application-wide state and structures.
Definition ApplicationContext.hpp:24