diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc index 4bc10e93ec..0ad6b8af5b 100644 --- a/gtk2_ardour/audio_region_view.cc +++ b/gtk2_ardour/audio_region_view.cc @@ -202,6 +202,8 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfd) fade_in_active_changed (); fade_out_active_changed (); + reset_width_dependent_items (_pixel_width); + fade_in_shape->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_in_event), fade_in_shape, this)); fade_in_handle->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_in_handle_event), fade_in_handle, this)); fade_out_shape->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_out_event), fade_out_shape, this)); diff --git a/gtk2_ardour/audio_streamview.cc b/gtk2_ardour/audio_streamview.cc index 22f8fa6239..c571cb1a7c 100644 --- a/gtk2_ardour/audio_streamview.cc +++ b/gtk2_ardour/audio_streamview.cc @@ -311,6 +311,7 @@ AudioStreamView::add_crossfade (boost::shared_ptr crossfade) for (list::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) { if ((*i)->crossfade == crossfade) { + if (!crossfades_visible || layer_display == Stacked) { (*i)->hide(); } else { @@ -340,10 +341,9 @@ AudioStreamView::add_crossfade (boost::shared_ptr crossfade) _samples_per_unit, region_color, *lview, *rview); - + cv->set_valid (true); crossfade->Invalidated.connect (mem_fun (*this, &AudioStreamView::remove_crossfade)); crossfade_views.push_back (cv); - if (!Config->get_xfades_visible() || !crossfades_visible || layer_display == Stacked) { cv->hide (); } @@ -390,6 +390,8 @@ AudioStreamView::redisplay_diskstream () apl->foreach_crossfade (this, &AudioStreamView::add_crossfade); } + RegionViewList copy; + for (i = region_views.begin(); i != region_views.end(); ) { tmp = i; tmp++; @@ -397,11 +399,47 @@ AudioStreamView::redisplay_diskstream () if (!(*i)->is_valid()) { delete *i; region_views.erase (i); + i = tmp; + continue; } else { (*i)->enable_display(true); } + /* + sort regionviews by layer so that when we call region_layered () + the canvas layering works out (in non-stacked mode). + */ + + if (copy.size() == 0) { + copy.push_front((*i)); + i = tmp; + continue; + } + + RegionViewList::iterator k = copy.begin(); + RegionViewList::iterator l = copy.end(); + l--; + + if ((*i)->region()->layer() <= (*k)->region()->layer()) { + copy.push_front((*i)); + i = tmp; + continue; + } else if ((*i)->region()->layer() >= (*l)->region()->layer()) { + copy.push_back((*i)); + i = tmp; + continue; + } + + for (RegionViewList::iterator j = copy.begin(); j != copy.end(); ++j) { + + if ((*j)->region()->layer() >= (*i)->region()->layer()) { + copy.insert(j, (*i)); + break; + } + } + i = tmp; + } for (xi = crossfade_views.begin(); xi != crossfade_views.end();) { @@ -416,10 +454,12 @@ AudioStreamView::redisplay_diskstream () xi = tmpx; } - /* now fix layering */ - - for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) { - region_layered (*i); + /* now fix canvas layering */ + + for (RegionViewList::iterator j = copy.begin(); j != copy.end(); ++j) { + (*j)->enable_display(true); + (*j)->set_y_position_and_height(0, height); + region_layered (*j); } } diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index da74ea96cc..1e726277d2 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -348,7 +348,8 @@ Editor::Editor () range_marker_drag_rect = 0; marker_drag_line = 0; - + tempo_map_change_idle_handler_id = -1; + canvas_hroizontally_scrolled_handler_id = -1; set_midi_edit_mode (MidiEditPencil, true); set_mouse_mode (MouseObject, true); @@ -1983,7 +1984,9 @@ Editor::set_snap_to (SnapType st) case SnapToAEighthBeat: case SnapToAQuarterBeat: case SnapToAThirdBeat: + compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + (nframes_t)(canvas_width * frames_per_unit)); update_tempo_based_rulers (); + break; default: /* relax */ break; @@ -2638,7 +2641,7 @@ Editor::setup_toolbar () /* Zoom */ zoom_box.set_spacing (1); - zoom_box.set_border_width (2); + zoom_box.set_border_width (0); zoom_in_button.set_name ("EditorTimeButton"); zoom_in_button.set_size_request(-1,16); @@ -3918,10 +3921,6 @@ Editor::set_frames_per_unit (double fpu) frames_per_unit = fpu; - if (frames != zoom_range_clock.current_duration()) { - zoom_range_clock.set (frames); - } - if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) { if (!selection->tracks.empty()) { for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { @@ -3963,8 +3962,9 @@ Editor::queue_visual_change (double fpu) pending_visual_change.frames_per_unit = fpu; if (pending_visual_change.idle_handler_id < 0) { - pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, _idle_visual_changer, this, 0); + pending_visual_change.idle_handler_id = g_idle_add ( _idle_visual_changer, this); } + } int @@ -3979,12 +3979,15 @@ Editor::idle_visual_changer () VisualChange::Type p = pending_visual_change.pending; pending_visual_change.pending = (VisualChange::Type) 0; - pending_visual_change.idle_handler_id = -1; if (p & VisualChange::ZoomLevel) { set_frames_per_unit (pending_visual_change.frames_per_unit); - } + compute_fixed_ruler_scale (); + compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + (nframes_t)(canvas_width * pending_visual_change.frames_per_unit)); + compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + (nframes_t)(canvas_width * pending_visual_change.frames_per_unit)); + update_tempo_based_rulers (); + } if (p & VisualChange::TimeOrigin) { if (pending_visual_change.time_origin != leftmost_frame) { horizontal_adjustment.set_value (pending_visual_change.time_origin/frames_per_unit); @@ -3994,6 +3997,7 @@ Editor::idle_visual_changer () redisplay_tempo (true); } } + pending_visual_change.idle_handler_id = -1; return 0; /* this is always a one-shot call */ } diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 7e96f9c9c5..4fc2bd0d18 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -476,6 +476,7 @@ class Editor : public PublicEditor void set_selected_regionview_from_region_list (boost::shared_ptr region, Selection::Operation op = Selection::Set); void collect_new_region_view (RegionView *); + void collect_and_select_new_region_view (RegionView *); Gtk::MenuItem* region_edit_menu_split_item; Gtk::MenuItem* region_edit_menu_split_multichannel_item; @@ -559,6 +560,7 @@ class Editor : public PublicEditor void initialize_rulers (); void update_just_smpte (); + void compute_fixed_ruler_scale (); //calculates the RulerScale of the fixed rulers void update_fixed_rulers (); void update_tempo_based_rulers (); void popup_ruler_menu (nframes_t where = 0, ItemType type = RegionItem); @@ -573,6 +575,55 @@ class Editor : public PublicEditor static gint _metric_get_frames (GtkCustomRulerMark **, gdouble, gdouble, gint); static gint _metric_get_minsec (GtkCustomRulerMark **, gdouble, gdouble, gint); + enum MinsecRulerScale { + minsec_show_seconds, + minsec_show_minutes, + minsec_show_hours, + minsec_show_frames + }; + + MinsecRulerScale minsec_ruler_scale; + + nframes_t minsec_mark_interval; + gint minsec_mark_modulo; + gint minsec_nmarks; + void set_minsec_ruler_scale (gdouble lower, gdouble upper); + + enum SMPTERulerScale { + smpte_show_bits, + smpte_show_frames, + smpte_show_seconds, + smpte_show_minutes, + smpte_show_hours + }; + + SMPTERulerScale smpte_ruler_scale; + + nframes_t smpte_mark_interval; + gint smpte_mark_modulo; + gint smpte_nmarks; + void set_smpte_ruler_scale (gdouble lower, gdouble upper); + + enum BBTRulerScale { + bbt_over, + bbt_show_64, + bbt_show_16, + bbt_show_4, + bbt_show_1, + bbt_show_beats, + bbt_show_ticks, + bbt_show_ticks_detail, + bbt_show_ticks_super_detail + }; + + BBTRulerScale bbt_ruler_scale; + + uint32_t bbt_bars; + gint bbt_nmarks; + uint32_t bbt_bar_helper_on; + uint32_t bbt_accent_modulo; + void compute_bbt_ruler_scale (nframes_t lower, nframes_t upper); + gint metric_get_smpte (GtkCustomRulerMark **, gdouble, gdouble, gint); gint metric_get_bbt (GtkCustomRulerMark **, gdouble, gdouble, gint); gint metric_get_frames (GtkCustomRulerMark **, gdouble, gdouble, gint); @@ -696,6 +747,8 @@ class Editor : public PublicEditor void tie_vertical_scrolling (); void canvas_horizontally_scrolled (); + static int _idle_canvas_horizontally_scrolled (void *arg); + bool idle_canvas_horizontally_scrolled (); struct VisualChange { enum Type { @@ -1261,6 +1314,8 @@ class Editor : public PublicEditor void handle_new_duration (); void initialize_canvas (); + int canvas_hroizontally_scrolled_handler_id; + void reset_horizontally_scrolling_region (Gtk::Allocation* alloc = 0); void reset_scrolling_region (Gtk::Allocation* alloc = 0); /* display control */ @@ -1341,6 +1396,8 @@ class Editor : public PublicEditor void remove_metric_marks (); void draw_metric_marks (const ARDOUR::Metrics& metrics); + void compute_current_bbt_points (nframes_t left, nframes_t right); + int tempo_map_change_idle_handler_id; void tempo_map_changed (ARDOUR::Change); void redisplay_tempo (bool immediate_redraw); diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc index 86beec387e..fbd4f13f02 100644 --- a/gtk2_ardour/editor_canvas.cc +++ b/gtk2_ardour/editor_canvas.cc @@ -360,7 +360,7 @@ Editor::track_canvas_size_allocated () transport_punchout_line->property_y1() = 0.0; transport_punchout_line->property_y2() = canvas_height; } - + compute_fixed_ruler_scale (); update_fixed_rulers(); redisplay_tempo (true); diff --git a/gtk2_ardour/editor_export_audio.cc b/gtk2_ardour/editor_export_audio.cc index 9b0a7c7cb5..3ab2012588 100644 --- a/gtk2_ardour/editor_export_audio.cc +++ b/gtk2_ardour/editor_export_audio.cc @@ -82,9 +82,9 @@ Editor::export_range (nframes_t start, nframes_t end) if (session) { if (export_dialog == 0) { export_dialog = new ExportSessionDialog (*this); + export_dialog->connect_to_session (session); } - export_dialog->connect_to_session (session); export_dialog->set_range (start, end); export_dialog->start_export(); } @@ -121,9 +121,9 @@ Editor::export_range_markers () if (export_range_markers_dialog == 0) { export_range_markers_dialog = new ExportRangeMarkersDialog(*this); + export_range_markers_dialog->connect_to_session (session); } - - export_range_markers_dialog->connect_to_session (session); + export_range_markers_dialog->start_export(); } } diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index c6bbf5ca5f..0827fc5321 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -2898,6 +2898,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) vector new_regionviews; for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { + RegionView* rv; RegionView* nrv; @@ -2924,7 +2925,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) } /* reset selection to new regionviews */ - + selection->set (new_regionviews); /* reset drag_info data to reflect the fact that we are dragging the copies */ @@ -3288,7 +3289,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) tvp2 = trackview_by_y_position (iy1 + y_delta); temp_rtv = dynamic_cast(tvp2); rv->set_y_position_and_height (0, temp_rtv->height); - + /* if you un-comment the following, the region colours will follow the track colours whilst dragging, personally, i think this can confuse things, but never mind. */ @@ -3358,7 +3359,7 @@ void Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) { nframes_t where; - RegionView* rv = reinterpret_cast (drag_info.data); + RegionView* rvdi = reinterpret_cast (drag_info.data); pair >::iterator,bool> insert_result; bool nocommit = true; double speed; @@ -3366,6 +3367,9 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event bool regionview_y_movement; bool regionview_x_movement; vector copies; + list > used_playlists; + list used_connections; + bool preserve_selection = false; /* first_move is set to false if the regionview has been moved in the motion handler. @@ -3404,8 +3408,8 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event speed = rtv->get_diskstream()->speed(); } - regionview_x_movement = (drag_info.last_frame_position != (nframes_t) (rv->region()->position()/speed)); - regionview_y_movement = (drag_info.last_trackview != &rv->get_time_axis_view()); + regionview_x_movement = (drag_info.last_frame_position != (nframes_t) (rvdi->region()->position()/speed)); + regionview_y_movement = (drag_info.last_trackview != &rvdi->get_time_axis_view()); //printf ("last_frame: %s position is %lu %g\n", rv->get_time_axis_view().name().c_str(), drag_info.last_frame_position, speed); //printf ("last_rackview: %s \n", drag_info.last_trackview->name().c_str()); @@ -3432,64 +3436,82 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event /* moved to a different audio track. */ - vector new_selection; - for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ) { - RegionView* rv = (*i); + RegionView* rv = (*i); double ix1, ix2, iy1, iy2; rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2); rv->get_canvas_group()->i2w (ix1, iy1); - TimeAxisView* tvp2 = trackview_by_y_position (iy1); - RouteTimeAxisView* rtv2 = dynamic_cast(tvp2); - boost::shared_ptr from_playlist = rv->region()->playlist(); + RouteTimeAxisView* rtv2 = dynamic_cast(trackview_by_y_position (iy1)); + boost::shared_ptr to_playlist = rtv2->playlist(); + if (! to_playlist->frozen()) { + /* + we haven't seen this playlist before. + we want to freeze it because we don't want to relayer per-region. + its much better to do that just once if the playlist is large. + */ + + /* + connect so the selection is changed when the new regionview finally appears (after thaw). + keep track of it so we can disconnect later. + */ + + sigc::connection c = rtv2->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_and_select_new_region_view)); + used_connections.push_back (c); + + /* undo */ + session->add_command (new MementoCommand(*to_playlist, &to_playlist->get_state(), 0)); + + /* remember used playlists so we can thaw them later */ + used_playlists.push_back(to_playlist); + to_playlist->freeze(); + } + where = (nframes_t) (unit_to_frame (ix1) * speed); boost::shared_ptr new_region (RegionFactory::create (rv->region())); - /* undo the previous hide_dependent_views so that xfades don't - disappear on copying regions - */ - - rv->get_time_axis_view().reveal_dependent_views (*rv); - if (!drag_info.copy) { - + + /* the region that used to be in the old playlist is not moved to the new one - we make a copy of it. as a result, any existing editor for the region should no longer be visible. */ - + + RouteTimeAxisView* from_playlist_rtv = dynamic_cast(&(*i)->get_trackview()); + boost::shared_ptr from_playlist = from_playlist_rtv->playlist(); + + if (! from_playlist->frozen()) { + from_playlist->freeze(); + used_playlists.push_back(from_playlist); + + sigc::connection c = rtv2->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_and_select_new_region_view)); + used_connections.push_back (c); + + session->add_command (new MementoCommand(*from_playlist, &from_playlist->get_state(), 0)); + } + rv->hide_region_editor(); rv->fake_set_opaque (false); - session->add_command (new MementoCommand(*from_playlist, &from_playlist->get_state(), 0)); from_playlist->remove_region ((rv->region())); - session->add_command (new MementoCommand(*from_playlist, 0, &from_playlist->get_state())); } else { /* the regionview we dragged around is a temporary copy, queue it for deletion */ - + copies.push_back (rv); } latest_regionview = 0; - - sigc::connection c = rtv2->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); - session->add_command (new MementoCommand(*to_playlist, &to_playlist->get_state(), 0)); + to_playlist->add_region (new_region, where); - session->add_command (new MementoCommand(*to_playlist, 0, &to_playlist->get_state())); - c.disconnect (); - - if (latest_regionview) { - new_selection.push_back (latest_regionview); - } /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region was selected in all of them, then removing it from the playlist will have removed all @@ -3506,6 +3528,7 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and we can just iterate. + */ if (drag_info.copy) { @@ -3514,12 +3537,15 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event if (selection->regions.empty()) { break; } else { - i = selection->regions.by_layer().begin(); + /* + XXX see above .. but we just froze the playlists.. we have to keep iterating, right? + */ + + //i = selection->regions.by_layer().begin(); + ++i; } } - } - - selection->set (new_selection); + } } else { @@ -3527,13 +3553,11 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event list regions = selection->regions.by_layer(); - if (drag_info.copy) { - selection->clear_regions(); - } - for (list::iterator i = regions.begin(); i != regions.end(); ++i) { - rv = (*i); + RegionView* rv = (*i); + boost::shared_ptr to_playlist = (*i)->region()->playlist(); + RouteTimeAxisView* from_rtv = dynamic_cast (&(rv->get_time_axis_view())); if (!rv->region()->can_move()) { continue; @@ -3541,10 +3565,9 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event if (regionview_x_movement) { double ownspeed = 1.0; - rtv = dynamic_cast (&(rv->get_time_axis_view())); - if (rtv && rtv->get_diskstream()) { - ownspeed = rtv->get_diskstream()->speed(); + if (from_rtv && from_rtv->get_diskstream()) { + ownspeed = from_rtv->get_diskstream()->speed(); } /* base the new region position on the current position of the regionview.*/ @@ -3560,13 +3583,16 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event where = rv->region()->position(); } - boost::shared_ptr to_playlist = rv->region()->playlist(); + if (! to_playlist->frozen()) { + sigc::connection c = from_rtv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_and_select_new_region_view)); + used_connections.push_back (c); - assert (to_playlist); + /* add the undo */ + session->add_command (new MementoCommand(*to_playlist, &to_playlist->get_state(), 0)); - /* add the undo */ - - session->add_command (new MementoCommand(*to_playlist, &to_playlist->get_state(), 0)); + used_playlists.push_back(to_playlist); + to_playlist->freeze(); + } if (drag_info.copy) { @@ -3582,36 +3608,42 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event /* add it */ - latest_regionview = 0; - sigc::connection c = rtv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); - to_playlist->add_region (newregion, (nframes_t) (where * rtv->get_diskstream()->speed())); - c.disconnect (); - - if (latest_regionview) { - rtv->reveal_dependent_views (*latest_regionview); - selection->add (latest_regionview); - } + to_playlist->add_region (newregion, (nframes_t) (where * from_rtv->get_diskstream()->speed())); /* if the original region was locked, we don't care for the new one */ - newregion->set_locked (false); + newregion->set_locked (false); + copies.push_back (rv); } else { /* just change the model */ rv->region()->set_position (where, (void*) this); + preserve_selection = true; } - /* add the redo */ - - session->add_command (new MementoCommand(*to_playlist, 0, &to_playlist->get_state())); - - if (drag_info.copy) { - copies.push_back (rv); - } } + + } + if (! preserve_selection) { + //selection->clear_regions(); + } + while (used_playlists.size() > 0) { + + list >::iterator i = used_playlists.begin(); + (*i)->thaw(); + + if (used_connections.size()) { + sigc::connection c = used_connections.front(); + c.disconnect(); + used_connections.pop_front(); + } + /* add the redo */ + + session->add_command (new MementoCommand(*(*i), 0, &(*i)->get_state())); + used_playlists.pop_front(); } out: @@ -3838,6 +3870,13 @@ Editor::collect_new_region_view (RegionView* rv) latest_regionview = rv; } +void +Editor::collect_and_select_new_region_view (RegionView* rv) +{ + selection->add(rv); + latest_regionview = rv; +} + void Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event) { @@ -3892,7 +3931,7 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event) /* we need to deselect all other regionviews, and select this one i'm ignoring undo stuff, because the region creation will take care of it */ - selection->set (latest_regionview); + //selection->set (latest_regionview); drag_info.item = latest_regionview->get_canvas_group(); drag_info.data = latest_regionview; @@ -4245,6 +4284,7 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) insert_result = motion_frozen_playlists.insert (pl); if (insert_result.second) { session->add_command(new MementoCommand(*pl, &pl->get_state(), 0)); + pl->freeze(); } } } @@ -4434,7 +4474,7 @@ Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) } for (set >::iterator p = motion_frozen_playlists.begin(); p != motion_frozen_playlists.end(); ++p) { - //(*p)->thaw (); + (*p)->thaw (); session->add_command (new MementoCommand(*(*p).get(), 0, &(*p)->get_state())); } diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index ca2d7039ad..2cc30aee17 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -117,6 +117,8 @@ Editor::split_region_at (nframes_t where) void Editor::split_regions_at (nframes_t where, RegionSelection& regions) { + list > used_playlists; + begin_reversible_command (_("split")); // if splitting a single region, and snap-to is using @@ -135,15 +137,19 @@ Editor::split_regions_at (nframes_t where, RegionSelection& regions) snap_to (where); } - for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) { - RegionSelection::iterator tmp; - - tmp = a; - ++tmp; + for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ++a) { boost::shared_ptr pl = (*a)->region()->playlist(); + if (! pl->frozen()) { + /* we haven't seen this playlist before */ + + /* remember used playlists so we can thaw them later */ + used_playlists.push_back(pl); + pl->freeze(); + } + AudioRegionView* const arv = dynamic_cast(*a); if (arv) _new_regionviews_show_envelope = arv->envelope_visible(); @@ -155,9 +161,13 @@ Editor::split_regions_at (nframes_t where, RegionSelection& regions) session->add_command(new MementoCommand(*pl, &before, &after)); } - a = tmp; - } + } + while (used_playlists.size() > 0) { + list >::iterator i = used_playlists.begin(); + (*i)->thaw(); + used_playlists.pop_front(); + } commit_reversible_command (); _new_regionviews_show_envelope = false; } diff --git a/gtk2_ardour/editor_rulers.cc b/gtk2_ardour/editor_rulers.cc index 88ff3a0c1e..72e70955cd 100644 --- a/gtk2_ardour/editor_rulers.cc +++ b/gtk2_ardour/editor_rulers.cc @@ -712,13 +712,16 @@ Editor::update_ruler_visibility () time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars)); time_canvas_event_box.queue_resize(); - + compute_fixed_ruler_scale(); update_fixed_rulers(); - //update_tempo_based_rulers(); - redisplay_tempo (false); time_canvas_event_box.show_all(); time_button_frame.show_all(); + + compute_current_bbt_points (leftmost_frame, leftmost_frame + (nframes_t)(canvas_width * frames_per_unit)); + compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + (nframes_t)(canvas_width * frames_per_unit)); + + redisplay_tempo (false); } void @@ -738,6 +741,22 @@ Editor::update_just_smpte () } } +void +Editor::compute_fixed_ruler_scale () +{ + if (session == 0) { + return; + } + + if (ruler_shown[ruler_metric_smpte]) { + set_smpte_ruler_scale (leftmost_frame, leftmost_frame + (canvas_width * frames_per_unit) ); + } + + if (ruler_shown[ruler_metric_minsec]) { + set_minsec_ruler_scale (leftmost_frame, leftmost_frame + (canvas_width * frames_per_unit) ); + } +} + void Editor::update_fixed_rulers () { @@ -781,7 +800,7 @@ Editor::update_tempo_based_rulers () } ruler_metrics[ruler_metric_bbt].units_per_pixel = frames_per_unit; - + if (ruler_shown[ruler_metric_bbt]) { gtk_custom_ruler_set_range (GTK_CUSTOM_RULER(_bbt_ruler), leftmost_frame, leftmost_frame+current_page_frames(), leftmost_frame, session->current_end_frame()); @@ -814,26 +833,15 @@ Editor::_metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble u return ruler_editor->metric_get_minsec (marks, lower, upper, maxchars); } -gint -Editor::metric_get_smpte (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars) +void +Editor::set_smpte_ruler_scale (gdouble lower, gdouble upper) { nframes_t range; - nframes_t pos; nframes_t spacer; nframes_t fr; - SMPTE::Time smpte; - gchar buf[16]; - gint nmarks = 0; - gint n; - bool show_bits = false; - bool show_frames = false; - bool show_seconds = false; - bool show_minutes = false; - bool show_hours = false; - int mark_modulo; if (session == 0) { - return 0; + return; } fr = session->frame_rate(); @@ -847,93 +855,115 @@ Editor::metric_get_smpte (GtkCustomRulerMark **marks, gdouble lower, gdouble upp range = (nframes_t) floor (upper - lower); if (range < (2 * session->frames_per_smpte_frame())) { /* 0 - 2 frames */ - show_bits = true; - mark_modulo = 20; - nmarks = 1 + (2 * Config->get_subframes_per_frame()); + smpte_ruler_scale = smpte_show_bits; + smpte_mark_modulo = 20; + smpte_nmarks = 2 + (2 * Config->get_subframes_per_frame()); } else if (range <= (fr / 4)) { /* 2 frames - 0.250 second */ - show_frames = true; - mark_modulo = 1; - nmarks = 1 + (range / (nframes_t)session->frames_per_smpte_frame()); + smpte_ruler_scale = smpte_show_frames; + smpte_mark_modulo = 1; + smpte_nmarks = 2 + (range / (nframes_t)session->frames_per_smpte_frame()); } else if (range <= (fr / 2)) { /* 0.25-0.5 second */ - show_frames = true; - mark_modulo = 2; - nmarks = 1 + (range / (nframes_t)session->frames_per_smpte_frame()); + smpte_ruler_scale = smpte_show_frames; + smpte_mark_modulo = 2; + smpte_nmarks = 2 + (range / (nframes_t)session->frames_per_smpte_frame()); } else if (range <= fr) { /* 0.5-1 second */ - show_frames = true; - mark_modulo = 5; - nmarks = 1 + (range / (nframes_t)session->frames_per_smpte_frame()); + smpte_ruler_scale = smpte_show_frames; + smpte_mark_modulo = 5; + smpte_nmarks = 2 + (range / (nframes_t)session->frames_per_smpte_frame()); } else if (range <= 2 * fr) { /* 1-2 seconds */ - show_frames = true; - mark_modulo = 10; - nmarks = 1 + (range / (nframes_t)session->frames_per_smpte_frame()); + smpte_ruler_scale = smpte_show_frames; + smpte_mark_modulo = 10; + smpte_nmarks = 2 + (range / (nframes_t)session->frames_per_smpte_frame()); } else if (range <= 8 * fr) { /* 2-8 seconds */ - show_seconds = true; - mark_modulo = 1; - nmarks = 1 + (range / fr); + smpte_ruler_scale = smpte_show_seconds; + smpte_mark_modulo = 1; + smpte_nmarks = 2 + (range / fr); } else if (range <= 16 * fr) { /* 8-16 seconds */ - show_seconds = true; - mark_modulo = 2; - nmarks = 1 + (range / fr); + smpte_ruler_scale = smpte_show_seconds; + smpte_mark_modulo = 2; + smpte_nmarks = 2 + (range / fr); } else if (range <= 30 * fr) { /* 16-30 seconds */ - show_seconds = true; - mark_modulo = 5; - nmarks = 1 + (range / fr); + smpte_ruler_scale = smpte_show_seconds; + smpte_mark_modulo = 5; + smpte_nmarks = 2 + (range / fr); } else if (range <= 60 * fr) { /* 30-60 seconds */ - show_seconds = true; - mark_modulo = 5; - nmarks = 1 + (range / fr); + smpte_ruler_scale = smpte_show_seconds; + smpte_mark_modulo = 5; + smpte_nmarks = 2 + (range / fr); } else if (range <= 2 * 60 * fr) { /* 1-2 minutes */ - show_seconds = true; - mark_modulo = 20; - nmarks = 1 + (range / fr); + smpte_ruler_scale = smpte_show_seconds; + smpte_mark_modulo = 15; + smpte_nmarks = 2 + (range / fr); } else if (range <= 4 * 60 * fr) { /* 2-4 minutes */ - show_seconds = true; - mark_modulo = 30; - nmarks = 1 + (range / fr); + smpte_ruler_scale = smpte_show_seconds; + smpte_mark_modulo = 30; + smpte_nmarks = 2 + (range / fr); } else if (range <= 10 * 60 * fr) { /* 4-10 minutes */ - show_minutes = true; - mark_modulo = 2; - nmarks = 1 + 10; + smpte_ruler_scale = smpte_show_minutes; + smpte_mark_modulo = 2; + smpte_nmarks = 2 + 10; } else if (range <= 30 * 60 * fr) { /* 10-30 minutes */ - show_minutes = true; - mark_modulo = 5; - nmarks = 1 + 30; + smpte_ruler_scale = smpte_show_minutes; + smpte_mark_modulo = 5; + smpte_nmarks = 2 + 30; } else if (range <= 60 * 60 * fr) { /* 30 minutes - 1hr */ - show_minutes = true; - mark_modulo = 10; - nmarks = 1 + 60; + smpte_ruler_scale = smpte_show_minutes; + smpte_mark_modulo = 10; + smpte_nmarks = 2 + 60; } else if (range <= 4 * 60 * 60 * fr) { /* 1 - 4 hrs*/ - show_minutes = true; - mark_modulo = 30; - nmarks = 1 + (60 * 4); + smpte_ruler_scale = smpte_show_minutes; + smpte_mark_modulo = 30; + smpte_nmarks = 2 + (60 * 4); } else if (range <= 8 * 60 * 60 * fr) { /* 4 - 8 hrs*/ - show_hours = true; - mark_modulo = 1; - nmarks = 1 + 8; + smpte_ruler_scale = smpte_show_hours; + smpte_mark_modulo = 1; + smpte_nmarks = 2 + 8; } else if (range <= 16 * 60 * 60 * fr) { /* 16-24 hrs*/ - show_hours = true; - mark_modulo = 1; - nmarks = 1 + 24; + smpte_ruler_scale = smpte_show_hours; + smpte_mark_modulo = 1; + smpte_nmarks = 2 + 24; } else { /* not possible if nframes_t is a 32 bit quantity */ - show_hours = true; - mark_modulo = 4; - nmarks = 1 + 24; + smpte_ruler_scale = smpte_show_hours; + smpte_mark_modulo = 4; + smpte_nmarks = 2 + 24; } +} + +gint +Editor::metric_get_smpte (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars) +{ + nframes_t pos; + nframes_t spacer; + SMPTE::Time smpte; + gchar buf[16]; + gint n; + + if (session == 0) { + return 0; + } + + if (lower > (spacer = (nframes_t)(128 * Editor::get_current_zoom ()))) { + lower = lower - spacer; + } else { + lower = 0; + } + pos = (nframes_t) floor (lower); - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks); - - if (show_bits) { + *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * smpte_nmarks); + switch (smpte_ruler_scale) { + case smpte_show_bits: + // Find smpte time of this sample (pos) with subframe accuracy session->sample_to_smpte(pos, smpte, true /* use_offset */, true /* use_subframes */ ); - for (n = 0; n < nmarks; n++) { + for (n = 0; n < smpte_nmarks; n++) { session->smpte_to_sample(smpte, pos, true /* use_offset */, true /* use_subframes */ ); - if ((smpte.subframes % mark_modulo) == 0) { + if ((smpte.subframes % smpte_mark_modulo) == 0) { if (smpte.subframes == 0) { (*marks)[n].style = GtkCustomRulerMarkMajor; snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", smpte.negative ? "-" : "", smpte.hours, smpte.minutes, smpte.seconds, smpte.frames); @@ -952,15 +982,16 @@ Editor::metric_get_smpte (GtkCustomRulerMark **marks, gdouble lower, gdouble upp // Increment subframes by one SMPTE::increment_subframes( smpte ); } - } else if (show_seconds) { + break; + case smpte_show_seconds: // Find smpte time of this sample (pos) session->sample_to_smpte(pos, smpte, true /* use_offset */, false /* use_subframes */ ); // Go to next whole second down SMPTE::seconds_floor( smpte ); - for (n = 0; n < nmarks; n++) { + for (n = 0; n < smpte_nmarks; n++) { session->smpte_to_sample(smpte, pos, true /* use_offset */, false /* use_subframes */ ); - if ((smpte.seconds % mark_modulo) == 0) { + if ((smpte.seconds % smpte_mark_modulo) == 0) { if (smpte.seconds == 0) { (*marks)[n].style = GtkCustomRulerMarkMajor; (*marks)[n].position = pos; @@ -978,15 +1009,16 @@ Editor::metric_get_smpte (GtkCustomRulerMark **marks, gdouble lower, gdouble upp (*marks)[n].label = g_strdup (buf); SMPTE::increment_seconds( smpte ); } - } else if (show_minutes) { + break; + case smpte_show_minutes: // Find smpte time of this sample (pos) session->sample_to_smpte(pos, smpte, true /* use_offset */, false /* use_subframes */ ); // Go to next whole minute down SMPTE::minutes_floor( smpte ); - for (n = 0; n < nmarks; n++) { + for (n = 0; n < smpte_nmarks; n++) { session->smpte_to_sample(smpte, pos, true /* use_offset */, false /* use_subframes */ ); - if ((smpte.minutes % mark_modulo) == 0) { + if ((smpte.minutes % smpte_mark_modulo) == 0) { if (smpte.minutes == 0) { (*marks)[n].style = GtkCustomRulerMarkMajor; } else { @@ -1002,15 +1034,17 @@ Editor::metric_get_smpte (GtkCustomRulerMark **marks, gdouble lower, gdouble upp (*marks)[n].position = pos; SMPTE::increment_minutes( smpte ); } - } else if (show_hours) { + + break; + case smpte_show_hours: // Find smpte time of this sample (pos) session->sample_to_smpte(pos, smpte, true /* use_offset */, false /* use_subframes */ ); // Go to next whole hour down SMPTE::hours_floor( smpte ); - for (n = 0; n < nmarks; n++) { + for (n = 0; n < smpte_nmarks; n++) { session->smpte_to_sample(smpte, pos, true /* use_offset */, false /* use_subframes */ ); - if ((smpte.hours % mark_modulo) == 0) { + if ((smpte.hours % smpte_mark_modulo) == 0) { (*marks)[n].style = GtkCustomRulerMarkMajor; snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", smpte.negative ? "-" : "", smpte.hours, smpte.minutes, smpte.seconds, smpte.frames); } else { @@ -1023,16 +1057,21 @@ Editor::metric_get_smpte (GtkCustomRulerMark **marks, gdouble lower, gdouble upp SMPTE::increment_hours( smpte ); } - } else { // show_frames + break; + case smpte_show_frames: // Find smpte time of this sample (pos) session->sample_to_smpte(pos, smpte, true /* use_offset */, false /* use_subframes */ ); // Go to next whole frame down SMPTE::frames_floor( smpte ); - for (n = 0; n < nmarks; n++) { + for (n = 0; n < smpte_nmarks; n++) { session->smpte_to_sample(smpte, pos, true /* use_offset */, false /* use_subframes */ ); - if ((smpte.frames % mark_modulo) == 0) { - (*marks)[n].style = GtkCustomRulerMarkMajor; + if ((smpte.frames % smpte_mark_modulo) == 0) { + if (smpte.frames == 0) { + (*marks)[n].style = GtkCustomRulerMarkMajor; + } else { + (*marks)[n].style = GtkCustomRulerMarkMinor; + } (*marks)[n].position = pos; snprintf (buf, sizeof(buf), "%s%02u:%02u:%02u:%02u", smpte.negative ? "-" : "", smpte.hours, smpte.minutes, smpte.seconds, smpte.frames); } else { @@ -1044,12 +1083,99 @@ Editor::metric_get_smpte (GtkCustomRulerMark **marks, gdouble lower, gdouble upp (*marks)[n].label = g_strdup (buf); SMPTE::increment( smpte ); } + + break; } - return nmarks; + return smpte_nmarks; } +void +Editor::compute_bbt_ruler_scale (nframes_t lower, nframes_t upper) +{ + if (session == 0) { + return; + } + TempoMap::BBTPointList::iterator i; + BBT_Time lower_beat, upper_beat; // the beats at each end of the ruler + + session->bbt_time((jack_nframes_t) lower, lower_beat); + session->bbt_time((jack_nframes_t) upper, upper_beat); + uint32_t beats = 0; + + bbt_accent_modulo = 1; + bbt_bar_helper_on = false; + bbt_bars = 0; + bbt_nmarks = 1; + + bbt_ruler_scale = bbt_over; + + switch (snap_type) { + case SnapToAThirdBeat: + bbt_beat_subdivision = 3; + break; + case SnapToAQuarterBeat: + bbt_beat_subdivision = 4; + break; + case SnapToAEighthBeat: + bbt_beat_subdivision = 8; + bbt_accent_modulo = 2; + break; + case SnapToASixteenthBeat: + bbt_beat_subdivision = 16; + bbt_accent_modulo = 4; + break; + case SnapToAThirtysecondBeat: + bbt_beat_subdivision = 32; + bbt_accent_modulo = 8; + break; + default: + bbt_beat_subdivision = 4; + break; + } + + if (current_bbt_points == 0 || current_bbt_points->empty()) { + return; + } + + i = current_bbt_points->end(); + i--; + if ((*i).beat >= (*current_bbt_points->begin()).beat) { + bbt_bars = (*i).bar - (*current_bbt_points->begin()).bar; + } else { + bbt_bars = (*i).bar - (*current_bbt_points->begin()).bar - 1; + } + beats = current_bbt_points->size() - bbt_bars; + + /*Only show the bar helper if there aren't many bars on the screen */ + if ((bbt_bars < 2) || (beats < 5)) { + bbt_bar_helper_on = true; + } + + if (bbt_bars > 8192) { + bbt_ruler_scale = bbt_over; + } else if (bbt_bars > 1024) { + bbt_ruler_scale = bbt_show_64; + } else if (bbt_bars > 256) { + bbt_ruler_scale = bbt_show_16; + } else if (bbt_bars > 64) { + bbt_ruler_scale = bbt_show_4; + } else if (bbt_bars > 10) { + bbt_ruler_scale = bbt_show_1; + } else if (bbt_bars > 2) { + bbt_ruler_scale = bbt_show_beats; + } else if (bbt_bars > 0) { + bbt_ruler_scale = bbt_show_ticks; + } else { + bbt_ruler_scale = bbt_show_ticks_detail; + } + + if ((bbt_ruler_scale == bbt_show_ticks_detail) && (lower_beat.beats == upper_beat.beats) && (upper_beat.ticks - lower_beat.ticks <= Meter::ticks_per_beat / 4)) { + bbt_ruler_scale = bbt_show_ticks_super_detail; + } +} + gint Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars) { @@ -1059,208 +1185,367 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper TempoMap::BBTPointList::iterator i; - uint32_t beats = 0; - uint32_t bars = 0; - uint32_t desirable_marks; - uint32_t magic_accent_number = 1; - gint nmarks; char buf[64]; gint n = 0; nframes_t pos; - bool bar_helper_on = true; - BBT_Time next_beat; nframes_t next_beat_pos; + uint32_t beats = 0; - if ((desirable_marks = maxchars / 7) == 0) { - return 0; - } - - /* align the tick marks to whatever we're snapping to... */ - - switch (snap_type) { - case SnapToAThirdBeat: - bbt_beat_subdivision = 3; - break; - case SnapToAQuarterBeat: - bbt_beat_subdivision = 4; - break; - case SnapToAEighthBeat: - bbt_beat_subdivision = 8; - magic_accent_number = 2; - break; - case SnapToASixteenthBeat: - bbt_beat_subdivision = 16; - magic_accent_number = 4; - break; - case SnapToAThirtysecondBeat: - bbt_beat_subdivision = 32; - magic_accent_number = 8; - break; - default: - bbt_beat_subdivision = 4; - break; - } + uint32_t tick = 0; + uint32_t skip; + uint32_t t; + nframes_t frame_skip; + double frame_skip_error; + double bbt_position_of_helper; + double accumulated_error; + bool i_am_accented = false; + bool helper_active = false; if (current_bbt_points == 0 || current_bbt_points->empty()) { return 0; } - i = current_bbt_points->end(); - i--; - bars = (*i).bar - (*current_bbt_points->begin()).bar; - beats = current_bbt_points->size() - bars; + switch (bbt_ruler_scale) { - /*Only show the bar helper if there aren't many bars on the screen */ - if (bars > 1) { - bar_helper_on = false; - } + case bbt_show_beats: + beats = current_bbt_points->size(); + bbt_nmarks = beats + 2; - if (desirable_marks > (beats / 4)) { - - /* we're in beat land...*/ - - uint32_t tick = 0; - uint32_t skip; - uint32_t t; - nframes_t frame_skip; - double frame_skip_error; - double accumulated_error; - double position_of_helper; - bool i_am_accented = false; - bool we_need_ticks = false; - bool helper_active = false; - - position_of_helper = lower + (30 * Editor::get_current_zoom ()); - - if (desirable_marks >= (beats)) { - nmarks = (beats * bbt_beat_subdivision) + 1; - we_need_ticks = true; - } else { - nmarks = beats + 1; - } - - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks); + *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); (*marks)[0].label = g_strdup(" "); (*marks)[0].position = lower; (*marks)[0].style = GtkCustomRulerMarkMicro; - for (n = 1, i = current_bbt_points->begin(); n < nmarks && i != current_bbt_points->end(); ++i) { - - if ((*i).frame < lower && (bar_helper_on)) { - snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat); - (*marks)[0].label = g_strdup (buf); - helper_active = true; + for (n = 1, i = current_bbt_points->begin(); n < bbt_nmarks && i != current_bbt_points->end(); ++i) { + if ((*i).type != TempoMap::Beat) { + continue; + } + if ((*i).frame < lower && (bbt_bar_helper_on)) { + snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat); + (*marks)[0].label = g_strdup (buf); + helper_active = true; } else { - if ((*i).type == TempoMap::Bar) { - if (((*i).frame < position_of_helper) && helper_active) { - snprintf (buf, sizeof(buf), " "); - } else { - snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); - } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = (*i).frame; - (*marks)[n].style = GtkCustomRulerMarkMajor; - n++; - - } else if (((*i).type == TempoMap::Beat) && ((*i).beat > 1)) { - ((((*i).frame < position_of_helper) && bar_helper_on) || !we_need_ticks) ? - snprintf (buf, sizeof(buf), " ") : snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat); - if (((*i).beat % 2 == 1) || we_need_ticks) { - (*marks)[n].style = GtkCustomRulerMarkMinor; - } else { - (*marks)[n].style = GtkCustomRulerMarkMicro; - } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = (*i).frame; - n++; - } - - } - - - /* Add the tick marks */ - - if (we_need_ticks && (*i).type == TempoMap::Beat) { - - /* Find the next beat */ - - next_beat.beats = (*i).beat; - next_beat.bars = (*i).bar; - - if ((*i).meter->beats_per_bar() > (next_beat.beats + 1)) { - next_beat.beats += 1; + if ((*i).beat == 1) { + (*marks)[n].style = GtkCustomRulerMarkMajor; + snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); + } else if (((*i).beat % 2 == 1)) { + (*marks)[n].style = GtkCustomRulerMarkMinor; + snprintf (buf, sizeof(buf), " "); } else { - next_beat.bars += 1; - next_beat.beats = 1; - } - - next_beat_pos = session->tempo_map().frame_time(next_beat); - - frame_skip = (nframes_t) floor (frame_skip_error = (session->frame_rate() * 60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute())); - frame_skip_error -= frame_skip; - skip = (uint32_t) (Meter::ticks_per_beat / bbt_beat_subdivision); - - pos = (*i).frame + frame_skip; - accumulated_error = frame_skip_error; - - tick = skip; - - for (t = 0; (tick < Meter::ticks_per_beat) && (n < nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) { - - if (t % magic_accent_number == (magic_accent_number - 1)) { - i_am_accented = true; - } - if (Editor::get_current_zoom () > 32) { - snprintf (buf, sizeof(buf), " "); - } else if ((Editor::get_current_zoom () > 8) && !i_am_accented) { - snprintf (buf, sizeof(buf), " "); - } else if (bar_helper_on && (pos < position_of_helper)) { - snprintf (buf, sizeof(buf), " "); - } else { - snprintf (buf, sizeof(buf), "%" PRIu32, tick); - } - - (*marks)[n].label = g_strdup (buf); - - /* Error compensation for float to nframes_t*/ - accumulated_error += frame_skip_error; - if (accumulated_error > 1) { - pos += 1; - accumulated_error -= 1.0f; - } - - (*marks)[n].position = pos; - - if ((bbt_beat_subdivision > 4) && i_am_accented) { - (*marks)[n].style = GtkCustomRulerMarkMinor; - } else { - (*marks)[n].style = GtkCustomRulerMarkMicro; - } - i_am_accented = false; - n++; - + (*marks)[n].style = GtkCustomRulerMarkMicro; + snprintf (buf, sizeof(buf), " "); } + (*marks)[n].label = g_strdup (buf); + (*marks)[n].position = (*i).frame; + n++; } } - return n; //return the actual number of marks made, since we might have skipped some fro fractional time signatures + break; - } else { + case bbt_show_ticks: - /* we're in bar land */ + beats = current_bbt_points->size(); + bbt_nmarks = (beats + 2) * bbt_beat_subdivision; - if (desirable_marks < (bars / 256)) { - nmarks = 1; - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks); - snprintf (buf, sizeof(buf), "too many bars... (currently %" PRIu32 ")", bars ); + bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ()); + *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); + + (*marks)[0].label = g_strdup(" "); + (*marks)[0].position = lower; + (*marks)[0].style = GtkCustomRulerMarkMicro; + + for (n = 1, i = current_bbt_points->begin(); n < bbt_nmarks && i != current_bbt_points->end(); ++i) { + if ((*i).type != TempoMap::Beat) { + continue; + } + if ((*i).frame < lower && (bbt_bar_helper_on)) { + snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat); + (*marks)[0].label = g_strdup (buf); + helper_active = true; + } else { + + if ((*i).beat == 1) { + (*marks)[n].style = GtkCustomRulerMarkMajor; + snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); + } else { + (*marks)[n].style = GtkCustomRulerMarkMinor; + snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat); + } + if (((*i).frame < bbt_position_of_helper) && helper_active) { + snprintf (buf, sizeof(buf), " "); + } + (*marks)[n].label = g_strdup (buf); + (*marks)[n].position = (*i).frame; + n++; + } + + /* Add the tick marks */ + + /* Find the next beat */ + next_beat.beats = (*i).beat; + next_beat.bars = (*i).bar; + next_beat.ticks = 0; + + if ((*i).meter->beats_per_bar() > (next_beat.beats + 1)) { + next_beat.beats += 1; + } else { + next_beat.bars += 1; + next_beat.beats = 1; + } + + next_beat_pos = session->tempo_map().frame_time(next_beat); + + frame_skip = (nframes_t) floor (frame_skip_error = (session->frame_rate() * 60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute())); + frame_skip_error -= frame_skip; + skip = (uint32_t) (Meter::ticks_per_beat / bbt_beat_subdivision); + + pos = (*i).frame + frame_skip; + accumulated_error = frame_skip_error; + + tick = skip; + + for (t = 0; (tick < Meter::ticks_per_beat) && (n < bbt_nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) { + + if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) { + i_am_accented = true; + } + + snprintf (buf, sizeof(buf), " "); + (*marks)[n].label = g_strdup (buf); + + /* Error compensation for float to nframes_t*/ + accumulated_error += frame_skip_error; + if (accumulated_error > 1) { + pos += 1; + accumulated_error -= 1.0f; + } + + (*marks)[n].position = pos; + + if ((bbt_beat_subdivision > 4) && i_am_accented) { + (*marks)[n].style = GtkCustomRulerMarkMinor; + } else { + (*marks)[n].style = GtkCustomRulerMarkMicro; + } + i_am_accented = false; + n++; + } + } + + break; + + case bbt_show_ticks_detail: + + beats = current_bbt_points->size(); + bbt_nmarks = (beats + 2) * bbt_beat_subdivision; + + bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ()); + *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); + + (*marks)[0].label = g_strdup(" "); + (*marks)[0].position = lower; + (*marks)[0].style = GtkCustomRulerMarkMicro; + + for (n = 1, i = current_bbt_points->begin(); n < bbt_nmarks && i != current_bbt_points->end(); ++i) { + if ((*i).type != TempoMap::Beat) { + continue; + } + if ((*i).frame < lower && (bbt_bar_helper_on)) { + snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat); + (*marks)[0].label = g_strdup (buf); + helper_active = true; + } else { + + if ((*i).beat == 1) { + (*marks)[n].style = GtkCustomRulerMarkMajor; + snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); + } else { + (*marks)[n].style = GtkCustomRulerMarkMinor; + snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat); + } + if (((*i).frame < bbt_position_of_helper) && helper_active) { + snprintf (buf, sizeof(buf), " "); + } + (*marks)[n].label = g_strdup (buf); + (*marks)[n].position = (*i).frame; + n++; + } + + /* Add the tick marks */ + + /* Find the next beat */ + + next_beat.beats = (*i).beat; + next_beat.bars = (*i).bar; + + if ((*i).meter->beats_per_bar() > (next_beat.beats + 1)) { + next_beat.beats += 1; + } else { + next_beat.bars += 1; + next_beat.beats = 1; + } + + next_beat_pos = session->tempo_map().frame_time(next_beat); + + frame_skip = (nframes_t) floor (frame_skip_error = (session->frame_rate() * 60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute())); + frame_skip_error -= frame_skip; + skip = (uint32_t) (Meter::ticks_per_beat / bbt_beat_subdivision); + + pos = (*i).frame + frame_skip; + accumulated_error = frame_skip_error; + + tick = skip; + + for (t = 0; (tick < Meter::ticks_per_beat) && (n < bbt_nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) { + + if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) { + i_am_accented = true; + } + + if (i_am_accented && (pos > bbt_position_of_helper)){ + snprintf (buf, sizeof(buf), "%" PRIu32, tick); + } else { + snprintf (buf, sizeof(buf), " "); + } + + (*marks)[n].label = g_strdup (buf); + + /* Error compensation for float to nframes_t*/ + accumulated_error += frame_skip_error; + if (accumulated_error > 1) { + pos += 1; + accumulated_error -= 1.0f; + } + + (*marks)[n].position = pos; + + if ((bbt_beat_subdivision > 4) && i_am_accented) { + (*marks)[n].style = GtkCustomRulerMarkMinor; + } else { + (*marks)[n].style = GtkCustomRulerMarkMicro; + } + i_am_accented = false; + n++; + } + } + + break; + + case bbt_show_ticks_super_detail: + + beats = current_bbt_points->size(); + bbt_nmarks = (beats + 2) * bbt_beat_subdivision; + + bbt_position_of_helper = lower + (30 * Editor::get_current_zoom ()); + *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); + + (*marks)[0].label = g_strdup(" "); + (*marks)[0].position = lower; + (*marks)[0].style = GtkCustomRulerMarkMicro; + + for (n = 1, i = current_bbt_points->begin(); n < bbt_nmarks && i != current_bbt_points->end(); ++i) { + if ((*i).type != TempoMap::Beat) { + continue; + } + if ((*i).frame < lower && (bbt_bar_helper_on)) { + snprintf (buf, sizeof(buf), "<%" PRIu32 "|%" PRIu32, (*i).bar, (*i).beat); + (*marks)[0].label = g_strdup (buf); + helper_active = true; + } else { + + if ((*i).beat == 1) { + (*marks)[n].style = GtkCustomRulerMarkMajor; + snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); + } else { + (*marks)[n].style = GtkCustomRulerMarkMinor; + snprintf (buf, sizeof(buf), "%" PRIu32, (*i).beat); + } + if (((*i).frame < bbt_position_of_helper) && helper_active) { + snprintf (buf, sizeof(buf), " "); + } + (*marks)[n].label = g_strdup (buf); + (*marks)[n].position = (*i).frame; + n++; + } + + /* Add the tick marks */ + + /* Find the next beat */ + + next_beat.beats = (*i).beat; + next_beat.bars = (*i).bar; + + if ((*i).meter->beats_per_bar() > (next_beat.beats + 1)) { + next_beat.beats += 1; + } else { + next_beat.bars += 1; + next_beat.beats = 1; + } + + next_beat_pos = session->tempo_map().frame_time(next_beat); + + frame_skip = (nframes_t) floor (frame_skip_error = (session->frame_rate() * 60) / (bbt_beat_subdivision * (*i).tempo->beats_per_minute())); + frame_skip_error -= frame_skip; + skip = (uint32_t) (Meter::ticks_per_beat / bbt_beat_subdivision); + + pos = (*i).frame + frame_skip; + accumulated_error = frame_skip_error; + + tick = skip; + + for (t = 0; (tick < Meter::ticks_per_beat) && (n < bbt_nmarks) && (pos < next_beat_pos) ; pos += frame_skip, tick += skip, ++t) { + + if (t % bbt_accent_modulo == (bbt_accent_modulo - 1)) { + i_am_accented = true; + } + + if (pos > bbt_position_of_helper) { + snprintf (buf, sizeof(buf), "%" PRIu32, tick); + } else { + snprintf (buf, sizeof(buf), " "); + } + + (*marks)[n].label = g_strdup (buf); + + /* Error compensation for float to nframes_t*/ + accumulated_error += frame_skip_error; + if (accumulated_error > 1) { + pos += 1; + accumulated_error -= 1.0f; + } + + (*marks)[n].position = pos; + + if ((bbt_beat_subdivision > 4) && i_am_accented) { + (*marks)[n].style = GtkCustomRulerMarkMinor; + } else { + (*marks)[n].style = GtkCustomRulerMarkMicro; + } + i_am_accented = false; + n++; + } + } + + break; + + case bbt_over: + bbt_nmarks = 1; + *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); + snprintf (buf, sizeof(buf), "cannot handle %" PRIu32 " bars", bbt_bars ); (*marks)[0].style = GtkCustomRulerMarkMajor; (*marks)[0].label = g_strdup (buf); (*marks)[0].position = lower; - } else if (desirable_marks < (uint32_t)(nmarks = (gint) (bars / 64) + 1)) { - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks); - for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < nmarks; i++) { + n = 1; + + break; + + case bbt_show_64: + bbt_nmarks = (gint) (bbt_bars / 64) + 1; + *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); + for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < bbt_nmarks; i++) { if ((*i).type == TempoMap::Bar) { if ((*i).bar % 64 == 1) { if ((*i).bar % 256 == 1) { @@ -1280,74 +1565,87 @@ Editor::metric_get_bbt (GtkCustomRulerMark **marks, gdouble lower, gdouble upper } } } - } else if (desirable_marks < (uint32_t)(nmarks = (bars / 16) + 1)) { - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks); - for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < nmarks; i++) { - if ((*i).type == TempoMap::Bar) { - if ((*i).bar % 16 == 1) { - if ((*i).bar % 64 == 1) { - snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); - (*marks)[n].style = GtkCustomRulerMarkMajor; - } else { - snprintf (buf, sizeof(buf), " "); - if ((*i).bar % 64 == 33) { - (*marks)[n].style = GtkCustomRulerMarkMinor; - } else { - (*marks)[n].style = GtkCustomRulerMarkMicro; - } - } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = (*i).frame; - n++; + break; + + case bbt_show_16: + bbt_nmarks = (bbt_bars / 16) + 1; + *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); + for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < bbt_nmarks; i++) { + if ((*i).type == TempoMap::Bar) { + if ((*i).bar % 16 == 1) { + if ((*i).bar % 64 == 1) { + snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); + (*marks)[n].style = GtkCustomRulerMarkMajor; + } else { + snprintf (buf, sizeof(buf), " "); + if ((*i).bar % 64 == 33) { + (*marks)[n].style = GtkCustomRulerMarkMinor; + } else { + (*marks)[n].style = GtkCustomRulerMarkMicro; } } + (*marks)[n].label = g_strdup (buf); + (*marks)[n].position = (*i).frame; + n++; + } } - } else if (desirable_marks < (uint32_t)(nmarks = (bars / 4) + 1)){ - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks); - for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < nmarks; ++i) { - if ((*i).type == TempoMap::Bar) { - if ((*i).bar % 4 == 1) { - if ((*i).bar % 16 == 1) { - snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); - (*marks)[n].style = GtkCustomRulerMarkMajor; - } else { - snprintf (buf, sizeof(buf), " "); - if ((*i).bar % 16 == 9) { - (*marks)[n].style = GtkCustomRulerMarkMinor; - } else { - (*marks)[n].style = GtkCustomRulerMarkMicro; - } - } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = (*i).frame; - n++; + } + break; + + case bbt_show_4: + bbt_nmarks = (bbt_bars / 4) + 1; + *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks); + for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < bbt_nmarks; ++i) { + if ((*i).type == TempoMap::Bar) { + if ((*i).bar % 4 == 1) { + if ((*i).bar % 16 == 1) { + snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); + (*marks)[n].style = GtkCustomRulerMarkMajor; + } else { + snprintf (buf, sizeof(buf), " "); + if ((*i).bar % 16 == 9) { + (*marks)[n].style = GtkCustomRulerMarkMinor; + } else { + (*marks)[n].style = GtkCustomRulerMarkMicro; } } + (*marks)[n].label = g_strdup (buf); + (*marks)[n].position = (*i).frame; + n++; + } } - } else { - nmarks = bars + 1; - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks ); - for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < nmarks; i++) { - if ((*i).type == TempoMap::Bar) { - if ((*i).bar % 4 == 1) { - snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); - (*marks)[n].style = GtkCustomRulerMarkMajor; - } else { - snprintf (buf, sizeof(buf), " "); - if ((*i).bar % 4 == 3) { - (*marks)[n].style = GtkCustomRulerMarkMinor; - } else { - (*marks)[n].style = GtkCustomRulerMarkMicro; - } - } - (*marks)[n].label = g_strdup (buf); - (*marks)[n].position = (*i).frame; - n++; - } - } - } - return n; + } + break; + + case bbt_show_1: + // default: + bbt_nmarks = bbt_bars + 2; + *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * bbt_nmarks ); + for (n = 0, i = current_bbt_points->begin(); i != current_bbt_points->end() && n < bbt_nmarks; i++) { + if ((*i).type == TempoMap::Bar) { + if ((*i).bar % 4 == 1) { + snprintf (buf, sizeof(buf), "%" PRIu32, (*i).bar); + (*marks)[n].style = GtkCustomRulerMarkMajor; + } else { + snprintf (buf, sizeof(buf), " "); + if ((*i).bar % 4 == 3) { + (*marks)[n].style = GtkCustomRulerMarkMinor; + } else { + (*marks)[n].style = GtkCustomRulerMarkMicro; + } + } + (*marks)[n].label = g_strdup (buf); + (*marks)[n].position = (*i).frame; + n++; + } + } + + break; + } + + return n; //return the actual number of marks made, since we might have skipped some from fractional time signatures + } gint @@ -1415,117 +1713,132 @@ sample_to_clock_parts ( nframes_t sample, return; } -gint -Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars) +void +Editor::set_minsec_ruler_scale (gdouble lower, gdouble upper) { nframes_t range; nframes_t fr; - nframes_t mark_interval; + nframes_t spacer; + + if (session == 0) { + return; + } + + fr = session->frame_rate(); + + /* to prevent 'flashing' */ + if (lower > (spacer = (nframes_t)(128 * Editor::get_current_zoom ()))) { + lower -= spacer; + } else { + lower = 0; + } + upper += spacer; + range = (nframes_t) (upper - lower); + + if (range < (fr / 50)) { + minsec_mark_interval = fr / 1000; /* show 1/1000 seconds */ + minsec_ruler_scale = minsec_show_frames; + minsec_mark_modulo = 10; + } else if (range <= (fr / 10)) { /* 0-0.1 second */ + minsec_mark_interval = fr / 1000; /* show 1/1000 seconds */ + minsec_ruler_scale = minsec_show_frames; + minsec_mark_modulo = 10; + } else if (range <= (fr / 2)) { /* 0-0.5 second */ + minsec_mark_interval = fr / 100; /* show 1/100 seconds */ + minsec_ruler_scale = minsec_show_frames; + minsec_mark_modulo = 100; + } else if (range <= fr) { /* 0-1 second */ + minsec_mark_interval = fr / 10; /* show 1/10 seconds */ + minsec_ruler_scale = minsec_show_frames; + minsec_mark_modulo = 200; + } else if (range <= 2 * fr) { /* 1-2 seconds */ + minsec_mark_interval = fr / 10; /* show 1/10 seconds */ + minsec_ruler_scale = minsec_show_frames; + minsec_mark_modulo = 500; + } else if (range <= 8 * fr) { /* 2-5 seconds */ + minsec_mark_interval = fr / 5; /* show 2 seconds */ + minsec_ruler_scale = minsec_show_frames; + minsec_mark_modulo = 1000; + } else if (range <= 16 * fr) { /* 8-16 seconds */ + minsec_mark_interval = fr; /* show 1 seconds */ + minsec_ruler_scale = minsec_show_seconds; + minsec_mark_modulo = 2; + } else if (range <= 30 * fr) { /* 10-30 seconds */ + minsec_mark_interval = fr; /* show 1 seconds */ + minsec_ruler_scale = minsec_show_seconds; + minsec_mark_modulo = 5; + } else if (range <= 60 * fr) { /* 30-60 seconds */ + minsec_mark_interval = fr; /* show 1 seconds */ + minsec_ruler_scale = minsec_show_seconds; + minsec_mark_modulo = 5; + } else if (range <= 2 * 60 * fr) { /* 1-2 minutes */ + minsec_mark_interval = 5 * fr; /* show 5 seconds */ + minsec_ruler_scale = minsec_show_seconds; + minsec_mark_modulo = 3; + } else if (range <= 4 * 60 * fr) { /* 4 minutes */ + minsec_mark_interval = 5 * fr; /* show 10 seconds */ + minsec_ruler_scale = minsec_show_seconds; + minsec_mark_modulo = 30; + } else if (range <= 10 * 60 * fr) { /* 10 minutes */ + minsec_mark_interval = 30 * fr; /* show 30 seconds */ + minsec_ruler_scale = minsec_show_seconds; + minsec_mark_modulo = 120; + } else if (range <= 30 * 60 * fr) { /* 10-30 minutes */ + minsec_mark_interval = 60 * fr; /* show 1 minute */ + minsec_ruler_scale = minsec_show_minutes; + minsec_mark_modulo = 5; + } else if (range <= 60 * 60 * fr) { /* 30 minutes - 1hr */ + minsec_mark_interval = 2 * 60 * fr; /* show 2 minutes */ + minsec_ruler_scale = minsec_show_minutes; + minsec_mark_modulo = 10; + } else if (range <= 4 * 60 * 60 * fr) { /* 1 - 4 hrs*/ + minsec_mark_interval = 5 * 60 * fr; /* show 10 minutes */ + minsec_ruler_scale = minsec_show_minutes; + minsec_mark_modulo = 30; + } else if (range <= 8 * 60 * 60 * fr) { /* 4 - 8 hrs*/ + minsec_mark_interval = 20 * 60 * fr; /* show 20 minutes */ + minsec_ruler_scale = minsec_show_minutes; + minsec_mark_modulo = 60; + } else if (range <= 16 * 60 * 60 * fr) { /* 16-24 hrs*/ + minsec_mark_interval = 60 * 60 * fr; /* show 60 minutes */ + minsec_ruler_scale = minsec_show_hours; + minsec_mark_modulo = 2; + } else { + + /* not possible if nframes_t is a 32 bit quantity */ + + minsec_mark_interval = 4 * 60 * 60 * fr; /* show 4 hrs */ + } + minsec_nmarks = 2 + (range / minsec_mark_interval); +} + +gint +Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble upper, gint maxchars) +{ nframes_t pos; nframes_t spacer; long hrs, mins, secs, millisecs; gchar buf[16]; - gint nmarks; gint n; - gint mark_modulo = 100; - bool show_seconds = false; - bool show_minutes = false; - bool show_hours = false; - nframes_t ilower = (nframes_t) floor (lower); - nframes_t iupper = (nframes_t) floor (upper); if (session == 0) { return 0; } - fr = session->frame_rate(); - /* to prevent 'flashing' */ if (lower > (spacer = (nframes_t)(128 * Editor::get_current_zoom ()))) { lower = lower - spacer; } else { lower = 0; } - upper = upper + spacer; - range = iupper - ilower; - if (range < (fr / 50)) { - mark_interval = fr / 100; /* show 1/100 seconds */ - mark_modulo = 10; - } else if (range <= (fr / 10)) { /* 0-0.1 second */ - mark_interval = fr / 50; /* show 1/50 seconds */ - mark_modulo = 20; - } else if (range <= (fr / 2)) { /* 0-0.5 second */ - mark_interval = fr / 20; /* show 1/20 seconds */ - mark_modulo = 100; - } else if (range <= fr) { /* 0-1 second */ - mark_interval = fr / 10; /* show 1/10 seconds */ - mark_modulo = 200; - } else if (range <= 2 * fr) { /* 1-2 seconds */ - mark_interval = fr / 2; /* show 1/2 seconds */ - mark_modulo = 500; - } else if (range <= 8 * fr) { /* 2-5 seconds */ - mark_interval = fr / 5; /* show 2 seconds */ - mark_modulo = 1000; - } else if (range <= 16 * fr) { /* 8-16 seconds */ - mark_interval = fr; /* show 1 seconds */ - show_seconds = true; - mark_modulo = 5; - } else if (range <= 30 * fr) { /* 10-30 seconds */ - mark_interval = fr; /* show 10 seconds */ - show_seconds = true; - mark_modulo = 5; - } else if (range <= 60 * fr) { /* 30-60 seconds */ - mark_interval = 5 * fr; /* show 5 seconds */ - show_seconds = true; - mark_modulo = 3; - } else if (range <= 2 * 60 * fr) { /* 1-2 minutes */ - mark_interval = 5 * fr; /* show 5 seconds */ - show_seconds = true; - mark_modulo = 3; - } else if (range <= 4 * 60 * fr) { /* 4 minutes */ - mark_interval = 10 * fr; /* show 10 seconds */ - show_seconds = true; - mark_modulo = 30; - } else if (range <= 10 * 60 * fr) { /* 10 minutes */ - mark_interval = 30 * fr; /* show 30 seconds */ - show_seconds = true; - mark_modulo = 60; - } else if (range <= 30 * 60 * fr) { /* 10-30 minutes */ - mark_interval = 60 * fr; /* show 1 minute */ - show_minutes = true; - mark_modulo = 5; - } else if (range <= 60 * 60 * fr) { /* 30 minutes - 1hr */ - mark_interval = 2 * 60 * fr; /* show 2 minutes */ - show_minutes = true; - mark_modulo = 10; - } else if (range <= 4 * 60 * 60 * fr) { /* 1 - 4 hrs*/ - mark_interval = 5 * 60 * fr; /* show 10 minutes */ - show_minutes = true; - mark_modulo = 30; - } else if (range <= 8 * 60 * 60 * fr) { /* 4 - 8 hrs*/ - mark_interval = 20 * 60 * fr; /* show 20 minutes */ - show_minutes = true; - mark_modulo = 60; - } else if (range <= 16 * 60 * 60 * fr) { /* 16-24 hrs*/ - mark_interval = 60 * 60 * fr; /* show 60 minutes */ - show_hours = true; - mark_modulo = 2; - } else { - - /* not possible if nframes_t is a 32 bit quantity */ - - mark_interval = 4 * 60 * 60 * fr; /* show 4 hrs */ - } - - nmarks = 1 + (range / mark_interval); - *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * nmarks); - pos = ((ilower + (mark_interval/2))/mark_interval) * mark_interval; - - if (show_seconds) { - for (n = 0; n < nmarks; pos += mark_interval, ++n) { - sample_to_clock_parts (pos, fr, &hrs, &mins, &secs, &millisecs); - if (secs % mark_modulo == 0) { + *marks = (GtkCustomRulerMark *) g_malloc (sizeof(GtkCustomRulerMark) * minsec_nmarks); + pos = ((((nframes_t) floor(lower)) + (minsec_mark_interval/2))/minsec_mark_interval) * minsec_mark_interval; + switch (minsec_ruler_scale) { + case minsec_show_seconds: + for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) { + sample_to_clock_parts (pos, session->frame_rate(), &hrs, &mins, &secs, &millisecs); + if (secs % minsec_mark_modulo == 0) { if (secs == 0) { (*marks)[n].style = GtkCustomRulerMarkMajor; } else { @@ -1539,10 +1852,11 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble up (*marks)[n].label = g_strdup (buf); (*marks)[n].position = pos; } - } else if (show_minutes) { - for (n = 0; n < nmarks; pos += mark_interval, ++n) { - sample_to_clock_parts (pos, fr, &hrs, &mins, &secs, &millisecs); - if (mins % mark_modulo == 0) { + break; + case minsec_show_minutes: + for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) { + sample_to_clock_parts (pos, session->frame_rate(), &hrs, &mins, &secs, &millisecs); + if (mins % minsec_mark_modulo == 0) { if (mins == 0) { (*marks)[n].style = GtkCustomRulerMarkMajor; } else { @@ -1556,10 +1870,11 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble up (*marks)[n].label = g_strdup (buf); (*marks)[n].position = pos; } - } else if (show_hours) { - for (n = 0; n < nmarks; pos += mark_interval, ++n) { - sample_to_clock_parts (pos, fr, &hrs, &mins, &secs, &millisecs); - if (hrs % mark_modulo == 0) { + break; + case minsec_show_hours: + for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) { + sample_to_clock_parts (pos, session->frame_rate(), &hrs, &mins, &secs, &millisecs); + if (hrs % minsec_mark_modulo == 0) { (*marks)[n].style = GtkCustomRulerMarkMajor; snprintf (buf, sizeof(buf), "%02ld:%02ld:%02ld.%03ld", hrs, mins, secs, millisecs); } else { @@ -1569,11 +1884,12 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble up (*marks)[n].label = g_strdup (buf); (*marks)[n].position = pos; } - } else { - for (n = 0; n < nmarks; pos += mark_interval, ++n) { - sample_to_clock_parts (pos, fr, &hrs, &mins, &secs, &millisecs); - if (millisecs % mark_modulo == 0) { - if (millisecs == 0) { + break; + case minsec_show_frames: + for (n = 0; n < minsec_nmarks; pos += minsec_mark_interval, ++n) { + sample_to_clock_parts (pos, session->frame_rate(), &hrs, &mins, &secs, &millisecs); + if (millisecs % minsec_mark_modulo == 0) { + if (secs == 0) { (*marks)[n].style = GtkCustomRulerMarkMajor; } else { (*marks)[n].style = GtkCustomRulerMarkMinor; @@ -1586,7 +1902,8 @@ Editor::metric_get_minsec (GtkCustomRulerMark **marks, gdouble lower, gdouble up (*marks)[n].label = g_strdup (buf); (*marks)[n].position = pos; } + break; } - return nmarks; + return minsec_nmarks; } diff --git a/gtk2_ardour/editor_tempodisplay.cc b/gtk2_ardour/editor_tempodisplay.cc index 09133a8823..831fe3b727 100644 --- a/gtk2_ardour/editor_tempodisplay.cc +++ b/gtk2_ardour/editor_tempodisplay.cc @@ -99,18 +99,44 @@ Editor::tempo_map_changed (Change ignored) return; } - ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::tempo_map_changed), ignored)); - - redisplay_tempo (false); // redraw rulers and measures + ENSURE_GUI_THREAD(bind (mem_fun (*this, &Editor::tempo_map_changed), ignored)); + + compute_current_bbt_points(leftmost_frame, leftmost_frame + (nframes_t)(canvas_width * frames_per_unit)); session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks); // redraw metric markers + update_tempo_based_rulers (); + if (tempo_map_change_idle_handler_id < 0) { + tempo_map_change_idle_handler_id = Glib::signal_idle().connect (mem_fun (*this, &Editor::redraw_measures)); + } } -/** - * This code was originally in tempo_map_changed, but this is called every time the canvas scrolls horizontally. - * That's why this is moved in here. The new tempo_map_changed is called when the ARDOUR::TempoMap actually changed. - */ void Editor::redisplay_tempo (bool immediate_redraw) +{ + if (!session) { + return; + } + + compute_current_bbt_points (leftmost_frame, leftmost_frame + (nframes_t)(canvas_width * frames_per_unit)); // redraw rulers and measures + + if (immediate_redraw) { + + hide_measures (); + + if (current_bbt_points) { + draw_measures (); + } + + } else if (tempo_map_change_idle_handler_id < 0) { + + tempo_map_change_idle_handler_id = Glib::signal_idle().connect (mem_fun (*this, &Editor::redraw_measures)); + + } + + update_tempo_based_rulers (); +} + +void +Editor::compute_current_bbt_points (nframes_t leftmost, nframes_t rightmost) { if (!session) { return; @@ -118,8 +144,8 @@ Editor::redisplay_tempo (bool immediate_redraw) BBT_Time previous_beat, next_beat; // the beats previous to the leftmost frame and after the rightmost frame - session->bbt_time(leftmost_frame, previous_beat); - session->bbt_time(leftmost_frame + current_page_frames(), next_beat); + session->bbt_time(leftmost, previous_beat); + session->bbt_time(rightmost, next_beat); if (previous_beat.beats > 1) { previous_beat.beats -= 1; @@ -129,7 +155,7 @@ Editor::redisplay_tempo (bool immediate_redraw) } previous_beat.ticks = 0; - if (session->tempo_map().meter_at(leftmost_frame + current_page_frames()).beats_per_bar () > next_beat.beats + 1) { + if (session->tempo_map().meter_at(rightmost).beats_per_bar () > next_beat.beats + 1) { next_beat.beats += 1; } else { next_beat.bars += 1; @@ -142,29 +168,7 @@ Editor::redisplay_tempo (bool immediate_redraw) current_bbt_points = 0; } - if (session) { - current_bbt_points = session->tempo_map().get_points (session->tempo_map().frame_time (previous_beat), session->tempo_map().frame_time (next_beat)); - update_tempo_based_rulers (); - } else { - current_bbt_points = 0; - } - - if (immediate_redraw) { - - hide_measures (); - - if (session && current_bbt_points) { - draw_measures (); - } - - } else { - - if (session && current_bbt_points) { - Glib::signal_idle().connect (mem_fun (*this, &Editor::redraw_measures)); - } else { - hide_measures (); - } - } + current_bbt_points = session->tempo_map().get_points (session->tempo_map().frame_time (previous_beat), session->tempo_map().frame_time (next_beat) + 1); } void @@ -179,6 +183,7 @@ Editor::redraw_measures () { hide_measures (); draw_measures (); + tempo_map_change_idle_handler_id = -1; return false; } diff --git a/gtk2_ardour/export_dialog.cc b/gtk2_ardour/export_dialog.cc index 2cf96fe02a..cbaee3d6d2 100644 --- a/gtk2_ardour/export_dialog.cc +++ b/gtk2_ardour/export_dialog.cc @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -86,8 +87,8 @@ static const gchar *dither_types[] = { }; static const gchar* channel_strings[] = { - N_("stereo"), - N_("mono"), + N_("Stereo"), + N_("Mono"), 0 }; @@ -112,7 +113,7 @@ ExportDialog::ExportDialog(PublicEditor& e) src_quality_label (_("Conversion Quality"), 1.0, 0.5), dither_type_label (_("Dither Type"), 1.0, 0.5), cuefile_only_checkbox (_("Export CD Marker File Only")), - file_browse_button (_("Browse")), + file_chooser (FILE_CHOOSER_ACTION_SAVE), track_selector_button (_("Specific tracks ...")) { guint32 n; @@ -123,6 +124,7 @@ ExportDialog::ExportDialog(PublicEditor& e) track_and_master_selection_allowed = true; channel_count_selection_allowed = true; export_cd_markers_allowed = true; + set_resizable (false); WindowTitle title(Glib::get_application_name()); title += _("Export"); @@ -134,8 +136,6 @@ ExportDialog::ExportDialog(PublicEditor& e) spec.running = false; - file_entry.set_name ("ExportFileNameEntry"); - master_list = ListStore::create (exp_cols); master_selector.set_model (master_list); @@ -176,11 +176,11 @@ ExportDialog::ExportDialog(PublicEditor& e) track_scroll.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); master_scroll.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); - get_vbox()->pack_start (file_frame, false, false); + get_vbox()->pack_start (file_frame, PACK_EXPAND_WIDGET); hpacker.set_spacing (5); hpacker.set_border_width (5); - hpacker.pack_start (format_frame, false, false); + hpacker.pack_start (format_frame, PACK_SHRINK ); master_scroll.add (master_selector); track_scroll.add (track_selector); @@ -195,19 +195,36 @@ ExportDialog::ExportDialog(PublicEditor& e) hpacker.pack_start (track_vpacker); - get_vbox()->pack_start (hpacker); + get_vbox()->pack_start (hpacker, PACK_SHRINK); track_selector_button.set_name ("EditorGTKButton"); track_selector_button.signal_clicked().connect (mem_fun(*this, &ExportDialog::track_selector_button_click)); - get_vbox()->pack_start (progress_bar, false, false); + Gtk::FileFilter filter_wav; + filter_wav.set_name("Wav files"); + filter_wav.add_mime_type("audio/wav"); + file_chooser.add_filter(filter_wav); + + Gtk::FileFilter filter_aiff; + filter_aiff.set_name("Aiff files"); + filter_aiff.add_mime_type("audio/aiff"); + filter_aiff.add_pattern("*.aif"); + filter_aiff.add_pattern("*.aiff"); + file_chooser.add_filter(filter_aiff); + + Gtk::FileFilter filter_any; + filter_any.set_name("All files"); + filter_any.add_pattern("*"); + file_chooser.add_filter(filter_any); + file_chooser.set_no_show_all(); - Gtkmm2ext::set_size_request_to_display_given_text (file_entry, X_("Kg/quite/a/reasonable/size/for/files/i/think"), 5, 8); + get_vbox()->pack_start (progress_bar, false, false, 5); + progress_bar.set_no_show_all(); + progress_bar.hide(); file_hbox.set_spacing (5); file_hbox.set_border_width (5); - file_hbox.pack_start (file_entry, true, true); - file_hbox.pack_start (file_browse_button, false, false); + file_hbox.pack_start (file_chooser, PACK_EXPAND_WIDGET); file_frame.add (file_hbox); file_frame.set_border_width (5); @@ -316,37 +333,35 @@ ExportDialog::ExportDialog(PublicEditor& e) cuefile_only_checkbox.set_name ("ExportCheckbox"); - format_table.set_homogeneous (false); + format_table.set_homogeneous (true); format_table.set_border_width (5); format_table.set_col_spacings (5); format_table.set_row_spacings (5); - format_table.attach (channel_count_label, 0, 1, 0, 1); - format_table.attach (channel_count_combo, 1, 2, 0, 1); + format_table.attach (channel_count_label, 0, 1, 0, 1, FILL, FILL); + format_table.attach (channel_count_combo, 1, 2, 0, 1, FILL, FILL); - format_table.attach (header_format_label, 0, 1, 1, 2); - format_table.attach (header_format_combo, 1, 2, 1, 2); + format_table.attach (header_format_label, 0, 1, 1, 2, FILL, FILL); + format_table.attach (header_format_combo, 1, 2, 1, 2, FILL, FILL); - format_table.attach (bitdepth_format_label, 0, 1, 2, 3); - format_table.attach (bitdepth_format_combo, 1, 2, 2, 3); + format_table.attach (bitdepth_format_label, 0, 1, 2, 3, FILL, FILL); + format_table.attach (bitdepth_format_combo, 1, 2, 2, 3, FILL, FILL); - format_table.attach (endian_format_label, 0, 1, 3, 4); - format_table.attach (endian_format_combo, 1, 2, 3, 4); + format_table.attach (endian_format_label, 0, 1, 3, 4, FILL, FILL); + format_table.attach (endian_format_combo, 1, 2, 3, 4, FILL, FILL); - format_table.attach (sample_rate_label, 0, 1, 4, 5); - format_table.attach (sample_rate_combo, 1, 2, 4, 5); + format_table.attach (sample_rate_label, 0, 1, 4, 5, FILL, FILL); + format_table.attach (sample_rate_combo, 1, 2, 4, 5, FILL, FILL); - format_table.attach (src_quality_label, 0, 1, 5, 6); - format_table.attach (src_quality_combo, 1, 2, 5, 6); + format_table.attach (src_quality_label, 0, 1, 5, 6, FILL, FILL); + format_table.attach (src_quality_combo, 1, 2, 5, 6, FILL, FILL); - format_table.attach (dither_type_label, 0, 1, 6, 7); - format_table.attach (dither_type_combo, 1, 2, 6, 7); + format_table.attach (dither_type_label, 0, 1, 6, 7, FILL, FILL); + format_table.attach (dither_type_combo, 1, 2, 6, 7, FILL, FILL); - format_table.attach (cue_file_label, 0, 1, 7, 8); - format_table.attach (cue_file_combo, 1, 2, 7, 8); - format_table.attach (cuefile_only_checkbox, 0, 2, 8, 9); - - file_entry.set_name ("ExportFileDisplay"); + format_table.attach (cue_file_label, 0, 1, 7, 8, FILL, FILL); + format_table.attach (cue_file_combo, 1, 2, 7, 8, FILL, FILL); + format_table.attach (cuefile_only_checkbox, 0, 2, 8, 9, FILL, FILL); signal_delete_event().connect (mem_fun(*this, &ExportDialog::window_closed)); @@ -354,15 +369,14 @@ ExportDialog::ExportDialog(PublicEditor& e) cancel_button->signal_clicked().connect (mem_fun(*this, &ExportDialog::end_dialog)); ok_button = add_button (_("Export"), RESPONSE_ACCEPT); ok_button->signal_clicked().connect (mem_fun(*this, &ExportDialog::do_export)); - - file_browse_button.set_name ("EditorGTKButton"); - file_browse_button.signal_clicked().connect (mem_fun(*this, &ExportDialog::browse)); - channel_count_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::channels_chosen)); bitdepth_format_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::bitdepth_chosen)); header_format_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::header_chosen)); sample_rate_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::sample_rate_chosen)); cue_file_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::cue_file_type_chosen)); + + file_chooser.signal_update_preview().connect (mem_fun(*this, &ExportDialog::file_chooser_selection_changed)); + } ExportDialog::~ExportDialog() @@ -373,24 +387,18 @@ void ExportDialog::do_not_allow_track_and_master_selection() { track_and_master_selection_allowed = false; - track_vpacker.set_no_show_all(); } void ExportDialog::do_not_allow_channel_count_selection() { channel_count_selection_allowed = false; - channel_count_combo.set_no_show_all(); - channel_count_label.set_no_show_all(); } void ExportDialog::do_not_allow_export_cd_markers() { export_cd_markers_allowed = false; - cue_file_label.set_no_show_all(); - cue_file_combo.set_no_show_all(); - cuefile_only_checkbox.set_no_show_all(); } void @@ -433,7 +441,7 @@ ExportDialog::set_state() { XMLNode* node = session->instant_xml(X_("ExportDialog")); XMLProperty* prop; - + bool fc_location_requested = false; if (node) { if ((prop = node->property (X_("sample_rate"))) != 0) { @@ -458,13 +466,28 @@ ExportDialog::set_state() endian_format_combo.set_active_text(prop->value()); } if ((prop = node->property (X_("filename"))) != 0) { - file_entry.set_text(prop->value()); + file_chooser.set_filename(prop->value()); + fc_location_requested = true; + file_chooser.set_current_folder(Glib::path_get_basename(prop->value())); } + if ((prop = node->property (X_("cue_file_type"))) != 0) { cue_file_combo.set_active_text(prop->value()); } } + if (!fc_location_requested) { + + /* + If the filename hasn't been set before, use the + current session's export directory as a default + location for the export. + */ + + file_chooser.set_current_folder (session->session_directory().export_path().to_string()); + file_chooser.set_current_name (_("export.wav")); + } + header_chosen (); bitdepth_chosen(); channels_chosen(); @@ -488,7 +511,7 @@ ExportDialog::set_state() if (!master) { /* default is to use all */ - if (channel_count_combo.get_active_text() == _("mono")) { + if (channel_count_combo.get_active_text() == _("Mono")) { nchns = 1; } else { nchns = 2; @@ -564,7 +587,7 @@ ExportDialog::save_state() node->add_property(X_("header_format"), header_format_combo.get_active_text()); node->add_property(X_("bitdepth_format"), bitdepth_format_combo.get_active_text()); node->add_property(X_("endian_format"), endian_format_combo.get_active_text()); - node->add_property(X_("filename"), file_entry.get_text()); + node->add_property(X_("filename"), file_chooser.get_filename()); node->add_property(X_("cue_file_type"), cue_file_combo.get_active_text()); XMLNode* tracks = new XMLNode(X_("Tracks")); @@ -888,7 +911,7 @@ ExportDialog::do_export_cd_markers (const string& path,const string& cuefile_typ void ExportDialog::do_export () { - string filepath = file_entry.get_text(); + string filepath = file_chooser.get_filename(); if(!is_filepath_valid(filepath)){ return; @@ -896,7 +919,7 @@ ExportDialog::do_export () if (export_cd_markers_allowed) { if (cue_file_combo.get_active_text () != _("None")) { - do_export_cd_markers (file_entry.get_text(), cue_file_combo.get_active_text ()); + do_export_cd_markers (file_chooser.get_filename(), cue_file_combo.get_active_text ()); } if (cuefile_only_checkbox.get_active()) { @@ -913,12 +936,15 @@ ExportDialog::do_export () // read user input into spec initSpec(filepath); + progress_bar.show(); progress_connection = Glib::signal_timeout().connect (mem_fun(*this, &ExportDialog::progress_timeout), 100); cancel_label.set_text (_("Stop Export")); export_audio_data(); progress_connection.disconnect (); + session->engine().freewheel (false); + progress_bar.hide(); end_dialog (); } @@ -937,9 +963,9 @@ ExportDialog::end_dialog () } } - session->finalize_audio_export (); + hide (); - hide_all (); + session->finalize_audio_export (); set_modal (false); ok_button->set_sensitive(true); @@ -967,11 +993,39 @@ ExportDialog::start_export () file_entry.set_text (export_file_path.to_string()); } - + progress_bar.set_fraction (0); + progress_bar.hide(); + progress_bar.set_no_show_all(); cancel_label.set_text (_("Cancel")); - show_all (); + show_all(); + + if (track_and_master_selection_allowed) { + track_vpacker.show(); + } else { + track_vpacker.hide(); + } + + file_chooser.show(); + + if (channel_count_selection_allowed) { + channel_count_combo.show(); + channel_count_label.show(); + } else { + channel_count_combo.hide(); + channel_count_label.hide(); + } + + if (export_cd_markers_allowed) { + cue_file_label.show(); + cue_file_combo.show(); + cuefile_only_checkbox.show(); + } else { + cue_file_label.hide(); + cue_file_combo.hide(); + cuefile_only_checkbox.hide(); + } if (session->master_out()) { track_scroll.hide (); @@ -979,15 +1033,21 @@ ExportDialog::start_export () master_scroll.hide (); track_selector_button.hide (); } + + track_and_master_selection_allowed = true; + channel_count_selection_allowed = true; + export_cd_markers_allowed = true; } void ExportDialog::header_chosen () { if (sndfile_header_format_from_string (header_format_combo.get_active_text ()) == SF_FORMAT_WAV) { + endian_format_combo.set_active_text (N_("Little-endian (Intel)")); endian_format_combo.set_sensitive (false); } else { endian_format_combo.set_sensitive (true); + endian_format_combo.set_active_text (N_("Big-endian (Mac)")); } } @@ -1019,6 +1079,65 @@ ExportDialog::cue_file_type_chosen () } } +void +ExportDialog::file_chooser_selection_changed () +{ + + /* + if the user selects an existing file from the 'browse for other folders' tab, + change the format settings to match the file. + */ + if (file_chooser.get_filename().length() == 0) { + return; + } + if (Glib::file_test(file_chooser.get_preview_filename(),Glib::FILE_TEST_IS_DIR)){ + file_chooser.set_current_name (_("")); + return; + } + if (!Glib::file_test(file_chooser.get_preview_filename(),Glib::FILE_TEST_EXISTS)) { + return; + } + + SoundFileInfo finfo; + string error_msg, format_str; + + if (!AudioFileSource::get_soundfile_info (file_chooser.get_preview_filename(), finfo, error_msg)) { + error << string_compose(_("Export: cannot open file \"%1\"."), error_msg ) << endmsg; + return; + } + + if (finfo.samplerate == 22050) { + sample_rate_combo.set_active_text (N_("22.05kHz")); + } else if (finfo.samplerate == 44100) { + sample_rate_combo.set_active_text (N_("44.1kHz")); + } else if (finfo.samplerate == 48000) { + sample_rate_combo.set_active_text (N_("48kHz")); + } else if (finfo.samplerate == 88200) { + sample_rate_combo.set_active_text (N_("88.2kHz")); + } else if (finfo.samplerate == 96000) { + sample_rate_combo.set_active_text (N_("96kHz")); + } else if (finfo.samplerate == 192000) { + sample_rate_combo.set_active_text (N_("192kHz")); + } + + if (finfo.channels == 1) { + channel_count_combo.set_active_text(N_("Mono")); + } else { + channel_count_combo.set_active_text(N_("Stereo")); + } + + string::size_type pos; + + pos = finfo.format_name.find_first_of (" "); + format_str = finfo.format_name.substr(pos + 1, 255); + pos = format_str.find_first_of (" "); + header_format_combo.set_active_text(format_str.substr(0, pos)); + + format_str = finfo.format_name; + pos = format_str.find_first_of (","); + bitdepth_format_combo.set_active_text(format_str.substr(pos + 2, 255)); +} + void ExportDialog::sample_rate_chosen () { @@ -1053,7 +1172,7 @@ ExportDialog::channels_chosen () { bool mono; - mono = (channel_count_combo.get_active_text() == _("mono")); + mono = (channel_count_combo.get_active_text() == _("Mono")); if (mono) { track_selector.get_column(2)->set_visible(false); @@ -1145,7 +1264,7 @@ ExportDialog::is_filepath_valid(string &filepath) return false; } else { - string txt = _("File already exists, do you want to overwrite it?"); + string txt = _("File ") + filepath + _(" already exists, do you want to overwrite it?"); MessageDialog msg (*this, txt, false, MESSAGE_QUESTION, BUTTONS_YES_NO, true); if ((ResponseType) msg.run() == Gtk::RESPONSE_NO) { return false; @@ -1175,7 +1294,7 @@ ExportDialog::initSpec(string &filepath) spec.stop = false; spec.port_map.clear(); - if (channel_count_combo.get_active_text() == _("mono")) { + if (channel_count_combo.get_active_text() == _("Mono")) { spec.channels = 1; } else { spec.channels = 2; @@ -1305,27 +1424,6 @@ ExportDialog::window_closed (GdkEventAny *ignored) return TRUE; } -void -ExportDialog::browse () -{ - FileChooserDialog dialog("Export to file", browse_action()); - dialog.set_transient_for(*this); - dialog.set_filename (file_entry.get_text()); - - dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); - dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK); - - int result = dialog.run(); - - if (result == Gtk::RESPONSE_OK) { - string filename = dialog.get_filename(); - - if (filename.length()) { - file_entry.set_text (filename); - } - } -} - void ExportDialog::track_selector_button_click () { diff --git a/gtk2_ardour/export_dialog.h b/gtk2_ardour/export_dialog.h index 596467d3e1..d518f5ec8a 100644 --- a/gtk2_ardour/export_dialog.h +++ b/gtk2_ardour/export_dialog.h @@ -134,7 +134,7 @@ class ExportDialog : public ArdourDialog Gtk::Entry file_entry; Gtk::HBox file_hbox; - Gtk::Button file_browse_button; + Gtk::FileChooserWidget file_chooser; Gtk::Button* ok_button; Gtk::Button* cancel_button; @@ -159,6 +159,7 @@ class ExportDialog : public ArdourDialog void bitdepth_chosen (); void sample_rate_chosen (); void cue_file_type_chosen(); + void file_chooser_selection_changed(); void fill_lists(); void write_track_and_master_selection_to_spec(); @@ -171,8 +172,6 @@ class ExportDialog : public ArdourDialog void track_selector_button_click (); - void browse (); - void set_state(); void save_state(); }; diff --git a/gtk2_ardour/region_view.cc b/gtk2_ardour/region_view.cc index 699ecdbcfa..cb8e7f235b 100644 --- a/gtk2_ardour/region_view.cc +++ b/gtk2_ardour/region_view.cc @@ -141,7 +141,7 @@ RegionView::init (Gdk::Color& basic_color, bool wfd) sync_mark->property_fill_color_rgba() = fill_color; sync_mark->hide(); - reset_width_dependent_items ((double) _region->length() / samples_per_unit); + //reset_width_dependent_items ((double) _region->length() / samples_per_unit); if (wfd) _enable_display = true; @@ -214,9 +214,14 @@ RegionView::region_changed (Change what_changed) if (what_changed & Region::SyncOffsetChanged) { region_sync_changed (); } + /* + this should not be needed now that only playlist can change layering + */ + /* if (what_changed & Region::LayerChanged) { region_layered (); } + */ if (what_changed & Region::LockChanged) { region_locked (); } diff --git a/gtk2_ardour/streamview.cc b/gtk2_ardour/streamview.cc index 1a3fb9a084..f6d6924a76 100644 --- a/gtk2_ardour/streamview.cc +++ b/gtk2_ardour/streamview.cc @@ -285,17 +285,18 @@ StreamView::apply_color (Gdk::Color& color, ColorTarget target) void StreamView::region_layered (RegionView* rv) { - rv->get_canvas_group()->lower_to_bottom(); - /* don't ever leave it at the bottom, since then it doesn't - get events - the parent group does instead ... - */ - - /* this used to be + 1, but regions to the left ended up below - ..something.. and couldn't receive events. why? good question. - */ - /* and now it's + 3 for midi note separator lines */ - rv->get_canvas_group()->raise (rv->region()->layer() + 3); + /* + Currently 'layer' has nothing to do with the desired canvas layer. + For now, ensure that multiple regionviews passed here in groups are + ordered by 'layer' (lowest to highest). + + (see AudioStreamView::redisplay_diskstream ()). + + We move them to the top layer as they arrive. + */ + + rv->get_canvas_group()->raise_to_top(); } void diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index af08d4569c..bcbc7c78ac 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -232,33 +232,11 @@ def CheckJackRecomputeLatency(context): context.Result(result) return result -# -# See if JACK supports jack_port_ensure_monitor_input() -# -jack_ensure_monitor_input_test = """ -#include -int main(int argc, char** argv) -{ - jack_port_t **port; - - jack_port_ensure_monitor (*port, 1); - return 0; - -} -""" - -def CheckJackEnsureMonitorInput(context): - context.Message('Checking for jack_port_ensure_monitor_input()...') - result = context.TryLink(jack_ensure_monitor_input_test, '.c') - context.Result(result) - return result - conf = Configure(ardour, custom_tests = { 'CheckJackClientOpen' : CheckJackClientOpen, 'CheckJackRecomputeLatencies' : CheckJackRecomputeLatencies, 'CheckJackRecomputeLatency' : CheckJackRecomputeLatency, - 'CheckJackVideoFrameOffset' : CheckJackVideoFrameOffset, - 'CheckJackEnsureMonitorInput' : CheckJackEnsureMonitorInput + 'CheckJackVideoFrameOffset' : CheckJackVideoFrameOffset }) if conf.CheckJackClientOpen(): @@ -272,11 +250,6 @@ if conf.CheckJackRecomputeLatency(): if conf.CheckJackVideoFrameOffset(): ardour.Append(CXXFLAGS="-DHAVE_JACK_VIDEO_SUPPORT") - -if conf.CheckJackEnsureMonitorInput(): - ardour.Append(CXXFLAGS='-DHAVE_JACK_PORT_ENSURE_MONITOR') -else: - print '\nWARNING: You need at least svn revision 985 of jack for hardware monitoring to work correctly.\n' # # Optional header files diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h index 7b22528bd1..3865019bc7 100644 --- a/libs/ardour/ardour/audiosource.h +++ b/libs/ardour/ardour/audiosource.h @@ -61,10 +61,6 @@ const nframes_t frames_per_peak = 256; /* returns the number of items in this `audio_source' */ - virtual nframes_t length() const { - return _length; - } - virtual nframes_t available_peaks (double zoom) const; virtual nframes_t read (Sample *dst, nframes_t start, nframes_t cnt) const; @@ -120,7 +116,6 @@ const nframes_t frames_per_peak = 256; bool _peaks_built; mutable Glib::Mutex _lock; mutable Glib::Mutex _peaks_ready_lock; - nframes_t _length; Glib::ustring peakpath; Glib::ustring _captured_for; diff --git a/libs/ardour/ardour/jack_port.h b/libs/ardour/ardour/jack_port.h index c3c31c938d..d973ed2cab 100644 --- a/libs/ardour/ardour/jack_port.h +++ b/libs/ardour/ardour/jack_port.h @@ -62,13 +62,7 @@ class JackPort : public virtual Port { } void ensure_monitor_input (bool yn) { - -#ifdef HAVE_JACK_PORT_ENSURE_MONITOR jack_port_ensure_monitor (_port, yn); -#else - jack_port_request_monitor(_port, yn); -#endif - } /*XXX completely bloody useless imho*/ diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 0c5a8e044f..8dd9ccc211 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -279,7 +279,7 @@ namespace ARDOUR { enum MonitorModel { HardwareMonitoring, SoftwareMonitoring, - ExternalMonitoring, + ExternalMonitoring }; enum DenormalModel { @@ -292,7 +292,7 @@ namespace ARDOUR { enum RemoteModel { UserOrdered, MixerOrdered, - EditorOrdered, + EditorOrdered }; enum CrossfadeModel { diff --git a/libs/ardour/audio_playlist.cc b/libs/ardour/audio_playlist.cc index f4c10cbc12..0631c9121b 100644 --- a/libs/ardour/audio_playlist.cc +++ b/libs/ardour/audio_playlist.cc @@ -337,6 +337,7 @@ AudioPlaylist::check_dependents (boost::shared_ptr r, bool norefresh) boost::shared_ptr top; boost::shared_ptr bottom; boost::shared_ptr xfade; + RegionList* touched_regions; if (in_set_state || in_partition) { return; @@ -398,7 +399,7 @@ AudioPlaylist::check_dependents (boost::shared_ptr r, bool norefresh) break; case OverlapExternal: - + /* [ -------- top ------- ] * {=========== bottom =============} */ @@ -411,11 +412,15 @@ AudioPlaylist::check_dependents (boost::shared_ptr r, bool norefresh) */ xfade_length = min ((nframes_t) 720, top->length()); - - xfade = boost::shared_ptr (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn)); - add_crossfade (xfade); + + if (top_region_at (top->first_frame()) == top) { + + xfade = boost::shared_ptr (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn)); + add_crossfade (xfade); + } if (top_region_at (top->last_frame() - 1) == top) { + /* only add a fade out if there is no region on top of the end of 'top' (which would cover it). @@ -425,9 +430,58 @@ AudioPlaylist::check_dependents (boost::shared_ptr r, bool norefresh) add_crossfade (xfade); } break; - + case OverlapStart: + + /* { ==== top ============ } + * [---- bottom -------------------] + */ + + if (Config->get_xfade_model() == FullCrossfade) { + touched_regions = regions_touched (top->first_frame(), bottom->last_frame()); + if (touched_regions->size() <= 2) { + xfade = boost::shared_ptr (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active())); + add_crossfade (xfade); + } + } else { + + touched_regions = regions_touched (top->first_frame(), + top->first_frame() + min ((nframes_t)Config->get_short_xfade_seconds() * _session.frame_rate(), + top->length())); + if (touched_regions->size() <= 2) { + xfade = boost::shared_ptr (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active())); + add_crossfade (xfade); + } + } + break; + case OverlapEnd: + + + /* [---- top ------------------------] + * { ==== bottom ============ } + */ + + if (Config->get_xfade_model() == FullCrossfade) { + + touched_regions = regions_touched (bottom->first_frame(), top->last_frame()); + if (touched_regions->size() <= 2) { + xfade = boost::shared_ptr (new Crossfade (region, other, + Config->get_xfade_model(), Config->get_xfades_active())); + add_crossfade (xfade); + } + + } else { + touched_regions = regions_touched (bottom->first_frame(), + bottom->first_frame() + min ((nframes_t)Config->get_short_xfade_seconds() * _session.frame_rate(), + bottom->length())); + if (touched_regions->size() <= 2) { + xfade = boost::shared_ptr (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active())); + add_crossfade (xfade); + } + } + break; default: - xfade = boost::shared_ptr (new Crossfade (region, other, Config->get_xfade_model(), Config->get_xfades_active())); + xfade = boost::shared_ptr (new Crossfade (region, other, + Config->get_xfade_model(), Config->get_xfades_active())); add_crossfade (xfade); } } @@ -471,6 +525,7 @@ void AudioPlaylist::notify_crossfade_added (boost::shared_ptr x) if (g_atomic_int_get(&block_notifications)) { _pending_xfade_adds.insert (_pending_xfade_adds.end(), x); } else { + NewCrossfade (x); /* EMIT SIGNAL */ } } diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index badd13412e..7405077cf3 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -486,7 +486,7 @@ ARDOUR::coverage (nframes_t sa, nframes_t ea, "B overlaps the end of A" */ - if ((sb >= sa) && (sb <= ea)) { + if ((sb > sa) && (sb <= ea)) { return OverlapEnd; } /* diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc index 09b54000d8..8d20d8539d 100644 --- a/libs/ardour/playlist.cc +++ b/libs/ardour/playlist.cc @@ -70,6 +70,7 @@ struct RegionSortByLastLayerOp { } }; + Playlist::Playlist (Session& sess, string nom, DataType type, bool hide) : SessionObject(sess, nom) , _type(type) @@ -350,7 +351,9 @@ Playlist::notify_region_removed (boost::shared_ptr r) /* this might not be true, but we have to act as though it could be. */ + pending_length = false; LengthChanged (); /* EMIT SIGNAL */ + pending_modified = false; Modified (); /* EMIT SIGNAL */ } } @@ -367,7 +370,9 @@ Playlist::notify_region_added (boost::shared_ptr r) pending_modified = true; pending_length = true; } else { + pending_length = false; LengthChanged (); /* EMIT SIGNAL */ + pending_modified = false; Modified (); /* EMIT SIGNAL */ } } @@ -378,7 +383,9 @@ Playlist::notify_length_changed () if (holding_state ()) { pending_length = true; } else { + pending_length = false; LengthChanged(); /* EMIT SIGNAL */ + pending_modified = false; Modified (); /* EMIT SIGNAL */ } } @@ -437,6 +444,7 @@ Playlist::flush_notifications () } pending_modified = false; Modified (); /* EMIT SIGNAL */ + } for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) { @@ -458,7 +466,7 @@ void Playlist::add_region (boost::shared_ptr region, nframes_t position, float times) { RegionLock rlock (this); - + delay_notifications(); times = fabs (times); int itimes = (int) floor (times); @@ -494,6 +502,8 @@ Playlist::add_region (boost::shared_ptr region, nframes_t position, floa boost::shared_ptr sub = RegionFactory::create (region, 0, length, name, region->layer(), region->flags()); add_region_internal (sub, pos); } + + release_notifications (); } void @@ -654,7 +664,6 @@ Playlist::partition (nframes_t start, nframes_t end, bool just_top_level) void Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, RegionList& thawlist) { - RegionLock rlock (this); boost::shared_ptr region; boost::shared_ptr current; string new_name; @@ -662,14 +671,19 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi OverlapType overlap; nframes_t pos1, pos2, pos3, pos4; RegionList new_regions; + RegionList copy; in_partition = true; + delay_notifications(); + /* need to work from a copy, because otherwise the regions we add during the process get operated on as well. */ - - RegionList copy = regions; + { + RegionLock rlock (this); + copy = regions; + } for (RegionList::iterator i = copy.begin(); i != copy.end(); i = tmp) { @@ -677,9 +691,10 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi ++tmp; current = *i; - + if (current->first_frame() == start && current->last_frame() == end) { if (cutting) { + RegionLock rlock (this); remove_region_internal (current); } continue; @@ -688,14 +703,14 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi if ((overlap = current->coverage (start, end)) == OverlapNone) { continue; } - + pos1 = current->position(); pos2 = start; pos3 = end; pos4 = current->last_frame(); if (overlap == OverlapInternal) { - + /* split: we need 3 new regions, the front, middle and end. cut: we need 2 regions, the front and end. */ @@ -715,9 +730,10 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi /* "middle" ++++++ */ - _session.region_name (new_name, current->name(), false); + _session.region_name (new_name, current->name(), false); //takes the session-wide region lock region = RegionFactory::create (current, pos2 - pos1, pos3 - pos2, new_name, regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit|Region::RightOfSplit)); + RegionLock rlock (this); add_region_internal (region, start); new_regions.push_back (region); } @@ -727,10 +743,11 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi _session.region_name (new_name, current->name(), false); region = RegionFactory::create (current, pos3 - pos1, pos4 - pos3, new_name, regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit)); - - add_region_internal (region, end); - new_regions.push_back (region); - + { + RegionLock rlock (this); + add_region_internal (region, end); + new_regions.push_back (region); + } /* "front" ***** */ current->freeze (); @@ -755,8 +772,9 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi /* end +++++ */ _session.region_name (new_name, current->name(), false); - region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, (layer_t) regions.size(), + region = RegionFactory::create (current, pos2 - pos1, pos4 - pos2, new_name, regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::LeftOfSplit)); + RegionLock rlock (this); add_region_internal (region, start); new_regions.push_back (region); } @@ -791,6 +809,7 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi _session.region_name (new_name, current->name(), false); region = RegionFactory::create (current, 0, pos3 - pos1, new_name, regions.size(), Region::Flag(current->flags()|Region::Automatic|Region::RightOfSplit)); + RegionLock rlock (this); add_region_internal (region, pos1); new_regions.push_back (region); } @@ -820,6 +839,7 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi */ if (cutting) { + RegionLock rlock (this); remove_region_internal (current); } new_regions.push_back (current); @@ -831,6 +851,8 @@ Playlist::partition_internal (nframes_t start, nframes_t end, bool cutting, Regi for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) { check_dependents (*i, false); } + + release_notifications (); } boost::shared_ptr @@ -1209,7 +1231,9 @@ Playlist::clear (bool with_signals) } if (with_signals) { + pending_length = false; LengthChanged (); + pending_modified = false; Modified (); } @@ -1587,7 +1611,7 @@ Playlist::relayer () /* don't send multiple Modified notifications when multiple regions are relayered. */ - + freeze (); /* build up a new list of regions on each layer */ @@ -1607,7 +1631,6 @@ Playlist::relayer () copy.sort (cmp); } - for (RegionList::iterator i = copy.begin(); i != copy.end(); ++i) { /* find the lowest layer that this region can go on */ diff --git a/libs/ardour/sndfile_helpers.cc b/libs/ardour/sndfile_helpers.cc index d47a9b9423..96dc2c7779 100644 --- a/libs/ardour/sndfile_helpers.cc +++ b/libs/ardour/sndfile_helpers.cc @@ -63,11 +63,11 @@ int sndfile_header_formats[SNDFILE_HEADER_FORMATS] = { }; const char * const sndfile_bitdepth_formats_strings[SNDFILE_BITDEPTH_FORMATS+1] = { - N_("16 bit"), - N_("24 bit"), - N_("32 bit"), - N_("8 bit"), - N_("float"), + N_("Signed 16 bit PCM"), + N_("Signed 24 bit PCM"), + N_("Signed 32 bit PCM"), + N_("Signed 8 bit PCM"), + N_("32 bit float"), 0 };