more MIDI paste improvements, plus move region-mute binding to PRIMARY-m and use...
[ardour.git] / gtk2_ardour / engine_dialog.cc
index c1ffcefb2b9306f1f0bc8da92fe67bb6495af9cc..9c0a39c5547a27cc8de3fdf984434768542a58bc 100644 (file)
@@ -5,7 +5,7 @@
 
 #include <glibmm.h>
 #include <gtkmm/messagedialog.h>
-#include <pbd/xml++.h>
+#include "pbd/xml++.h"
 
 #ifdef __APPLE__
 #include <CoreAudio/CoreAudio.h>
 #include <alsa/asoundlib.h>
 #endif
 
-#include <ardour/profile.h>
+#include "ardour/profile.h"
 #include <jack/jack.h>
 
 #include <gtkmm/stock.h>
 #include <gtkmm2ext/utils.h>
 
-#include <pbd/convert.h>
-#include <pbd/error.h>
-#include <pbd/pathscanner.h>
+#include "pbd/convert.h"
+#include "pbd/error.h"
+#include "pbd/pathscanner.h"
 
 #ifdef __APPLE
 #include <CFBundle.h>
@@ -122,9 +122,6 @@ EngineControl::EngineControl ()
        set_popdown_strings (driver_combo, strings);
        driver_combo.set_active_text (strings.front());
 
-       /* figure out available devices and set up interface_combo */
-
-       enumerate_devices ();
        driver_combo.signal_changed().connect (mem_fun (*this, &EngineControl::driver_changed));
        driver_changed ();
 
@@ -221,6 +218,8 @@ EngineControl::EngineControl ()
        realtime_button.signal_toggled().connect (mem_fun (*this, &EngineControl::realtime_changed));
        realtime_changed ();
 
+#if PROVIDE_TOO_MANY_OPTIONS
+
 #ifndef __APPLE__
        label = manage (new Label (_("Realtime Priority")));
        label->set_alignment (1.0, 0.5);
@@ -265,6 +264,7 @@ EngineControl::EngineControl ()
        options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0);
        ++row;
 
+#endif /* PROVIDE_TOO_MANY_OPTIONS */
        label = manage (new Label (_("Number of ports")));
        label->set_alignment (1.0, 0.5);
        options_packer.attach (ports_spinner, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0));
@@ -376,12 +376,14 @@ EngineControl::build_command_line (vector<string>& cmd)
 
        str = timeout_combo.get_active_text ();
        if (str != _("Ignore")) {
-               double secs;
+               double secs = 0;
                uint32_t msecs;
-               atof (str);
+               secs = atof (str);
                msecs = (uint32_t) floor (secs * 1000.0);
-               cmd.push_back ("-t");
-               cmd.push_back (to_string (msecs, std::dec));
+               if (msecs > 0) {
+                       cmd.push_back ("-t");
+                       cmd.push_back (to_string (msecs, std::dec));
+               }
        }
 
        if (no_memory_lock_button.get_active()) {
@@ -428,10 +430,20 @@ EngineControl::build_command_line (vector<string>& cmd)
                cmd.push_back ("netjack");
        } else if (driver == X_("FFADO")) {
                using_ffado = true;
-               cmd.push_back ("ffado");
+
+               /* do this until FFADO becomes the standard */
+
+               char* hack = getenv ("ARDOUR_FIREWIRE_DRIVER_NAME");
+
+               if (hack) {
+                       cmd.push_back (hack);
+               } else {
+                       cmd.push_back ("freebob");
+               }
+
        } else if ( driver == X_("Dummy")) {
-      using_dummy = true;
-      cmd.push_back ("dummy");
+               using_dummy = true;
+               cmd.push_back ("dummy");
        }
 
        /* driver arguments */
@@ -445,21 +457,29 @@ EngineControl::build_command_line (vector<string>& cmd)
                        
                } else if (str == _("Playback/Recording on 2 Devices")) {
                        
+                       string input_device = get_device_name (driver, input_device_combo.get_active_text());
+                       string output_device = get_device_name (driver, output_device_combo.get_active_text());
+
+                       if (input_device.empty() || output_device.empty()) {
+                               cmd.clear ();
+                               return;
+                       }
+
                        cmd.push_back ("-C");
-                       cmd.push_back (get_device_name (driver, input_device_combo.get_active_text()));
+                       cmd.push_back (input_device);
                        cmd.push_back ("-P");
-                       cmd.push_back (get_device_name (driver, output_device_combo.get_active_text()));
-                       
+                       cmd.push_back (output_device);
+
                } else if (str == _("Playback only")) {
                        cmd.push_back ("-P");
                } else if (str == _("Recording only")) {
                        cmd.push_back ("-C");
                }
 
-      if (! using_dummy ) {
-                  cmd.push_back ("-n");
-                  cmd.push_back (to_string ((uint32_t) floor (periods_spinner.get_value()), std::dec));
-      }
+               if (! using_dummy ) {
+                       cmd.push_back ("-n");
+                       cmd.push_back (to_string ((uint32_t) floor (periods_spinner.get_value()), std::dec));
+               }
        }
 
        cmd.push_back ("-r");
@@ -471,8 +491,15 @@ EngineControl::build_command_line (vector<string>& cmd)
        if (using_alsa) {
                
                if (audio_mode_combo.get_active_text() != _("Playback/Recording on 2 Devices")) {
+
+                       string device = get_device_name (driver, interface_combo.get_active_text());
+                       if (device.empty()) {
+                               cmd.clear ();
+                               return;
+                       }
+
                        cmd.push_back ("-d");
-                       cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
+                       cmd.push_back (device);
                } 
 
                if (hw_meter_button.get_active()) {
@@ -506,8 +533,15 @@ EngineControl::build_command_line (vector<string>& cmd)
 
 #ifdef __APPLE__
                // note: older versions of the CoreAudio JACK backend use -n instead of -d here
+               
+               string device = get_device_name (driver, interface_combo.get_active_text());
+               if (device.empty()) {
+                       cmd.clear ();
+                       return;
+               }
+
                cmd.push_back ("-d");
-               cmd.push_back (get_device_name (driver, interface_combo.get_active_text()));
+               cmd.push_back (device);
 #endif
 
        } else if (using_oss) {
@@ -537,6 +571,10 @@ EngineControl::setup_engine ()
        std::string cwd = "/tmp";
 
        build_command_line (args);
+       
+       if (args.empty()) {
+               return 1; // try again
+       }
 
        Glib::ustring jackdrc_path = Glib::get_home_dir();
        jackdrc_path += "/.jackdrc";
@@ -546,10 +584,12 @@ EngineControl::setup_engine ()
                error << string_compose (_("cannot open JACK rc file %1 to store parameters"), jackdrc_path) << endmsg;
                return -1;
        }
-
+       cerr << "JACK COMMAND: ";
        for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) {
+               cerr << (*i) << ' ';
                jackdrc << (*i) << ' ';
        }
+       cerr << endl;
        jackdrc << endl;
        jackdrc.close ();
 
@@ -567,18 +607,29 @@ EngineControl::realtime_changed ()
 }
 
 void
-EngineControl::enumerate_devices ()
+EngineControl::enumerate_devices (const string& driver)
 {
        /* note: case matters for the map keys */
 
-#ifdef __APPLE__
-       devices["CoreAudio"] = enumerate_coreaudio_devices ();
+       if (driver == "CoreAudio") {
+#ifdef __APPLE__               
+               devices[driver] = enumerate_coreaudio_devices ();
+#endif
+
+#ifndef __APPLE__
+       } else if (driver == "ALSA") {
+               devices[driver] = enumerate_alsa_devices ();
+       } else if (driver == "FFADO") {
+               devices[driver] = enumerate_ffado_devices ();
+       } else if (driver == "OSS") {
+               devices[driver] = enumerate_oss_devices ();
+       } else if (driver == "Dummy") {
+               devices[driver] = enumerate_dummy_devices ();
+       } else if (driver == "NetJACK") {
+               devices[driver] = enumerate_netjack_devices ();
+       }
 #else
-       devices["ALSA"] = enumerate_alsa_devices ();
-       devices["FFADO"] = enumerate_ffado_devices ();
-       devices["OSS"] = enumerate_oss_devices ();
-       devices["Dummy"] = enumerate_dummy_devices ();
-       devices["NetJACK"] = enumerate_netjack_devices ();
+        }
 #endif
 }
 
@@ -669,6 +720,7 @@ EngineControl::enumerate_coreaudio_devices ()
                delete [] coreDeviceIDs;
        }
 
+
        if (devs.size() == 0) {
                MessageDialog msg (_("\
 You do not have any audio devices capable of\n\
@@ -689,6 +741,7 @@ Ardour and choose the relevant device then."
                exit (1);
        }
 
+
        return devs;
 }
 #else
@@ -757,8 +810,10 @@ vector<string>
 EngineControl::enumerate_ffado_devices ()
 {
        vector<string> devs;
+       backend_devs.clear ();
        return devs;
 }
+
 vector<string>
 EngineControl::enumerate_freebob_devices ()
 {
@@ -789,11 +844,19 @@ void
 EngineControl::driver_changed ()
 {
        string driver = driver_combo.get_active_text();
-       vector<string>& strings = devices[driver];
        string::size_type maxlen = 0;
        int maxindex = -1;
        int n = 0;
 
+       enumerate_devices (driver);
+
+       vector<string>& strings = devices[driver];
+
+       if (strings.empty() && driver != "FFADO" && driver != "Dummy") {
+               error << string_compose (_("No devices found for driver \"%1\""), driver) << endmsg;
+               return;
+       }
+       
        for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) {
                if ((*i).length() > maxlen) {
                        maxlen = (*i).length();
@@ -809,7 +872,7 @@ EngineControl::driver_changed ()
                interface_combo.set_active_text (strings.front());
                input_device_combo.set_active_text (strings.front());
                output_device_combo.set_active_text (strings.front());
-       }
+       } 
        
        if (driver == "ALSA") {
                soft_mode_button.set_sensitive (true);
@@ -867,7 +930,7 @@ EngineControl::audio_mode_changed ()
        }
 }
 
-static bool jack_server_filter(const string& str, void *arg)
+static bool jack_server_filter(const string& str, void */*arg*/)
 {
    return str == "jackd" || str == "jackdmp";
 }
@@ -885,7 +948,7 @@ EngineControl::find_jack_servers (vector<string>& strings)
 
        _NSGetExecutablePath (execpath, &pathsz);
        
-       Glib::ustring path (Glib::path_get_dirname (execpath));
+       string path (Glib::path_get_dirname (execpath));
        path += "/jackd";
 
        if (Glib::file_test (path, FILE_TEST_EXISTS)) {
@@ -907,8 +970,36 @@ EngineControl::find_jack_servers (vector<string>& strings)
        PathScanner scanner;
        vector<string *> *jack_servers;
        std::map<string,int> un;
-       
-       path = getenv ("PATH");
+       char *p;
+       bool need_minimal_path = false;
+
+       p = getenv ("PATH");
+
+       if (p && *p) {
+               path = p;
+       } else {
+               need_minimal_path = true;
+       }
+
+#ifdef __APPLE__
+       // many mac users don't have PATH set up to include
+       // likely installed locations of JACK
+       need_minimal_path = true;
+#endif
+
+       if (need_minimal_path) {
+               if (path.empty()) {
+                       path = "/usr/bin:/bin:/usr/local/bin:/opt/local/bin";
+               } else {
+                       path += ":/usr/local/bin:/opt/local/bin";
+               }
+       }
+
+#ifdef __APPLE__
+       // push it back into the environment so that auto-started JACK can find it.
+       // XXX why can't we just expect OS X users to have PATH set correctly? we can't ...
+       setenv ("PATH", path.c_str(), 1);
+#endif
 
        jack_servers = scanner (path, jack_server_filter, 0, false, true);
        
@@ -930,6 +1021,15 @@ EngineControl::get_device_name (const string& driver, const string& human_readab
        vector<string>::iterator n;
        vector<string>::iterator i;
 
+       if (human_readable.empty()) {
+               /* this can happen if the user's .ardourrc file has a device name from
+                  another computer system in it
+               */
+               MessageDialog msg (_("You need to choose an audio device first."));
+               msg.run ();
+               return string();
+       }
+
        if (backend_devs.empty()) {
                return human_readable;
        }
@@ -941,12 +1041,9 @@ EngineControl::get_device_name (const string& driver, const string& human_readab
        }
        
        if (i == devices[driver].end()) {
-               fatal << string_compose (_("programming error: %1"), "true hardware name for ID missing") << endmsg;
-               /*NOTREACHED*/
+               warning << string_compose (_("Audio device \"%1\" not known on this computer."), human_readable) << endmsg;
        }
 
-       /* keep gcc happy */
-
        return string();
 }
 
@@ -1066,31 +1163,32 @@ EngineControl::set_state (const XMLNode& root)
        XMLNodeList          clist;
        XMLNodeConstIterator citer;
        XMLNode* child;
-       XMLProperty* prop;
-
-   bool using_dummy = false;
-
+       XMLProperty* prop = NULL;
+       bool using_dummy = false;
+       
        int val;
        string strval;
-
-   if ( (child = root.child("driver"))){
-      prop = child->property("val");
-      if (prop && (prop->value() == "Dummy") ) {
-         using_dummy = true;
-      }
-   }
-
+       
+       if ( (child = root.child ("driver"))){
+               prop = child->property("val");
+               if (prop && (prop->value() == "Dummy") ) {
+                       using_dummy = true;
+               }
+       }
+       
        clist = root.children();
 
        for (citer = clist.begin(); citer != clist.end(); ++citer) {
-
+               if ( prop && (prop->value() == "FFADO" ))
+                               continue;
                child = *citer;
 
                prop = child->property ("val");
 
                if (!prop || prop->value().empty()) {
-         if ( using_dummy && ( child->name() == "interface" || child->name() == "inputdevice" || child->name() == "outputdevice" ))
-               continue;
+
+                       if ( using_dummy && ( child->name() == "interface" || child->name() == "inputdevice" || child->name() == "outputdevice" ))
+                               continue;
                        error << string_compose (_("AudioSetup value for %1 is missing data"), child->name()) << endmsg;
                        continue;
                }