1 /*
2 Copyright (C) 2008, 2009 Andres Cabrera
3 mantaraya36@gmail.com
4
5 This file is part of CsoundQt.
6
7 CsoundQt is free software; you can redistribute it
8 and/or modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 CsoundQt is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with Csound; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307 USA
21 */
22
23 #include <QProcess>
24 #include <QFile>
25 #include <QTemporaryFile>
26 #include <QTextStream>
27 #include <QDir>
28 #include <QApplication>
29 #include <QDebug>
30
31 #include "csound.h"
32 #include "configlists.h"
33
34 typedef QPair<QString, QString> QStringPair;
35
36
ConfigLists()37 ConfigLists::ConfigLists()
38 {
39 fileTypeNames << "wav" << "aiff" << "au" << "avr"
40 << "caf" << "flac" << "htk" << "ircam"
41 << "mat4" << "mat5" << "nis" << "paf"
42 << "pvf" << "raw" << "sd2" << "sds"
43 << "svx" << "voc" << "w64" << "wavex";
44
45 fileTypeExtensions << "*.wav" << "*.aif;*.aiff" << "*.au" << "*.avr"
46 << "*.caf" << "*.flac" << "*.htk;*.*" << "*.ircam;*.*"
47 << "*.mat4;*.*" << "*.mat5;*.*" << "*.nis;*.*" << "*.paf;*.*"
48 << "*.pvf" << "*.raw;*.*" << "*.sd2;*.*" << "*.sds;*.*"
49 << "*.svx;*.*" << "*.voc;*.*" << "*.w64;*.wav" << "*.wavex;*.wav";
50
51 fileTypeLongNames << "WAVE" << "AIFF" << "au" << "avr"
52 << "CAF" << "FLAC" << "htk" << "ircam"
53 << "mat4" << "mat5" << "nis" << "paf"
54 << "pvf" << "Raw (Headerless)" << "Sound Designer II" << "sds"
55 << "svx" << "voc" << "WAVE (w64)" << "WAVE (wavex)";
56
57 fileFormatFlags << "24bit" << "short"<< "uchar"
58 << "schar"<< "float"<< "long";
59 fileFormatNames << "24 Bit" << "16 Bit (short)" << "unsigned 8-bit"
60 << "signed 8-bit" << "32 bit float"<< "long (32-bit)";
61
62 refreshModules();
63
64 languages << "English" << "Spanish" << "German" << "French" << "Portuguese"
65 << "Italian" << "Turkish" << "Finnish" << "Russian" << "Korean"
66 << "Persian";
67
68 languageCodes << "en" << "es" << "de" << "fr" << "pt"
69 << "it" << "tr" << "fi" << "ru" << "kr"
70 << "fa";
71 }
72
73
~ConfigLists()74 ConfigLists::~ConfigLists()
75 {
76 }
77
msgCallback(CSOUND * csound,int attr,const char * fmt,va_list args)78 void ConfigLists::msgCallback(CSOUND *csound, int attr, const char *fmt, va_list args)
79 {
80 Q_UNUSED(attr);
81 QString *ud = (QString *) csoundGetHostData(csound);
82 QString msg;
83 msg = msg.vsprintf(fmt, args);
84 if (msg.isEmpty()) {
85 return;
86 }
87 ud->append(msg);
88 }
89
refreshModules()90 void ConfigLists::refreshModules()
91 {
92 rtMidiNames.clear();
93 rtAudioNames.clear();
94 CSOUND *csound = csoundCreate(nullptr);
95 char *name, *type;
96 int n = 0;
97 while(!csoundGetModule(csound, n++, &name, &type)) {
98 if (strcmp(type, "audio") == 0) {
99 rtAudioNames << name;
100 }
101 }
102 rtAudioNames << "null"; // add also none (-+rtaudio=null)
103 n = 0;
104 while(!csoundGetModule(csound, n++, &name, &type)) {
105 if (strcmp(type, "midi") == 0) {
106 rtMidiNames << name;
107 }
108 }
109 if (rtAudioNames.contains("jack")) {
110 rtMidiNames << "jack";
111 }
112 rtMidiNames << "virtual" << "none";
113 csoundDestroy(csound);
114 }
115
getMidiInputDevices(QString module)116 QHash<QString,QString> ConfigLists::getMidiInputDevices(QString module)
117 {
118 // based on code by Steven Yi
119 QHash<QString,QString> deviceList;
120 #ifdef CSOUND6
121 CSOUND *cs = csoundCreate(nullptr);
122 if (module=="jack") {
123 csoundSetOption(cs, "-+rtaudio=jack");
124 csoundSetOption(cs, "-+rtmidi=jack");
125 }
126 csoundSetMIDIModule(cs, module.toLatin1().data());
127 int i,newn, n = csoundGetMIDIDevList(cs, nullptr, 0);
128 CS_MIDIDEVICE *devs = (CS_MIDIDEVICE *) malloc(n*sizeof(CS_MIDIDEVICE));
129 newn = csoundGetMIDIDevList(cs,devs,0);
130 if (newn != n) {
131 qDebug() << "Device number changed";
132 return deviceList;
133 }
134 for (i = 0; i < n; i++) {
135 qDebug() << "Device "<<i << devs[i].device_name;
136 QString displayName, id;
137 if (module=="jack") {
138 displayName = devs[i].device_name;
139 id = devs[i].device_name;
140 } else {
141 displayName = QString("%1 (%2)")
142 .arg(devs[i].device_name)
143 .arg(devs[i].interface_name);
144 id = QString(devs[i].device_id);
145 }
146 deviceList.insert(displayName, id);
147 }
148 free(devs);
149 csoundDestroy(cs);
150 #else
151 if (module == "none") {
152 return deviceList;
153 }
154 if (module == "alsa") {
155 QProcess amidi;
156 amidi.start("amidi", QStringList() << "-l");
157 if (!amidi.waitForFinished())
158 return deviceList;
159
160 QByteArray result = amidi.readAllStandardOutput();
161 QString values = QString(result);
162 QStringList st = values.split("\n");
163 st.takeFirst(); // Remove first column lines
164 for (int i = 0; i < st.size(); i++){
165 QStringList parts = st[i].split(" ", QString::SkipEmptyParts);
166 if (parts.size() > 0 && parts[0].contains("I")) {
167 QString devname = parts[1]; // Devce name
168 parts.takeFirst(); // Remove IO flags
169 QString fullname = parts.join(" ") ; // Full name with description
170 deviceList.insert(fullname, devname);
171 }
172 }
173 deviceList.insert("All available devices ", "a");
174 }
175 else if (module == "virtual") {
176 QString name = qApp->translate("Enabled", "Virtual MIDI keyboard Enabled");
177 deviceList.insert(name, "0");
178 }
179 else { // if not alsa (i.e. winmm or portmidi)
180 QFile file(":/test.csd");
181 if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
182 return deviceList;
183 QString jackCSD = QString(file.readAll());
184 QString tempText = jackCSD;
185 tempText.replace("$SR", "441000");
186 QTemporaryFile tempFile(QDir::tempPath() + QDir::separator() + "testcsdCsoundQtXXXXXX.csd");
187 tempFile.open();
188 QTextStream out(&tempFile);
189 out << tempText;
190 tempFile.close();
191 tempFile.open();
192
193 QStringList flags;
194 QString rtMidiFlag = "-+rtmidi=" + module;
195 flags << "-+msg_color=false" << rtMidiFlag << "-otest" << "-n" << "-M999" << tempFile.fileName();
196 QStringList messages = runCsoundInternally(flags);
197
198 QString startText, endText;
199 if (module == "portmidi") {
200 startText = "The available MIDI";
201 endText = "*** PortMIDI";
202 }
203 else if (module == "winmm") {
204 startText = "The available MIDI";
205 endText = "rtmidi: input device number is out of range";
206 }
207 else if (module == "coremidi") {
208 int index = messages.indexOf(QRegExp("[0-9]{1,1} MIDI sources in system\\s*"));
209 if (index >= 0) {
210 for (int i = 0; i < messages[index].split(" ")[0].toInt(); i++) {
211 deviceList.insert(QString::number(i), QString::number(i));
212 }
213 }
214 }
215 else if (module == "alsaseq") {
216 //FIXME parse alsaseq devices
217 }
218 if (startText == "" && endText == "") {
219 return deviceList;
220 }
221 bool collect = false;
222 foreach (QString line, messages) {
223 if (collect) {
224 if (endText.length() > 0 && line.indexOf(endText) >= 0) {
225 collect = false;
226 }
227 else {
228 if (line.indexOf(":") >= 0) {
229 // qDebug() << line;
230 QString fullname = line.mid(line.indexOf(":") + 1).trimmed();
231 QString devname = line.mid(0,line.indexOf(":")).trimmed();
232 deviceList.insert(fullname, devname);
233 }
234 }
235 }
236 else if (line.indexOf(startText) >= 0) {
237 collect = true;
238 }
239 }
240 }
241 #endif
242 qDebug()<<"Devices found: "<<deviceList;
243 return deviceList;
244 }
245
getMidiOutputDevices(QString module)246 QList<QPair<QString, QString> > ConfigLists::getMidiOutputDevices(QString module)
247 {
248 QList<QPair<QString, QString> > deviceList;
249 #ifdef CSOUND6
250 CSOUND *cs = csoundCreate(nullptr);
251 if (module=="jack") {
252 csoundSetOption(cs, "-+rtaudio=jack");
253 csoundSetOption(cs, "-+rtmidi=jack");
254 }
255 csoundSetMIDIModule(cs, module.toLatin1().data());
256 int i,newn, n = csoundGetMIDIDevList(cs, nullptr, 1);
257 CS_MIDIDEVICE *devs = (CS_MIDIDEVICE *) malloc(n*sizeof(CS_MIDIDEVICE));
258 newn = csoundGetMIDIDevList(cs,devs,1);
259 if (newn != n) {
260 qDebug() << "Device number changed";
261 return deviceList;
262 }
263 for (i = 0; i < n; i++) {
264 // qDebug() << devs[i].device_name;
265 QString displayName, id;
266 if (module=="jack") {
267 displayName = devs[i].device_name;
268 id = devs[i].device_name;
269 } else {
270 displayName = QString("%1 (%2)")
271 .arg(devs[i].device_name)
272 .arg(devs[i].interface_name);
273 id = QString(devs[i].device_id);
274 }
275
276 deviceList.append(QStringPair(displayName, id));
277 }
278 free(devs);
279 csoundDestroy(cs);
280 #else
281 if (module == "none") {
282 return deviceList;
283 }
284 if (module == "alsa") {
285 QProcess amidi;
286 amidi.start("amidi", QStringList() << "-l");
287 if (!amidi.waitForFinished())
288 return deviceList;
289
290 QByteArray result = amidi.readAllStandardOutput();
291 QString values = QString(result);
292 QStringList st = values.split("\n");
293 st.takeFirst(); // Remove first column lines
294 for (int i = 0; i < st.size(); i++){
295 QStringList parts = st[i].split(" ", QString::SkipEmptyParts);
296 if (parts.size() > 0 && parts[0].contains("O")) {
297 QPair<QString, QString> device;
298 device.second = parts[1]; // Devce name
299 parts.takeFirst(); // Remove IO flags
300 device.first = parts.join(" ") ; // Full name with description
301 deviceList.append(device);
302 }
303 }
304 }
305 else if (module == "virtual") {
306 // do nothing
307 }
308 else { // if not alsa (i.e. winmm or portmidi)
309 QFile file(":/test.csd");
310 if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
311 return deviceList;
312 QString jackCSD = QString(file.readAll());
313 QString tempText = jackCSD;
314 tempText.replace("$SR", "441000");
315 QTemporaryFile tempFile(QDir::tempPath() + QDir::separator() + "testcsdCsoundQtXXXXXX.csd");
316 tempFile.open();
317 QTextStream out(&tempFile);
318 out << tempText;
319 tempFile.close();
320 tempFile.open();
321
322 QStringList flags;
323 flags << "-+msg_color=false" << "-otest" << "-n" << "-Q999" << tempFile.fileName();
324 QStringList messages = runCsoundInternally(flags);
325
326 QString startText, endText;
327 if (module == "portmidi") {
328 startText = "The available MIDI";
329 endText = "*** PortMIDI";
330 }
331 else if (module == "winmm") {
332 startText = "The available MIDI";
333 endText = "rtmidi: output device number is out of range";
334 }
335 if (startText == "" && endText == "") {
336 return deviceList;
337 }
338 bool collect = false;
339 foreach (QString line, messages) {
340 if (collect) {
341 if (endText.length() > 0 && line.indexOf(endText) >= 0) {
342 collect = false;
343 }
344 else {
345 if (line.indexOf(":") >= 0) {
346 qDebug("%s", line.toLocal8Bit().constData());
347 QPair<QString, QString> device;
348 device.first = line.mid(line.indexOf(":") + 1).trimmed();
349 device.second = line.mid(0,line.indexOf(":")).trimmed();
350 deviceList.append(device);
351 }
352 }
353 }
354 else if (line.indexOf(startText) >= 0) {
355 collect = true;
356 }
357 }
358 }
359 #endif
360 return deviceList;
361 }
362
getAudioInputDevices(QString module)363 QList<QPair<QString, QString> > ConfigLists::getAudioInputDevices(QString module)
364 {
365 QList<QStringPair> deviceList;
366 #ifdef CSOUND6
367 CSOUND *cs = csoundCreate(nullptr);
368 csoundSetRTAudioModule(cs, module.toLatin1().data());
369 int i,newn, n = csoundGetAudioDevList(cs, nullptr, 0);
370 CS_AUDIODEVICE *devs = (CS_AUDIODEVICE *) malloc(n*sizeof(CS_AUDIODEVICE));
371 newn = csoundGetAudioDevList(cs,devs,0);
372 if (newn != n) {
373 qDebug() << "Device number changed";
374 return deviceList;
375 }
376 for (i = 0; i < n; i++) {
377 // qDebug() << "evs[i].device_name;
378 deviceList.append(QStringPair(devs[i].device_name, devs[i].device_id));
379 }
380 free(devs);
381 csoundDestroy(cs);
382 #else
383 if (module == "none") {
384 return deviceList;
385 }
386 if (module == "alsa") {
387 QFile f("/proc/asound/pcm");
388 f.open(QIODevice::ReadOnly | QIODevice::Text);
389 QString values = QString(f.readAll());
390 QStringList st = values.split("\n");
391 foreach (QString line, st) {
392 if (line.indexOf("capture") >= 0) {
393 QStringList parts = line.split(":");
394
395 QStringList cardId = parts[0].split("-");
396 QString buffer = "";
397 buffer.append(parts[1]).append(" : ").append(parts[2]);
398
399 QPair<QString, QString> device;
400 device.first = buffer;
401 device.second = "adc:hw:" + QString::number(cardId[0].toInt()) + "," + QString::number(cardId[1].toInt());
402 deviceList.append(device);
403 }
404 }
405 }
406 else if (module == "jack") {
407 QFile file(":/test.csd");
408 if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
409 return deviceList;
410 QString jackCSD = QString(file.readAll());
411 QString tempText = jackCSD;
412 tempText.replace("$SR", "1000");
413 QTemporaryFile tempFile(QDir::tempPath() + QDir::separator() + "testcsdCsoundQtXXXXXX.csd");
414 tempFile.open();
415 QTextStream out(&tempFile);
416 out << tempText;
417 tempFile.close();
418 tempFile.open();
419
420 QStringList flags;
421 QString previousLine = "";
422 // -odac is needed otherwise csound segfaults
423 flags << "-+msg_color=false" << "-+rtaudio=jack" << "-iadc:xxx" << "-odac:xxx" << "-B2048" << tempFile.fileName();
424 QStringList messages = runCsoundInternally(flags);
425
426 QString sr = "";
427 foreach (QString line, messages) { // Need to run again if sample rate does not match...
428 if (line.indexOf("does not match JACK sample rate") >= 0) {
429 sr = line.mid(line.lastIndexOf(" ") + 1);
430 }
431 if (line.endsWith("channel)\n") || line.endsWith("channels)\n")) {
432 QStringList parts = previousLine.split("\"");
433 QPair<QString, QString> device;
434 device.first = parts[1];
435 device.second = "adc:" + parts[1];
436 deviceList.append(device);
437 }
438 previousLine = line;
439 }
440 if (sr == "") {
441 return deviceList;
442 }
443
444 tempText = jackCSD;
445 tempText.replace("$SR", sr);
446 out << tempText;
447 tempFile.close();
448 tempFile.open();
449
450 messages = runCsoundInternally(flags); // run with same flags as before
451
452 foreach (QString line, messages) {
453 if (line.endsWith("channel)\n") || line.endsWith("channels)\n")) {
454 QStringList parts = previousLine.split("\"");
455 QPair<QString, QString> device;
456 device.first = parts[1];
457 device.second = "adc:" + parts[1];
458 deviceList.append(device);
459 }
460 previousLine = line;
461 }
462 } //ends if (module=="jack")
463 else { // if not alsa or jack (i.e. coreaudio or portaudio)
464 QFile file(":/test.csd");
465 if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
466 return deviceList;
467 QString jackCSD = QString(file.readAll());
468 QString tempText = jackCSD;
469 tempText.replace("$SR", "1000");
470 QTemporaryFile tempFile(QDir::tempPath() + QDir::separator() + "testcsdCsoundQtXXXXXX.csd");
471 tempFile.open();
472 QTextStream out(&tempFile);
473 out << tempText;
474 tempFile.close();
475 tempFile.open();
476
477 QStringList flags;
478 QString rtAudioFlag = "-+rtaudio=" + module + " ";
479 flags << "-+msg_color=false" << rtAudioFlag << "-iadc999" << "-odac999" << "-d" << tempFile.fileName();
480 QStringList messages = runCsoundInternally(flags);
481
482 QString startText, endText;
483 if (module=="portaudio") {
484 startText = "PortAudio: available";
485 endText = "error:";
486 }
487 else if (module=="winmm" || module=="mme") {
488 startText = "The available input devices are:";
489 endText = "device number is out of range";
490 }
491 else if (module=="coreaudio") {
492 startText = "CoreAudio Module: found";
493 endText = "";
494 }
495 if (startText == "" && endText == "") {
496 return deviceList;
497 }
498 bool collect = false;
499 foreach (QString line, messages) {
500 if (collect) {
501 if (endText.length() > 0 && line.indexOf(endText) >= 0) {
502 collect = false;
503 }
504 else {
505 if (module == "coreaudio") {
506 QString coreAudioMatch = "=> CoreAudio device";
507
508 if (line.indexOf(coreAudioMatch) >= 0) {
509 line = line.mid(coreAudioMatch.length()).trimmed();
510
511 QPair<QString, QString> device;
512 device.first = line.mid(line.indexOf(":")).trimmed();
513 device.second = "adc" + line.left(line.indexOf(":"));
514 deviceList.append(device);
515 }
516 } // if not coreaudio, i.e. portaudio
517 else if (line.indexOf(":") >= 0) {
518 QPair<QString, QString> device;
519 device.first = line.mid(line.indexOf(":") + 1).trimmed();
520 device.second = "adc" + line.left(line.indexOf(":")).trimmed();
521 deviceList.append(device);
522 }
523 }
524 }
525 else if (line.indexOf(startText) >= 0) {
526 collect = true;
527 }
528 }
529 }
530 #endif
531 return deviceList;
532 }
533
534
getAudioOutputDevices(QString module)535 QList<QPair<QString, QString> > ConfigLists::getAudioOutputDevices(QString module)
536 {
537 QList<QPair<QString, QString> > deviceList;
538 #ifdef CSOUND6
539 CSOUND *cs = csoundCreate(nullptr);
540 csoundSetRTAudioModule(cs, module.toLatin1().data());
541 int i,newn, n = csoundGetAudioDevList(cs, nullptr, 1);
542 CS_AUDIODEVICE *devs = (CS_AUDIODEVICE *) malloc(n*sizeof(CS_AUDIODEVICE));
543 newn = csoundGetAudioDevList(cs,devs,1);
544 if (newn != n) {
545 qDebug() << "OutputDevices Device number changed";
546 return deviceList;
547 }
548 for (i = 0; i < n; i++) {
549 // qDebug() << devs[i].device_name;
550 deviceList.append(QStringPair(devs[i].device_name, devs[i].device_id));
551 }
552 free(devs);
553 csoundDestroy(cs);
554 #else
555 if (module == "none") {
556 return deviceList;
557 }
558 if (module == "alsa") {
559 QFile f("/proc/asound/pcm");
560 f.open(QIODevice::ReadOnly | QIODevice::Text);
561 QString values = QString(f.readAll());
562 QStringList st = values.split("\n");
563 foreach (QString line, st) {
564 if (line.indexOf("playback") >= 0) {
565 QStringList parts = line.split(":");
566
567 QStringList cardId = parts[0].split("-");
568 QString buffer = "";
569 buffer.append(parts[1]).append(" : ").append(parts[2]);
570
571 QPair<QString, QString> device;
572 device.first = buffer;
573 device.second = "dac:hw:" + QString::number(cardId[0].toInt()) + "," + QString::number(cardId[1].toInt());
574 deviceList.append(device);
575 }
576 }
577 }
578 else if (module=="jack") {
579 QFile file(":/test.csd");
580 if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
581 return deviceList;
582 QString jackCSD = QString(file.readAll());
583 QString tempText = jackCSD;
584 tempText.replace("$SR", "1000");
585 QTemporaryFile tempFile(QDir::tempPath() + QDir::separator() + "testcsdCsoundQtXXXXXX.csd");
586 tempFile.open();
587 QTextStream out(&tempFile);
588 out << tempText;
589 tempFile.close();
590 tempFile.open();
591
592 QStringList flags;
593 QString previousLine = "";
594 flags << "-+msg_color=false" << "-+rtaudio=jack" << "-odac:xxx" << "-B2048" << tempFile.fileName();
595 QStringList messages = runCsoundInternally(flags);
596
597 QString sr = "";
598 foreach (QString line, messages) {
599 if (line.indexOf("does not match JACK sample rate") >= 0) {
600 sr = line.mid(line.lastIndexOf(" ") + 1);
601 }
602 if (line.endsWith("channel)\n") || line.endsWith("channels)\n")) {
603 QStringList parts = previousLine.split("\"");
604 QPair<QString, QString> device;
605 device.first = parts[1];
606 device.second = "dac:" + parts[1];
607 deviceList.append(device);
608 }
609 previousLine = line;
610 }
611 if (sr == "") {
612 return deviceList;
613 }
614
615 tempText = jackCSD;
616 tempText.replace("$SR", sr);
617 out << tempText;
618 tempFile.close();
619 tempFile.open();
620
621 messages = runCsoundInternally(flags); // run with same flags as before
622
623 foreach (QString line, messages) {
624 if (line.endsWith("channel)\n") || line.endsWith("channels)\n")) {
625 QStringList parts = previousLine.split("\"");
626 QPair<QString, QString> device;
627 device.first = parts[1];
628 device.second = "dac:" + parts[1];
629 deviceList.append(device);
630 }
631 previousLine = line;
632 }
633 } //ends if (module=="jack")
634 else { // if not alsa or jack (i.e. coreaudio or portaudio)
635 QFile file(":/test.csd");
636 if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
637 return deviceList;
638 QString jackCSD = QString(file.readAll());
639 QString tempText = jackCSD;
640 tempText.replace("$SR", "1000");
641 QTemporaryFile tempFile(QDir::tempPath() + QDir::separator() + "testcsdCsoundQtXXXXXX.csd");
642 tempFile.open();
643 QTextStream out(&tempFile);
644 out << tempText;
645 tempFile.close();
646 tempFile.open();
647
648 QStringList flags;
649 QString rtAudioFlag = "-+rtaudio=" + module + " ";
650 flags << "-+msg_color=false" << rtAudioFlag << "-odac999" << tempFile.fileName();
651 QStringList messages = runCsoundInternally(flags);
652
653 QString startText, endText;
654 if (module=="portaudio") {
655 startText = "PortAudio: available";
656 endText = "error:";
657 }
658 else if (module=="winmm" || module=="mme") {
659 startText = "The available output devices are:";
660 endText = "device number is out of range";
661 }
662 else if (module=="coreaudio") {
663 startText = "CoreAudio Module: found";
664 endText = "";
665 }
666 if (startText == "" && endText == "") {
667 return deviceList;
668 }
669 bool collect = false;
670 foreach (QString line, messages) {
671 if (collect) {
672 if (endText.length() > 0 && line.indexOf(endText) >= 0) {
673 collect = false;
674 }
675 else {
676 if (module == "coreaudio") {
677 QString coreAudioMatch = "=> CoreAudio device";
678
679 if (line.indexOf(coreAudioMatch) >= 0) {
680 line = line.mid(coreAudioMatch.length()).trimmed();
681
682 QPair<QString, QString> device;
683 device.first = line.mid(line.indexOf(":")).trimmed();
684 device.second = "dac" + line.left(line.indexOf(":"));
685 deviceList.append(device);
686 }
687 } // if not coreaudio, i.e. portaudio
688 else if (line.indexOf(":") >= 0) {
689 QPair<QString, QString> device;
690 device.first = line.mid(line.indexOf(":") + 1).trimmed();
691 device.second = "dac" + line.left(line.indexOf(":")).trimmed();
692 deviceList.append(device);
693 }
694 }
695 }
696 else if (line.indexOf(startText) >= 0) {
697 collect = true;
698 }
699 }
700 }
701 #endif
702 return deviceList;
703 }
704
runCsoundInternally(QStringList flags)705 QStringList ConfigLists::runCsoundInternally(QStringList flags)
706 {
707 #if CS_APIVERSION>=4
708 const char *argv[33];
709 #else
710 char *argv[33];
711 #endif
712 int index = 1;
713 Q_ASSERT(flags.size() < 32);
714 argv[0] = (char *) calloc(7, sizeof(char));
715 strncpy((char *) argv[0], "csound", 6);
716
717 foreach (QString flag, flags) {
718 argv[index] = (char *) calloc(flag.size()+1, sizeof(char));
719 strncpy((char *) argv[index], flag.toLatin1(), flag.size());
720 index++;
721 }
722 int argc = flags.size() + 1;
723 #ifdef MACOSX_PRE_SNOW
724 //Remember menu bar to set it after FLTK grabs it
725 menuBarHandle = GetMenuBar();
726 #endif
727 CSOUND *csoundD;
728 m_messages.clear();
729 csoundD=csoundCreate(&m_messages);
730
731 csoundSetMessageCallback(csoundD, msgCallback);
732 int result = csoundCompile(csoundD,argc,argv);
733
734 if(!result) {
735 csoundPerform(csoundD);
736 } else {
737 qDebug() << "Error compiling.";
738 qDebug() << m_messages;
739 }
740
741 // FIXME This crashes on Linux for portmidi! And messes up devices on OS X
742 csoundDestroy(csoundD);
743
744 #ifdef MACOSX_PRE_SNOW
745 // Put menu bar back
746 SetMenuBar(menuBarHandle);
747 #endif
748 return m_messages.split("\n");
749 }
750
751
isJackRunning()752 bool ConfigLists::isJackRunning() {
753 CSOUND *cs = csoundCreate(nullptr);
754 csoundSetRTAudioModule(cs, "jack");
755 int n = csoundGetAudioDevList(cs, nullptr, 1);
756 qDebug() << "isJackRunning" << n;
757 csoundDestroy(cs);
758 return n > 0;
759 }
760