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 <gtkmm/messagedialog.h>
33 #include <pbd/error.h>
34 #include <pbd/compose.h>
35 #include <pbd/basename.h>
36 #include <pbd/pathscanner.h>
37 #include <pbd/failed_constructor.h>
38 #include <gtkmm2ext/gtk_ui.h>
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/click_box.h>
41 #include <gtkmm2ext/fastmeter.h>
42 #include <gtkmm2ext/stop_signal.h>
43 #include <gtkmm2ext/popup.h>
45 #include <midi++/port.h>
46 #include <midi++/mmc.h>
48 #include <ardour/ardour.h>
49 #include <ardour/port.h>
50 #include <ardour/audioengine.h>
51 #include <ardour/playlist.h>
52 #include <ardour/utils.h>
53 #include <ardour/diskstream.h>
54 #include <ardour/filesource.h>
55 #include <ardour/recent_sessions.h>
56 #include <ardour/session_diskstream.h>
57 #include <ardour/port.h>
58 #include <ardour/audio_track.h>
61 #include "ardour_ui.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 "color_manager.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 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile)
92 : Gtkmm2ext::UI ("ardour", argcp, argvp, rcfile),
94 primary_clock (X_("TransportClockDisplay"), true, false, true),
95 secondary_clock (X_("SecondaryClockDisplay"), true, false, true),
96 preroll_clock (X_("PreRollClock"), true, true),
97 postroll_clock (X_("PostRollClock"), true, true),
101 adjuster_table (3, 3),
105 preroll_button (_("pre\nroll")),
106 postroll_button (_("post\nroll")),
110 big_clock ("BigClockDisplay", true),
114 time_master_button (_("time\nmaster")),
116 shuttle_units_button (_("% ")),
118 punch_in_button (_("punch\nin")),
119 punch_out_button (_("punch\nout")),
120 auto_return_button (_("auto\nreturn")),
121 auto_play_button (_("auto\nplay")),
122 auto_input_button (_("auto\ninput")),
123 click_button (_("click")),
124 auditioning_alert_button (_("AUDITIONING")),
125 solo_alert_button (_("SOLO")),
129 using namespace Gtk::Menu_Helpers;
135 if (theArdourUI == 0) {
139 ActionManager::init ();
143 color_manager = new ColorManager();
145 std::string color_file = ARDOUR::find_config_file("ardour.colors");
147 color_manager->load (color_file);
149 m_new_session_dialog = 0;
150 m_new_session_dialog_ref = NewSessionDialogFactory::create();
151 m_new_session_dialog_ref->get_widget_derived (NewSessionDialogFactory::top_level_widget_name(), m_new_session_dialog);
155 _session_is_new = false;
156 big_clock_window = 0;
157 session_selector_window = 0;
158 last_key_press_time = 0;
159 connection_editor = 0;
160 add_route_dialog = 0;
165 open_session_selector = 0;
166 have_configure_timeout = false;
167 have_disk_overrun_displayed = false;
168 have_disk_underrun_displayed = false;
169 _will_create_new_session_automatically = false;
170 session_loaded = false;
171 last_speed_displayed = -1.0f;
173 last_configure_time.tv_sec = 0;
174 last_configure_time.tv_usec = 0;
176 shuttle_grabbed = false;
178 shuttle_max_speed = 8.0f;
180 set_shuttle_units (Percentage);
181 set_shuttle_behaviour (Sprung);
183 shuttle_style_menu = 0;
184 shuttle_unit_menu = 0;
186 gettimeofday (&last_peak_grab, 0);
187 gettimeofday (&last_shuttle_request, 0);
189 ARDOUR::DiskStream::CannotRecordNoInput.connect (mem_fun(*this, &ARDOUR_UI::cannot_record_no_input));
190 ARDOUR::DiskStream::DeleteSources.connect (mem_fun(*this, &ARDOUR_UI::delete_sources_in_the_right_thread));
191 ARDOUR::DiskStream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
192 ARDOUR::DiskStream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
194 /* handle pending state with a dialog */
196 ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
198 /* have to wait for AudioEngine and Configuration before proceeding */
202 ARDOUR_UI::cannot_record_no_input (DiskStream* ds)
204 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::cannot_record_no_input), ds));
206 string msg = string_compose (_("\
207 You cannot record-enable\n\
209 because it has no input connections.\n\
210 You would be wasting space recording silence."),
213 MessageDialog message (*editor, msg);
218 ARDOUR_UI::set_engine (AudioEngine& e)
222 engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped));
223 engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running));
224 engine->Halted.connect (mem_fun(*this, &ARDOUR_UI::engine_halted));
225 engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate));
229 keyboard = new Keyboard;
230 install_keybindings ();
234 meter_path = ARDOUR::find_data_file("v_meter_strip.xpm", "pixmaps");
235 if (meter_path.empty()) {
236 error << _("no vertical meter strip image found") << endmsg;
239 FastMeter::set_vertical_xpm (meter_path);
241 meter_path = ARDOUR::find_data_file("h_meter_strip.xpm", "pixmaps");
242 if (meter_path.empty()) {
243 error << _("no horizontal meter strip image found") << endmsg;
246 FastMeter::set_horizontal_xpm (meter_path);
248 if (setup_windows ()) {
249 throw failed_constructor ();
252 if (GTK_ARDOUR::show_key_actions) {
253 vector<string> names;
254 vector<string> paths;
256 vector<AccelKey> bindings;
258 ActionManager::get_all_actions (names, paths, keys, bindings);
260 vector<string>::iterator n;
261 vector<string>::iterator k;
262 for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) {
263 cerr << "Action: " << (*n) << " bound to " << (*k) << endl;
269 /* start with timecode, metering enabled
272 blink_timeout_tag = -1;
274 /* this being a GUI and all, we want peakfiles */
276 FileSource::set_build_peakfiles (true);
277 FileSource::set_build_missing_peakfiles (true);
279 if (Source::start_peak_thread ()) {
280 throw failed_constructor();
283 /* start the time-of-day-clock */
285 update_wall_clock ();
286 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
288 update_disk_space ();
290 update_sample_rate (engine->frame_rate());
292 starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
293 stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
296 ARDOUR_UI::~ARDOUR_UI ()
298 save_ardour_state ();
312 if (add_route_dialog) {
313 delete add_route_dialog;
316 Source::stop_peak_thread ();
320 ARDOUR_UI::configure_timeout ()
325 if (last_configure_time.tv_sec == 0 && last_configure_time.tv_usec == 0) {
326 /* no configure events yet */
330 gettimeofday (&now, 0);
331 timersub (&now, &last_configure_time, &diff);
333 /* force a gap of 0.5 seconds since the last configure event
336 if (diff.tv_sec == 0 && diff.tv_usec < 500000) {
339 have_configure_timeout = false;
340 save_ardour_state ();
346 ARDOUR_UI::configure_handler (GdkEventConfigure* conf)
348 if (have_configure_timeout) {
349 gettimeofday (&last_configure_time, 0);
351 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
352 have_configure_timeout = true;
359 ARDOUR_UI::save_ardour_state ()
361 if (!keyboard || !mixer || !editor) {
365 /* XXX this is all a bit dubious. add_extra_xml() uses
366 a different lifetime model from add_instant_xml().
369 XMLNode* node = new XMLNode (keyboard->get_state());
370 Config->add_extra_xml (*node);
371 Config->save_state();
373 XMLNode& enode (static_cast<Stateful*>(editor)->get_state());
374 XMLNode& mnode (mixer->get_state());
377 session->add_instant_xml(enode, session->path());
378 session->add_instant_xml(mnode, session->path());
380 Config->add_instant_xml(enode, get_user_ardour_path());
381 Config->add_instant_xml(mnode, get_user_ardour_path());
386 ARDOUR_UI::startup ()
388 /* Once the UI is up and running, start the audio engine. Doing
389 this before the UI is up and running can cause problems
390 when not running with SCHED_FIFO, because the amount of
391 CPU and disk work needed to get the UI started can interfere
392 with the scheduling of the audio thread.
395 Glib::signal_idle().connect (mem_fun(*this, &ARDOUR_UI::start_engine));
401 if (session && session->dirty()) {
402 switch (ask_about_saving_session(_("quit"))) {
407 /* use the default name */
408 if (save_state_canfail ("")) {
409 /* failed - don't quit */
410 MessageDialog msg (*editor,
412 Ardour was unable to save your session.\n\n\
413 If you still wish to quit, please use the\n\n\
414 \"Just quit\" option."));
428 ARDOUR_UI::ask_about_saving_session (const string & what)
430 ArdourDialog window (_("ardour: save session?"));
431 Gtk::Label prompt_label;
434 msg = string_compose(_("Save and %1"), what);
435 window.add_button (msg, RESPONSE_ACCEPT);
436 msg = string_compose(_("Just %1"), what);
437 window.add_button (msg, RESPONSE_APPLY);
438 msg = string_compose(_("Don't %1"), what);
439 window.add_button (msg, RESPONSE_REJECT);
441 Gtk::Button noquit_button (msg);
442 noquit_button.set_name ("EditorGTKButton");
447 if (session->snap_name() == session->name()) {
450 type = _("snapshot");
452 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?"),
453 type, session->snap_name());
455 prompt_label.set_text (prompt);
456 prompt_label.set_alignment (0.5, 0.5);
457 prompt_label.set_name (X_("PrompterLabel"));
459 window.get_vbox()->pack_start (prompt_label);
461 window.set_name (_("Prompter"));
462 window.set_position (Gtk::WIN_POS_MOUSE);
463 window.set_modal (true);
466 save_the_session = 0;
468 editor->ensure_float (window);
470 ResponseType r = (ResponseType) window.run();
475 case RESPONSE_ACCEPT: // save and get out of here
477 case RESPONSE_APPLY: // get out of here
487 ARDOUR_UI::every_second ()
490 update_buffer_load ();
491 update_disk_space ();
492 // update_disk_rate ();
497 ARDOUR_UI::every_point_one_seconds ()
502 /* do not attempt to grab peak power more than once per cycle.
505 gettimeofday (&now, 0);
506 timersub (&now, &last_peak_grab, &diff);
508 if ((diff.tv_usec + (diff.tv_sec * 1000000)) >= engine->usecs_per_cycle()) {
509 IO::GrabPeakPower(); /* EMIT_SIGNAL */
510 last_peak_grab = now;
513 update_speed_display ();
514 RapidScreenUpdate(); /* EMIT_SIGNAL */
519 ARDOUR_UI::every_point_zero_one_seconds ()
521 SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
526 ARDOUR_UI::update_sample_rate (jack_nframes_t ignored)
530 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored));
532 if (!engine->connected()) {
534 snprintf (buf, sizeof (buf), _("disconnected"));
538 jack_nframes_t rate = engine->frame_rate();
540 if (fmod (rate, 1000.0) != 0.0) {
541 snprintf (buf, sizeof (buf), _("SR: %.1f kHz / %4.1f msecs"),
542 (float) rate/1000.0f,
543 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
545 snprintf (buf, sizeof (buf), _("SR: %u kHz / %4.1f msecs"),
547 (engine->frames_per_cycle() / (float) rate) * 1000.0f);
551 sample_rate_label.set_text (buf);
555 ARDOUR_UI::update_cpu_load ()
558 snprintf (buf, sizeof (buf), _("DSP Load: %.1f%%"), engine->get_cpu_load());
559 cpu_load_label.set_text (buf);
563 ARDOUR_UI::update_disk_rate ()
568 snprintf (buf, sizeof (buf), _("Disk r:%5.1f w:%5.1f MB/s"),
569 session->read_data_rate()/1048576.0f, session->write_data_rate()/1048576.0f);
570 disk_rate_label.set_text (buf);
572 disk_rate_label.set_text ("");
577 ARDOUR_UI::update_buffer_load ()
582 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"),
583 session->playback_load(), session->capture_load());
584 buffer_load_label.set_text (buf);
586 buffer_load_label.set_text ("");
591 ARDOUR_UI::count_recenabled_diskstreams (DiskStream& ds)
593 if (ds.record_enabled()) {
594 rec_enabled_diskstreams++;
599 ARDOUR_UI::update_disk_space()
605 jack_nframes_t frames = session->available_capture_duration();
608 if (frames == max_frames) {
609 strcpy (buf, _("space: 24hrs+"));
614 jack_nframes_t fr = session->frame_rate();
616 if (session->actively_recording()){
618 rec_enabled_diskstreams = 0;
619 session->foreach_diskstream (this, &ARDOUR_UI::count_recenabled_diskstreams);
621 if (rec_enabled_diskstreams) {
622 frames /= rec_enabled_diskstreams;
627 /* hmmm. shall we divide by the route count? or the diskstream count?
628 or what? for now, do nothing ...
633 hrs = frames / (fr * 3600);
634 frames -= hrs * fr * 3600;
635 mins = frames / (fr * 60);
636 frames -= mins * fr * 60;
639 snprintf (buf, sizeof(buf), _("space: %02dh:%02dm:%02ds"), hrs, mins, secs);
642 disk_space_label.set_text (buf);
646 ARDOUR_UI::update_wall_clock ()
653 tm_now = localtime (&now);
655 sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
656 wall_clock_label.set_text (buf);
661 ARDOUR_UI::control_methods_adjusted ()
666 which_method = (int) online_control_button->adjustment.get_value();
667 switch (which_method) {
669 allow_mmc_and_local ();
678 fatal << _("programming error: impossible control method") << endmsg;
684 ARDOUR_UI::mmc_device_id_adjusted ()
689 int dev_id = (int) mmc_id_button->adjustment.get_value();
690 mmc->set_device_id (dev_id);
696 ARDOUR_UI::session_menu (GdkEventButton *ev)
698 session_popup_menu->popup (0, 0);
703 ARDOUR_UI::redisplay_recent_sessions ()
705 vector<string *> *sessions;
706 vector<string *>::iterator i;
707 RecentSessionsSorter cmp;
709 recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
710 recent_session_model->clear ();
713 ARDOUR::read_recent_sessions (rs);
716 recent_session_display.set_model (recent_session_model);
720 /* sort them alphabetically */
721 sort (rs.begin(), rs.end(), cmp);
722 sessions = new vector<string*>;
724 for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
725 sessions->push_back (new string ((*i).second));
728 for (i = sessions->begin(); i != sessions->end(); ++i) {
730 vector<string*>* states;
731 vector<const gchar*> item;
732 string fullpath = *(*i);
734 /* remove any trailing / */
736 if (fullpath[fullpath.length()-1] == '/') {
737 fullpath = fullpath.substr (0, fullpath.length()-1);
740 /* now get available states for this session */
742 if ((states = Session::possible_states (fullpath)) == 0) {
747 TreeModel::Row row = *(recent_session_model->append());
749 row[recent_session_columns.visible_name] = PBD::basename (fullpath);
750 row[recent_session_columns.fullpath] = fullpath;
752 if (states->size() > 1) {
754 /* add the children */
756 for (vector<string*>::iterator i2 = states->begin(); i2 != states->end(); ++i2) {
758 TreeModel::Row child_row = *(recent_session_model->append (row.children()));
760 child_row[recent_session_columns.visible_name] = **i2;
761 child_row[recent_session_columns.fullpath] = fullpath;
770 recent_session_display.set_model (recent_session_model);
775 ARDOUR_UI::build_session_selector ()
777 session_selector_window = new ArdourDialog ("session selector");
779 Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
781 session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
782 session_selector_window->add_button (Stock::OK, RESPONSE_ACCEPT);
784 recent_session_model = TreeStore::create (recent_session_columns);
785 recent_session_display.set_model (recent_session_model);
786 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
787 recent_session_display.set_headers_visible (false);
789 scroller->add (recent_session_display);
790 scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
792 session_selector_window->set_name ("SessionSelectorWindow");
793 session_selector_window->set_size_request (200, 400);
794 session_selector_window->get_vbox()->pack_start (*scroller);
795 session_selector_window->show_all_children();
799 ARDOUR_UI::open_recent_session ()
801 /* popup selector window */
803 if (session_selector_window == 0) {
804 build_session_selector ();
807 redisplay_recent_sessions ();
809 ResponseType r = (ResponseType) session_selector_window->run ();
811 session_selector_window->hide();
814 case RESPONSE_ACCEPT:
820 Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
822 if (i == recent_session_model->children().end()) {
826 Glib::ustring path = (*i)[recent_session_columns.fullpath];
827 Glib::ustring state = (*i)[recent_session_columns.visible_name];
829 _session_is_new = false;
831 load_session (path, state);
835 ARDOUR_UI::filter_ardour_session_dirs (const FileFilter::Info& info)
839 if (stat (info.filename.c_str(), &statbuf) != 0) {
843 if (!S_ISDIR(statbuf.st_mode)) {
847 string session_file = info.filename;
849 session_file += PBD::basename (info.filename);
850 session_file += ".ardour";
852 if (stat (session_file.c_str(), &statbuf) != 0) {
856 return S_ISREG (statbuf.st_mode);
860 ARDOUR_UI::open_session ()
862 /* popup selector window */
864 if (open_session_selector == 0) {
866 /* ardour sessions are folders */
868 open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN);
869 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
870 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
872 FileFilter session_filter;
873 session_filter.add_pattern ("*.ardour");
874 session_filter.set_name (_("Ardour sessions"));
875 open_session_selector->add_filter (session_filter);
876 open_session_selector->set_filter (session_filter);
879 int response = open_session_selector->run();
880 open_session_selector->hide ();
883 case RESPONSE_ACCEPT:
886 open_session_selector->hide();
890 open_session_selector->hide();
891 string session_path = open_session_selector->get_filename();
895 if (session_path.length() > 0) {
896 if (Session::find_session (session_path, path, name, isnew) == 0) {
897 _session_is_new = isnew;
898 load_session (path, name);
905 ARDOUR_UI::session_add_midi_track ()
907 cerr << _("Patience is a virtue.\n");
911 ARDOUR_UI::session_add_audio_route (bool disk, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode)
916 warning << _("You cannot add a track without a session already loaded.") << endmsg;
922 if ((route = session->new_audio_track (input_channels, output_channels, mode)) == 0) {
923 error << _("could not create new audio track") << endmsg;
926 if ((route = session->new_audio_route (input_channels, output_channels)) == 0) {
927 error << _("could not create new audio bus") << endmsg;
932 if (need_control_room_outs) {
938 route->set_stereo_control_outs (control_lr_channels);
939 route->control_outs()->set_stereo_pan (pans, this);
941 #endif /* CONTROLOUTS */
945 MessageDialog msg (*editor,
946 _("There are insufficient JACK ports available\n\
947 to create a new track or bus.\n\
948 You should save Ardour, exit and\n\
949 restart JACK with more ports."));
955 ARDOUR_UI::diskstream_added (DiskStream* ds)
960 ARDOUR_UI::do_transport_locate (jack_nframes_t new_position)
962 jack_nframes_t _preroll;
965 _preroll = session->convert_to_frames_at (new_position, session->preroll);
967 if (new_position > _preroll) {
968 new_position -= _preroll;
973 session->request_locate (new_position);
978 ARDOUR_UI::transport_goto_start ()
981 session->goto_start();
984 /* force displayed area in editor to start no matter
985 what "follow playhead" setting is.
989 editor->reposition_x_origin (session->current_start_frame());
995 ARDOUR_UI::transport_goto_zero ()
998 session->request_locate (0);
1001 /* force displayed area in editor to start no matter
1002 what "follow playhead" setting is.
1006 editor->reposition_x_origin (0);
1012 ARDOUR_UI::transport_goto_end ()
1015 jack_nframes_t frame = session->current_end_frame();
1016 session->request_locate (frame);
1018 /* force displayed area in editor to start no matter
1019 what "follow playhead" setting is.
1023 editor->reposition_x_origin (frame);
1029 ARDOUR_UI::transport_stop ()
1035 if (session->is_auditioning()) {
1036 session->cancel_audition ();
1040 if (session->get_auto_loop()) {
1041 session->request_auto_loop (false);
1044 session->request_stop ();
1048 ARDOUR_UI::transport_stop_and_forget_capture ()
1051 session->request_stop (true);
1056 ARDOUR_UI::remove_last_capture()
1059 editor->remove_last_capture();
1064 ARDOUR_UI::transport_record ()
1067 switch (session->record_status()) {
1068 case Session::Disabled:
1069 if (session->ntracks() == 0) {
1070 string txt = _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu.");
1071 MessageDialog msg (*editor, txt);
1075 session->maybe_enable_record ();
1077 case Session::Recording:
1078 case Session::Enabled:
1079 session->disable_record (true);
1085 ARDOUR_UI::transport_roll ()
1093 rolling = session->transport_rolling ();
1095 if (session->get_auto_loop()) {
1096 session->request_auto_loop (false);
1097 auto_loop_button.set_active (false);
1098 roll_button.set_active (true);
1099 } else if (session->get_play_range ()) {
1100 session->request_play_range (false);
1101 play_selection_button.set_active (false);
1102 } else if (rolling) {
1103 session->request_locate (session->last_transport_start(), true);
1106 session->request_transport_speed (1.0f);
1110 ARDOUR_UI::transport_loop()
1113 if (session->get_auto_loop()) {
1114 if (session->transport_rolling()) {
1115 Location * looploc = session->locations()->auto_loop_location();
1117 session->request_locate (looploc->start(), true);
1122 session->request_auto_loop (true);
1128 ARDOUR_UI::transport_play_selection ()
1134 if (!session->get_play_range()) {
1135 session->request_stop ();
1138 editor->play_selection ();
1142 ARDOUR_UI::transport_rewind (int option)
1144 float current_transport_speed;
1147 current_transport_speed = session->transport_speed();
1149 if (current_transport_speed >= 0.0f) {
1152 session->request_transport_speed (-1.0f);
1155 session->request_transport_speed (-4.0f);
1158 session->request_transport_speed (-0.5f);
1163 session->request_transport_speed (current_transport_speed * 1.5f);
1169 ARDOUR_UI::transport_forward (int option)
1171 float current_transport_speed;
1174 current_transport_speed = session->transport_speed();
1176 if (current_transport_speed <= 0.0f) {
1179 session->request_transport_speed (1.0f);
1182 session->request_transport_speed (4.0f);
1185 session->request_transport_speed (0.5f);
1190 session->request_transport_speed (current_transport_speed * 1.5f);
1196 ARDOUR_UI::toggle_monitor_enable (guint32 dstream)
1204 if ((ds = session->diskstream_by_id (dstream)) != 0) {
1205 Port *port = ds->io()->input (0);
1206 port->request_monitor_input (!port->monitoring_input());
1211 ARDOUR_UI::toggle_record_enable (guint32 dstream)
1219 if ((ds = session->diskstream_by_id (dstream)) != 0) {
1220 ds->set_record_enabled (!ds->record_enabled(), this);
1225 ARDOUR_UI::queue_transport_change ()
1227 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
1231 ARDOUR_UI::map_transport_state ()
1233 float sp = session->transport_speed();
1236 transport_rolling ();
1237 } else if (sp < 0.0f) {
1238 transport_rewinding ();
1239 } else if (sp > 0.0f) {
1240 transport_forwarding ();
1242 transport_stopped ();
1247 ARDOUR_UI::send_all_midi_feedback ()
1250 session->send_all_midi_feedback();
1255 ARDOUR_UI::allow_local_only ()
1261 ARDOUR_UI::allow_mmc_only ()
1267 ARDOUR_UI::allow_mmc_and_local ()
1273 ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg)
1275 snprintf (buf, sizeof(buf), "%s", ((GlobalClickBox *) arg)->strings[
1276 (int) adj.get_value()].c_str());
1280 ARDOUR_UI::engine_stopped ()
1282 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
1283 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1284 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1289 ARDOUR_UI::engine_running ()
1291 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
1292 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
1293 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
1297 ARDOUR_UI::engine_halted ()
1299 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted));
1301 ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
1302 ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
1304 update_sample_rate (0);
1306 MessageDialog msg (*editor,
1308 JACK has either been shutdown or it\n\
1309 disconnected Ardour because Ardour\n\
1310 was not fast enough. You can save the\n\
1311 session and/or try to reconnect to JACK ."));
1316 ARDOUR_UI::do_engine_start ()
1322 catch (AudioEngine::PortRegistrationFailure& err) {
1324 error << _("Unable to create all required ports")
1332 error << _("Unable to start the session running")
1342 ARDOUR_UI::start_engine ()
1344 if (do_engine_start () == 0) {
1345 if (session && _session_is_new) {
1346 /* we need to retain initial visual
1347 settings for a new session
1349 session->save_state ("");
1352 /* there is too much going on, in too many threads, for us to
1353 end up with a clean session. So wait 1 second after loading,
1354 and fix it up. its ugly, but until i come across a better
1355 solution, its what we have.
1358 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::make_session_clean), 1000);
1365 ARDOUR_UI::update_clocks ()
1367 Clock (session->audible_frame()); /* EMIT_SIGNAL */
1371 ARDOUR_UI::start_clocking ()
1373 clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
1377 ARDOUR_UI::stop_clocking ()
1379 clock_signal_connection.disconnect ();
1383 ARDOUR_UI::toggle_clocking ()
1386 if (clock_button.get_active()) {
1395 ARDOUR_UI::_blink (void *arg)
1398 ((ARDOUR_UI *) arg)->blink ();
1405 Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
1409 ARDOUR_UI::start_blinking ()
1411 /* Start the blink signal. Everybody with a blinking widget
1412 uses Blink to drive the widget's state.
1415 if (blink_timeout_tag < 0) {
1417 blink_timeout_tag = gtk_timeout_add (240, _blink, this);
1422 ARDOUR_UI::stop_blinking ()
1424 if (blink_timeout_tag >= 0) {
1425 gtk_timeout_remove (blink_timeout_tag);
1426 blink_timeout_tag = -1;
1432 ARDOUR_UI::add_diskstream_to_menu (DiskStream& dstream)
1434 using namespace Gtk;
1435 using namespace Menu_Helpers;
1437 if (dstream.hidden()) {
1441 MenuList& items = diskstream_menu->items();
1442 items.push_back (MenuElem (dstream.name(), bind (mem_fun(*this, &ARDOUR_UI::diskstream_selected), (gint32) dstream.id())));
1446 ARDOUR_UI::diskstream_selected (gint32 id)
1448 selected_dstream = id;
1453 ARDOUR_UI::select_diskstream (GdkEventButton *ev)
1455 using namespace Gtk;
1456 using namespace Menu_Helpers;
1462 diskstream_menu = new Menu();
1463 diskstream_menu->set_name ("ArdourContextMenu");
1464 using namespace Gtk;
1465 using namespace Menu_Helpers;
1467 MenuList& items = diskstream_menu->items();
1468 items.push_back (MenuElem (_("No Stream"), (bind (mem_fun(*this, &ARDOUR_UI::diskstream_selected), -1))));
1470 session->foreach_diskstream (this, &ARDOUR_UI::add_diskstream_to_menu);
1473 diskstream_menu->popup (ev->button, ev->time);
1475 diskstream_menu->popup (0, 0);
1478 selected_dstream = -1;
1482 delete diskstream_menu;
1484 return selected_dstream;
1488 ARDOUR_UI::name_io_setup (AudioEngine& engine,
1494 if (io.n_inputs() == 0) {
1499 /* XXX we're not handling multiple ports yet. */
1501 const char **connections = io.input(0)->get_connections();
1503 if (connections == 0 || connections[0] == '\0') {
1506 buf = connections[0];
1513 if (io.n_outputs() == 0) {
1518 /* XXX we're not handling multiple ports yet. */
1520 const char **connections = io.output(0)->get_connections();
1522 if (connections == 0 || connections[0] == '\0') {
1525 buf = connections[0];
1533 ARDOUR_UI::snapshot_session ()
1535 ArdourPrompter prompter (true);
1542 now = now.substr (0, now.length() - 1);
1544 prompter.set_name ("Prompter");
1545 prompter.set_prompt (_("Name for snapshot"));
1546 prompter.set_initial_text (now);
1548 switch (prompter.run()) {
1549 case RESPONSE_ACCEPT:
1550 prompter.get_result (snapname);
1551 if (snapname.length()){
1552 save_state (snapname);
1562 ARDOUR_UI::save_state (const string & name)
1564 (void) save_state_canfail (name);
1568 ARDOUR_UI::save_state_canfail (string name)
1573 if (name.length() == 0) {
1574 name = session->snap_name();
1577 if ((ret = session->save_state (name)) != 0) {
1581 save_ardour_state (); /* XXX cannot fail? yeah, right ... */
1586 ARDOUR_UI::restore_state (string name)
1589 if (name.length() == 0) {
1590 name = session->name();
1592 session->restore_state (name);
1597 ARDOUR_UI::primary_clock_value_changed ()
1600 session->request_locate (primary_clock.current_time ());
1605 ARDOUR_UI::secondary_clock_value_changed ()
1608 session->request_locate (secondary_clock.current_time ());
1613 ARDOUR_UI::rec_enable_button_blink (bool onoff, DiskStream *dstream, Widget *w)
1615 if (session && dstream && dstream->record_enabled()) {
1617 Session::RecordState rs;
1619 rs = session->record_status ();
1622 case Session::Disabled:
1623 case Session::Enabled:
1624 if (w->get_state() != STATE_SELECTED) {
1625 w->set_state (STATE_SELECTED);
1629 case Session::Recording:
1630 if (w->get_state() != STATE_ACTIVE) {
1631 w->set_state (STATE_ACTIVE);
1637 if (w->get_state() != STATE_NORMAL) {
1638 w->set_state (STATE_NORMAL);
1644 ARDOUR_UI::transport_rec_enable_blink (bool onoff)
1650 switch (session->record_status()) {
1651 case Session::Enabled:
1653 rec_button.set_state (1);
1655 rec_button.set_state (0);
1659 case Session::Recording:
1660 rec_button.set_state (2);
1664 rec_button.set_state (0);
1670 ARDOUR_UI::hide_and_quit (GdkEventAny *ev, ArdourDialog *window)
1678 ARDOUR_UI::start_keyboard_prefix ()
1680 keyboard->start_prefix();
1684 ARDOUR_UI::save_template ()
1687 ArdourPrompter prompter (true);
1690 prompter.set_name (X_("Prompter"));
1691 prompter.set_prompt (_("Name for mix template:"));
1692 prompter.set_initial_text(session->name() + _("-template"));
1694 switch (prompter.run()) {
1695 case RESPONSE_ACCEPT:
1696 prompter.get_result (name);
1698 if (name.length()) {
1699 session->save_template (name);
1709 ARDOUR_UI::new_session (bool startup, std::string predetermined_path)
1711 m_new_session_dialog->show_all();
1712 m_new_session_dialog->set_transient_for(*editor);
1713 m_new_session_dialog->set_name(predetermined_path);
1715 int response = Gtk::RESPONSE_CANCEL;
1718 response = m_new_session_dialog->run ();
1720 if(response == Gtk::RESPONSE_OK) {
1722 _session_is_new = true;
1724 std::string session_name = m_new_session_dialog->session_name();
1725 std::string session_path = m_new_session_dialog->session_folder();
1728 XXX This is needed because session constructor wants a
1729 non-existant path. hopefully this will be fixed at some point.
1731 session_path = Glib::build_filename(session_path, session_name);
1733 std::string template_name = m_new_session_dialog->session_template_name();
1735 if (m_new_session_dialog->use_session_template()) {
1737 load_session (session_path, session_name, &template_name);
1743 Session::AutoConnectOption iconnect;
1744 Session::AutoConnectOption oconnect;
1746 if (m_new_session_dialog->create_control_bus()) {
1747 cchns = (uint32_t) m_new_session_dialog->control_channel_count();
1752 if (m_new_session_dialog->create_master_bus()) {
1753 mchns = (uint32_t) m_new_session_dialog->master_channel_count();
1758 if (m_new_session_dialog->connect_inputs()) {
1759 iconnect = Session::AutoConnectPhysical;
1761 iconnect = Session::AutoConnectOption (0);
1764 /// @todo some minor tweaks.
1766 if (m_new_session_dialog->connect_outs_to_master()) {
1767 oconnect = Session::AutoConnectMaster;
1768 } else if (m_new_session_dialog->connect_outs_to_physical()) {
1769 oconnect = Session::AutoConnectPhysical;
1771 oconnect = Session::AutoConnectOption (0);
1774 uint32_t nphysin = (uint32_t) m_new_session_dialog->input_limit_count();
1775 uint32_t nphysout = (uint32_t) m_new_session_dialog->output_limit_count();
1777 build_session (session_path,
1785 engine->frame_rate() * 60 * 5);
1789 } while(response == Gtk::RESPONSE_HELP);
1790 m_new_session_dialog->hide_all();
1794 ARDOUR_UI::load_session (const string & path, const string & snap_name, string* mix_template)
1796 Session *new_session;
1798 session_loaded = false;
1799 x = unload_session ();
1807 /* if it already exists, we must have write access */
1809 if (::access (path.c_str(), F_OK) == 0 && ::access (path.c_str(), W_OK)) {
1810 MessageDialog msg (*editor, _("\
1811 You do not have write access to this session.\n\
1812 This prevents the session from being loaded."));
1818 new_session = new Session (*engine, path, snap_name, mix_template);
1823 error << string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg;
1827 connect_to_session (new_session);
1829 //if (engine->running()) {
1830 //mixer->show_window();
1832 session_loaded = true;
1837 ARDOUR_UI::make_session_clean ()
1840 session->set_clean ();
1847 ARDOUR_UI::build_session (const string & path, const string & snap_name,
1848 uint32_t control_channels,
1849 uint32_t master_channels,
1850 Session::AutoConnectOption input_connect,
1851 Session::AutoConnectOption output_connect,
1854 jack_nframes_t initial_length)
1856 Session *new_session;
1859 session_loaded = false;
1860 x = unload_session ();
1867 _session_is_new = true;
1870 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
1871 control_channels, master_channels, nphysin, nphysout, initial_length);
1876 error << string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg;
1880 connect_to_session (new_session);
1882 //if (engine->running()) {
1883 //mixer->show_window();
1885 session_loaded = true;
1893 editor->show_window ();
1897 if (session && mixer) {
1898 // mixer->show_window ();
1907 ARDOUR_UI::show_splash ()
1910 about = new About();
1916 ARDOUR_UI::hide_splash ()
1924 ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title, const string & msg)
1928 removed = rep.paths.size();
1931 MessageDialog msg (*editor, X_("cleanupresults"),
1933 No audio files were ready for cleanup\n\n\
1934 If this seems suprising, check for any existing\n\
1935 snapshots. These may still include regions that\n\
1936 require some unused files to continue to exist."));
1941 ArdourDialog results (_("ardour: cleanup"), true);
1943 struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
1944 CleanupResultsModelColumns() {
1948 Gtk::TreeModelColumn<Glib::ustring> visible_name;
1949 Gtk::TreeModelColumn<Glib::ustring> fullpath;
1953 Glib::RefPtr<Gtk::ListStore> results_model;
1954 CleanupResultsModelColumns results_columns;
1955 Gtk::TreeView results_display;
1957 results_model = ListStore::create (results_columns);
1958 results_display.set_model (results_model);
1959 results_display.append_column (list_title, results_columns.visible_name);
1960 results_display.set_headers_visible (true);
1962 Gtk::ScrolledWindow list_scroller;
1965 if (rep.space < 1048576.0f) {
1967 txt.set_text (string_compose (msg, removed, _("files"), (float) rep.space / 1024.0f, "kilo"));
1969 txt.set_text (string_compose (msg, removed, _("file"), (float) rep.space / 1024.0f, "kilo"));
1973 txt.set_text (string_compose (msg, removed, _("files"), (float) rep.space / 1048576.0f, "mega"));
1975 txt.set_text (string_compose (msg, removed, _("file"), (float) rep.space / 1048576.0f, "mega"));
1979 results.get_vbox()->pack_start (txt, false, false);
1981 for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
1982 TreeModel::Row row = *(results_model->append());
1983 row[results_columns.visible_name] = *i;
1984 row[results_columns.fullpath] = *i;
1987 list_scroller.add (results_display);
1988 list_scroller.set_size_request (-1, 250);
1989 list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1991 results.get_vbox()->pack_start (list_scroller, true, true);
1992 results.add_button (Stock::OK, RESPONSE_ACCEPT);
1993 results.set_position (Gtk::WIN_POS_MOUSE);
1999 ARDOUR_UI::cleanup ()
2002 /* shouldn't happen: menu item is insensitive */
2006 ArdourDialog checker (_("ardour cleanup"));
2007 Gtk::Label label (_("\
2008 Cleanup is a destructive operation.\n\
2009 ALL undo/redo information will be lost if you cleanup.\n\
2010 Unused audio files will be moved to a \"dead sounds\" location."));
2012 checker.get_vbox()->pack_start (label, false, false);
2013 checker.add_button (Stock::OK, RESPONSE_ACCEPT);
2014 checker.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2016 checker.set_name (_("CleanupDialog"));
2017 checker.set_wmclass (_("ardour_cleanup"), "Ardour");
2018 checker.set_position (Gtk::WIN_POS_MOUSE);
2020 switch (checker.run()) {
2021 case RESPONSE_ACCEPT:
2027 Session::cleanup_report rep;
2029 editor->prepare_for_cleanup ();
2031 if (session->cleanup_sources (rep)) {
2035 display_cleanup_results (rep,
2038 The following %1 %2 were not in use.\n\
2039 The next time you flush the wastebasket\n\
2040 it will release an additional %3 %4bytes\n\
2046 ARDOUR_UI::flush_trash ()
2049 /* shouldn't happen: menu item is insensitive */
2053 Session::cleanup_report rep;
2055 if (session->cleanup_trash_sources (rep)) {
2059 display_cleanup_results (rep,
2061 _("The following %1 file%2 were deleted, releasing %3 %4bytes of disk space"));
2065 ARDOUR_UI::add_route ()
2073 if (add_route_dialog == 0) {
2074 add_route_dialog = new AddRouteDialog;
2075 editor->ensure_float (*add_route_dialog);
2078 if (add_route_dialog->is_visible()) {
2079 /* we're already doing this */
2083 ResponseType r = (ResponseType) add_route_dialog->run ();
2085 add_route_dialog->hide();
2088 case RESPONSE_ACCEPT:
2095 if ((count = add_route_dialog->count()) <= 0) {
2099 uint32_t input_chan = add_route_dialog->channels ();
2100 uint32_t output_chan;
2101 string name_template = add_route_dialog->name_template ();
2102 bool track = add_route_dialog->track ();
2104 Session::AutoConnectOption oac = session->get_output_auto_connect();
2106 if (oac & Session::AutoConnectMaster) {
2107 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
2109 output_chan = input_chan;
2112 /* XXX do something with name template */
2116 session_add_audio_track (input_chan, output_chan, add_route_dialog->mode());
2118 session_add_audio_bus (input_chan, output_chan);
2122 while (Main::events_pending()) {
2129 ARDOUR_UI::mixer_settings () const
2134 node = session->instant_xml(X_("Mixer"), session->path());
2136 node = Config->instant_xml(X_("Mixer"), get_user_ardour_path());
2140 node = new XMLNode (X_("Mixer"));
2147 ARDOUR_UI::editor_settings () const
2152 node = session->instant_xml(X_("Editor"), session->path());
2154 node = Config->instant_xml(X_("Editor"), get_user_ardour_path());
2158 node = new XMLNode (X_("Editor"));
2164 ARDOUR_UI::keyboard_settings () const
2168 node = Config->extra_xml(X_("Keyboard"));
2171 node = new XMLNode (X_("Keyboard"));
2177 ARDOUR_UI::halt_on_xrun_message ()
2179 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::halt_on_xrun_message));
2181 MessageDialog msg (*editor,
2182 _("Recording was stopped because your system could not keep up."));
2187 ARDOUR_UI::delete_sources_in_the_right_thread (list<ARDOUR::Source*>* deletion_list)
2189 ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::delete_sources_in_the_right_thread), deletion_list));
2191 for (list<Source*>::iterator i = deletion_list->begin(); i != deletion_list->end(); ++i) {
2195 delete deletion_list;
2199 ARDOUR_UI::disk_overrun_handler ()
2201 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
2203 if (!have_disk_overrun_displayed) {
2204 have_disk_overrun_displayed = true;
2205 MessageDialog msg (*editor, X_("diskrate dialog"), _("\
2206 The disk system on your computer\n\
2207 was not able to keep up with Ardour.\n\
2209 Specifically, it failed to write data to disk\n\
2210 quickly enough to keep up with recording.\n"));
2212 have_disk_overrun_displayed = false;
2217 ARDOUR_UI::disk_underrun_handler ()
2219 ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
2221 if (!have_disk_underrun_displayed) {
2222 have_disk_underrun_displayed = true;
2223 MessageDialog msg (*editor,
2224 (_("The disk system on your computer\n\
2225 was not able to keep up with Ardour.\n\
2227 Specifically, it failed to read data from disk\n\
2228 quickly enough to keep up with playback.\n")));
2230 have_disk_underrun_displayed = false;
2235 ARDOUR_UI::disk_underrun_message_gone ()
2237 have_disk_underrun_displayed = false;
2241 ARDOUR_UI::disk_overrun_message_gone ()
2243 have_disk_underrun_displayed = false;
2247 ARDOUR_UI::pending_state_dialog ()
2249 ArdourDialog dialog ("pending state dialog");
2251 This session appears to have been in\n\
2252 middle of recording when ardour or\n\
2253 the computer was shutdown.\n\
2255 Ardour can recover any captured audio for\n\
2256 you, or it can ignore it. Please decide\n\
2257 what you would like to do.\n"));
2259 dialog.get_vbox()->pack_start (message);
2260 dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT);
2261 dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT);
2263 dialog.set_position (WIN_POS_CENTER);
2266 switch (dialog.run ()) {
2267 case RESPONSE_ACCEPT:
2278 ARDOUR_UI::disconnect_from_jack ()
2281 if( engine->disconnect_from_jack ()) {
2282 MessageDialog msg (*editor, _("Could not disconnect from JACK"));
2286 update_sample_rate (0);
2291 ARDOUR_UI::reconnect_to_jack ()
2294 if (engine->reconnect_to_jack ()) {
2295 MessageDialog msg (*editor, _("Could not reconnect to JACK"));
2299 update_sample_rate (0);
2304 ARDOUR_UI::set_jack_buffer_size (jack_nframes_t nframes)
2306 engine->request_buffer_size (nframes);
2307 update_sample_rate (0);
2311 ARDOUR_UI::cmdline_new_session (string path)
2313 if (path[0] != '/') {
2314 char buf[PATH_MAX+1];
2317 getcwd (buf, sizeof (buf));
2324 new_session (false, path);
2326 _will_create_new_session_automatically = false; /* done it */
2327 return FALSE; /* don't call it again */