enough with umpteen "i18n.h" files. Consolidate on pbd/i18n.h
[ardour.git] / libs / backends / jack / jack_utils.cc
1 /*
2     Copyright (C) 2010 Paul Davis
3     Copyright (C) 2011 Tim Mayberry
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #ifdef HAVE_ALSA
22 #include "ardouralsautil/devicelist.h"
23 #endif
24
25 #ifdef __APPLE__
26 #include <CoreAudio/CoreAudio.h>
27 #include <CoreFoundation/CFString.h>
28 #include <sys/param.h>
29 #include <mach-o/dyld.h>
30 #endif
31
32 #ifdef PLATFORM_WINDOWS
33 #include <shobjidl.h>  //  Needed for
34 #include <shlguid.h>   // 'IShellLink'
35 #endif
36
37 #if (defined PLATFORM_WINDOWS && defined HAVE_PORTAUDIO)
38 #include <portaudio.h>
39 #endif
40
41 #include <boost/scoped_ptr.hpp>
42
43 #include "pbd/gstdio_compat.h"
44 #include <glibmm/miscutils.h>
45
46 #include "pbd/epa.h"
47 #include "pbd/error.h"
48 #include "pbd/convert.h"
49 #include "pbd/file_utils.h"
50 #include "pbd/search_path.h"
51
52 #include "jack_utils.h"
53
54 #ifdef __APPLE
55 #include <CFBundle.h>
56 #endif
57
58 #include "pbd/i18n.h"
59
60 using namespace std;
61 using namespace PBD;
62
63 namespace ARDOUR {
64         // The pretty driver names
65         const char * const portaudio_driver_name = X_("Portaudio");
66         const char * const coreaudio_driver_name = X_("CoreAudio");
67         const char * const alsa_driver_name = X_("ALSA");
68         const char * const oss_driver_name = X_("OSS");
69         const char * const freebob_driver_name = X_("FreeBoB");
70         const char * const ffado_driver_name = X_("FFADO");
71         const char * const netjack_driver_name = X_("NetJACK");
72         const char * const dummy_driver_name = X_("Dummy");
73 }
74
75 namespace {
76
77         // The real driver names
78         const char * const portaudio_driver_command_line_name = X_("portaudio");
79         const char * const coreaudio_driver_command_line_name = X_("coreaudio");
80         const char * const alsa_driver_command_line_name = X_("alsa");
81         const char * const oss_driver_command_line_name = X_("oss");
82         const char * const freebob_driver_command_line_name = X_("freebob");
83         const char * const ffado_driver_command_line_name = X_("firewire");
84         const char * const netjack_driver_command_line_name = X_("netjack");
85         const char * const dummy_driver_command_line_name = X_("dummy");
86
87         // should we provide more "pretty" names like above?
88         const char * const alsa_seq_midi_driver_name = X_("alsa");
89         const char * const alsa_raw_midi_driver_name = X_("alsarawmidi");
90         const char * const alsaseq_midi_driver_name = X_("seq");
91         const char * const alsaraw_midi_driver_name = X_("raw");
92         const char * const winmme_midi_driver_name = X_("winmme");
93         const char * const coremidi_midi_driver_name = X_("coremidi");
94
95         // this should probably be translated
96         const char * const default_device_name = X_("Default");
97 }
98
99 static ARDOUR::MidiOptions midi_options;
100
101 std::string
102 get_none_string ()
103 {
104         return _("None");
105 }
106
107 void
108 ARDOUR::get_jack_audio_driver_names (vector<string>& audio_driver_names)
109 {
110 #ifdef PLATFORM_WINDOWS
111         audio_driver_names.push_back (portaudio_driver_name);
112 #elif __APPLE__
113         audio_driver_names.push_back (coreaudio_driver_name);
114 #else
115 #ifdef HAVE_ALSA
116         audio_driver_names.push_back (alsa_driver_name);
117 #endif
118         audio_driver_names.push_back (oss_driver_name);
119         audio_driver_names.push_back (freebob_driver_name);
120         audio_driver_names.push_back (ffado_driver_name);
121 #endif
122         audio_driver_names.push_back (netjack_driver_name);
123         audio_driver_names.push_back (dummy_driver_name);
124 }
125
126 void
127 ARDOUR::get_jack_default_audio_driver_name (string& audio_driver_name)
128 {
129         vector<string> drivers;
130         get_jack_audio_driver_names (drivers);
131         audio_driver_name = drivers.front ();
132 }
133
134 void
135 ARDOUR::get_jack_sample_rate_strings (vector<string>& samplerates)
136 {
137         // do these really need to be translated?
138         samplerates.push_back (_("8000Hz"));
139         samplerates.push_back (_("22050Hz"));
140         samplerates.push_back (_("44100Hz"));
141         samplerates.push_back (_("48000Hz"));
142         samplerates.push_back (_("88200Hz"));
143         samplerates.push_back (_("96000Hz"));
144         samplerates.push_back (_("192000Hz"));
145 }
146
147 string
148 ARDOUR::get_jack_default_sample_rate ()
149 {
150         return _("48000Hz");
151 }
152
153 void
154 ARDOUR::get_jack_period_size_strings (std::vector<std::string>& period_sizes)
155 {
156         period_sizes.push_back ("32");
157         period_sizes.push_back ("64");
158         period_sizes.push_back ("128");
159         period_sizes.push_back ("256");
160         period_sizes.push_back ("512");
161         period_sizes.push_back ("1024");
162         period_sizes.push_back ("2048");
163         period_sizes.push_back ("4096");
164         period_sizes.push_back ("8192");
165 }
166
167 string
168 ARDOUR::get_jack_default_period_size ()
169 {
170         return "1024";
171 }
172
173 void
174 ARDOUR::get_jack_dither_mode_strings (const string& driver, vector<string>& dither_modes)
175 {
176         dither_modes.push_back (get_none_string ());
177
178         if (driver == alsa_driver_name ) {
179                 dither_modes.push_back (_("Triangular"));
180                 dither_modes.push_back (_("Rectangular"));
181                 dither_modes.push_back (_("Shaped"));
182         }
183 }
184
185 string
186 ARDOUR::get_jack_default_dither_mode (const string& /*driver*/)
187 {
188         return get_none_string ();
189 }
190
191 string
192 ARDOUR::get_jack_latency_string (string samplerate, float periods, string period_size)
193 {
194         uint32_t rate = atoi (samplerate);
195         float psize = atof (period_size);
196
197         char buf[32];
198         snprintf (buf, sizeof(buf), "%.1fmsec", (periods * psize) / (rate/1000.0));
199
200         return buf;
201 }
202
203 bool
204 get_jack_command_line_audio_driver_name (const string& driver_name, string& command_line_name)
205 {
206         using namespace ARDOUR;
207         if (driver_name == portaudio_driver_name) {
208                 command_line_name = portaudio_driver_command_line_name;
209                 return true;
210         } else if (driver_name == coreaudio_driver_name) {
211                 command_line_name = coreaudio_driver_command_line_name;
212                 return true;
213         } else if (driver_name == alsa_driver_name) {
214                 command_line_name = alsa_driver_command_line_name;
215                 return true;
216         } else if (driver_name == oss_driver_name) {
217                 command_line_name = oss_driver_command_line_name;
218                 return true;
219         } else if (driver_name == freebob_driver_name) {
220                 command_line_name = freebob_driver_command_line_name;
221                 return true;
222         } else if (driver_name == ffado_driver_name) {
223                 command_line_name = ffado_driver_command_line_name;
224                 return true;
225         } else if (driver_name == netjack_driver_name) {
226                 command_line_name = netjack_driver_command_line_name;
227                 return true;
228         } else if (driver_name == dummy_driver_name) {
229                 command_line_name = dummy_driver_command_line_name;
230                 return true;
231         }
232         return false;
233 }
234
235 bool
236 get_jack_command_line_audio_device_name (const string& driver_name,
237                 const string& device_name, string& command_line_device_name)
238 {
239         using namespace ARDOUR;
240         device_map_t devices;
241
242         get_jack_device_names_for_audio_driver (driver_name, devices);
243
244         for (device_map_t::const_iterator i = devices.begin (); i != devices.end(); ++i) {
245                 if (i->first == device_name) {
246                         command_line_device_name = i->second;
247                         return true;
248                 }
249         }
250         return false;
251 }
252
253 bool
254 get_jack_command_line_dither_mode (const string& dither_mode, string& command_line_dither_mode)
255 {
256         using namespace ARDOUR;
257
258         if (dither_mode == _("Triangular")) {
259                 command_line_dither_mode = "triangular";
260                 return true;
261         } else if (dither_mode == _("Rectangular")) {
262                 command_line_dither_mode = "rectangular";
263                 return true;
264         } else if (dither_mode == _("Shaped")) {
265                 command_line_dither_mode = "shaped";
266                 return true;
267         }
268
269         return false;
270 }
271
272 void
273 ARDOUR::get_jack_alsa_device_names (device_map_t& devices)
274 {
275 #ifdef HAVE_ALSA
276         get_alsa_audio_device_names(devices);
277 #else
278         /* silence a compiler unused variable warning */
279         (void) devices;
280 #endif
281 }
282
283 #ifdef __APPLE__
284 static OSStatus
285 getDeviceUIDFromID( AudioDeviceID id, char *name, size_t nsize)
286 {
287         UInt32 size = sizeof(CFStringRef);
288         CFStringRef UI;
289         OSStatus res = AudioDeviceGetProperty(id, 0, false,
290                 kAudioDevicePropertyDeviceUID, &size, &UI);
291         if (res == noErr)
292                 CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding());
293         CFRelease(UI);
294         return res;
295 }
296 #endif
297
298 void
299 ARDOUR::get_jack_coreaudio_device_names (device_map_t& devices)
300 {
301 #ifdef __APPLE__
302         // Find out how many Core Audio devices are there, if any...
303         // (code snippet gently "borrowed" from St?hane Letz jackdmp;)
304         OSStatus err;
305         Boolean isWritable;
306         UInt32 outSize = sizeof(isWritable);
307
308         err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices,
309                                            &outSize, &isWritable);
310         if (err == noErr) {
311                 // Calculate the number of device available...
312                 int numCoreDevices = outSize / sizeof(AudioDeviceID);
313                 // Make space for the devices we are about to get...
314                 AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices];
315                 err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices,
316                                                &outSize, (void *) coreDeviceIDs);
317                 if (err == noErr) {
318                         // Look for the CoreAudio device name...
319                         char coreDeviceName[256];
320                         UInt32 nameSize;
321
322                         for (int i = 0; i < numCoreDevices; i++) {
323
324                                 nameSize = sizeof (coreDeviceName);
325
326                                 /* enforce duplex devices only */
327
328                                 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
329                                                                  0, true, kAudioDevicePropertyStreams,
330                                                                  &outSize, &isWritable);
331
332                                 if (err != noErr || outSize == 0) {
333                                         continue;
334                                 }
335
336                                 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
337                                                                  0, false, kAudioDevicePropertyStreams,
338                                                                  &outSize, &isWritable);
339
340                                 if (err != noErr || outSize == 0) {
341                                         continue;
342                                 }
343
344                                 err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i],
345                                                                  0, true, kAudioDevicePropertyDeviceName,
346                                                                  &outSize, &isWritable);
347                                 if (err == noErr) {
348                                         err = AudioDeviceGetProperty(coreDeviceIDs[i],
349                                                                      0, true, kAudioDevicePropertyDeviceName,
350                                                                      &nameSize, (void *) coreDeviceName);
351                                         if (err == noErr) {
352                                                 char drivername[128];
353
354                                                 // this returns the unique id for the device
355                                                 // that must be used on the commandline for jack
356
357                                                 if (getDeviceUIDFromID(coreDeviceIDs[i], drivername, sizeof (drivername)) == noErr) {
358                                                         devices.insert (make_pair (coreDeviceName, drivername));
359                                                 }
360                                         }
361                                 }
362                         }
363                 }
364                 delete [] coreDeviceIDs;
365         }
366 #else
367         /* silence a compiler unused variable warning */
368         (void) devices;
369 #endif
370 }
371
372 void
373 ARDOUR::get_jack_portaudio_device_names (device_map_t& devices)
374 {
375 #if (defined PLATFORM_WINDOWS && defined HAVE_PORTAUDIO)
376         if (Pa_Initialize() != paNoError) {
377                 return;
378         }
379
380         for (PaDeviceIndex i = 0; i < Pa_GetDeviceCount (); ++i) {
381                 string api_name;
382                 string readable_name;
383                 string jack_device_name;
384                 const PaDeviceInfo* device_info = Pa_GetDeviceInfo(i);
385
386                 if (device_info != NULL) { // it should never be ?
387                         api_name = Pa_GetHostApiInfo (device_info->hostApi)->name;
388                         readable_name = api_name + " " + device_info->name;
389                         jack_device_name = api_name + "::" + device_info->name;
390                         devices.insert (make_pair (readable_name, jack_device_name));
391                 }
392         }
393         Pa_Terminate();
394 #else
395         /* silence a compiler unused variable warning */
396         (void) devices;
397 #endif
398 }
399
400 void
401 ARDOUR::get_jack_oss_device_names (device_map_t& devices)
402 {
403         devices.insert (make_pair (default_device_name, default_device_name));
404 }
405
406 void
407 ARDOUR::get_jack_freebob_device_names (device_map_t& devices)
408 {
409         devices.insert (make_pair (default_device_name, default_device_name));
410 }
411
412 void
413 ARDOUR::get_jack_ffado_device_names (device_map_t& devices)
414 {
415         devices.insert (make_pair (default_device_name, default_device_name));
416 }
417
418 void
419 ARDOUR::get_jack_netjack_device_names (device_map_t& devices)
420 {
421         devices.insert (make_pair (default_device_name, default_device_name));
422 }
423
424 void
425 ARDOUR::get_jack_dummy_device_names (device_map_t& devices)
426 {
427         devices.insert (make_pair (default_device_name, default_device_name));
428 }
429
430 bool
431 ARDOUR::get_jack_device_names_for_audio_driver (const string& driver_name, device_map_t& devices)
432 {
433         devices.clear();
434
435         if (driver_name == portaudio_driver_name) {
436                 get_jack_portaudio_device_names (devices);
437         } else if (driver_name == coreaudio_driver_name) {
438                 get_jack_coreaudio_device_names (devices);
439         } else if (driver_name == alsa_driver_name) {
440                 get_jack_alsa_device_names (devices);
441         } else if (driver_name == oss_driver_name) {
442                 get_jack_oss_device_names (devices);
443         } else if (driver_name == freebob_driver_name) {
444                 get_jack_freebob_device_names (devices);
445         } else if (driver_name == ffado_driver_name) {
446                 get_jack_ffado_device_names (devices);
447         } else if (driver_name == netjack_driver_name) {
448                 get_jack_netjack_device_names (devices);
449         } else if (driver_name == dummy_driver_name) {
450                 get_jack_dummy_device_names (devices);
451         }
452
453         return !devices.empty();
454 }
455
456
457 std::vector<std::string>
458 ARDOUR::get_jack_device_names_for_audio_driver (const string& driver_name)
459 {
460         std::vector<std::string> readable_names;
461         device_map_t devices;
462
463         get_jack_device_names_for_audio_driver (driver_name, devices);
464
465         for (device_map_t::const_iterator i = devices.begin (); i != devices.end(); ++i) {
466                 readable_names.push_back (i->first);
467         }
468
469         return readable_names;
470 }
471
472 bool
473 ARDOUR::get_jack_audio_driver_supports_two_devices (const string& driver)
474 {
475         return (driver == alsa_driver_name || driver == oss_driver_name);
476 }
477
478 bool
479 ARDOUR::get_jack_audio_driver_supports_latency_adjustment (const string& driver)
480 {
481         return (driver == alsa_driver_name || driver == coreaudio_driver_name ||
482                         driver == ffado_driver_name || driver == portaudio_driver_name);
483 }
484
485 bool
486 ARDOUR::get_jack_audio_driver_supports_setting_period_count (const string& driver)
487 {
488         return !(driver == dummy_driver_name || driver == coreaudio_driver_name ||
489                         driver == portaudio_driver_name);
490 }
491
492 bool
493 ARDOUR::get_jack_server_application_names (std::vector<std::string>& server_names)
494 {
495 #ifdef PLATFORM_WINDOWS
496         server_names.push_back ("jackd.exe");
497 #else
498         server_names.push_back ("jackd");
499         server_names.push_back ("jackdmp");
500 #endif
501         return !server_names.empty();
502 }
503
504 void
505 ARDOUR::set_path_env_for_jack_autostart (const vector<std::string>& dirs)
506 {
507 #ifdef __APPLE__
508         // push it back into the environment so that auto-started JACK can find it.
509         // XXX why can't we just expect OS X users to have PATH set correctly? we can't ...
510         setenv ("PATH", Searchpath(dirs).to_string().c_str(), 1);
511 #else
512         /* silence a compiler unused variable warning */
513         (void) dirs;
514 #endif
515 }
516
517 bool
518 ARDOUR::get_jack_server_dir_paths (vector<std::string>& server_dir_paths)
519 {
520 #ifdef __APPLE__
521         /* this magic lets us finds the path to the OSX bundle, and then
522            we infer JACK's location from there
523         */
524
525         char execpath[MAXPATHLEN+1];
526         uint32_t pathsz = sizeof (execpath);
527
528         _NSGetExecutablePath (execpath, &pathsz);
529
530         server_dir_paths.push_back (Glib::path_get_dirname (execpath));
531 #endif
532
533         Searchpath sp(string(g_getenv("PATH")));
534
535 #ifdef PLATFORM_WINDOWS
536 // N.B. The #define (immediately below) can be safely removed once we know that this code builds okay with mingw
537 #ifdef COMPILER_MSVC
538         IShellLinkA  *pISL = NULL;
539         IPersistFile *ppf  = NULL;
540
541         // Mixbus creates a Windows shortcut giving the location of its
542         // own (bundled) version of Jack. Let's see if that shortcut exists
543         if (SUCCEEDED (CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pISL)))
544         {
545                 if (SUCCEEDED (pISL->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf)))
546                 {
547                         char  target_path[MAX_PATH];
548                         char  shortcut_pathA[MAX_PATH];
549                         WCHAR shortcut_pathW[MAX_PATH];
550
551                         // Our Windows installer should have created a shortcut to the Jack
552                         // server so let's start by finding out what drive it got installed on
553                         if (char *env_path = getenv ("windir"))
554                         {
555                                 strcpy (shortcut_pathA, env_path);
556                                 shortcut_pathA[2] = '\0'; // Gives us just the drive letter and colon
557                         }
558                         else // Assume 'C:'
559                                 strcpy (shortcut_pathA, "C:");
560
561                         strcat (shortcut_pathA, "\\Program Files (x86)\\Jack\\Start Jack.lnk");
562
563                         MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, shortcut_pathA, -1, shortcut_pathW, MAX_PATH);
564
565                         // If it did, load the shortcut into our persistent file
566                         if (SUCCEEDED (ppf->Load(shortcut_pathW, 0)))
567                         {
568                                 // Read the target information from the shortcut object
569                                 if (S_OK == (pISL->GetPath (target_path, MAX_PATH, NULL, SLGP_UNCPRIORITY)))
570                                 {
571                                         char *p = strrchr (target_path, '\\');
572
573                                         if (p)
574                                         {
575                                                 *p = NULL;
576                                                 sp.push_back (target_path);
577                                         }
578                                 }
579                         }
580                 }
581         }
582
583         if (ppf)
584                 ppf->Release();
585
586         if (pISL)
587                 pISL->Release();
588 #endif
589
590         gchar *install_dir = g_win32_get_package_installation_directory_of_module (NULL);
591         if (install_dir) {
592                 sp.push_back (install_dir);
593                 g_free (install_dir);
594         }
595         // don't try and use a system wide JACK install yet.
596 #else
597         if (sp.empty()) {
598                 sp.push_back ("/usr/bin");
599                 sp.push_back ("/bin");
600                 sp.push_back ("/usr/local/bin");
601                 sp.push_back ("/opt/local/bin");
602         }
603 #endif
604
605         std::copy (sp.begin(), sp.end(), std::back_inserter(server_dir_paths));
606
607         return !server_dir_paths.empty();
608 }
609
610 bool
611 ARDOUR::get_jack_server_paths (const vector<std::string>& server_dir_paths,
612                 const vector<string>& server_names,
613                 vector<std::string>& server_paths)
614 {
615         for (vector<string>::const_iterator i = server_names.begin(); i != server_names.end(); ++i) {
616                 find_files_matching_pattern (server_paths, server_dir_paths, *i);
617         }
618         return !server_paths.empty();
619 }
620
621 bool
622 ARDOUR::get_jack_server_paths (vector<std::string>& server_paths)
623 {
624         vector<std::string> server_dirs;
625
626         if (!get_jack_server_dir_paths (server_dirs)) {
627                 return false;
628         }
629
630         vector<string> server_names;
631
632         if (!get_jack_server_application_names (server_names)) {
633                 return false;
634         }
635
636         if (!get_jack_server_paths (server_dirs, server_names, server_paths)) {
637                 return false;
638         }
639
640         return !server_paths.empty();
641 }
642
643 bool
644 ARDOUR::get_jack_default_server_path (std::string& server_path)
645 {
646         vector<std::string> server_paths;
647
648         if (!get_jack_server_paths (server_paths)) {
649                 return false;
650         }
651
652         server_path = server_paths.front ();
653         return true;
654 }
655
656 string
657 quote_string (const string& str)
658 {
659         return "\"" + str + "\"";
660 }
661
662 ARDOUR::JackCommandLineOptions::JackCommandLineOptions ()
663         : server_path ()
664         , timeout(0)
665         , no_mlock(false)
666         , ports_max(128)
667         , realtime(true)
668         , priority(0)
669         , unlock_gui_libs(false)
670         , verbose(false)
671         , temporary(true)
672         , driver()
673         , input_device()
674         , output_device()
675         , num_periods(2)
676         , period_size(1024)
677         , samplerate(48000)
678         , input_latency(0)
679         , output_latency(0)
680         , hardware_metering(false)
681         , hardware_monitoring(false)
682         , dither_mode()
683         , force16_bit(false)
684         , soft_mode(false)
685         , midi_driver()
686 {
687
688 }
689
690 bool
691 ARDOUR::get_jack_command_line_string (JackCommandLineOptions& options, string& command_line)
692 {
693         vector<string> args;
694
695         args.push_back (options.server_path);
696
697 #ifdef PLATFORM_WINDOWS
698         // must use sync mode on windows
699         args.push_back ("-S");
700 #endif
701
702 #if (defined PLATFORM_WINDOWS || defined __APPLE__)
703         // midi systems needs to be added before the audio driver for jack2
704         if (!options.midi_driver.empty () && options.midi_driver != get_none_string ()) {
705                 args.push_back ("-X");
706                 args.push_back (options.midi_driver);
707         }
708 #endif
709
710         /* XXX hack to enforce qjackctl-like behaviour */
711         if (options.timeout == 0) {
712                 options.timeout = 200;
713         }
714
715         if (options.timeout) {
716                 args.push_back ("-t");
717                 args.push_back (to_string (options.timeout, std::dec));
718         }
719
720         if (options.no_mlock) {
721                 args.push_back ("-m");
722         }
723
724         args.push_back ("-p");
725         args.push_back (to_string(options.ports_max, std::dec));
726
727         if (options.realtime) {
728                 args.push_back ("-R");
729                 if (options.priority != 0) {
730                         args.push_back ("-P");
731                         args.push_back (to_string(options.priority, std::dec));
732                 }
733         } else {
734                 args.push_back ("-r");
735         }
736
737         if (options.unlock_gui_libs) {
738                 args.push_back ("-u");
739         }
740
741         if (options.verbose) {
742                 args.push_back ("-v");
743         }
744
745         if (options.temporary) {
746                 args.push_back ("-T");
747         }
748
749         if (options.driver == alsa_driver_name) {
750                 if (options.midi_driver == alsa_seq_midi_driver_name) {
751                         args.push_back ("-X");
752                         args.push_back ("alsa_midi");
753                 } else if (options.midi_driver == alsa_raw_midi_driver_name) {
754                         args.push_back ("-X");
755                         args.push_back ("alsarawmidi");
756                 }
757         }
758
759         string command_line_driver_name;
760
761         string command_line_input_device_name;
762         string command_line_output_device_name;
763
764         if (!get_jack_command_line_audio_driver_name (options.driver, command_line_driver_name)) {
765                 return false;
766         }
767
768         args.push_back ("-d");
769         args.push_back (command_line_driver_name);
770
771         if (options.driver != dummy_driver_name) {
772                 if (options.output_device.empty() && options.input_device.empty()) {
773                         return false;
774                 }
775
776
777                 if (!get_jack_command_line_audio_device_name (options.driver,
778                                         options.input_device, command_line_input_device_name)) {
779                         return false;
780                 }
781
782                 if (!get_jack_command_line_audio_device_name (options.driver,
783                                         options.output_device, command_line_output_device_name)) {
784                         return false;
785                 }
786
787                 if (options.input_device.empty()) {
788                         // playback only
789                         if (options.output_device.empty()) {
790                                 return false;
791                         }
792                         args.push_back ("-P");
793                 } else if (options.output_device.empty()) {
794                         // capture only
795                         if (options.input_device.empty()) {
796                                 return false;
797                         }
798                         args.push_back ("-C");
799                 } else if (options.input_device != options.output_device) {
800                         // capture and playback on two devices if supported
801                         if (get_jack_audio_driver_supports_two_devices (options.driver)) {
802                                 args.push_back ("-C");
803                                 args.push_back (command_line_input_device_name);
804                                 args.push_back ("-P");
805                                 args.push_back (command_line_output_device_name);
806                         } else {
807                                 return false;
808                         }
809                 }
810
811                 if (options.input_channels) {
812                         args.push_back ("-i");
813                         args.push_back (to_string (options.input_channels, std::dec));
814                 }
815
816                 if (options.output_channels) {
817                         args.push_back ("-o");
818                         args.push_back (to_string (options.output_channels, std::dec));
819                 }
820
821                 if (get_jack_audio_driver_supports_setting_period_count (options.driver)) {
822                         args.push_back ("-n");
823                         args.push_back (to_string (options.num_periods, std::dec));
824                 }
825         } else {
826                 // jackd dummy backend
827                 if (options.input_channels) {
828                         args.push_back ("-C");
829                         args.push_back (to_string (options.input_channels, std::dec));
830                 }
831
832                 if (options.output_channels) {
833                         args.push_back ("-P");
834                         args.push_back (to_string (options.output_channels, std::dec));
835                 }
836         }
837
838         args.push_back ("-r");
839         args.push_back (to_string (options.samplerate, std::dec));
840
841         args.push_back ("-p");
842         args.push_back (to_string (options.period_size, std::dec));
843
844         if (get_jack_audio_driver_supports_latency_adjustment (options.driver)) {
845                 if (options.input_latency) {
846                         args.push_back ("-I");
847                         args.push_back (to_string (options.input_latency, std::dec));
848                 }
849                 if (options.output_latency) {
850                         args.push_back ("-O");
851                         args.push_back (to_string (options.output_latency, std::dec));
852                 }
853         }
854
855         if (options.driver != dummy_driver_name) {
856                 if (options.input_device == options.output_device && options.input_device != default_device_name) {
857                         args.push_back ("-d");
858                         args.push_back (command_line_input_device_name);
859                 }
860         }
861
862         if (options.driver == alsa_driver_name) {
863                 if (options.hardware_metering) {
864                         args.push_back ("-M");
865                 }
866                 if (options.hardware_monitoring) {
867                         args.push_back ("-H");
868                 }
869
870                 string command_line_dither_mode;
871                 if (get_jack_command_line_dither_mode (options.dither_mode, command_line_dither_mode)) {
872                         args.push_back ("-z");
873                         args.push_back (command_line_dither_mode);
874                 }
875                 if (options.force16_bit) {
876                         args.push_back ("-S");
877                 }
878                 if (options.soft_mode) {
879                         args.push_back ("-s");
880                 }
881         }
882
883         if (options.driver == alsa_driver_name) {
884
885                 if (options.midi_driver != alsa_seq_midi_driver_name) {
886                         if (!options.midi_driver.empty() && options.midi_driver != get_none_string ()) {
887                                 args.push_back ("-X");
888                                 args.push_back (options.midi_driver);
889                         }
890                 }
891         }
892
893         ostringstream oss;
894
895         for (vector<string>::const_iterator i = args.begin(); i != args.end();) {
896                 if (i->find_first_of(' ') != string::npos) {
897                         oss << "\"" << *i << "\"";
898                 } else {
899                         oss << *i;
900                 }
901                 if (++i != args.end()) oss << ' ';
902         }
903
904         command_line = oss.str();
905         return true;
906 }
907
908 string
909 ARDOUR::get_jack_server_config_file_name ()
910 {
911         return ".jackdrc";
912 }
913
914 std::string
915 ARDOUR::get_jack_server_user_config_dir_path ()
916 {
917         return Glib::get_home_dir ();
918 }
919
920 std::string
921 ARDOUR::get_jack_server_user_config_file_path ()
922 {
923         return Glib::build_filename (get_jack_server_user_config_dir_path (), get_jack_server_config_file_name ());
924 }
925
926 bool
927 ARDOUR::write_jack_config_file (const std::string& config_file_path, const string& command_line)
928 {
929         if (!g_file_set_contents (config_file_path.c_str(), command_line.c_str(), -1, NULL)) {
930                 error << string_compose (_("cannot open JACK rc file %1 to store parameters"), config_file_path) << endmsg;
931                 return false;
932         }
933         return true;
934 }
935
936 vector<string>
937 ARDOUR::enumerate_midi_options ()
938 {
939         if (midi_options.empty()) {
940 #ifdef HAVE_ALSA
941                 midi_options.push_back (make_pair (_("(legacy) ALSA raw devices"), alsaraw_midi_driver_name));
942                 midi_options.push_back (make_pair (_("(legacy) ALSA sequencer"), alsaseq_midi_driver_name));
943                 midi_options.push_back (make_pair (_("ALSA (JACK1, 0.124 and later)"), alsa_seq_midi_driver_name));
944                 midi_options.push_back (make_pair (_("ALSA (JACK2, 1.9.8 and later)"), alsa_raw_midi_driver_name));
945 #endif
946 #if (defined PLATFORM_WINDOWS && defined HAVE_PORTAUDIO)
947                 /* Windows folks: what name makes sense here? Are there other
948                    choices as well ?
949                 */
950                 midi_options.push_back (make_pair (_("System MIDI (MME)"), winmme_midi_driver_name));
951 #endif
952 #ifdef __APPLE__
953                 midi_options.push_back (make_pair (_("CoreMIDI"), coremidi_midi_driver_name));
954 #endif
955         }
956
957         vector<string> v;
958
959         for (MidiOptions::const_iterator i = midi_options.begin(); i != midi_options.end(); ++i) {
960                 v.push_back (i->first);
961         }
962
963         v.push_back (get_none_string());
964
965         return v;
966 }
967
968 int
969 ARDOUR::set_midi_option (ARDOUR::JackCommandLineOptions& options, const string& opt)
970 {
971         if (opt.empty() || opt == get_none_string()) {
972                 options.midi_driver = "";
973                 return 0;
974         }
975
976         for (MidiOptions::const_iterator i = midi_options.begin(); i != midi_options.end(); ++i) {
977                 if (i->first == opt) {
978                         options.midi_driver = i->second;
979                         return 0;
980                 }
981         }
982
983         return -1;
984 }
985