X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fbackends%2Fjack%2Fjack_utils.cc;h=6fb3201c99802fb0b859f18646ee2d034db45c81;hb=34d9b2148ebf834267821bf9c437e520b4eb05d7;hp=a78c6491c79176f9825ddffbd4346ba44fa1f703;hpb=c985a64d5851634a77bc013a7f66ef8d9ccefcae;p=ardour.git diff --git a/libs/backends/jack/jack_utils.cc b/libs/backends/jack/jack_utils.cc index a78c6491c7..6fb3201c99 100644 --- a/libs/backends/jack/jack_utils.cc +++ b/libs/backends/jack/jack_utils.cc @@ -19,7 +19,7 @@ */ #ifdef HAVE_ALSA -#include +#include "ardouralsautil/devicelist.h" #endif #ifdef __APPLE__ @@ -29,16 +29,18 @@ #include #endif -#ifdef HAVE_PORTAUDIO -#include +#ifdef PLATFORM_WINDOWS +#include // Needed for +#include // 'IShellLink' #endif -#include - -#include +#if (defined PLATFORM_WINDOWS && defined HAVE_PORTAUDIO) +#include +#endif #include +#include "pbd/gstdio_compat.h" #include #include "pbd/epa.h" @@ -83,6 +85,8 @@ namespace { const char * const dummy_driver_command_line_name = X_("dummy"); // should we provide more "pretty" names like above? + const char * const alsa_seq_midi_driver_name = X_("alsa"); + const char * const alsa_raw_midi_driver_name = X_("alsarawmidi"); const char * const alsaseq_midi_driver_name = X_("seq"); const char * const alsaraw_midi_driver_name = X_("raw"); const char * const winmme_midi_driver_name = X_("winmme"); @@ -92,6 +96,8 @@ namespace { const char * const default_device_name = X_("Default"); } +static ARDOUR::MidiOptions midi_options; + std::string get_none_string () { @@ -101,7 +107,7 @@ get_none_string () void ARDOUR::get_jack_audio_driver_names (vector& audio_driver_names) { -#ifdef WIN32 +#ifdef PLATFORM_WINDOWS audio_driver_names.push_back (portaudio_driver_name); #elif __APPLE__ audio_driver_names.push_back (coreaudio_driver_name); @@ -267,60 +273,7 @@ void ARDOUR::get_jack_alsa_device_names (device_map_t& devices) { #ifdef HAVE_ALSA - snd_ctl_t *handle; - snd_ctl_card_info_t *info; - snd_pcm_info_t *pcminfo; - snd_ctl_card_info_alloca(&info); - snd_pcm_info_alloca(&pcminfo); - string devname; - int cardnum = -1; - int device = -1; - - while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) { - - devname = "hw:"; - devname += PBD::to_string (cardnum, std::dec); - - if (snd_ctl_open (&handle, devname.c_str(), 0) >= 0 && snd_ctl_card_info (handle, info) >= 0) { - - if (snd_ctl_card_info (handle, info) < 0) { - continue; - } - - string card_name = snd_ctl_card_info_get_name (info); - - /* change devname to use ID, not number */ - - devname = "hw:"; - devname += snd_ctl_card_info_get_id (info); - - while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) { - - /* only detect duplex devices here. more - * complex arrangements are beyond our scope - */ - - snd_pcm_info_set_device (pcminfo, device); - snd_pcm_info_set_subdevice (pcminfo, 0); - snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_CAPTURE); - - if (snd_ctl_pcm_info (handle, pcminfo) >= 0) { - - snd_pcm_info_set_device (pcminfo, device); - snd_pcm_info_set_subdevice (pcminfo, 0); - snd_pcm_info_set_stream (pcminfo, SND_PCM_STREAM_PLAYBACK); - - if (snd_ctl_pcm_info (handle, pcminfo) >= 0) { - devname += ','; - devname += PBD::to_string (device, std::dec); - devices.insert (std::make_pair (card_name, devname)); - } - } - } - - snd_ctl_close(handle); - } - } + get_alsa_audio_device_names(devices); #else /* silence a compiler unused variable warning */ (void) devices; @@ -419,7 +372,7 @@ ARDOUR::get_jack_coreaudio_device_names (device_map_t& devices) void ARDOUR::get_jack_portaudio_device_names (device_map_t& devices) { -#ifdef HAVE_PORTAUDIO +#if (defined PLATFORM_WINDOWS && defined HAVE_PORTAUDIO) if (Pa_Initialize() != paNoError) { return; } @@ -539,7 +492,7 @@ ARDOUR::get_jack_audio_driver_supports_setting_period_count (const string& drive bool ARDOUR::get_jack_server_application_names (std::vector& server_names) { -#ifdef WIN32 +#ifdef PLATFORM_WINDOWS server_names.push_back ("jackd.exe"); #else server_names.push_back ("jackd"); @@ -579,7 +532,61 @@ ARDOUR::get_jack_server_dir_paths (vector& server_dir_paths) Searchpath sp(string(g_getenv("PATH"))); -#ifdef WIN32 +#ifdef PLATFORM_WINDOWS +// N.B. The #define (immediately below) can be safely removed once we know that this code builds okay with mingw +#ifdef COMPILER_MSVC + IShellLinkA *pISL = NULL; + IPersistFile *ppf = NULL; + + // Mixbus creates a Windows shortcut giving the location of its + // own (bundled) version of Jack. Let's see if that shortcut exists + if (SUCCEEDED (CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void**)&pISL))) + { + if (SUCCEEDED (pISL->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf))) + { + char target_path[MAX_PATH]; + char shortcut_pathA[MAX_PATH]; + WCHAR shortcut_pathW[MAX_PATH]; + + // Our Windows installer should have created a shortcut to the Jack + // server so let's start by finding out what drive it got installed on + if (char *env_path = getenv ("windir")) + { + strcpy (shortcut_pathA, env_path); + shortcut_pathA[2] = '\0'; // Gives us just the drive letter and colon + } + else // Assume 'C:' + strcpy (shortcut_pathA, "C:"); + + strcat (shortcut_pathA, "\\Program Files (x86)\\Jack\\Start Jack.lnk"); + + MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, shortcut_pathA, -1, shortcut_pathW, MAX_PATH); + + // If it did, load the shortcut into our persistent file + if (SUCCEEDED (ppf->Load(shortcut_pathW, 0))) + { + // Read the target information from the shortcut object + if (S_OK == (pISL->GetPath (target_path, MAX_PATH, NULL, SLGP_UNCPRIORITY))) + { + char *p = strrchr (target_path, '\\'); + + if (p) + { + *p = NULL; + sp.push_back (target_path); + } + } + } + } + } + + if (ppf) + ppf->Release(); + + if (pISL) + pISL->Release(); +#endif + gchar *install_dir = g_win32_get_package_installation_directory_of_module (NULL); if (install_dir) { sp.push_back (install_dir); @@ -606,8 +613,7 @@ ARDOUR::get_jack_server_paths (const vector& server_dir_paths, vector& server_paths) { for (vector::const_iterator i = server_names.begin(); i != server_names.end(); ++i) { - Glib::PatternSpec ps (*i); - find_matching_files_in_directories (server_dir_paths, ps, server_paths); + find_files_matching_pattern (server_paths, server_dir_paths, *i); } return !server_paths.empty(); } @@ -688,11 +694,13 @@ ARDOUR::get_jack_command_line_string (JackCommandLineOptions& options, string& c args.push_back (options.server_path); -#ifdef WIN32 +#ifdef PLATFORM_WINDOWS // must use sync mode on windows args.push_back ("-S"); +#endif - // this needs to be added now on windows +#if (defined PLATFORM_WINDOWS || defined __APPLE__) + // midi systems needs to be added before the audio driver for jack2 if (!options.midi_driver.empty () && options.midi_driver != get_none_string ()) { args.push_back ("-X"); args.push_back (options.midi_driver); @@ -734,14 +742,25 @@ ARDOUR::get_jack_command_line_string (JackCommandLineOptions& options, string& c args.push_back ("-v"); } -#ifndef WIN32 if (options.temporary) { args.push_back ("-T"); } -#endif + + if (options.driver == alsa_driver_name) { + if (options.midi_driver == alsa_seq_midi_driver_name) { + args.push_back ("-X"); + args.push_back ("alsa_midi"); + } else if (options.midi_driver == alsa_raw_midi_driver_name) { + args.push_back ("-X"); + args.push_back ("alsarawmidi"); + } + } string command_line_driver_name; + string command_line_input_device_name; + string command_line_output_device_name; + if (!get_jack_command_line_audio_driver_name (options.driver, command_line_driver_name)) { return false; } @@ -749,60 +768,71 @@ ARDOUR::get_jack_command_line_string (JackCommandLineOptions& options, string& c args.push_back ("-d"); args.push_back (command_line_driver_name); - if (options.output_device.empty() && options.input_device.empty()) { - return false; - } - - string command_line_input_device_name; - string command_line_output_device_name; - - if (!get_jack_command_line_audio_device_name (options.driver, - options.input_device, command_line_input_device_name)) { - return false; - } + if (options.driver != dummy_driver_name) { + if (options.output_device.empty() && options.input_device.empty()) { + return false; + } - if (!get_jack_command_line_audio_device_name (options.driver, - options.output_device, command_line_output_device_name)) { - return false; - } - if (options.input_device.empty()) { - // playback only - if (options.output_device.empty()) { + if (!get_jack_command_line_audio_device_name (options.driver, + options.input_device, command_line_input_device_name)) { return false; } - args.push_back ("-P"); - } else if (options.output_device.empty()) { - // capture only - if (options.input_device.empty()) { + + if (!get_jack_command_line_audio_device_name (options.driver, + options.output_device, command_line_output_device_name)) { return false; } - args.push_back ("-C"); - } else if (options.input_device != options.output_device) { - // capture and playback on two devices if supported - if (get_jack_audio_driver_supports_two_devices (options.driver)) { - args.push_back ("-C"); - args.push_back (command_line_input_device_name); + + if (options.input_device.empty()) { + // playback only + if (options.output_device.empty()) { + return false; + } args.push_back ("-P"); - args.push_back (command_line_output_device_name); - } else { - return false; + } else if (options.output_device.empty()) { + // capture only + if (options.input_device.empty()) { + return false; + } + args.push_back ("-C"); + } else if (options.input_device != options.output_device) { + // capture and playback on two devices if supported + if (get_jack_audio_driver_supports_two_devices (options.driver)) { + args.push_back ("-C"); + args.push_back (command_line_input_device_name); + args.push_back ("-P"); + args.push_back (command_line_output_device_name); + } else { + return false; + } } - } - if (options.input_channels) { - args.push_back ("-i"); - args.push_back (to_string (options.input_channels, std::dec)); - } + if (options.input_channels) { + args.push_back ("-i"); + args.push_back (to_string (options.input_channels, std::dec)); + } - if (options.output_channels) { - args.push_back ("-o"); - args.push_back (to_string (options.output_channels, std::dec)); - } + if (options.output_channels) { + args.push_back ("-o"); + args.push_back (to_string (options.output_channels, std::dec)); + } + + if (get_jack_audio_driver_supports_setting_period_count (options.driver)) { + args.push_back ("-n"); + args.push_back (to_string (options.num_periods, std::dec)); + } + } else { + // jackd dummy backend + if (options.input_channels) { + args.push_back ("-C"); + args.push_back (to_string (options.input_channels, std::dec)); + } - if (get_jack_audio_driver_supports_setting_period_count (options.driver)) { - args.push_back ("-n"); - args.push_back (to_string (options.num_periods, std::dec)); + if (options.output_channels) { + args.push_back ("-P"); + args.push_back (to_string (options.output_channels, std::dec)); + } } args.push_back ("-r"); @@ -822,9 +852,11 @@ ARDOUR::get_jack_command_line_string (JackCommandLineOptions& options, string& c } } - if (options.input_device == options.output_device && options.input_device != default_device_name) { - args.push_back ("-d"); - args.push_back (command_line_input_device_name); + if (options.driver != dummy_driver_name) { + if (options.input_device == options.output_device && options.input_device != default_device_name) { + args.push_back ("-d"); + args.push_back (command_line_input_device_name); + } } if (options.driver == alsa_driver_name) { @@ -846,21 +878,26 @@ ARDOUR::get_jack_command_line_string (JackCommandLineOptions& options, string& c if (options.soft_mode) { args.push_back ("-s"); } + } - if (!options.midi_driver.empty() && options.midi_driver != get_none_string ()) { - args.push_back ("-X"); - args.push_back (options.midi_driver); + if (options.driver == alsa_driver_name) { + + if (options.midi_driver != alsa_seq_midi_driver_name) { + if (!options.midi_driver.empty() && options.midi_driver != get_none_string ()) { + args.push_back ("-X"); + args.push_back (options.midi_driver); + } } } ostringstream oss; for (vector::const_iterator i = args.begin(); i != args.end();) { -#ifdef WIN32 - oss << quote_string (*i); -#else - oss << *i; -#endif + if (i->find_first_of(' ') != string::npos) { + oss << "\"" << *i << "\""; + } else { + oss << *i; + } if (++i != args.end()) oss << ' '; } @@ -889,14 +926,60 @@ ARDOUR::get_jack_server_user_config_file_path () bool ARDOUR::write_jack_config_file (const std::string& config_file_path, const string& command_line) { - ofstream jackdrc (config_file_path.c_str()); - - if (!jackdrc) { + if (!g_file_set_contents (config_file_path.c_str(), command_line.c_str(), -1, NULL)) { error << string_compose (_("cannot open JACK rc file %1 to store parameters"), config_file_path) << endmsg; return false; } - - jackdrc << command_line << endl; - jackdrc.close (); return true; } + +vector +ARDOUR::enumerate_midi_options () +{ + if (midi_options.empty()) { +#ifdef HAVE_ALSA + midi_options.push_back (make_pair (_("(legacy) ALSA raw devices"), alsaraw_midi_driver_name)); + midi_options.push_back (make_pair (_("(legacy) ALSA sequencer"), alsaseq_midi_driver_name)); + midi_options.push_back (make_pair (_("ALSA (JACK1, 0.124 and later)"), alsa_seq_midi_driver_name)); + midi_options.push_back (make_pair (_("ALSA (JACK2, 1.9.8 and later)"), alsa_raw_midi_driver_name)); +#endif +#if (defined PLATFORM_WINDOWS && defined HAVE_PORTAUDIO) + /* Windows folks: what name makes sense here? Are there other + choices as well ? + */ + midi_options.push_back (make_pair (_("System MIDI (MME)"), winmme_midi_driver_name)); +#endif +#ifdef __APPLE__ + midi_options.push_back (make_pair (_("CoreMIDI"), coremidi_midi_driver_name)); +#endif + } + + vector v; + + for (MidiOptions::const_iterator i = midi_options.begin(); i != midi_options.end(); ++i) { + v.push_back (i->first); + } + + v.push_back (get_none_string()); + + return v; +} + +int +ARDOUR::set_midi_option (ARDOUR::JackCommandLineOptions& options, const string& opt) +{ + if (opt.empty() || opt == get_none_string()) { + options.midi_driver = ""; + return 0; + } + + for (MidiOptions::const_iterator i = midi_options.begin(); i != midi_options.end(); ++i) { + if (i->first == opt) { + options.midi_driver = i->second; + return 0; + } + } + + return -1; +} +