2 Copyright (C) 1999-2002 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 #include <pbd/error.h>
32 #include <pbd/compose.h>
33 #include <pbd/basename.h>
34 #include <pbd/pathscanner.h>
35 #include <pbd/failed_constructor.h>
36 #include <gtkmm2ext/gtk_ui.h>
37 #include <gtkmm2ext/pix.h>
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/click_box.h>
40 #include <gtkmm2ext/fastmeter.h>
41 #include <gtkmm2ext/stop_signal.h>
42 #include <gtkmm2ext/popup.h>
44 #include <midi++/port.h>
45 #include <midi++/mmc.h>
47 #include <ardour/ardour.h>
48 #include <ardour/port.h>
49 #include <ardour/audioengine.h>
50 #include <ardour/playlist.h>
51 #include <ardour/utils.h>
52 #include <ardour/diskstream.h>
53 #include <ardour/filesource.h>
54 #include <ardour/recent_sessions.h>
55 #include <ardour/session_diskstream.h>
56 #include <ardour/port.h>
57 #include <ardour/audio_track.h>
60 #include "ardour_ui.h"
61 #include "ardour_message.h"
62 #include "public_editor.h"
63 #include "audio_clock.h"
68 #include "keyboard_target.h"
69 #include "add_route_dialog.h"
70 #include "new_session_dialog.h"
73 #include "gui_thread.h"
74 #include "meter_xpms.h"
78 using namespace ARDOUR;
79 using namespace Gtkmm2ext;
83 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
85 sigc::signal<void,bool> ARDOUR_UI::Blink;
86 sigc::signal<void> ARDOUR_UI::RapidScreenUpdate;
87 sigc::signal<void> ARDOUR_UI::SuperRapidScreenUpdate;
88 sigc::signal<void,jack_nframes_t> ARDOUR_UI::Clock;
90 static const char* channel_setup_names[] = {
101 vector<string> channel_combo_strings;
103 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile)
105 : Gtkmm2ext::UI ("ardour", argcp, argvp, rcfile),
107 primary_clock (X_("TransportClockDisplay"), true, false, true),
108 secondary_clock (X_("SecondaryClockDisplay"), true, false, true),
109 preroll_clock (X_("PreRollClock"), true, true),
110 postroll_clock (X_("PostRollClock"), true, true),
114 adjuster_table (3, 3),
118 preroll_button (_("pre\nroll")),
119 postroll_button (_("post\nroll")),
123 big_clock ("BigClockDisplay", true),
127 time_master_button (_("time\nmaster")),
129 shuttle_units_button (_("% ")),
131 punch_in_button (_("punch\nin")),
132 punch_out_button (_("punch\nout")),
133 auto_return_button (_("auto\nreturn")),
134 auto_play_button (_("auto\nplay")),
135 auto_input_button (_("auto\ninput")),
136 click_button (_("click")),
137 auditioning_alert_button (_("AUDITIONING")),
138 solo_alert_button (_("SOLO")),
142 using namespace Gtk::Menu_Helpers;
146 /* actually, its already loaded, but ... */
148 cerr << "Loading UI configuration file " << rcfile << endl;
152 if (theArdourUI == 0) {
156 ActionManager::init ();
158 m_new_session_dialog = 0;
159 m_new_session_dialog_ref = NewSessionDialogFactory::create();
160 m_new_session_dialog_ref->get_widget_derived (NewSessionDialogFactory::top_level_widget_name(), m_new_session_dialog);
164 _session_is_new = false;
165 big_clock_window = 0;
166 session_selector_window = 0;
167 last_key_press_time = 0;
168 connection_editor = 0;
169 add_route_dialog = 0;
174 open_session_selector = 0;
175 have_configure_timeout = false;
176 have_disk_overrun_displayed = false;
177 have_disk_underrun_displayed = false;
178 _will_create_new_session_automatically = false;
179 session_loaded = false;
180 last_speed_displayed = -1.0f;
182 last_configure_time.tv_sec = 0;
183 last_configure_time.tv_usec = 0;
185 shuttle_grabbed = false;
188 set_shuttle_units (Percentage);
189 set_shuttle_behaviour (Sprung);
191 shuttle_style_menu = 0;
192 shuttle_unit_menu = 0;
194 gettimeofday (&last_peak_grab, 0);
195 gettimeofday (&last_shuttle_request, 0);
197 ARDOUR::DiskStream::CannotRecordNoInput.connect (mem_fun(*this, &ARDOUR_UI::cannot_record_no_input));
198 ARDOUR::DiskStream::DeleteSources.connect (mem_fun(*this, &ARDOUR_UI::delete_sources_in_the_right_thread));
199 ARDOUR::DiskStream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
200 ARDOUR::DiskStream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
202 /* handle pending state with a dialog */
204 ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
206 channel_combo_strings = internationalize (channel_setup_names);
208 /* have to wait for AudioEngine and Configuration before proceeding */
212 ARDOUR_UI::cannot_record_no_input (DiskStream* ds)
214 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::cannot_record_no_input), ds));
216 string msg = string_compose (_("\
217 You cannot record-enable\n\
219 because it has no input connections.\n\
220 You would be wasting space recording silence."),
223 ArdourMessage message (editor, X_("cannotrecord"), msg);
227 ARDOUR_UI::set_engine (AudioEngine& e)
231 engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped));
232 engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running));
233 engine->Halted.connect (mem_fun(*this, &ARDOUR_UI::engine_halted));
234 engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate));
238 keyboard = new Keyboard;
239 install_keybindings ();
241 FastMeter::set_vertical_xpm (v_meter_strip_xpm);
242 FastMeter::set_horizontal_xpm (h_meter_strip_xpm);
244 if (setup_windows ()) {
245 throw failed_constructor ();
248 if (GTK_ARDOUR::show_key_actions) {
249 vector<string> names;
250 vector<string> paths;
252 vector<AccelKey> bindings;
254 ActionManager::get_all_actions (names, paths, keys, bindings);
256 vector<string>::iterator n;
257 vector<string>::iterator k;
258 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
259 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
265 /* start with timecode, metering enabled
268 blink_timeout_tag = -1;
270 /* this being a GUI and all, we want peakfiles */
272 FileSource::set_build_peakfiles (true);
273 FileSource::set_build_missing_peakfiles (true);
275 if (Source::start_peak_thread ()) {
276 throw failed_constructor();
279 /* start the time-of-day-clock */
281 update_wall_clock ();
282 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
284 update_disk_space ();
286 update_sample_rate (engine->frame_rate());
288 starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
289 stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
292 ARDOUR_UI::~ARDOUR_UI ()
294 save_ardour_state ();
308 if (add_route_dialog) {
309 delete add_route_dialog;
312 Source::stop_peak_thread ();
316 ARDOUR_UI::configure_timeout ()
321 if (last_configure_time.tv_sec == 0 && last_configure_time.tv_usec == 0) {
322 /* no configure events yet */
326 gettimeofday (&now, 0);
327 timersub (&now, &last_configure_time, &diff);
329 /* force a gap of 0.5 seconds since the last configure event
332 if (diff.tv_sec == 0 && diff.tv_usec < 500000) {
335 have_configure_timeout = false;
336 save_ardour_state ();
342 ARDOUR_UI::configure_handler (GdkEventConfigure* conf)
344 if (have_configure_timeout) {
345 gettimeofday (&last_configure_time, 0);
347 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
348 have_configure_timeout = true;
355 ARDOUR_UI::save_ardour_state ()
357 if (!keyboard || !mixer || !editor) {
361 /* XXX this is all a bit dubious. add_extra_xml() uses
362 a different lifetime model from add_instant_xml().
365 XMLNode* node = new XMLNode (keyboard->get_state());
366 Config->add_extra_xml (*node);
367 Config->save_state();
369 XMLNode& enode (static_cast<Stateful*>(editor)->get_state());
370 XMLNode& mnode (mixer->get_state());
373 session->add_instant_xml(enode, session->path());
374 session->add_instant_xml(mnode, session->path());
376 Config->add_instant_xml(enode, Config->get_user_ardour_path());
377 Config->add_instant_xml(mnode, Config->get_user_ardour_path());
382 ARDOUR_UI::startup ()
384 /* Once the UI is up and running, start the audio engine. Doing
385 this before the UI is up and running can cause problems
386 when not running with SCHED_FIFO, because the amount of
387 CPU and disk work needed to get the UI started can interfere
388 with the scheduling of the audio thread.
391 Glib::signal_idle().connect (mem_fun(*this, &ARDOUR_UI::start_engine));
397 if (session && session->dirty()) {
398 switch (ask_about_saving_session(_("quit"))) {
403 /* use the default name */
404 if (save_state_canfail ("")) {
405 /* failed - don't quit */
406 ArdourMessage (editor, X_("badsave dialog"),
408 Ardour was unable to save your session.\n\n\
409 If you still wish to quit, please use the\n\n\
410 \"Just quit\" option."));
423 ARDOUR_UI::ask_about_saving_session (const string & what)
425 ArdourDialog window (_("ardour: save session?"));
426 Gtk::Label prompt_label;
429 msg = string_compose(_("Save and %1"), what);
430 window.add_button (msg, RESPONSE_ACCEPT);
431 msg = string_compose(_("Just %1"), what);
432 window.add_button (msg, RESPONSE_APPLY);
433 msg = string_compose(_("Don't %1"), what);
434 window.add_button (msg, RESPONSE_REJECT);
436 Gtk::Button noquit_button (msg);
437 noquit_button.set_name ("EditorGTKButton");
442 if (session->snap_name() == session->name()) {
445 type = _("snapshot");
447 prompt = string_compose(_("The %1\n\"%2\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"),
448 type, session->snap_name());
450 prompt_label.set_text (prompt);
451 prompt_label.set_alignment (0.5, 0.5);
452 prompt_label.set_name (X_("PrompterLabel"));
454 window.get_vbox()->pack_start (prompt_label);
456 window.set_name (_("Prompter"));
457 window.set_position (Gtk::WIN_POS_MOUSE);
458 window.set_modal (true);
461 save_the_session = 0;
463 editor->ensure_float (window);
465 ResponseType r = (ResponseType) window.run();
470 case RESPONSE_ACCEPT: // save and get out of here
472 case RESPONSE_APPLY: // get out of here
482 ARDOUR_UI::every_second ()
485 update_buffer_load ();
486 update_disk_space ();
487 // update_disk_rate ();
492 ARDOUR_UI::every_point_one_seconds ()
497 /* do not attempt to grab peak power more than once per cycle.
500 gettimeofday (&now, 0);
501 timersub (&now, &last_peak_grab, &diff);
503 if ((diff.tv_usec + (diff.tv_sec * 1000000)) >= engine->usecs_per_cycle()) {
504 IO::GrabPeakPower(); /* EMIT_SIGNAL */
505 last_peak_grab = now;
508 update_speed_display ();
509 RapidScreenUpdate(); /* EMIT_SIGNAL */
514 ARDOUR_UI::every_point_zero_one_seconds ()
516 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
521 ARDOUR_UI::update_sample_rate (jack_nframes_t ignored)
525 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored));
527 if (!engine->connected()) {
529 snprintf (buf, sizeof (buf), _("disconnected"));
533 jack_nframes_t rate = engine->frame_rate();
535 if (fmod (rate, 1000.0) != 0.0) {
536 snprintf (buf, sizeof (buf), _("SR: %.1f kHz / %4.1f msecs"),
537 (float) rate/1000.0f,
538 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
540 snprintf (buf, sizeof (buf), _("SR: %u kHz / %4.1f msecs"),
542 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
546 sample_rate_label.set_text (buf);
550 ARDOUR_UI::update_cpu_load ()
553 snprintf (buf, sizeof (buf), _("DSP Load: %.1f%%"), engine->get_cpu_load());
554 cpu_load_label.set_text (buf);
558 ARDOUR_UI::update_disk_rate ()
563 snprintf (buf, sizeof (buf), _("Disk r:%5.1f w:%5.1f MB/s"),
564 session->read_data_rate()/1048576.0f, session->write_data_rate()/1048576.0f);
565 disk_rate_label.set_text (buf);
567 disk_rate_label.set_text ("");
572 ARDOUR_UI::update_buffer_load ()
577 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
578 session->playback_load(), session->capture_load());
579 buffer_load_label.set_text (buf);
581 buffer_load_label.set_text ("");
586 ARDOUR_UI::count_recenabled_diskstreams (DiskStream& ds)
588 if (ds.record_enabled()) {
589 rec_enabled_diskstreams++;
594 ARDOUR_UI::update_disk_space()
600 jack_nframes_t frames = session->available_capture_duration();
603 if (frames == max_frames) {
604 strcpy (buf, _("space: 24hrs+"));
609 jack_nframes_t fr = session->frame_rate();
611 if (session->actively_recording()){
613 rec_enabled_diskstreams = 0;
614 session->foreach_diskstream (this, &ARDOUR_UI::count_recenabled_diskstreams);
616 if (rec_enabled_diskstreams) {
617 frames /= rec_enabled_diskstreams;
622 /* hmmm. shall we divide by the route count? or the diskstream count?
623 or what? for now, do nothing ...
628 hrs = frames / (fr * 3600);
629 frames -= hrs * fr * 3600;
630 mins = frames / (fr * 60);
631 frames -= mins * fr * 60;
634 snprintf (buf, sizeof(buf), _("space: %02dh:%02dm:%02ds"), hrs, mins, secs);
637 disk_space_label.set_text (buf);
641 ARDOUR_UI::update_wall_clock ()
648 tm_now = localtime (&now);
650 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
651 wall_clock_label.set_text (buf);
656 ARDOUR_UI::control_methods_adjusted ()
661 which_method = (int) online_control_button->adjustment.get_value();
662 switch (which_method) {
664 allow_mmc_and_local ();
673 fatal << _("programming error: impossible control method") << endmsg;
679 ARDOUR_UI::mmc_device_id_adjusted ()
684 int dev_id = (int) mmc_id_button->adjustment.get_value();
685 mmc->set_device_id (dev_id);
691 ARDOUR_UI::map_some_session_state (ToggleButton& button,
692 bool (Session::*get)() const)
701 if (button.get_active() != (x = (session->*get)())) {
702 button.set_active (x);
707 ARDOUR_UI::session_menu (GdkEventButton *ev)
709 session_popup_menu->popup (0, 0);
714 ARDOUR_UI::redisplay_recent_sessions ()
716 vector<string *> *sessions;
717 vector<string *>::iterator i;
718 RecentSessionsSorter cmp;
720 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
721 recent_session_model->clear ();
724 ARDOUR::read_recent_sessions (rs);
727 recent_session_display.set_model (recent_session_model);
731 /* sort them alphabetically */
732 sort (rs.begin(), rs.end(), cmp);
733 sessions = new vector<string*>;
735 for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
736 sessions->push_back (new string ((*i).second));
739 for (i = sessions->begin(); i != sessions->end(); ++i) {
741 vector<string*>* states;
742 vector<const gchar*> item;
743 string fullpath = *(*i);
745 /* remove any trailing / */
747 if (fullpath[fullpath.length()-1] == '/') {
748 fullpath = fullpath.substr (0, fullpath.length()-1);
751 /* now get available states for this session */
753 if ((states = Session::possible_states (fullpath)) == 0) {
758 TreeModel::Row row = *(recent_session_model->append());
760 row[recent_session_columns.visible_name] = PBD::basename (fullpath);
761 row[recent_session_columns.fullpath] = fullpath;
763 if (states->size() > 1) {
765 /* add the children */
767 for (vector<string*>::iterator i2 = states->begin(); i2 != states->end(); ++i2) {
769 TreeModel::Row child_row = *(recent_session_model->append (row.children()));
771 child_row[recent_session_columns.visible_name] = **i2;
772 child_row[recent_session_columns.fullpath] = fullpath;
781 recent_session_display.set_model (recent_session_model);
786 ARDOUR_UI::build_session_selector ()
788 session_selector_window = new ArdourDialog ("session selector");
790 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
792 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
793 session_selector_window->add_button (Stock::OK, RESPONSE_ACCEPT);
795 recent_session_model = TreeStore::create (recent_session_columns);
796 recent_session_display.set_model (recent_session_model);
797 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
798 recent_session_display.set_headers_visible (false);
800 scroller->add (recent_session_display);
801 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
803 session_selector_window->set_name ("SessionSelectorWindow");
804 session_selector_window->set_size_request (200, 400);
805 session_selector_window->get_vbox()->pack_start (*scroller);
806 session_selector_window->show_all_children();
810 ARDOUR_UI::open_recent_session ()
812 /* popup selector window */
814 if (session_selector_window == 0) {
815 build_session_selector ();
818 redisplay_recent_sessions ();
820 ResponseType r = (ResponseType) session_selector_window->run ();
822 session_selector_window->hide();
825 case RESPONSE_ACCEPT:
831 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
833 if (i == recent_session_model->children().end()) {
837 Glib::ustring path = (*i)[recent_session_columns.fullpath];
838 Glib::ustring state = (*i)[recent_session_columns.visible_name];
840 _session_is_new = false;
842 load_session (path, state);
846 ARDOUR_UI::filter_ardour_session_dirs (const FileFilter::Info& info)
850 if (stat (info.filename.c_str(), &statbuf) != 0) {
854 if (!S_ISDIR(statbuf.st_mode)) {
858 string session_file = info.filename;
860 session_file += PBD::basename (info.filename);
861 session_file += ".ardour";
863 if (stat (session_file.c_str(), &statbuf) != 0) {
867 return S_ISREG (statbuf.st_mode);
871 ARDOUR_UI::open_session ()
873 /* popup selector window */
875 if (open_session_selector == 0) {
877 /* ardour sessions are folders */
879 open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN);
880 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
881 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
883 FileFilter session_filter;
884 session_filter.add_pattern ("*.ardour");
885 session_filter.set_name (_("Ardour sessions"));
886 open_session_selector->add_filter (session_filter);
887 open_session_selector->set_filter (session_filter);
890 int response = open_session_selector->run();
891 open_session_selector->hide ();
894 case RESPONSE_ACCEPT:
897 open_session_selector->hide();
901 open_session_selector->hide();
902 string session_path = open_session_selector->get_filename();
906 if (session_path.length() > 0) {
907 if (Session::find_session (session_path, path, name, isnew) == 0) {
908 _session_is_new = isnew;
909 load_session (path, name);
916 ARDOUR_UI::session_add_midi_track ()
918 cerr << _("Patience is a virtue.\n");
922 ARDOUR_UI::session_add_audio_route (bool disk, int32_t input_channels, int32_t output_channels)
927 warning << _("You cannot add a track without a session already loaded.") << endmsg;
933 if ((route = session->new_audio_track (input_channels, output_channels)) == 0) {
934 error << _("could not create new audio track") << endmsg;
937 if ((route = session->new_audio_route (input_channels, output_channels)) == 0) {
938 error << _("could not create new audio bus") << endmsg;
943 if (need_control_room_outs) {
949 route->set_stereo_control_outs (control_lr_channels);
950 route->control_outs()->set_stereo_pan (pans, this);
952 #endif /* CONTROLOUTS */
956 ArdourMessage msg (editor, X_("noport dialog"),
957 _("There are insufficient JACK ports available\n\
958 to create a new track or bus.\n\
959 You should save Ardour, exit and\n\
960 restart JACK with more ports."));
965 ARDOUR_UI::diskstream_added (DiskStream* ds)
970 ARDOUR_UI::do_transport_locate (jack_nframes_t new_position)
972 jack_nframes_t _preroll;
975 _preroll = session->convert_to_frames_at (new_position, session->preroll);
977 if (new_position > _preroll) {
978 new_position -= _preroll;
983 session->request_locate (new_position);
988 ARDOUR_UI::transport_goto_start ()
991 session->request_locate (0);
994 /* force displayed area in editor to start no matter
995 what "follow playhead" setting is.
999 editor->reposition_x_origin (0);
1005 ARDOUR_UI::transport_goto_end ()
1008 jack_nframes_t frame = session->current_end_frame();
1009 session->request_locate (frame);
1011 /* force displayed area in editor to start no matter
1012 what "follow playhead" setting is.
1016 editor->reposition_x_origin (frame);
1022 ARDOUR_UI::transport_stop ()
1028 if (session->is_auditioning()) {
1029 session->cancel_audition ();
1033 if (session->get_auto_loop()) {
1034 session->request_auto_loop (false);
1037 session->request_stop ();
1041 ARDOUR_UI::transport_stop_and_forget_capture ()
1044 session->request_stop (true);
1049 ARDOUR_UI::remove_last_capture()
1052 editor->remove_last_capture();
1057 ARDOUR_UI::transport_record ()
1060 switch (session->record_status()) {
1061 case Session::Disabled:
1062 if (session->ntracks() == 0) {
1063 string txt = _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu.");
1064 ArdourMessage msg (editor, X_("cannotrecenable"), txt);
1067 session->maybe_enable_record ();
1069 case Session::Recording:
1070 case Session::Enabled:
1071 session->disable_record ();
1077 ARDOUR_UI::transport_roll ()
1085 rolling = session->transport_rolling ();
1087 if (session->get_auto_loop()) {
1088 session->request_auto_loop (false);
1089 auto_loop_button.set_active (false);
1090 roll_button.set_active (true);
1091 } else if (session->get_play_range ()) {
1092 session->request_play_range (false);
1093 play_selection_button.set_active (false);
1094 } else if (rolling) {
1095 session->request_locate (session->last_transport_start(), true);
1098 session->request_transport_speed (1.0f);
1102 ARDOUR_UI::transport_loop()
1105 if (session->get_auto_loop()) {
1106 if (session->transport_rolling()) {
1107 Location * looploc = session->locations()->auto_loop_location();
1109 session->request_locate (looploc->start(), true);
1114 session->request_auto_loop (true);
1120 ARDOUR_UI::transport_play_selection ()
1126 if (!session->get_play_range()) {
1127 session->request_stop ();
1130 editor->play_selection ();
1134 ARDOUR_UI::transport_rewind (int option)
1136 float current_transport_speed;
1139 current_transport_speed = session->transport_speed();
1141 if (current_transport_speed >= 0.0f) {
1144 session->request_transport_speed (-1.0f);
1147 session->request_transport_speed (-4.0f);
1150 session->request_transport_speed (-0.5f);
1155 session->request_transport_speed (current_transport_speed * 1.5f);
1161 ARDOUR_UI::transport_forward (int option)
1163 float current_transport_speed;
1166 current_transport_speed = session->transport_speed();
1168 if (current_transport_speed <= 0.0f) {
1171 session->request_transport_speed (1.0f);
1174 session->request_transport_speed (4.0f);
1177 session->request_transport_speed (0.5f);
1182 session->request_transport_speed (current_transport_speed * 1.5f);
1188 ARDOUR_UI::toggle_monitor_enable (guint32 dstream)
1196 if ((ds = session->diskstream_by_id (dstream)) != 0) {
1197 Port *port = ds->io()->input (0);
1198 port->request_monitor_input (!port->monitoring_input());
1203 ARDOUR_UI::toggle_record_enable (guint32 dstream)
1211 if ((ds = session->diskstream_by_id (dstream)) != 0) {
1212 ds->set_record_enabled (!ds->record_enabled(), this);
1217 ARDOUR_UI::queue_transport_change ()
1219 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
1223 ARDOUR_UI::map_transport_state ()
1225 float sp = session->transport_speed();
1228 transport_rolling ();
1229 } else if (sp < 0.0f) {
1230 transport_rewinding ();
1231 } else if (sp > 0.0f) {
1232 transport_forwarding ();
1234 transport_stopped ();
1239 ARDOUR_UI::send_all_midi_feedback ()
1242 session->send_all_midi_feedback();
1247 ARDOUR_UI::allow_local_only ()
1253 ARDOUR_UI::allow_mmc_only ()
1259 ARDOUR_UI::allow_mmc_and_local ()
1265 ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg)
1267 snprintf (buf, sizeof(buf), "%s", ((GlobalClickBox *) arg)->strings[
1268 (int) adj.get_value()].c_str());
1272 ARDOUR_UI::engine_stopped ()
1274 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
1275 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1276 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1281 ARDOUR_UI::engine_running ()
1283 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
1284 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1285 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1289 ARDOUR_UI::engine_halted ()
1291 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted));
1293 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1294 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1296 update_sample_rate (0);
1298 ArdourMessage msg (editor, X_("halted"),
1300 JACK has either been shutdown or it\n\
1301 disconnected Ardour because Ardour\n\
1302 was not fast enough. You can save the\n\
1303 session and/or try to reconnect to JACK ."));
1307 ARDOUR_UI::do_engine_start ()
1313 catch (AudioEngine::PortRegistrationFailure& err) {
1315 error << _("Unable to create all required ports")
1323 error << _("Unable to start the session running")
1333 ARDOUR_UI::start_engine ()
1335 if (do_engine_start () == 0) {
1336 if (session && _session_is_new) {
1337 /* we need to retain initial visual
1338 settings for a new session
1340 session->save_state ("");
1343 /* there is too much going on, in too many threads, for us to
1344 end up with a clean session. So wait 1 second after loading,
1345 and fix it up. its ugly, but until i come across a better
1346 solution, its what we have.
1349 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::make_session_clean), 1000);
1356 ARDOUR_UI::update_clocks ()
1358 Clock (session->audible_frame()); /* EMIT_SIGNAL */
1362 ARDOUR_UI::start_clocking ()
1364 clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
1368 ARDOUR_UI::stop_clocking ()
1370 clock_signal_connection.disconnect ();
1374 ARDOUR_UI::toggle_clocking ()
1377 if (clock_button.get_active()) {
1386 ARDOUR_UI::_blink (void *arg)
1389 ((ARDOUR_UI *) arg)->blink ();
1396 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1400 ARDOUR_UI::start_blinking ()
1402 /* Start the blink signal. Everybody with a blinking widget
1403 uses Blink to drive the widget's state.
1406 if (blink_timeout_tag < 0) {
1408 blink_timeout_tag = gtk_timeout_add (240, _blink, this);
1413 ARDOUR_UI::stop_blinking ()
1415 if (blink_timeout_tag >= 0) {
1416 gtk_timeout_remove (blink_timeout_tag);
1417 blink_timeout_tag = -1;
1423 ARDOUR_UI::add_diskstream_to_menu (DiskStream& dstream)
1425 using namespace Gtk;
1426 using namespace Menu_Helpers;
1428 if (dstream.hidden()) {
1432 MenuList& items = diskstream_menu->items();
1433 items.push_back (MenuElem (dstream.name(), bind (mem_fun(*this, &ARDOUR_UI::diskstream_selected), (gint32) dstream.id())));
1437 ARDOUR_UI::diskstream_selected (gint32 id)
1439 selected_dstream = id;
1444 ARDOUR_UI::select_diskstream (GdkEventButton *ev)
1446 using namespace Gtk;
1447 using namespace Menu_Helpers;
1453 diskstream_menu = new Menu();
1454 diskstream_menu->set_name ("ArdourContextMenu");
1455 using namespace Gtk;
1456 using namespace Menu_Helpers;
1458 MenuList& items = diskstream_menu->items();
1459 items.push_back (MenuElem (_("No Stream"), (bind (mem_fun(*this, &ARDOUR_UI::diskstream_selected), -1))));
1461 session->foreach_diskstream (this, &ARDOUR_UI::add_diskstream_to_menu);
1464 diskstream_menu->popup (ev->button, ev->time);
1466 diskstream_menu->popup (0, 0);
1469 selected_dstream = -1;
1473 delete diskstream_menu;
1475 return selected_dstream;
1479 ARDOUR_UI::name_io_setup (AudioEngine& engine,
1485 if (io.n_inputs() == 0) {
1490 /* XXX we're not handling multiple ports yet. */
1492 const char **connections = io.input(0)->get_connections();
1494 if (connections == 0 || connections[0] == '\0') {
1497 buf = connections[0];
1504 if (io.n_outputs() == 0) {
1509 /* XXX we're not handling multiple ports yet. */
1511 const char **connections = io.output(0)->get_connections();
1513 if (connections == 0 || connections[0] == '\0') {
1516 buf = connections[0];
1524 ARDOUR_UI::snapshot_session ()
1526 ArdourPrompter prompter (true);
1533 now = now.substr (0, now.length() - 1);
1535 prompter.set_name ("Prompter");
1536 prompter.set_prompt (_("Name for snapshot"));
1537 prompter.set_initial_text (now);
1539 switch (prompter.run()) {
1540 case RESPONSE_ACCEPT:
1541 prompter.get_result (snapname);
1542 if (snapname.length()){
1543 save_state (snapname);
1553 ARDOUR_UI::save_state (const string & name)
1555 (void) save_state_canfail (name);
1559 ARDOUR_UI::save_state_canfail (string name)
1564 if (name.length() == 0) {
1565 name = session->snap_name();
1568 if ((ret = session->save_state (name)) != 0) {
1572 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
1577 ARDOUR_UI::restore_state (string name)
1580 if (name.length() == 0) {
1581 name = session->name();
1583 session->restore_state (name);
1588 ARDOUR_UI::primary_clock_value_changed ()
1591 session->request_locate (primary_clock.current_time ());
1596 ARDOUR_UI::secondary_clock_value_changed ()
1599 session->request_locate (secondary_clock.current_time ());
1604 ARDOUR_UI::rec_enable_button_blink (bool onoff, DiskStream *dstream, Widget *w)
1606 if (session && dstream && dstream->record_enabled()) {
1608 Session::RecordState rs;
1610 rs = session->record_status ();
1613 case Session::Disabled:
1614 case Session::Enabled:
1615 if (w->get_state() != STATE_SELECTED) {
1616 w->set_state (STATE_SELECTED);
1620 case Session::Recording:
1621 if (w->get_state() != STATE_ACTIVE) {
1622 w->set_state (STATE_ACTIVE);
1628 if (w->get_state() != STATE_NORMAL) {
1629 w->set_state (STATE_NORMAL);
1635 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
1641 switch (session->record_status()) {
1642 case Session::Enabled:
1644 rec_button.set_state (1);
1646 rec_button.set_state (0);
1650 case Session::Recording:
1651 rec_button.set_state (2);
1655 rec_button.set_state (0);
1661 ARDOUR_UI::hide_and_quit (GdkEventAny *ev, ArdourDialog *window)
1669 ARDOUR_UI::start_keyboard_prefix ()
1671 keyboard->start_prefix();
1675 ARDOUR_UI::save_template ()
1678 ArdourPrompter prompter (true);
1681 prompter.set_name (X_("Prompter"));
1682 prompter.set_prompt (_("Name for mix template:"));
1683 prompter.set_initial_text(session->name() + _("-template"));
1685 switch (prompter.run()) {
1686 case RESPONSE_ACCEPT:
1687 prompter.get_result (name);
1689 if (name.length()) {
1690 session->save_template (name);
1700 ARDOUR_UI::new_session (bool startup, std::string predetermined_path)
1702 m_new_session_dialog->show_all();
1703 m_new_session_dialog->set_transient_for(*editor);
1704 m_new_session_dialog->set_name(predetermined_path);
1706 int response = Gtk::RESPONSE_CANCEL;
1709 response = m_new_session_dialog->run ();
1711 if(response == Gtk::RESPONSE_OK) {
1713 _session_is_new = true;
1715 std::string session_name = m_new_session_dialog->session_name();
1716 std::string session_path = m_new_session_dialog->session_folder();
1719 XXX This is needed because session constructor wants a
1720 non-existant path. hopefully this will be fixed at some point.
1722 session_path = Glib::build_filename(session_path, session_name);
1724 std::string template_name = m_new_session_dialog->session_template_name();
1726 if (m_new_session_dialog->use_session_template()) {
1728 load_session (session_path, session_name, &template_name);
1734 Session::AutoConnectOption iconnect;
1735 Session::AutoConnectOption oconnect;
1737 if (m_new_session_dialog->create_control_bus()) {
1738 cchns = (uint32_t) m_new_session_dialog->control_channel_count();
1743 if (m_new_session_dialog->create_master_bus()) {
1744 mchns = (uint32_t) m_new_session_dialog->master_channel_count();
1749 if (m_new_session_dialog->connect_inputs()) {
1750 iconnect = Session::AutoConnectPhysical;
1752 iconnect = Session::AutoConnectOption (0);
1755 /// @todo some minor tweaks.
1757 if (m_new_session_dialog->connect_outs_to_master()) {
1758 oconnect = Session::AutoConnectMaster;
1759 } else if (m_new_session_dialog->connect_outs_to_physical()) {
1760 oconnect = Session::AutoConnectPhysical;
1762 oconnect = Session::AutoConnectOption (0);
1765 uint32_t nphysin = (uint32_t) m_new_session_dialog->input_limit_count();
1766 uint32_t nphysout = (uint32_t) m_new_session_dialog->output_limit_count();
1768 build_session (session_path,
1776 engine->frame_rate() * 60 * 5);
1780 } while(response == Gtk::RESPONSE_HELP);
1781 m_new_session_dialog->hide_all();
1785 ARDOUR_UI::load_session (const string & path, const string & snap_name, string* mix_template)
1787 Session *new_session;
1789 session_loaded = false;
1790 x = unload_session ();
1798 /* if it already exists, we must have write access */
1800 if (::access (path.c_str(), F_OK) == 0 && ::access (path.c_str(), W_OK)) {
1801 ArdourMessage msg (editor, X_("noaccess dialog"), _("\
1802 You do not have write access to this session.\n\
1803 This prevents the session from being loaded."));
1808 new_session = new Session (*engine, path, snap_name, mix_template);
1813 error << string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg;
1817 connect_to_session (new_session);
1819 //if (engine->running()) {
1820 //mixer->show_window();
1822 session_loaded = true;
1827 ARDOUR_UI::make_session_clean ()
1830 session->set_clean ();
1837 ARDOUR_UI::build_session (const string & path, const string & snap_name,
1838 uint32_t control_channels,
1839 uint32_t master_channels,
1840 Session::AutoConnectOption input_connect,
1841 Session::AutoConnectOption output_connect,
1844 jack_nframes_t initial_length)
1846 Session *new_session;
1849 session_loaded = false;
1850 x = unload_session ();
1857 _session_is_new = true;
1860 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
1861 control_channels, master_channels, nphysin, nphysout, initial_length);
1866 error << string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg;
1870 connect_to_session (new_session);
1872 //if (engine->running()) {
1873 //mixer->show_window();
1875 session_loaded = true;
1883 editor->show_window ();
1887 if (session && mixer) {
1888 // mixer->show_window ();
1897 ARDOUR_UI::show_splash ()
1900 about = new About();
1906 ARDOUR_UI::hide_splash ()
1914 ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title, const string & msg)
1918 removed = rep.paths.size();
1921 ArdourMessage msg (editor, X_("cleanupresults"),
1923 No audio files were ready for cleanup\n\n\
1924 If this seems suprising, check for any existing\n\
1925 snapshots. These may still include regions that\n\
1926 require some unused files to continue to exist."));
1930 ArdourDialog results (_("ardour: cleanup"), true);
1932 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
1933 CleanupResultsModelColumns() {
1937 Gtk::TreeModelColumn<Glib::ustring> visible_name;
1938 Gtk::TreeModelColumn<Glib::ustring> fullpath;
1942 Glib::RefPtr<Gtk::ListStore> results_model;
1943 CleanupResultsModelColumns results_columns;
1944 Gtk::TreeView results_display;
1946 results_model = ListStore::create (results_columns);
1947 results_display.set_model (results_model);
1948 results_display.append_column (list_title, results_columns.visible_name);
1949 results_display.set_headers_visible (true);
1951 Gtk::ScrolledWindow list_scroller;
1954 if (rep.space < 1048576.0f) {
1956 txt.set_text (string_compose (msg, removed, _("files"), (float) rep.space / 1024.0f, "kilo"));
1958 txt.set_text (string_compose (msg, removed, _("file"), (float) rep.space / 1024.0f, "kilo"));
1962 txt.set_text (string_compose (msg, removed, _("files"), (float) rep.space / 1048576.0f, "mega"));
1964 txt.set_text (string_compose (msg, removed, _("file"), (float) rep.space / 1048576.0f, "mega"));
1968 results.get_vbox()->pack_start (txt, false, false);
1970 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
1971 TreeModel::Row row = *(results_model->append());
1972 row[results_columns.visible_name] = *i;
1973 row[results_columns.fullpath] = *i;
1976 list_scroller.add (results_display);
1977 list_scroller.set_size_request (-1, 250);
1978 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1980 results.get_vbox()->pack_start (list_scroller, true, true);
1981 results.add_button (Stock::OK, RESPONSE_ACCEPT);
1982 results.set_position (Gtk::WIN_POS_MOUSE);
1988 ARDOUR_UI::cleanup ()
1991 /* shouldn't happen: menu item is insensitive */
1995 ArdourDialog checker (_("ardour cleanup"));
1996 Gtk::Label label (_("\
1997 Cleanup is a destructive operation.\n\
1998 ALL undo/redo information will be lost if you cleanup.\n\
1999 Unused audio files will be moved to a \"dead sounds\" location."));
2001 checker.get_vbox()->pack_start (label, false, false);
2002 checker.add_button (Stock::OK, RESPONSE_ACCEPT);
2003 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2005 checker.set_name (_("CleanupDialog"));
2006 checker.set_wmclass (_("ardour_cleanup"), "Ardour");
2007 checker.set_position (Gtk::WIN_POS_MOUSE);
2009 switch (checker.run()) {
2010 case RESPONSE_ACCEPT:
2016 Session::cleanup_report rep;
2018 editor->prepare_for_cleanup ();
2020 if (session->cleanup_sources (rep)) {
2024 display_cleanup_results (rep,
2027 The following %1 %2 were not in use.\n\
2028 The next time you flush the wastebasket\n\
2029 it will release an additional %3 %4bytes\n\
2035 ARDOUR_UI::flush_trash ()
2038 /* shouldn't happen: menu item is insensitive */
2042 Session::cleanup_report rep;
2044 if (session->cleanup_trash_sources (rep)) {
2048 display_cleanup_results (rep,
2050 _("The following %1 file%2 were deleted, releasing %3 %4bytes of disk space"));
2054 ARDOUR_UI::add_route ()
2062 if (add_route_dialog == 0) {
2063 add_route_dialog = new AddRouteDialog;
2064 editor->ensure_float (*add_route_dialog);
2067 if (add_route_dialog->is_visible()) {
2068 /* we're already doing this */
2072 ResponseType r = (ResponseType) add_route_dialog->run ();
2074 add_route_dialog->hide();
2077 case RESPONSE_ACCEPT:
2084 if ((count = add_route_dialog->count()) <= 0) {
2088 uint32_t input_chan = add_route_dialog->channels ();
2089 uint32_t output_chan;
2090 string name_template = add_route_dialog->name_template ();
2091 bool track = add_route_dialog->track ();
2093 Session::AutoConnectOption oac = session->get_output_auto_connect();
2095 if (oac & Session::AutoConnectMaster) {
2096 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
2098 output_chan = input_chan;
2101 /* XXX do something with name template */
2105 session_add_audio_track (input_chan, output_chan);
2107 session_add_audio_bus (input_chan, output_chan);
2111 while (Main::events_pending()) {
2118 ARDOUR_UI::mixer_settings () const
2123 node = session->instant_xml(X_("Mixer"), session->path());
2125 node = Config->instant_xml(X_("Mixer"), Config->get_user_ardour_path());
2129 node = new XMLNode (X_("Mixer"));
2136 ARDOUR_UI::editor_settings () const
2141 node = session->instant_xml(X_("Editor"), session->path());
2143 node = Config->instant_xml(X_("Editor"), Config->get_user_ardour_path());
2147 node = new XMLNode (X_("Editor"));
2153 ARDOUR_UI::keyboard_settings () const
2157 node = Config->extra_xml(X_("Keyboard"));
2160 node = new XMLNode (X_("Keyboard"));
2166 ARDOUR_UI::halt_on_xrun_message ()
2168 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::halt_on_xrun_message));
2170 ArdourMessage msg (editor, X_("haltonxrun"),
2171 _("Recording was stopped because your system could not keep up."));
2175 ARDOUR_UI::delete_sources_in_the_right_thread (list<ARDOUR::Source*>* deletion_list)
2177 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::delete_sources_in_the_right_thread), deletion_list));
2179 for (list<Source*>::iterator i = deletion_list->begin(); i != deletion_list->end(); ++i) {
2183 delete deletion_list;
2187 ARDOUR_UI::disk_overrun_handler ()
2189 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
2191 if (!have_disk_overrun_displayed) {
2192 have_disk_overrun_displayed = true;
2193 ArdourMessage msg (editor, X_("diskrate dialog"), _("\
2194 The disk system on your computer\n\
2195 was not able to keep up with Ardour.\n\
2197 Specifically, it failed to write data to disk\n\
2198 quickly enough to keep up with recording.\n"));
2199 have_disk_overrun_displayed = false;
2204 ARDOUR_UI::disk_underrun_handler ()
2206 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
2208 if (!have_disk_underrun_displayed) {
2209 have_disk_underrun_displayed = true;
2210 ArdourMessage msg (editor, X_("diskrate2 dialog"),
2211 (_("The disk system on your computer\n\
2212 was not able to keep up with Ardour.\n\
2214 Specifically, it failed to read data from disk\n\
2215 quickly enough to keep up with playback.\n")));
2216 have_disk_underrun_displayed = false;
2221 ARDOUR_UI::disk_underrun_message_gone ()
2223 have_disk_underrun_displayed = false;
2227 ARDOUR_UI::disk_overrun_message_gone ()
2229 have_disk_underrun_displayed = false;
2233 ARDOUR_UI::pending_state_dialog ()
2235 ArdourDialog dialog ("pending state dialog");
2237 This session appears to have been in\n\
2238 middle of recording when ardour or\n\
2239 the computer was shutdown.\n\
2241 Ardour can recover any captured audio for\n\
2242 you, or it can ignore it. Please decide\n\
2243 what you would like to do.\n"));
2245 dialog.get_vbox()->pack_start (message);
2246 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
2247 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
2249 dialog.set_position (WIN_POS_CENTER);
2252 switch (dialog.run ()) {
2253 case RESPONSE_ACCEPT:
2264 ARDOUR_UI::disconnect_from_jack ()
2267 if( engine->disconnect_from_jack ()) {
2268 ArdourMessage msg (editor, X_("nojack dialog"),
2269 _("Could not disconnect from JACK"));
2272 update_sample_rate (0);
2277 ARDOUR_UI::reconnect_to_jack ()
2280 if (engine->reconnect_to_jack ()) {
2281 ArdourMessage msg (editor, X_("nojack dialog"),
2282 _("Could not reconnect to JACK"));
2285 update_sample_rate (0);
2290 ARDOUR_UI::set_jack_buffer_size (jack_nframes_t nframes)
2292 engine->request_buffer_size (nframes);
2293 update_sample_rate (0);
2297 ARDOUR_UI::cmdline_new_session (string path)
2299 if (path[0] != '/') {
2300 char buf[PATH_MAX+1];
2303 getcwd (buf, sizeof (buf));
2310 new_session (false, path);
2312 _will_create_new_session_automatically = false; /* done it */
2313 return FALSE; /* don't call it again */