diff options
-rw-r--r-- | gtk2_ardour/ardev_common.sh.in | 1 | ||||
-rw-r--r-- | gtk2_ardour/ardour_ui.cc | 1 | ||||
-rw-r--r-- | gtk2_ardour/engine_dialog.cc | 877 | ||||
-rw-r--r-- | gtk2_ardour/engine_dialog.h | 135 | ||||
-rw-r--r-- | libs/ardour/ardour/audio_backend.h | 31 | ||||
-rw-r--r-- | libs/ardour/ardour/audioengine.h | 10 | ||||
-rw-r--r-- | libs/ardour/ardour/jack_audiobackend.h | 6 | ||||
-rw-r--r-- | libs/ardour/audioengine.cc | 12 | ||||
-rw-r--r-- | libs/ardour/jack_api.cc | 7 | ||||
-rw-r--r-- | libs/ardour/jack_audiobackend.cc | 24 |
10 files changed, 236 insertions, 868 deletions
diff --git a/gtk2_ardour/ardev_common.sh.in b/gtk2_ardour/ardev_common.sh.in index 897bfcf7c2..2bd9c51515 100644 --- a/gtk2_ardour/ardev_common.sh.in +++ b/gtk2_ardour/ardev_common.sh.in @@ -17,6 +17,7 @@ export ARDOUR_DATA_PATH=$TOP:$TOP/build:$TOP/gtk2_ardour:$TOP/build/gtk2_ardour: export ARDOUR_MIDIMAPS_PATH=$TOP/midi_maps:. export ARDOUR_MCP_PATH=$TOP/mcp:. export ARDOUR_EXPORT_FORMATS_PATH=$TOP/export:. +export ARDOUR_BACKEND_PATH=$TOP/build/libs/ardour # # even though we set the above variables, ardour requires that these diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 7e6ce10300..fca86c585b 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -397,7 +397,6 @@ ARDOUR_UI::attach_to_engine () engine->SampleRateChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::update_sample_rate, this, _1), gui_context()); engine->Halted.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::engine_halted, this, _1, false)); - engine->BackendAvailable.connect_same_thread (forever_connections, boost::bind (&ARDOUR_UI::post_engine, this)); ARDOUR::Port::set_connecting_blocked (ARDOUR_COMMAND_LINE::no_connect_ports); diff --git a/gtk2_ardour/engine_dialog.cc b/gtk2_ardour/engine_dialog.cc index b52d3a7a15..b4e5c72050 100644 --- a/gtk2_ardour/engine_dialog.cc +++ b/gtk2_ardour/engine_dialog.cc @@ -66,33 +66,25 @@ using namespace PBD; using namespace Glib; EngineControl::EngineControl () - : periods_adjustment (2, 2, 16, 1, 2), - periods_spinner (periods_adjustment), - ports_adjustment (128, 8, 1024, 1, 16), - ports_spinner (ports_adjustment), - input_latency_adjustment (0, 0, 99999, 1), - input_latency (input_latency_adjustment), - output_latency_adjustment (0, 0, 99999, 1), - output_latency (output_latency_adjustment), - realtime_button (_("Realtime")), - no_memory_lock_button (_("Do not lock memory")), - unlock_memory_button (_("Unlock memory")), - soft_mode_button (_("No zombies")), - monitor_button (_("Provide monitor ports")), - force16bit_button (_("Force 16 bit")), - hw_monitor_button (_("H/W monitoring")), - hw_meter_button (_("H/W metering")), - verbose_output_button (_("Verbose output")), - start_button (_("Start")), - stop_button (_("Stop")), + : input_latency_adjustment (0, 0, 99999, 1) + , input_latency (input_latency_adjustment) + , output_latency_adjustment (0, 0, 99999, 1) + , output_latency (output_latency_adjustment) + , input_channels_adjustment (2, 0, 256, 1) + , input_channels (input_channels_adjustment) + , output_channels_adjustment (2, 0, 256, 1) + , output_channels (output_channels_adjustment) + , ports_adjustment (128, 8, 1024, 1, 16) + , ports_spinner (ports_adjustment) + , realtime_button (_("Realtime")) #ifdef __APPLE___ - basic_packer (5, 2), - options_packer (4, 2), - device_packer (4, 2) + , basic_packer (6, 2) + , options_packer (4, 2) + , device_packer (4, 2) #else - basic_packer (8, 2), - options_packer (14, 2), - device_packer (6, 2) + , basic_packer (9, 2) + , options_packer (14, 2) + , device_packer (6, 2) #endif { using namespace Notebook_Helpers; @@ -102,59 +94,24 @@ EngineControl::EngineControl () _used = false; - strings.push_back (_("8000Hz")); - strings.push_back (_("22050Hz")); - strings.push_back (_("44100Hz")); - strings.push_back (_("48000Hz")); - strings.push_back (_("88200Hz")); - strings.push_back (_("96000Hz")); - strings.push_back (_("192000Hz")); - set_popdown_strings (sample_rate_combo, strings); - sample_rate_combo.set_active_text ("48000Hz"); + /* basic parameters */ - strings.clear (); - strings.push_back ("32"); - strings.push_back ("64"); - strings.push_back ("128"); - strings.push_back ("256"); - strings.push_back ("512"); - strings.push_back ("1024"); - strings.push_back ("2048"); - strings.push_back ("4096"); - strings.push_back ("8192"); - set_popdown_strings (period_size_combo, strings); - period_size_combo.set_active_text ("1024"); + basic_packer.set_spacings (6); strings.clear (); - strings.push_back (_("None")); - strings.push_back (_("Triangular")); - strings.push_back (_("Rectangular")); - strings.push_back (_("Shaped")); - set_popdown_strings (dither_mode_combo, strings); - dither_mode_combo.set_active_text (_("None")); - /* basic parameters */ + vector<const ARDOUR::AudioBackendInfo*> backends = ARDOUR::AudioEngine::instance()->available_backends(); + for (vector<const ARDOUR::AudioBackendInfo*>::const_iterator b = backends.begin(); b != backends.end(); ++b) { + strings.push_back ((*b)->name); + } - basic_packer.set_spacings (6); + set_popdown_strings (backend_combo, strings); + backend_combo.set_active_text (strings.front()); - strings.clear (); -#ifdef __APPLE__ - strings.push_back (X_("CoreAudio")); -#else -#ifndef __FreeBSD__ - strings.push_back (X_("ALSA")); -#endif - strings.push_back (X_("OSS")); - strings.push_back (X_("FreeBoB")); - strings.push_back (X_("FFADO")); -#endif - strings.push_back (X_("NetJACK")); - strings.push_back (X_("Dummy")); - set_popdown_strings (driver_combo, strings); - driver_combo.set_active_text (strings.front()); + backend_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::backend_changed)); + backend_changed (); driver_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::driver_changed)); - driver_changed (); strings.clear (); strings.push_back (_("Playback/recording on 1 device")); @@ -176,6 +133,11 @@ EngineControl::EngineControl () row = 0; + label = manage (left_aligned_label (_("Audio Driver:"))); + basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + basic_packer.attach (backend_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); + row++; + label = manage (left_aligned_label (_("Driver:"))); basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); basic_packer.attach (driver_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); @@ -193,16 +155,8 @@ EngineControl::EngineControl () label = manage (left_aligned_label (_("Buffer size:"))); basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - basic_packer.attach (period_size_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - row++; - -#if !defined(__APPLE__) && !defined(__FreeBSD__) - label = manage (left_aligned_label (_("Number of buffers:"))); - basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - basic_packer.attach (periods_spinner, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - periods_spinner.set_value (2); + basic_packer.attach (buffer_size_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); row++; -#endif label = manage (left_aligned_label (_("Approximate latency:"))); basic_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); @@ -210,8 +164,7 @@ EngineControl::EngineControl () row++; sample_rate_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::redisplay_latency)); - periods_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &EngineControl::redisplay_latency)); - period_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::redisplay_latency)); + buffer_size_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::redisplay_latency)); redisplay_latency(); row++; /* no audio mode with CoreAudio, its duplex or nuthin' */ @@ -227,22 +180,7 @@ EngineControl::EngineControl () input_device_combo.set_size_request (250, -1); output_device_combo.set_size_request (250, -1); - /* - - if (engine_running()) { - start_button.set_sensitive (false); - } else { - stop_button.set_sensitive (false); - } - - start_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::start_engine)); - stop_button.signal_clicked().connect (sigc::mem_fun (*this, &EngineControl::start_engine)); - */ - - button_box.pack_start (start_button, false, false); - button_box.pack_start (stop_button, false, false); - - // basic_packer.attach (button_box, 0, 2, 8, 9, FILL|EXPAND, (AttachOptions) 0); + interface_combo.signal_changed().connect (sigc::mem_fun (*this, &EngineControl::interface_changed)); /* options */ @@ -254,46 +192,6 @@ EngineControl::EngineControl () realtime_button.set_active (true); -#if PROVIDE_TOO_MANY_OPTIONS - -#if !defined(__APPLE__) && !defined(__FreeBSD__) - options_packer.attach (no_memory_lock_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - ++row; - options_packer.attach (unlock_memory_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - ++row; - options_packer.attach (soft_mode_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - ++row; - options_packer.attach (monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - ++row; - options_packer.attach (force16bit_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - ++row; - options_packer.attach (hw_monitor_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - ++row; - options_packer.attach (hw_meter_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - ++row; - options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - ++row; -#else - options_packer.attach (verbose_output_button, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - ++row; -#endif - - strings.clear (); - strings.push_back (_("Ignore")); - strings.push_back ("500 msec"); - strings.push_back ("1 sec"); - strings.push_back ("2 sec"); - strings.push_back ("10 sec"); - set_popdown_strings (timeout_combo, strings); - timeout_combo.set_active_text (strings.front ()); - - label = manage (new Label (_("Client timeout"))); - label->set_alignment (1.0, 0.5); - options_packer.attach (timeout_combo, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0)); - options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - ++row; - -#endif /* PROVIDE_TOO_MANY_OPTIONS */ label = manage (left_aligned_label (_("Number of ports:"))); options_packer.attach (ports_spinner, 1, 2, row, row + 1, FILL|EXPAND, AttachOptions(0)); options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); @@ -311,23 +209,6 @@ EngineControl::EngineControl () ++row; #endif - find_jack_servers (server_strings); - - if (server_strings.empty()) { - fatal << _("No JACK server found anywhere on this system. Please install JACK and restart") << endmsg; - /*NOTREACHED*/ - } - - set_popdown_strings (serverpath_combo, server_strings); - serverpath_combo.set_active_text (server_strings.front()); - - if (server_strings.size() > 1) { - label = manage (left_aligned_label (_("Server:"))); - options_packer.attach (*label, 0, 1, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - options_packer.attach (serverpath_combo, 1, 2, row, row + 1, FILL|EXPAND, (AttachOptions) 0); - ++row; - } - /* device settings */ device_packer.set_spacings (6); @@ -386,514 +267,93 @@ EngineControl::~EngineControl () } void -EngineControl::build_command_line (vector<string>& cmd) +EngineControl::backend_changed () { - string str; - string driver; - bool using_alsa = false; - bool using_coreaudio = false; - bool using_dummy = false; - bool using_ffado = false; - - /* first, path to jackd */ - - cmd.push_back (serverpath_combo.get_active_text ()); - - /* now jackd arguments */ - - str = timeout_combo.get_active_text (); + string backend_name = backend_combo.get_active_text(); + boost::shared_ptr<ARDOUR::AudioBackend> backend; - if (str != _("Ignore")) { - - double secs = 0; - uint32_t msecs; - secs = atof (str); - msecs = (uint32_t) floor (secs * 1000.0); - - if (msecs > 0) { - cmd.push_back ("-t"); - cmd.push_back (to_string (msecs, std::dec)); - } - } - - if (no_memory_lock_button.get_active()) { - cmd.push_back ("-m"); /* no munlock */ + if (!(backend = ARDOUR::AudioEngine::instance()->set_backend (backend_name, "ardour", ""))) { + /* eh? */ + return; } - cmd.push_back ("-p"); /* port max */ - cmd.push_back (to_string ((uint32_t) floor (ports_spinner.get_value()), std::dec)); - - if (realtime_button.get_active()) { - cmd.push_back ("-R"); + if (backend->requires_driver_selection()) { + vector<string> drivers = backend->enumerate_drivers(); + set_popdown_strings (driver_combo, drivers); + driver_combo.set_active_text (drivers.front()); + driver_changed (); } else { - cmd.push_back ("-r"); /* override jackd's default --realtime */ - } - - if (unlock_memory_button.get_active()) { - cmd.push_back ("-u"); - } - - if (verbose_output_button.get_active()) { - cmd.push_back ("-v"); + list_devices (); } - - /* now add fixed arguments (not user-selectable) */ - - cmd.push_back ("-T"); // temporary */ - - /* next the driver */ - - cmd.push_back ("-d"); - - driver = driver_combo.get_active_text (); - - if (driver == X_("ALSA")) { - using_alsa = true; - cmd.push_back ("alsa"); - } else if (driver == X_("OSS")) { - cmd.push_back ("oss"); - } else if (driver == X_("CoreAudio")) { - using_coreaudio = true; - cmd.push_back ("coreaudio"); - } else if (driver == X_("NetJACK")) { - cmd.push_back ("netjack"); - } else if (driver == X_("FreeBoB")) { - cmd.push_back ("freebob"); - } else if (driver == X_("FFADO")) { - using_ffado = true; - cmd.push_back ("firewire"); - } else if ( driver == X_("Dummy")) { - using_dummy = true; - cmd.push_back ("dummy"); - } - - /* driver arguments */ - - if (!using_coreaudio) { - str = audio_mode_combo.get_active_text(); - - if (str == _("Playback/recording on 1 device")) { - - /* relax */ - - } 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 (input_device); - - cmd.push_back ("-P"); - 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)); - } - } - - cmd.push_back ("-r"); - cmd.push_back (to_string (get_rate(), std::dec)); - - cmd.push_back ("-p"); - cmd.push_back (period_size_combo.get_active_text()); - - if (using_alsa || using_ffado || using_coreaudio) { - - double val = input_latency_adjustment.get_value(); - - if (val) { - cmd.push_back ("-I"); - cmd.push_back (to_string ((uint32_t) val, std::dec)); - } - - val = output_latency_adjustment.get_value(); - - if (val) { - cmd.push_back ("-O"); - cmd.push_back (to_string ((uint32_t) val, std::dec)); - } - } - - 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 (device); - } - - if (hw_meter_button.get_active()) { - cmd.push_back ("-M"); - } - - if (hw_monitor_button.get_active()) { - cmd.push_back ("-H"); - } - - str = dither_mode_combo.get_active_text(); - - if (str == _("None")) { - } else if (str == _("Triangular")) { - cmd.push_back ("-z triangular"); - } else if (str == _("Rectangular")) { - cmd.push_back ("-z rectangular"); - } else if (str == _("Shaped")) { - cmd.push_back ("-z shaped"); - } - - if (force16bit_button.get_active()) { - cmd.push_back ("-S"); - } - - if (soft_mode_button.get_active()) { - cmd.push_back ("-s"); - } - - str = midi_driver_combo.get_active_text (); - - if (str == _("seq")) { - cmd.push_back ("-X seq"); - } else if (str == _("raw")) { - cmd.push_back ("-X raw"); - } - } else if (using_coreaudio) { - -#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 (device); -#endif - - } -} - -int -EngineControl::setup_engine () -{ - vector<string> args; - std::string cwd = "/tmp"; - - build_command_line (args); - - if (args.empty()) { - return 1; // try again - } - - std::string jackdrc_path = Glib::get_home_dir(); - jackdrc_path += "/.jackdrc"; - - ofstream jackdrc (jackdrc_path.c_str()); - if (!jackdrc) { - error << string_compose (_("cannot open JACK rc file %1 to store parameters"), jackdrc_path) << endmsg; - return -1; - } - - for (vector<string>::iterator i = args.begin(); i != args.end(); ++i) { - jackdrc << (*i) << ' '; - } - - jackdrc << endl; - jackdrc.close (); - - _used = true; - - return 0; } void -EngineControl::enumerate_devices (const string& driver) -{ - /* note: case matters for the map keys */ - - if (driver == "CoreAudio") { -#ifdef __APPLE__ - devices[driver] = enumerate_coreaudio_devices (); -#endif - -#if !defined(__APPLE__) && !defined(__FreeBSD__) - } else if (driver == "ALSA") { - devices[driver] = enumerate_alsa_devices (); - } else if (driver == "FreeBOB") { - devices[driver] = enumerate_freebob_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 - } -#endif -} - -#ifdef __APPLE__ -static OSStatus -getDeviceUIDFromID( AudioDeviceID id, char *name, size_t nsize) -{ - UInt32 size = sizeof(CFStringRef); - CFStringRef UI; - OSStatus res = AudioDeviceGetProperty(id, 0, false, - kAudioDevicePropertyDeviceUID, &size, &UI); - if (res == noErr) - CFStringGetCString(UI,name,nsize,CFStringGetSystemEncoding()); - CFRelease(UI); - return res; -} - -vector<string> -EngineControl::enumerate_coreaudio_devices () -{ - vector<string> devs; - - // Find out how many Core Audio devices are there, if any... - // (code snippet gently "borrowed" from St?hane Letz jackdmp;) - OSStatus err; - Boolean isWritable; - UInt32 outSize = sizeof(isWritable); - - backend_devs.clear (); - - err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, - &outSize, &isWritable); - if (err == noErr) { - // Calculate the number of device available... - int numCoreDevices = outSize / sizeof(AudioDeviceID); - // Make space for the devices we are about to get... - AudioDeviceID *coreDeviceIDs = new AudioDeviceID [numCoreDevices]; - err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, - &outSize, (void *) coreDeviceIDs); - if (err == noErr) { - // Look for the CoreAudio device name... - char coreDeviceName[256]; - UInt32 nameSize; - - for (int i = 0; i < numCoreDevices; i++) { - - nameSize = sizeof (coreDeviceName); - - /* enforce duplex devices only */ - - err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i], - 0, true, kAudioDevicePropertyStreams, - &outSize, &isWritable); - - if (err != noErr || outSize == 0) { - continue; - } - - err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i], - 0, false, kAudioDevicePropertyStreams, - &outSize, &isWritable); - - if (err != noErr || outSize == 0) { - continue; - } - - err = AudioDeviceGetPropertyInfo(coreDeviceIDs[i], - 0, true, kAudioDevicePropertyDeviceName, - &outSize, &isWritable); - if (err == noErr) { - err = AudioDeviceGetProperty(coreDeviceIDs[i], - 0, true, kAudioDevicePropertyDeviceName, - &nameSize, (void *) coreDeviceName); - if (err == noErr) { - char drivername[128]; - - // this returns the unique id for the device - // that must be used on the commandline for jack - - if (getDeviceUIDFromID(coreDeviceIDs[i], drivername, sizeof (drivername)) == noErr) { - devs.push_back (coreDeviceName); - backend_devs.push_back (drivername); - } - } - } - } - } - delete [] coreDeviceIDs; - } - - - if (devs.size() == 0) { - MessageDialog msg (string_compose (_("\ -You do not have any audio devices capable of\n\ -simultaneous playback and recording.\n\n\ -Please use Applications -> Utilities -> Audio MIDI Setup\n\ -to create an \"aggregrate\" device, or install a suitable\n\ -audio interface.\n\n\ -Please send email to Apple and ask them why new Macs\n\ -have no duplex audio device.\n\n\ -Alternatively, if you really want just playback\n\ -or recording but not both, start JACK before running\n\ -%1 and choose the relevant device then." - ), PROGRAM_NAME), - true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK); - msg.set_title (_("No suitable audio devices")); - msg.set_position (Gtk::WIN_POS_MOUSE); - msg.run (); - exit (1); - } - - - return devs; -} -#else - -#if !defined(__FreeBSD__) -vector<string> -EngineControl::enumerate_alsa_devices () +EngineControl::list_devices () { - vector<string> devs; - - 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; - - backend_devs.clear (); - - while (snd_card_next (&cardnum) >= 0 && cardnum >= 0) { - - devname = "hw:"; - devname += to_string (cardnum, std::dec); - - if (snd_ctl_open (&handle, devname.c_str(), 0) >= 0 && snd_ctl_card_info (handle, info) >= 0) { - - while (snd_ctl_pcm_next_device (handle, &device) >= 0 && device >= 0) { + boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend(); + assert (backend); - 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) { - devs.push_back (snd_pcm_info_get_name (pcminfo)); - devname += ','; - devname += to_string (device, std::dec); - backend_devs.push_back (devname); - } - } - - snd_ctl_close(handle); - } - } - - return devs; -} -#endif - -vector<string> -EngineControl::enumerate_ffado_devices () -{ - vector<string> devs; - backend_devs.clear (); - return devs; + /* now fill out devices, mark sample rates, buffer sizes insensitive */ + + vector<string> devices = backend->enumerate_devices (); + + set_popdown_strings (interface_combo, devices); + interface_combo.set_active_text (devices.front()); + set_popdown_strings (input_device_combo, devices); + input_device_combo.set_active_text (devices.front()); + set_popdown_strings (output_device_combo, devices); + output_device_combo.set_active_text (devices.front()); + + interface_changed (); } - -vector<string> -EngineControl::enumerate_freebob_devices () + +void +EngineControl::driver_changed () { - vector<string> devs; - return devs; -} + boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend(); + assert (backend); -vector<string> -EngineControl::enumerate_oss_devices () -{ - vector<string> devs; - return devs; -} -vector<string> -EngineControl::enumerate_dummy_devices () -{ - vector<string> devs; - return devs; -} -vector<string> -EngineControl::enumerate_netjack_devices () -{ - vector<string> devs; - return devs; + backend->set_driver (driver_combo.get_active_text()); + list_devices (); } -#endif void -EngineControl::driver_changed () +EngineControl::interface_changed () { - string driver = driver_combo.get_active_text(); - string::size_type maxlen = 0; - int n = 0; - - enumerate_devices (driver); - - vector<string>& strings = devices[driver]; - - if (strings.empty() && driver != "FreeBoB" && driver != "FFADO" && driver != "Dummy") { - return; - } - - for (vector<string>::iterator i = strings.begin(); i != strings.end(); ++i, ++n) { - if ((*i).length() > maxlen) { - maxlen = (*i).length(); + boost::shared_ptr<ARDOUR::AudioBackend> backend = ARDOUR::AudioEngine::instance()->current_backend(); + assert (backend); + string device_name = interface_combo.get_active_text (); + vector<string> s; + + /* sample rates */ + + vector<float> sr = backend->available_sample_rates (device_name); + for (vector<float>::const_iterator x = sr.begin(); x != sr.end(); ++x) { + char buf[32]; + if (fmod (*x, 1000.0f)) { + snprintf (buf, sizeof (buf), "%.1f kHz", (*x)/1000.0); + } else { + snprintf (buf, sizeof (buf), "%.0f kHz", (*x)/1000.0); } + s.push_back (buf); } - set_popdown_strings (interface_combo, strings); - set_popdown_strings (input_device_combo, strings); - set_popdown_strings (output_device_combo, strings); + set_popdown_strings (sample_rate_combo, s); + sample_rate_combo.set_active_text (s.front()); - if (!strings.empty()) { - interface_combo.set_active_text (strings.front()); - input_device_combo.set_active_text (strings.front()); - output_device_combo.set_active_text (strings.front()); - } + /* buffer sizes */ - if (driver == "ALSA") { - soft_mode_button.set_sensitive (true); - force16bit_button.set_sensitive (true); - hw_monitor_button.set_sensitive (true); - hw_meter_button.set_sensitive (true); - monitor_button.set_sensitive (true); - } else { - soft_mode_button.set_sensitive (false); - force16bit_button.set_sensitive (false); - hw_monitor_button.set_sensitive (false); - hw_meter_button.set_sensitive (false); - monitor_button.set_sensitive (false); + s.clear (); + vector<uint32_t> bs = backend->available_buffer_sizes(device_name); + for (vector<uint32_t>::const_iterator x = bs.begin(); x != bs.end(); ++x) { + char buf[32]; + snprintf (buf, sizeof (buf), "%u", *x); + s.push_back (buf); } -} + + set_popdown_strings (buffer_size_combo, s); + buffer_size_combo.set_active_text (s.front()); +} uint32_t EngineControl::get_rate () @@ -912,15 +372,10 @@ void EngineControl::redisplay_latency () { uint32_t rate = get_rate(); -#if defined(__APPLE__) || defined(__FreeBSD__) - float periods = 2; -#else - float periods = periods_adjustment.get_value(); -#endif - float period_size = atof (period_size_combo.get_active_text()); + float period_size = atof (buffer_size_combo.get_active_text()); char buf[32]; - snprintf (buf, sizeof(buf), "%.1fmsec", (periods * period_size) / (rate/1000.0)); + snprintf (buf, sizeof(buf), "%.1fmsec", (2 * period_size) / (rate/1000.0)); latency_label.set_text (buf); latency_label.set_alignment (0, 0.5); @@ -946,127 +401,6 @@ EngineControl::audio_mode_changed () } } -static bool jack_server_filter(const string& str, void */*arg*/) -{ - return str == "jackd" || str == "jackdmp"; -} - -void -EngineControl::find_jack_servers (vector<string>& strings) -{ -#ifdef __APPLE__ - /* this magic lets us finds the path to the OSX bundle, and then - we infer JACK's location from there - */ - - char execpath[MAXPATHLEN+1]; - uint32_t pathsz = sizeof (execpath); - - _NSGetExecutablePath (execpath, &pathsz); - - string path (Glib::path_get_dirname (execpath)); - path += "/jackd"; - - if (Glib::file_test (path, FILE_TEST_EXISTS)) { - strings.push_back (path); - } - - if (getenv ("ARDOUR_WITH_JACK")) { - /* no other options - only use the JACK we supply */ - if (strings.empty()) { - fatal << string_compose (_("JACK appears to be missing from the %1 bundle"), PROGRAM_NAME) << endmsg; - /*NOTREACHED*/ - } - return; - } -#else - string path; -#endif - - PathScanner scanner; - vector<string *> *jack_servers; - std::map<string,int> un; - 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); - if (!jack_servers) { - return; - } - - vector<string *>::iterator iter; - - for (iter = jack_servers->begin(); iter != jack_servers->end(); iter++) { - string p = **iter; - - if (un[p]++ == 0) { - strings.push_back(p); - } - } -} - - -string -EngineControl::get_device_name (const string& driver, const string& human_readable) -{ - 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.set_position (WIN_POS_MOUSE); - msg.run (); - return string(); - } - - if (backend_devs.empty()) { - return human_readable; - } - - for (i = devices[driver].begin(), n = backend_devs.begin(); i != devices[driver].end(); ++i, ++n) { - if (human_readable == (*i)) { - return (*n); - } - } - - if (i == devices[driver].end()) { - warning << string_compose (_("Audio device \"%1\" not known on this computer."), human_readable) << endmsg; - } - - return string(); -} - XMLNode& EngineControl::get_state () { @@ -1074,6 +408,7 @@ EngineControl::get_state () XMLNode* child; std::string path; +#if 0 child = new XMLNode ("periods"); child->add_property ("val", to_string (periods_adjustment.get_value(), std::dec)); root->add_child_nocopy (*child); @@ -1165,7 +500,7 @@ EngineControl::get_state () child = new XMLNode ("mididriver"); child->add_property ("val", midi_driver_combo.get_active_text()); root->add_child_nocopy (*child); - +#endif return *root; } @@ -1181,7 +516,7 @@ EngineControl::set_state (const XMLNode& root) int val; string strval; - +#if 0 if ( (child = root.child ("driver"))){ prop = child->property("val"); @@ -1316,4 +651,10 @@ EngineControl::set_state (const XMLNode& root) midi_driver_combo.set_active_text(strval); } } +#endif +} + +int +EngineControl::setup_engine () +{ } diff --git a/gtk2_ardour/engine_dialog.h b/gtk2_ardour/engine_dialog.h index 0d7ce29b46..ac96fbc520 100644 --- a/gtk2_ardour/engine_dialog.h +++ b/gtk2_ardour/engine_dialog.h @@ -47,80 +47,67 @@ class EngineControl : public Gtk::VBox { void set_state (const XMLNode&); private: - Gtk::Adjustment periods_adjustment; - Gtk::SpinButton periods_spinner; - Gtk::Adjustment ports_adjustment; - Gtk::SpinButton ports_spinner; - Gtk::Adjustment input_latency_adjustment; - Gtk::SpinButton input_latency; - Gtk::Adjustment output_latency_adjustment; - Gtk::SpinButton output_latency; - Gtk::Label latency_label; - - Gtk::CheckButton realtime_button; - Gtk::CheckButton no_memory_lock_button; - Gtk::CheckButton unlock_memory_button; - Gtk::CheckButton soft_mode_button; - Gtk::CheckButton monitor_button; - Gtk::CheckButton force16bit_button; - Gtk::CheckButton hw_monitor_button; - Gtk::CheckButton hw_meter_button; - Gtk::CheckButton verbose_output_button; - - Gtk::Button start_button; - Gtk::Button stop_button; - Gtk::HButtonBox button_box; - - Gtk::ComboBoxText sample_rate_combo; - Gtk::ComboBoxText period_size_combo; - - Gtk::ComboBoxText preset_combo; - Gtk::ComboBoxText serverpath_combo; - Gtk::ComboBoxText driver_combo; - Gtk::ComboBoxText interface_combo; - Gtk::ComboBoxText timeout_combo; - Gtk::ComboBoxText dither_mode_combo; - Gtk::ComboBoxText audio_mode_combo; - Gtk::ComboBoxText input_device_combo; - Gtk::ComboBoxText output_device_combo; - Gtk::ComboBoxText midi_driver_combo; - - Gtk::Table basic_packer; - Gtk::Table options_packer; - Gtk::Table device_packer; - Gtk::HBox basic_hbox; - Gtk::HBox options_hbox; - Gtk::HBox device_hbox; - Gtk::Notebook notebook; - - bool _used; - - static bool engine_running (); - - void driver_changed (); - void build_command_line (std::vector<std::string>&); - - std::map<std::string,std::vector<std::string> > devices; - std::vector<std::string> backend_devs; - void enumerate_devices (const std::string& driver); - -#ifdef __APPLE__ - std::vector<std::string> enumerate_coreaudio_devices (); -#else - std::vector<std::string> enumerate_alsa_devices (); - std::vector<std::string> enumerate_oss_devices (); - std::vector<std::string> enumerate_netjack_devices (); - std::vector<std::string> enumerate_freebob_devices (); - std::vector<std::string> enumerate_ffado_devices (); - std::vector<std::string> enumerate_dummy_devices (); -#endif - - void redisplay_latency (); - uint32_t get_rate(); - void audio_mode_changed (); - std::vector<std::string> server_strings; - void find_jack_servers (std::vector<std::string>&); - std::string get_device_name (const std::string& driver, const std::string& human_readable_name); + /* core fields used by all backends */ + + Gtk::ComboBoxText backend_combo; + Gtk::ComboBoxText input_device_combo; + Gtk::ComboBoxText output_device_combo; + Gtk::ComboBoxText sample_rate_combo; + Gtk::ComboBoxText buffer_size_combo; + Gtk::Adjustment input_latency_adjustment; + Gtk::SpinButton input_latency; + Gtk::Adjustment output_latency_adjustment; + Gtk::SpinButton output_latency; + Gtk::Adjustment input_channels_adjustment; + Gtk::SpinButton input_channels; + Gtk::Adjustment output_channels_adjustment; + Gtk::SpinButton output_channels; + Gtk::Adjustment ports_adjustment; + Gtk::SpinButton ports_spinner; + Gtk::Label latency_label; + + /* JACK specific */ + + Gtk::CheckButton realtime_button; + Gtk::CheckButton no_memory_lock_button; + Gtk::CheckButton unlock_memory_button; + Gtk::CheckButton soft_mode_button; + Gtk::CheckButton monitor_button; + Gtk::CheckButton force16bit_button; + Gtk::CheckButton hw_monitor_button; + Gtk::CheckButton hw_meter_button; + Gtk::CheckButton verbose_output_button; + + + Gtk::ComboBoxText preset_combo; + Gtk::ComboBoxText serverpath_combo; + Gtk::ComboBoxText driver_combo; + Gtk::ComboBoxText interface_combo; + Gtk::ComboBoxText timeout_combo; + Gtk::ComboBoxText dither_mode_combo; + Gtk::ComboBoxText audio_mode_combo; + Gtk::ComboBoxText midi_driver_combo; + + Gtk::Table basic_packer; + Gtk::Table options_packer; + Gtk::Table device_packer; + Gtk::HBox basic_hbox; + Gtk::HBox options_hbox; + Gtk::HBox device_hbox; + Gtk::Notebook notebook; + + bool _used; + + static bool engine_running (); + + void driver_changed (); + void backend_changed (); + + void redisplay_latency (); + uint32_t get_rate(); + void audio_mode_changed (); + void interface_changed (); + void list_devices (); }; #endif /* __gtk2_ardour_engine_dialog_h__ */ diff --git a/libs/ardour/ardour/audio_backend.h b/libs/ardour/ardour/audio_backend.h index 18c8cb8931..08dd7fb0b5 100644 --- a/libs/ardour/ardour/audio_backend.h +++ b/libs/ardour/ardour/audio_backend.h @@ -68,6 +68,33 @@ class AudioBackend { /* Discovering devices and parameters */ + /** Return true if this backend requires the selection of a "driver" + * before any device can be selected. Return false otherwise. + * + * Intended mainly to differentiate between meta-APIs like JACK + * which can still expose different backends (such as ALSA or CoreAudio + * or FFADO or netjack) and those like ASIO or CoreAudio which + * do not. + */ + virtual bool requires_driver_selection() const { return false; } + + /** If the return value of requires_driver_selection() is true, + * then this function can return the list of known driver names. + * + * If the return value of requires_driver_selection() is false, + * then this function should not be called. If it is called + * its return value is an empty vector of strings. + */ + virtual std::vector<std::string> enumerate_drivers() const { return std::vector<std::string>(); } + + /** Returns zero if the backend can successfully use @param name as the + * driver, non-zero otherwise. + * + * Should not be used unless the backend returns true from + * requires_driver_selection() + */ + virtual int set_driver (const std::string& /*drivername*/) { return 0; } + /** Returns a collection of strings identifying devices known * to this backend. Any of these strings may be used to identify a * device in other calls to the backend, though any of them may become @@ -358,8 +385,8 @@ struct AudioBackendInfo { * configured and does not need (re)configuration in order * to be usable. Return false otherwise. * - * Note that this may return true if (re)configuration is possible, - * but not required. + * Note that this may return true if (re)configuration, even though + * not currently required, is still possible. */ bool (*already_configured)(); }; diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index 5046206542..6fb13b7ae0 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -74,7 +74,8 @@ public: int discover_backends(); std::vector<const AudioBackendInfo*> available_backends() const; std::string current_backend_name () const; - int set_backend (const std::string&, const std::string& arg1, const std::string& arg2); + boost::shared_ptr<AudioBackend> set_backend (const std::string&, const std::string& arg1, const std::string& arg2); + boost::shared_ptr<AudioBackend> current_backend() const { return _backend; } bool setup_required () const; ProcessThread* main_thread() const { return _main_thread; } @@ -172,13 +173,6 @@ public: PBD::Signal0<void> Running; PBD::Signal0<void> Stopped; - /* these two are emitted as we create backends that - can actually be used to do stuff (e.g. register ports) - */ - - PBD::Signal0<void> BackendAvailable; - PBD::Signal0<void> BackendRemoved; - static AudioEngine* instance() { return _instance; } static void destroy(); void died (); diff --git a/libs/ardour/ardour/jack_audiobackend.h b/libs/ardour/ardour/jack_audiobackend.h index 4fef602119..59b5b88105 100644 --- a/libs/ardour/ardour/jack_audiobackend.h +++ b/libs/ardour/ardour/jack_audiobackend.h @@ -49,7 +49,12 @@ class JACKAudioBackend : public AudioBackend { bool connected() const; bool is_realtime () const; + bool requires_driver_selection() const; + std::vector<std::string> enumerate_drivers () const; + int set_driver (const std::string&); + std::vector<std::string> enumerate_devices () const; + std::vector<float> available_sample_rates (const std::string& device) const; std::vector<uint32_t> available_buffer_sizes (const std::string& device) const; uint32_t available_input_channel_count (const std::string& device) const; @@ -151,6 +156,7 @@ class JACKAudioBackend : public AudioBackend { /* pffooo */ + std::string _target_driver; std::string _target_device; float _target_sample_rate; uint32_t _target_buffer_size; diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index f9bdffb94b..0c88e7c0fd 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -561,18 +561,16 @@ AudioEngine::drop_backend () if (_backend) { _backend->stop (); _backend.reset (); - - BackendRemoved(); /* EMIT SIGNAL */ } } -int +boost::shared_ptr<AudioBackend> AudioEngine::set_backend (const std::string& name, const std::string& arg1, const std::string& arg2) { BackendMap::iterator b = _backends.find (name); if (b == _backends.end()) { - return -1; + return boost::shared_ptr<AudioBackend>(); } drop_backend (); @@ -590,12 +588,10 @@ AudioEngine::set_backend (const std::string& name, const std::string& arg1, cons } catch (exception& e) { error << string_compose (_("Could not create backend for %1: %2"), name, e.what()) << endmsg; - return -1; + return boost::shared_ptr<AudioBackend>(); } - BackendAvailable (); /* EMIT SIGNAL */ - - return 0; + return _backend; } /* BACKEND PROXY WRAPPERS */ diff --git a/libs/ardour/jack_api.cc b/libs/ardour/jack_api.cc index b6cf3693b5..fcfc499107 100644 --- a/libs/ardour/jack_api.cc +++ b/libs/ardour/jack_api.cc @@ -90,16 +90,13 @@ extern "C" { * must be non-mangled. */ - using namespace ARDOUR; - - AudioBackendInfo descriptor = { + ARDOUR::AudioBackendInfo descriptor = { "JACK", instantiate, deinstantiate, backend_factory, portengine_factory, - already_configured + already_configured, }; - } diff --git a/libs/ardour/jack_audiobackend.cc b/libs/ardour/jack_audiobackend.cc index ed412f3f5a..97031cfaff 100644 --- a/libs/ardour/jack_audiobackend.cc +++ b/libs/ardour/jack_audiobackend.cc @@ -88,11 +88,31 @@ JACKAudioBackend::is_realtime () const return jack_is_realtime (_priv_jack); } +bool +JACKAudioBackend::requires_driver_selection() const +{ + return true; +} + +vector<string> +JACKAudioBackend::enumerate_drivers () const +{ + vector<string> s; + get_jack_audio_driver_names (s); + return s; +} + +int +JACKAudioBackend::set_driver (const std::string& name) +{ + _target_driver = name; + return 0; +} + vector<string> JACKAudioBackend::enumerate_devices () const { - vector<string> devices; - return devices; + return get_jack_device_names_for_audio_driver (_target_driver); } vector<float> |