2 #include <Audio/AudioInterface.hpp>
3 #include <Audio/PortAudioInterface.hpp>
4 #include <Audio/Settings/Model.hpp>
6 #include <score/widgets/SignalUtils.hpp>
13 #if __has_include(<pa_win_wmme.h>)
15 class MMEFactory final :
public AudioFactory
17 SCORE_CONCRETE(
"f5950e60-dac3-4254-bfb7-b94c96c679aa")
19 std::vector<PortAudioCard> devices;
21 MMEFactory() { rescan(); }
23 ~MMEFactory()
override { }
24 bool available() const noexcept
override {
return true; }
28 auto device_in = ossia::find_if(devices, [&](
const PortAudioCard& dev) {
29 return dev.raw_name == set.getCardIn() && dev.hostapi != paInDevelopment;
31 auto device_out = ossia::find_if(devices, [&](
const PortAudioCard& dev) {
32 return dev.raw_name == set.getCardOut() && dev.hostapi != paInDevelopment;
35 if(device_in == devices.end() || device_out == devices.end())
37 auto device_in = ossia::find_if(devices, [&](
const PortAudioCard& dev) {
38 return dev.raw_name ==
"Microsoft Sound Mapper - Input";
40 auto device_out = ossia::find_if(devices, [&](
const PortAudioCard& dev) {
41 return dev.raw_name ==
"Microsoft Sound Mapper - Output";
44 if(device_in != devices.end() && device_out != devices.end())
46 set.setCardIn(device_in->raw_name);
47 set.setCardOut(device_out->raw_name);
48 set.setDefaultIn(device_in->inputChan);
49 set.setDefaultOut(device_out->outputChan);
50 set.setRate(device_out->rate);
54 auto device_in = ossia::find_if(
55 devices, [&](
const PortAudioCard& dev) {
return dev.inputChan > 0; });
56 auto device_out = ossia::find_if(
57 devices, [&](
const PortAudioCard& dev) {
return dev.outputChan > 0; });
58 if(device_in != devices.end())
60 set.setCardIn(device_in->raw_name);
61 set.setDefaultIn(device_in->inputChan);
69 if(device_out != devices.end())
71 set.setCardOut(device_out->raw_name);
72 set.setDefaultOut(device_out->outputChan);
73 set.setRate(device_out->rate);
87 if(device_out != devices.end())
89 set.setDefaultIn(device_out->inputChan);
90 set.setDefaultOut(device_out->outputChan);
91 set.setRate(device_out->rate);
102 PortAudioScope portaudio;
104 devices.push_back(PortAudioCard{{}, {}, QObject::tr(
"No device"), -1, 0, 0, {}});
105 for(
int i = 0; i < Pa_GetHostApiCount(); i++)
107 auto hostapi = Pa_GetHostApiInfo(i);
108 if(hostapi->type == PaHostApiTypeId::paMME)
110 for(
int card = 0; card < hostapi->deviceCount; card++)
112 auto dev_idx = Pa_HostApiDeviceIndexToDeviceIndex(i, card);
113 auto dev = Pa_GetDeviceInfo(dev_idx);
114 auto raw_name = QString::fromUtf8(Pa_GetDeviceInfo(dev_idx)->name);
116 devices.push_back(PortAudioCard{
117 "MME", raw_name, raw_name, dev_idx, dev->maxInputChannels,
118 dev->maxOutputChannels, hostapi->type, dev->defaultSampleRate});
125 QString prettyName()
const override {
return QObject::tr(
"MME"); }
126 std::shared_ptr<ossia::audio_engine> make_engine(
129 return std::make_shared<ossia::portaudio_engine>(
130 "ossia score", set.getCardIn().toStdString(), set.getCardOut().toStdString(),
131 set.getDefaultIn(), set.getDefaultOut(), set.getRate(), 1024, paMME);
134 void setCardIn(QComboBox* combo, QString val)
136 auto dev_it = ossia::find_if(devices, [&](
const PortAudioCard& d) {
137 return d.raw_name == val && d.inputChan > 0;
139 if(dev_it != devices.end())
141 combo->setCurrentIndex(dev_it->in_index);
144 void setCardOut(QComboBox* combo, QString val)
146 auto dev_it = ossia::find_if(devices, [&](
const PortAudioCard& d) {
147 return d.raw_name == val && d.outputChan > 0;
149 if(dev_it != devices.end())
151 combo->setCurrentIndex(dev_it->out_index);
155 void updateSampleRates(
156 QComboBox* rate,
const PortAudioCard& input,
const PortAudioCard& output)
158 PortAudioScope scope;
160 for(
int sr : {44100, 48000, 88200, 96000, 192000})
162 PaStreamParameters iParams{}, oParams{};
163 iParams.device = input.dev_idx;
164 iParams.channelCount = input.inputChan;
165 iParams.sampleFormat = paFloat32;
166 iParams.suggestedLatency = 0.02;
168 oParams.device = output.dev_idx;
169 oParams.channelCount = output.outputChan;
170 oParams.sampleFormat = paFloat32;
171 oParams.suggestedLatency = 0.02;
173 if(
auto err = Pa_IsFormatSupported(
nullptr, &oParams, sr);
174 err == paFormatIsSupported)
176 rate->addItem(QString::number(sr));
180 qDebug() <<
"MME: samplerate errpr " << err << Pa_GetErrorText(err);
185 QWidget* make_settings(
189 auto w =
new QWidget{parent};
190 auto lay =
new QFormLayout{w};
192 auto card_in =
new QComboBox{w};
193 auto card_out =
new QComboBox{w};
195 auto rate =
new QComboBox{w};
198 auto updateRates = [=] {
200 rate, devices[card_in->itemData(card_in->currentIndex()).toInt()],
201 devices[card_out->itemData(card_in->currentIndex()).toInt()]);
205 card_in->addItem(devices.front().pretty_name, 0);
206 card_out->addItem(devices.front().pretty_name, 0);
207 devices.front().in_index = 0;
208 devices.front().out_index = 0;
211 for(std::size_t i = 1; i < devices.size(); i++)
213 auto& card = devices[i];
215 if(card.inputChan > 0)
217 card_in->addItem(card.pretty_name, (
int)i);
218 card.in_index = card_in->count() - 1;
220 if(card.outputChan > 0)
222 card_out->addItem(card.pretty_name, (
int)i);
223 card.out_index = card_out->count() - 1;
230 lay->addRow(QObject::tr(
"Input device"), card_in);
232 auto update_dev = [=, &m, &m_disp](
const PortAudioCard& dev) {
233 if(dev.raw_name != m.getCardIn())
235 m_disp.submitDeferredCommand<Audio::Settings::SetModelCardIn>(m, dev.raw_name);
236 m_disp.submitDeferredCommand<Audio::Settings::SetModelDefaultIn>(
238 if(dev.hostapi != PaHostApiTypeId::paMME)
240 if(dev.out_index != -1 && dev.out_index != card_out->currentIndex())
241 card_out->setCurrentIndex(dev.out_index);
247 card_in, SignalUtils::QComboBox_currentIndexChanged_int(), &v, [=](
int i) {
248 update_dev(devices[card_in->itemData(i).toInt()]);
252 if(m.getCardIn().isEmpty())
254 auto default_in = Pa_GetDefaultInputDevice();
256 for(
auto& v : devices)
258 if(v.dev_idx == default_in)
267 setCardIn(card_in, m.getCardIn());
274 lay->addRow(QObject::tr(
"Output device"), card_out);
276 auto update_dev = [=, &m, &m_disp](
const PortAudioCard& dev) {
277 if(dev.raw_name != m.getCardOut())
279 m_disp.submitDeferredCommand<Audio::Settings::SetModelCardOut>(
281 m_disp.submitDeferredCommand<Audio::Settings::SetModelDefaultOut>(
283 if(dev.hostapi != PaHostApiTypeId::paMME)
285 if(dev.in_index != -1 && dev.in_index != card_in->currentIndex())
286 card_in->setCurrentIndex(dev.in_index);
292 card_out, SignalUtils::QComboBox_currentIndexChanged_int(), &v, [=](
int i) {
293 update_dev(devices[card_out->itemData(i).toInt()]);
297 if(m.getCardOut().isEmpty())
299 auto default_out = Pa_GetDefaultOutputDevice();
300 for(
auto& v : devices)
302 if(v.dev_idx == default_out)
311 setCardOut(card_out, m.getCardOut());
318 lay->addRow(QObject::tr(
"Sample rate"), rate);
329 con(m, &Model::changed, w, [=, &m] {
330 setCardIn(card_in, m.getCardIn());
331 setCardOut(card_out, m.getCardOut());
Definition: score-plugin-audio/Audio/Settings/Model.hpp:22
Definition: score-plugin-audio/Audio/Settings/View.hpp:19
Definition: SettingsCommandDispatcher.hpp:10
Used to access all the application-wide state and structures.
Definition: ApplicationContext.hpp:24