summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/JackDriver.cpp125
-rw-r--r--src/JackDriver.h48
-rw-r--r--src/Patchage.cpp214
-rw-r--r--src/Patchage.h20
-rw-r--r--src/patchage.glade381
5 files changed, 764 insertions, 24 deletions
diff --git a/src/JackDriver.cpp b/src/JackDriver.cpp
index 9bc837d..875f8f1 100644
--- a/src/JackDriver.cpp
+++ b/src/JackDriver.cpp
@@ -20,6 +20,8 @@
#include <iostream>
#include "config.h"
#include <jack/jack.h>
+#include <jack/statistics.h>
+#include <jack/thread.h>
#include "PatchageFlowCanvas.h"
#include "JackDriver.h"
#include "Patchage.h"
@@ -32,8 +34,11 @@ using namespace LibFlowCanvas;
JackDriver::JackDriver(Patchage* app)
-: m_app(app),
- m_client(NULL)
+: m_app(app)
+, m_client(NULL)
+, m_is_activated(false)
+, m_xruns(0)
+, m_xrun_delay(0)
{
m_last_pos.frame = 0;
m_last_pos.valid = (jack_position_bits_t)0;
@@ -60,19 +65,27 @@ JackDriver::attach(bool launch_daemon)
jack_options_t options = (!launch_daemon) ? JackNoStartServer : JackNullOption;
m_client = jack_client_open("Patchage", options, NULL);
if (m_client == NULL) {
- m_app->status_message("[JACK] Unable to attach");
+ m_app->status_message("[JACK] Unable to create client");
+ m_is_activated = false;
} else {
jack_set_error_function(error_cb);
jack_on_shutdown(m_client, jack_shutdown_cb, this);
jack_set_port_registration_callback(m_client, jack_port_registration_cb, this);
jack_set_graph_order_callback(m_client, jack_graph_order_cb, this);
+ jack_set_buffer_size_callback(m_client, jack_buffer_size_cb, this);
+ jack_set_xrun_callback(m_client, jack_xrun_cb, this);
m_is_dirty = true;
-
- jack_activate(m_client);
-
- signal_attached.emit();
- m_app->status_message("[JACK] Attached");
+ m_buffer_size = jack_get_buffer_size(m_client);
+
+ if (!jack_activate(m_client)) {
+ m_is_activated = true;
+ signal_attached.emit();
+ m_app->status_message("[JACK] Attached");
+ } else {
+ m_app->status_message("[JACK] ERROR: Failed to attach");
+ m_is_activated = false;
+ }
}
}
@@ -85,6 +98,7 @@ JackDriver::detach()
jack_client_close(m_client);
m_client = NULL;
destroy_all_ports();
+ m_is_activated = false;
signal_detached.emit();
m_app->status_message("[JACK] Detached");
}
@@ -144,7 +158,7 @@ JackDriver::create_port(boost::shared_ptr<PatchageModule> parent, jack_port_t* p
void
JackDriver::refresh()
{
- m_mutex.lock();
+ //m_mutex.lock();
if (m_client == NULL) {
// Shutdown
@@ -153,7 +167,7 @@ JackDriver::refresh()
signal_detached.emit();
}
m_is_dirty = false;
- m_mutex.unlock();
+ //m_mutex.unlock();
return;
}
@@ -266,7 +280,7 @@ JackDriver::refresh()
free(ports);
undirty();
- m_mutex.unlock();
+ //m_mutex.unlock();
}
@@ -331,6 +345,8 @@ JackDriver::jack_port_registration_cb(jack_port_id_t port_id, int /*registered*/
jack_port_t* const port = jack_port_by_id(me->m_client, port_id);
const string full_name = jack_port_name(port);
+
+ jack_reset_max_delayed_usecs(me->m_client);
//(me->m_mutex).lock();
@@ -353,6 +369,8 @@ JackDriver::jack_graph_order_cb(void* jack_driver)
JackDriver* me = reinterpret_cast<JackDriver*>(jack_driver);
assert(me->m_client);
+ jack_reset_max_delayed_usecs(me->m_client);
+
//(me->m_mutex).lock();
me->m_is_dirty = true;
//(me->m_mutex).unlock();
@@ -361,6 +379,47 @@ JackDriver::jack_graph_order_cb(void* jack_driver)
}
+int
+JackDriver::jack_buffer_size_cb(jack_nframes_t buffer_size, void* jack_driver)
+{
+ assert(jack_driver);
+ JackDriver* me = reinterpret_cast<JackDriver*>(jack_driver);
+ assert(me->m_client);
+
+ jack_reset_max_delayed_usecs(me->m_client);
+
+ //(me->m_mutex).lock();
+ me->m_buffer_size = buffer_size;
+ me->reset_xruns();
+ me->reset_delay();
+ //(me->m_mutex).unlock();
+
+ return 0;
+}
+
+
+int
+JackDriver::jack_xrun_cb(void* jack_driver)
+{
+ assert(jack_driver);
+ JackDriver* me = reinterpret_cast<JackDriver*>(jack_driver);
+ assert(me->m_client);
+
+ //(me->m_mutex).lock();
+ me->m_xruns++;
+ me->m_xrun_delay = jack_get_xrun_delayed_usecs(me->m_client);
+ jack_reset_max_delayed_usecs(me->m_client);
+
+ //cerr << "** XRUN Delay = " << me->m_xrun_delay << endl;
+
+ me->m_is_dirty = true;
+
+ //(me->m_mutex).unlock();
+
+ return 0;
+}
+
+
void
JackDriver::jack_shutdown_cb(void* jack_driver)
{
@@ -368,6 +427,8 @@ JackDriver::jack_shutdown_cb(void* jack_driver)
JackDriver* me = reinterpret_cast<JackDriver*>(jack_driver);
assert(me->m_client);
+ jack_reset_max_delayed_usecs(me->m_client);
+
//(me->m_mutex).lock();
me->m_client = NULL;
me->m_is_dirty = true;
@@ -382,3 +443,45 @@ JackDriver::error_cb(const char* msg)
}
+jack_nframes_t
+JackDriver::buffer_size()
+{
+ if (m_is_activated)
+ return m_buffer_size;
+ else
+ return jack_get_buffer_size(m_client);
+}
+
+
+void
+JackDriver::reset_xruns()
+{
+ m_xruns = 0;
+ m_xrun_delay = 0;
+}
+
+
+void
+JackDriver::set_buffer_size(jack_nframes_t size)
+{
+ if (m_client && jack_set_buffer_size(m_client, size))
+ m_app->status_message("[JACK] ERROR: Unable to set buffer size");
+}
+
+void
+JackDriver::set_realtime(bool /*realtime*/, int /*priority*/)
+{
+ /* need a jack_set_realtime, this doesn't make sense
+ pthread_t jack_thread = jack_client_thread_id(m_client);
+
+ if (realtime)
+ if (jack_acquire_real_time_scheduling(jack_thread, priority))
+ m_app->status_message("[JACK] ERROR: Unable to set real-time priority");
+ else
+ if (jack_drop_real_time_scheduling(jack_thread))
+ m_app->status_message("[JACK] ERROR: Unable to drop real-time priority");
+
+ cerr << "Set Jack realtime: " << realtime << endl;
+ */
+}
+
diff --git a/src/JackDriver.h b/src/JackDriver.h
index 01dc49d..c581df0 100644
--- a/src/JackDriver.h
+++ b/src/JackDriver.h
@@ -21,6 +21,7 @@
#include <string>
#include <boost/shared_ptr.hpp>
#include <jack/jack.h>
+#include <jack/statistics.h>
#include <raul/Mutex.h>
#include "Driver.h"
class Patchage;
@@ -46,6 +47,7 @@ public:
void detach();
bool is_attached() const { return (m_client != NULL); }
+ bool is_realtime() const { return m_client && jack_is_realtime(m_client); }
void refresh();
bool connect(boost::shared_ptr<PatchagePort> src,
@@ -57,6 +59,9 @@ public:
void start_transport() { jack_transport_start(m_client); }
void stop_transport() { jack_transport_stop(m_client); }
+ void reset_xruns();
+ void reset_delay() { jack_reset_max_delayed_usecs(m_client); }
+
void rewind_transport() {
jack_position_t zero;
zero.frame = 0;
@@ -64,18 +69,20 @@ public:
jack_transport_reposition(m_client, &zero);
}
+ //jack_client_t* client() { return m_client; }
+
+ jack_nframes_t buffer_size();
+ void set_buffer_size(jack_nframes_t size);
-private:
- Patchage* m_app;
+ inline float sample_rate() { return jack_get_sample_rate(m_client); }
- jack_client_t* m_client;
+ void set_realtime(bool realtime, int priority=80);
- Mutex m_mutex;
+ inline size_t xruns() { return m_xruns; }
- list<string> m_added_ports;
- list<string> m_removed_ports;
+ inline float max_delay() { return jack_get_max_delayed_usecs(m_client); }
- jack_position_t m_last_pos;
+private:
boost::shared_ptr<PatchagePort> create_port(boost::shared_ptr<PatchageModule> parent,
jack_port_t* port);
@@ -86,9 +93,30 @@ private:
void update_time();
- static void jack_port_registration_cb(jack_port_id_t port_id, int registered, void* controller);
- static int jack_graph_order_cb(void* controller);
- static void jack_shutdown_cb(void* controller);
+ static void jack_port_registration_cb(jack_port_id_t port_id, int registered, void* me);
+ static int jack_graph_order_cb(void* me);
+ static int jack_buffer_size_cb(jack_nframes_t buffer_size, void* me);
+ static int jack_xrun_cb(void* me);
+ static void jack_shutdown_cb(void* me);
+
+ Patchage* m_app;
+
+ jack_client_t* m_client;
+
+ bool m_is_activated;
+
+ //Mutex m_mutex;
+
+ list<string> m_added_ports;
+ list<string> m_removed_ports;
+
+ jack_position_t m_last_pos;
+
+ jack_nframes_t m_buffer_size;
+ size_t m_xruns;
+ float m_xrun_delay;
+
+ bool m_settings_changed;
};
diff --git a/src/Patchage.cpp b/src/Patchage.cpp
index b7e00ef..357f334 100644
--- a/src/Patchage.cpp
+++ b/src/Patchage.cpp
@@ -14,6 +14,7 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <cmath>
#include "Patchage.h"
#include "config.h"
#include <libgnomecanvasmm.h>
@@ -22,6 +23,7 @@
#include <pthread.h>
#include "StateManager.h"
#include "PatchageFlowCanvas.h"
+#include <jack/statistics.h>
#include "JackDriver.h"
#include "JackSettingsDialog.h"
#ifdef HAVE_LASH
@@ -34,6 +36,40 @@
// FIXME: include to avoid undefined reference to boost SP debug hooks stuff
#include <raul/SharedPtr.h>
+
+
+/* Gtk helpers (resize combo boxes) */
+
+static void
+gtkmm_get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
+ int& width,
+ int& height)
+{
+ Pango::Rectangle ink_rect = layout->get_ink_extents ();
+
+ width = (ink_rect.get_width() + PANGO_SCALE / 2) / PANGO_SCALE;
+ height = (ink_rect.get_height() + PANGO_SCALE / 2) / PANGO_SCALE;
+}
+
+static void
+gtkmm_set_width_for_given_text (Gtk::Widget &w, const gchar *text,
+ gint hpadding/*, gint vpadding*/)
+
+{
+ int old_width, old_height;
+ w.get_size_request(old_width, old_height);
+
+ int width, height;
+ w.ensure_style ();
+
+ gtkmm_get_ink_pixel_size (w.create_pango_layout (text), width, height);
+ w.set_size_request(width + hpadding, old_height);//height + vpadding);
+}
+
+/* end Gtk helpers */
+
+
+
Patchage::Patchage(int argc, char** argv)
: m_pane_closed(false),
m_update_pane_position(true),
@@ -122,7 +158,19 @@ Patchage::Patchage(int argc, char** argv)
xml->get_widget("stop_but", m_stop_button);
xml->get_widget("zoom_full_but", m_zoom_full_button);
xml->get_widget("zoom_normal_but", m_zoom_normal_button);
+ //xml->get_widget("main_statusbar", m_status_bar);
+ //xml->get_widget("main_load_progress", m_load_progress_bar);
+ xml->get_widget("main_jack_connect_toggle", m_jack_connect_toggle);
+ xml->get_widget("main_jack_realtime_check", m_jack_realtime_check);
+ xml->get_widget("main_buffer_size_combo", m_buffer_size_combo);
+ xml->get_widget("main_sample_rate_combo", m_sample_rate_combo);
+ xml->get_widget("main_xrun_progress", m_xrun_progress_bar);
+ xml->get_widget("main_xrun_counter", m_xrun_counter);
+ xml->get_widget("main_clear_load_button", m_clear_load_button);
+ gtkmm_set_width_for_given_text(*m_buffer_size_combo, "4096", 40);
+ gtkmm_set_width_for_given_text(*m_sample_rate_combo, "44.1", 40);
+
m_canvas_scrolledwindow->add(*m_canvas);
//m_canvas_scrolledwindow->signal_event().connect(sigc::mem_fun(m_canvas, &FlowCanvas::scroll_event_handler));
m_canvas->scroll_to(static_cast<int>(m_canvas->width()/2 - 320),
@@ -130,10 +178,18 @@ Patchage::Patchage(int argc, char** argv)
m_zoom_slider->signal_value_changed().connect(sigc::mem_fun(this, &Patchage::zoom_changed));
+ m_jack_connect_toggle->signal_toggled().connect(sigc::mem_fun(this, &Patchage::jack_connect_changed));
+
+ m_buffer_size_combo->signal_changed().connect(sigc::mem_fun(this, &Patchage::buffer_size_changed));
+ m_sample_rate_combo->signal_changed().connect(sigc::mem_fun(this, &Patchage::sample_rate_changed));
+ m_jack_realtime_check->signal_toggled().connect(sigc::mem_fun(this, &Patchage::realtime_changed));
+
m_rewind_button->signal_clicked().connect(sigc::mem_fun(m_jack_driver, &JackDriver::rewind_transport));
m_play_button->signal_clicked().connect(sigc::mem_fun(m_jack_driver, &JackDriver::start_transport));
m_stop_button->signal_clicked().connect(sigc::mem_fun(m_jack_driver, &JackDriver::stop_transport));
+ m_clear_load_button->signal_clicked().connect(sigc::mem_fun(this, &Patchage::clear_load));
+
m_zoom_normal_button->signal_clicked().connect(sigc::bind(
sigc::mem_fun(this, &Patchage::zoom), 1.0));
@@ -165,7 +221,7 @@ Patchage::Patchage(int argc, char** argv)
m_menu_view_messages->signal_toggled().connect( sigc::mem_fun(this, &Patchage::show_messages_toggled));
m_menu_help_about->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_help_about));
- attach_menu_items();
+ connect_widgets();
update_state();
@@ -189,6 +245,9 @@ Patchage::Patchage(int argc, char** argv)
// Idle callback, check if we need to refresh
Glib::signal_timeout().connect(sigc::mem_fun(this, &Patchage::idle_callback), 100);
+
+ // Faster idle callback to update DSP load progress bar
+ //Glib::signal_timeout().connect(sigc::mem_fun(this, &Patchage::update_load), 50);
}
@@ -218,6 +277,10 @@ Patchage::attach()
#endif
menu_view_refresh();
+
+ update_toolbar();
+
+ //m_status_bar->push("Connected to JACK server");
}
@@ -250,6 +313,76 @@ Patchage::idle_callback()
m_refresh = false;
}
+ update_load();
+
+ return true;
+}
+
+
+void
+Patchage::update_toolbar()
+{
+ m_jack_connect_toggle->set_active(m_jack_driver->is_attached());
+ m_jack_realtime_check->set_active(m_jack_driver->is_realtime());
+
+ if (m_jack_driver->is_attached()) {
+ m_buffer_size_combo->set_active((int)log2f(m_jack_driver->buffer_size()) - 5);
+
+ switch ((int)m_jack_driver->sample_rate()) {
+ case 44100:
+ m_sample_rate_combo->set_active(0);
+ break;
+ case 48000:
+ m_sample_rate_combo->set_active(1);
+ break;
+ case 96000:
+ m_sample_rate_combo->set_active(2);
+ break;
+ default:
+ m_sample_rate_combo->set_active(-1);
+ status_message("[JACK] ERROR: Unknown sample rate");
+ break;
+ }
+ }
+}
+
+
+bool
+Patchage::update_load()
+{
+ if (!m_jack_driver->is_attached())
+ return true;
+
+ static float last_delay = 0;
+
+ const float max_delay = m_jack_driver->max_delay();
+
+ if (max_delay != last_delay) {
+ const float sample_rate = m_jack_driver->sample_rate();
+ const float buffer_size = m_jack_driver->buffer_size();
+ const float period = buffer_size / sample_rate * 1000000; // usecs
+ /*
+ if (max_delay > 0) {
+ cerr << "SR: " << sample_rate << ", BS: " << buffer_size << ", P = " << period
+ << ", MD: " << max_delay << endl;
+ }*/
+
+ m_xrun_progress_bar->set_fraction(max_delay / period);
+
+ char tmp_buf[8];
+ snprintf(tmp_buf, 8, "%zd", m_jack_driver->xruns());
+
+ //m_xrun_progress_bar->set_text(string(tmp_buf) + " XRuns");
+ m_xrun_counter->set_text(tmp_buf);
+
+ if (max_delay > period) {
+ m_xrun_progress_bar->set_fraction(1.0);
+ m_jack_driver->reset_delay();
+ }
+
+ last_delay = max_delay;
+ }
+
return true;
}
@@ -312,7 +445,7 @@ Patchage::status_message(const string& msg)
* (eg. disable "Connect to Jack" when Patchage is already connected to Jack)
*/
void
-Patchage::attach_menu_items()
+Patchage::connect_widgets()
{
#ifdef HAVE_LASH
m_lash_driver->signal_attached.connect(sigc::bind(
@@ -330,6 +463,12 @@ Patchage::attach_menu_items()
sigc::mem_fun(m_menu_lash_disconnect, &Gtk::MenuItem::set_sensitive), false));
#endif
+ m_jack_driver->signal_attached.connect(
+ sigc::mem_fun(this, &Patchage::update_toolbar));
+
+ m_jack_driver->signal_attached.connect(sigc::bind(
+ sigc::mem_fun(m_jack_connect_toggle, &Gtk::ToggleButton::set_active), true));
+
m_jack_driver->signal_attached.connect(sigc::bind(
sigc::mem_fun(m_menu_jack_launch, &Gtk::MenuItem::set_sensitive), false));
m_jack_driver->signal_attached.connect(sigc::bind(
@@ -338,6 +477,8 @@ Patchage::attach_menu_items()
sigc::mem_fun(m_menu_jack_disconnect, &Gtk::MenuItem::set_sensitive), true));
m_jack_driver->signal_detached.connect(sigc::bind(
+ sigc::mem_fun(m_jack_connect_toggle, &Gtk::ToggleButton::set_active), false));
+ m_jack_driver->signal_detached.connect(sigc::bind(
sigc::mem_fun(m_menu_jack_launch, &Gtk::MenuItem::set_sensitive), true));
m_jack_driver->signal_detached.connect(sigc::bind(
sigc::mem_fun(m_menu_jack_connect, &Gtk::MenuItem::set_sensitive), true));
@@ -518,3 +659,72 @@ Patchage::store_window_location()
}
+void
+Patchage::clear_load()
+{
+ cerr << "CLEAR LOAD\n";
+ m_xrun_progress_bar->set_fraction(0.0);
+ m_jack_driver->reset_xruns();
+ m_jack_driver->reset_delay();
+}
+
+
+void
+Patchage::buffer_size_changed()
+{
+ const int selected = m_buffer_size_combo->get_active_row_number();
+
+ if (selected == -1) {
+ update_toolbar();
+ } else {
+ jack_nframes_t buffer_size = 1 << (selected+5);
+
+ //cerr << "BS Changed: " << selected << ": " << buffer_size << endl;
+
+ m_jack_driver->set_buffer_size(buffer_size);
+ }
+}
+
+
+void
+Patchage::sample_rate_changed()
+{
+ const int selected = m_sample_rate_combo->get_active_row_number();
+
+ if (selected == -1) {
+ update_toolbar();
+ } else {
+ jack_nframes_t rate = 44100; // selected == 0
+ if (selected == 1)
+ rate = 48000;
+ else if (selected == 2)
+ rate = 96000;
+
+ //cerr << "SR Changed: " << selected << ": " << rate << endl;
+
+ //m_jack_driver->set_sample_rate(rate);
+ }
+}
+
+
+void
+Patchage::realtime_changed()
+{
+ m_jack_driver->set_realtime(m_jack_realtime_check->get_active());
+}
+
+
+void
+Patchage::jack_connect_changed()
+{
+ const bool selected = m_jack_connect_toggle->get_active();
+
+ if (selected != m_jack_driver->is_attached()) {
+ if (selected) {
+ m_jack_driver->attach(true);
+ } else {
+ m_jack_driver->detach();
+ }
+ }
+}
+
diff --git a/src/Patchage.h b/src/Patchage.h
index 7de2ef0..46d134a 100644
--- a/src/Patchage.h
+++ b/src/Patchage.h
@@ -53,6 +53,8 @@ public:
void attach();
void quit() { m_main_window->hide(); }
+ void clear_load();
+
void update_state();
void store_window_location();
@@ -63,7 +65,7 @@ public:
{ return m_main_paned->property_max_position() - m_messages_expander->get_label_widget()->get_height() - 8; }
protected:
- void attach_menu_items();
+ void connect_widgets();
void menu_store_positions();
void menu_file_quit();
@@ -73,7 +75,14 @@ protected:
void zoom(double z);
void zoom_changed();
bool idle_callback();
+ bool update_load();
+ void update_toolbar();
+ void jack_connect_changed();
+ void buffer_size_changed();
+ void sample_rate_changed();
+ void realtime_changed();
+
void on_pane_position_changed();
void on_messages_expander_changed();
@@ -131,6 +140,15 @@ protected:
Gtk::Button* m_stop_button;
Gtk::Button* m_zoom_normal_button;
Gtk::Button* m_zoom_full_button;
+ //Gtk::ProgressBar* m_load_progress_bar;
+ Gtk::ToggleButton* m_jack_connect_toggle;
+ Gtk::ToggleButton* m_jack_realtime_check;
+ Gtk::ComboBox* m_buffer_size_combo;
+ Gtk::ComboBox* m_sample_rate_combo;
+ Gtk::ProgressBar* m_xrun_progress_bar;
+ Gtk::Entry* m_xrun_counter;
+ Gtk::Button* m_clear_load_button;
+ //Gtk::Statusbar* m_status_bar;
};
#endif // PATCHAGE_H
diff --git a/src/patchage.glade b/src/patchage.glade
index 85d8eba..86d02d5 100644
--- a/src/patchage.glade
+++ b/src/patchage.glade
@@ -466,6 +466,386 @@
</child>
<child>
+ <widget class="GtkToolbar" id="toolbar2">
+ <property name="visible">True</property>
+ <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+ <property name="toolbar_style">GTK_TOOLBAR_BOTH</property>
+ <property name="tooltips">True</property>
+ <property name="show_arrow">True</property>
+
+ <child>
+ <widget class="GtkToolItem" id="toolitem15">
+ <property name="visible">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+
+ <child>
+ <widget class="GtkToggleButton" id="main_jack_connect_toggle">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="image621">
+ <property name="visible">True</property>
+ <property name="stock">gtk-connect</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">JACK</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolItem" id="toolitem16">
+ <property name="visible">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="main_jack_realtime_check">
+ <property name="border_width">1</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Realtime</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolItem" id="toolitem28">
+ <property name="visible">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox4">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkComboBoxEntry" id="main_buffer_size_combo">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">32
+64
+128
+256
+512
+1024
+2048
+4096</property>
+ <property name="add_tearoffs">False</property>
+ <property name="has_frame">True</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">1</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">frames @</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">2</property>
+ <property name="ypad">2</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">1</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBoxEntry" id="main_sample_rate_combo">
+ <property name="border_width">2</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="items" translatable="yes">44.1
+48
+96</property>
+ <property name="add_tearoffs">False</property>
+ <property name="has_frame">True</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">1</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">kHz</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkSeparatorToolItem" id="separatortoolitem3">
+ <property name="border_width">4</property>
+ <property name="visible">True</property>
+ <property name="draw">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolItem" id="toolitem22">
+ <property name="visible">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+
+ <child>
+ <widget class="GtkButton" id="main_clear_load_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkImage" id="image622">
+ <property name="visible">True</property>
+ <property name="stock">gtk-clear</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkToolItem" id="toolitem30">
+ <property name="visible">True</property>
+ <property name="visible_horizontal">True</property>
+ <property name="visible_vertical">True</property>
+ <property name="is_important">False</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment3">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox5">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkProgressBar" id="main_xrun_progress">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Delay/XRun Indicator
+
+The bar represents the maximum processing delay as a fraction of the time available for a cycle. If the bar reaches 100%, an XRun will occur.</property>
+ <property name="orientation">GTK_PROGRESS_LEFT_TO_RIGHT</property>
+ <property name="fraction">0</property>
+ <property name="pulse_step">0.10000000149</property>
+ <property name="text" translatable="yes">XRun %</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ </widget>
+ <packing>
+ <property name="padding">1</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="main_xrun_counter">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes">0</property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">*</property>
+ <property name="activates_default">False</property>
+ <property name="width_chars">3</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
<widget class="GtkToolbar" id="toolbar1">
<property name="visible">True</property>
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
@@ -610,6 +990,7 @@
<child>
<widget class="GtkSeparatorToolItem" id="separatortoolitem2">
+ <property name="border_width">4</property>
<property name="visible">True</property>
<property name="draw">True</property>
<property name="visible_horizontal">True</property>