From 2dd0b9321c87838e9f2276c02f5942daac2b836e Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Fri, 6 Apr 2007 23:42:07 +0000 Subject: [PATCH 1/1] modified fix from carl for region copy-moves-original-to-start bug; change verbose canvas cursor color to be more distinct and readable; fix naming issues with imported files containing ':'; make sure [N] channels count shows up for whole files in region list; fix #1575, a subtle and nasty bug; improve positioning of verbose canvas cursor for ruler drags (but has a wierd side effect git-svn-id: svn://localhost/ardour2/trunk@1675 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/ardour.colors | 2 +- gtk2_ardour/editor_mouse.cc | 42 +++++++--- gtk2_ardour/editor_ops.cc | 5 +- gtk2_ardour/editor_region_list.cc | 14 +++- gtk2_ardour/editor_rulers.cc | 13 ++- gtk2_ardour/region_selection.cc | 8 +- gtk2_ardour/region_view.cc | 1 + libs/ardour/ardour/audiofilesource.h | 3 +- libs/ardour/ardour/sndfilesource.h | 2 + libs/ardour/audiofilesource.cc | 117 +++++++++++++++++---------- libs/ardour/panner.cc | 19 +---- libs/ardour/sndfilesource.cc | 6 ++ 12 files changed, 147 insertions(+), 85 deletions(-) diff --git a/gtk2_ardour/ardour.colors b/gtk2_ardour/ardour.colors index b68d270e6e..fa89646e09 100644 --- a/gtk2_ardour/ardour.colors +++ b/gtk2_ardour/ardour.colors @@ -42,7 +42,7 @@ cLocationRange 0.29 0.48 0.35 1.0 cLocationCDMarker 0.12 0.91 0.77 1.0 cLocationLoop 0.21 0.59 0.31 1.0 cLocationPunch 0.49 0.23 0.23 1.0 -cVerboseCanvasCursor 0 0 0 0.74 +cVerboseCanvasCursor 0.96 0.95 0.08 0.74 cRangeDragBarRect 0.59 0.59 0.59 0.78 cRangeDragBarRectFill 0.78 0.82 0.70 0.43 cRangeDragRect 0.59 0.59 0.59 0.78 diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index b5c8042672..39680980d6 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -323,8 +323,8 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it Selection::Operation op = Keyboard::selection_type (event->button.state); bool press = (event->type == GDK_BUTTON_PRESS); - begin_reversible_command (_("select on click")); - + // begin_reversible_command (_("select on click")); + switch (item_type) { case RegionItem: if (mouse_mode != MouseRange) { @@ -379,9 +379,9 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it break; } - if (commit) { - commit_reversible_command (); - } +// if (commit) { +// commit_reversible_command (); +// } } bool @@ -3287,12 +3287,10 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event if (regionview_y_movement) { /* moved to a different audio track. */ + + vector new_selection; - list new_selection; - new_selection = selection->regions.by_layer(); - selection->clear_regions (); - - for (list::const_iterator i = new_selection.begin(); i != new_selection.end(); ++i) { + for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ) { RegionView* rv = (*i); @@ -3334,15 +3332,37 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event c.disconnect (); if (latest_regionview) { - selection->add (latest_regionview); + new_selection.push_back (latest_regionview); } if (drag_info.copy) { // get rid of the copy delete rv; } + + /* 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 + trace of it from the selection (i.e. there were N regions selected, we removed 1, + but since its the same playlist for N tracks, all N tracks updated themselves, removed the + corresponding regionview, and the selection is now empty). + + this could have invalidated any and all iterators into the region selection. + + the heuristic we use here is: if the region selection is empty, break out of the loop + here. if the region selection is not empty, then restart the loop because we know that + we must have removed at least the region(view) we've just been working on as well as any + that we processed on previous iterations. + */ + + if (selection->regions.empty()) { + break; + } else { + i = selection->regions.by_layer().begin(); + } } + selection->set (new_selection); + } else { /* motion within a single track */ diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index f8e6f41a9e..f80ec708eb 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -2831,8 +2831,9 @@ Editor::cut_copy_regions (CutCopyOp op) case Copy: if (!ar) break; - - npl->add_region ((*x)->region(), (*x)->region()->position() - first_position); + + /* copy region before adding, so we're not putting same object into two different playlists */ + npl->add_region (RegionFactory::create ((*x)->region()), (*x)->region()->position() - first_position); break; case Clear: diff --git a/gtk2_ardour/editor_region_list.cc b/gtk2_ardour/editor_region_list.cc index 56196623ed..df23ac503c 100644 --- a/gtk2_ardour/editor_region_list.cc +++ b/gtk2_ardour/editor_region_list.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -138,12 +139,13 @@ Editor::add_audio_region_to_region_display (boost::shared_ptr regio if (region->source()->name()[0] == '/') { // external file if (region->whole_file()) { - str = ".../"; boost::shared_ptr afs = boost::dynamic_pointer_cast(region->source()); + str = ".../"; + if (afs) { - str += region_name_from_path (afs->path(), region->n_channels() > 1); + str = region_name_from_path (afs->path(), region->n_channels() > 1); } else { str += region->source()->name(); } @@ -158,6 +160,14 @@ Editor::add_audio_region_to_region_display (boost::shared_ptr regio } + if (region->n_channels() > 1) { + std::stringstream foo; + foo << region->n_channels (); + str += " ["; + str += foo.str(); + str += ']'; + } + if (missing_source) { str += _(" (MISSING)"); } diff --git a/gtk2_ardour/editor_rulers.cc b/gtk2_ardour/editor_rulers.cc index 6338993ae2..992d67b9be 100644 --- a/gtk2_ardour/editor_rulers.cc +++ b/gtk2_ardour/editor_rulers.cc @@ -260,12 +260,12 @@ Editor::ruler_mouse_motion (GdkEventMotion* ev) /* need to use the correct x,y, the event lies */ time_canvas_event_box.get_window()->get_pointer (x, y, state); - - track_canvas.c2w (x, y, wcx, wcy); - track_canvas.w2c (wcx, wcy, cx, cy); - - nframes_t where = leftmost_frame + pixel_to_frame (x); + time_canvas.c2w (x, y, wcx, wcy); + time_canvas.w2c (wcx, wcy, cx, cy); + wcx = x; + nframes_t where = event_frame ((GdkEvent*) ev, &wcx, (double *) 0); + cx = wcx; /// ripped from maybe_autoscroll, and adapted to work here nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit); @@ -307,8 +307,7 @@ Editor::ruler_mouse_motion (GdkEventMotion* ev) break; } - if (cursor) - { + if (cursor) { cursor->set_position (where); if (cursor == edit_cursor) { diff --git a/gtk2_ardour/region_selection.cc b/gtk2_ardour/region_selection.cc index 34810691f5..7ac7763773 100644 --- a/gtk2_ardour/region_selection.cc +++ b/gtk2_ardour/region_selection.cc @@ -31,12 +31,16 @@ using namespace sigc; RegionSelection::RegionSelection () { + RegionView::RegionViewGoingAway.connect (mem_fun(*this, &RegionSelection::remove_it)); + _current_start = 0; _current_end = 0; } RegionSelection::RegionSelection (const RegionSelection& other) { + RegionView::RegionViewGoingAway.connect (mem_fun(*this, &RegionSelection::remove_it)); + for (RegionSelection::const_iterator i = other.begin(); i != other.end(); ++i) { add (*i); } @@ -44,8 +48,6 @@ RegionSelection::RegionSelection (const RegionSelection& other) _current_end = other._current_end; } - - RegionSelection& RegionSelection::operator= (const RegionSelection& other) { @@ -86,8 +88,6 @@ RegionSelection::add (RegionView* rv) return false; } - rv->RegionViewGoingAway.connect (mem_fun(*this, &RegionSelection::remove_it)); - if (rv->region()->first_frame() < _current_start || empty()) { _current_start = rv->region()->first_frame(); } diff --git a/gtk2_ardour/region_view.cc b/gtk2_ardour/region_view.cc index 3e6921aab9..7a8f9b5d6a 100644 --- a/gtk2_ardour/region_view.cc +++ b/gtk2_ardour/region_view.cc @@ -24,6 +24,7 @@ #include #include +#include #include #include diff --git a/libs/ardour/ardour/audiofilesource.h b/libs/ardour/ardour/audiofilesource.h index 6bc9ec4207..dce06c1ca0 100644 --- a/libs/ardour/ardour/audiofilesource.h +++ b/libs/ardour/ardour/audiofilesource.h @@ -81,6 +81,7 @@ class AudioFileSource : public AudioSource { virtual void mark_capture_start (nframes_t) {} virtual void mark_capture_end () {} virtual void clear_capture_marks() {} + virtual bool one_of_several_channels () const { return false; } virtual int update_header (nframes_t when, struct tm&, time_t) = 0; virtual int flush_header () = 0; @@ -161,7 +162,7 @@ class AudioFileSource : public AudioSource { virtual void set_timeline_position (int64_t pos); virtual void set_header_timeline_position () = 0; - bool find (Glib::ustring& path, bool must_exist, bool& is_new); + bool find (Glib::ustring& path, bool must_exist, bool& is_new, uint16_t& chan); bool removable() const; bool writable() const { return _flags & Writable; } }; diff --git a/libs/ardour/ardour/sndfilesource.h b/libs/ardour/ardour/sndfilesource.h index 2fc3872887..916e9da49e 100644 --- a/libs/ardour/ardour/sndfilesource.h +++ b/libs/ardour/ardour/sndfilesource.h @@ -56,6 +56,8 @@ class SndFileSource : public AudioFileSource { bool set_destructive (bool yn); + bool one_of_several_channels () const; + static void setup_standard_crossfades (nframes_t sample_rate); static const AudioFileSource::Flag default_writable_flags; diff --git a/libs/ardour/audiofilesource.cc b/libs/ardour/audiofilesource.cc index 929cfc8083..3a02c4c4b0 100644 --- a/libs/ardour/audiofilesource.cc +++ b/libs/ardour/audiofilesource.cc @@ -93,15 +93,17 @@ AudioFileSource::AudioFileSource (Session& s, ustring path, Flag flags, SampleFo AudioFileSource::AudioFileSource (Session& s, const XMLNode& node, bool must_exist) : AudioSource (s, node), _flags (Flag (Writable|CanRename)) - /* _channel is set in set_state() */ + /* _channel is set in set_state() or init() */ { /* constructor used for existing internal-to-session files. file must exist */ if (set_state (node)) { throw failed_constructor (); } + + string foo = _name; - if (init (_name, must_exist)) { + if (init (foo, must_exist)) { throw failed_constructor (); } } @@ -136,7 +138,7 @@ AudioFileSource::init (ustring pathstr, bool must_exist) _peaks_built = false; file_is_new = false; - if (!find (pathstr, must_exist, is_new)) { + if (!find (pathstr, must_exist, is_new, _channel)) { throw non_existent_source (); } @@ -361,42 +363,13 @@ AudioFileSource::move_to_trash (const ustring& trash_dir_name) } bool -AudioFileSource::find (ustring& pathstr, bool must_exist, bool& isnew) +AudioFileSource::find (ustring& pathstr, bool must_exist, bool& isnew, uint16_t& chan) { ustring::size_type pos; bool ret = false; isnew = false; - /* i (paul) made a nasty design error by using ':' as a special character in - Ardour 0.99 .. this hack tries to make things sort of work. - */ - - if ((pos = pathstr.find_last_of (':')) != ustring::npos) { - if (Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS)) { - /* its a real file, no problem */ - - } else { - - if (must_exist) { - - /* older session using file:channel syntax */ - - warning << string_compose (_("This older session references an embedded\n\ -non-mono audio file:\n\n%1\n\n \ -The session file may be edited or the file must be removed before it can be used."), - short_path (pathstr, 48)) - << endmsg; - return false; - - } else { - - /* new derived file (e.g. for timefx) being created in a newer session */ - - } - } - } - if (pathstr[0] != '/') { /* non-absolute pathname: find pathstr in search path */ @@ -421,12 +394,60 @@ The session file may be edited or the file must be removed before it can be used if (fullpath[fullpath.length()-1] != '/') { fullpath += '/'; } + fullpath += pathstr; + + /* i (paul) made a nasty design error by using ':' as a special character in + Ardour 0.99 .. this hack tries to make things sort of work. + */ - if (access (fullpath.c_str(), R_OK) == 0) { - keeppath = fullpath; - ++cnt; - } + if ((pos = pathstr.find_last_of (':')) != ustring::npos) { + + if (Glib::file_test (fullpath, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { + + /* its a real file, no problem */ + + keeppath = fullpath; + ++cnt; + + } else { + + if (must_exist) { + + /* might be an older session using file:channel syntax. see if the version + without the :suffix exists + */ + + ustring shorter = pathstr.substr (0, pos); + fullpath = *i; + + if (fullpath[fullpath.length()-1] != '/') { + fullpath += '/'; + } + + fullpath += shorter; + + if (Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { + chan = atoi (pathstr.substr (pos+1)); + pathstr = shorter; + keeppath = fullpath; + ++cnt; + } + + } else { + + /* new derived file (e.g. for timefx) being created in a newer session */ + + } + } + + } else { + + if (Glib::file_test (fullpath, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { + keeppath = fullpath; + ++cnt; + } + } } if (cnt > 1) { @@ -443,7 +464,7 @@ The session file may be edited or the file must be removed before it can be used isnew = true; } } - + _name = pathstr; _path = keeppath; ret = true; @@ -451,18 +472,31 @@ The session file may be edited or the file must be removed before it can be used } else { /* external files and/or very very old style sessions include full paths */ + + /* ugh, handle ':' situation */ + + if ((pos = pathstr.find_last_of (':')) != ustring::npos) { + + ustring shorter = pathstr.substr (0, pos); + + if (Glib::file_test (shorter, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { + chan = atoi (pathstr.substr (pos+1)); + pathstr = shorter; + } + } _path = pathstr; + if (is_embedded()) { _name = pathstr; } else { _name = pathstr.substr (pathstr.find_last_of ('/') + 1); } - - if (access (_path.c_str(), R_OK) != 0) { - /* file does not exist or we cannot read it */ + if (!Glib::file_test (pathstr, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) { + /* file does not exist or we cannot read it */ + if (must_exist) { error << string_compose(_("Filesource: cannot find required file (%1): %2"), _path, strerror (errno)) << endmsg; goto out; @@ -483,6 +517,7 @@ The session file may be edited or the file must be removed before it can be used /* already exists */ ret = true; + } } diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc index deb131e6fc..563d4e90d4 100644 --- a/libs/ardour/panner.cc +++ b/libs/ardour/panner.cc @@ -653,10 +653,7 @@ Multi2dPanner::distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nfram } pan = left * gain_coeff; - - for (; n < nframes; ++n) { - dst[n] += src[n] * pan; - } + Session::mix_buffers_with_gain(dst+n,src+n,nframes-n,pan); } else { @@ -666,20 +663,10 @@ Multi2dPanner::distribute (Sample* src, Sample** obufs, gain_t gain_coeff, nfram if ((pan *= gain_coeff) != 1.0f) { if (pan != 0.0f) { - - for (nframes_t n = 0; n < nframes; ++n) { - dst[n] += src[n] * pan; - } - + Session::mix_buffers_with_gain(dst,src,nframes,pan); } - - } else { - - for (nframes_t n = 0; n < nframes; ++n) { - dst[n] += src[n]; - } - + Session::mix_buffers_no_gain(dst,src,nframes); } #endif #ifdef CAN_INTERP diff --git a/libs/ardour/sndfilesource.cc b/libs/ardour/sndfilesource.cc index 8aecbc3cdc..24647030ab 100644 --- a/libs/ardour/sndfilesource.cc +++ b/libs/ardour/sndfilesource.cc @@ -894,3 +894,9 @@ SndFileSource::get_timecode_info (SNDFILE* sf, SF_BROADCAST_INFO* binfo, bool& e ret |= (uint32_t) binfo->time_reference_low; return ret; } + +bool +SndFileSource::one_of_several_channels () const +{ + return _info.channels > 1; +} -- 2.30.2