summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2011-05-16 02:17:58 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2011-05-16 02:17:58 +0000
commit0a9cef7720ed9bd83442d284d18831437b80a482 (patch)
tree73f8b7e6780bbaf57bcf14dccb6d759556220cef
parent88a6513e76e397bdd19d4e76eaf44da8170cf73a (diff)
very basic Join (regions) editing operation. not finished yet, no undoable, no sensible name for new region, etc. etc
git-svn-id: svn://localhost/ardour2/branches/3.0@9518 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/editor.h1
-rw-r--r--gtk2_ardour/editor_actions.cc1
-rw-r--r--gtk2_ardour/editor_ops.cc24
-rw-r--r--gtk2_ardour/route_time_axis.cc21
-rw-r--r--gtk2_ardour/route_time_axis.h2
-rw-r--r--libs/ardour/ardour/audio_playlist_source.h1
-rw-r--r--libs/ardour/ardour/audiosource.h18
-rw-r--r--libs/ardour/ardour/playlist.h4
-rw-r--r--libs/ardour/ardour/region.h1
-rw-r--r--libs/ardour/ardour/source.h4
-rw-r--r--libs/ardour/ardour/source_factory.h3
-rw-r--r--libs/ardour/audio_playlist_source.cc36
-rw-r--r--libs/ardour/audiosource.cc28
-rw-r--r--libs/ardour/playlist.cc82
-rw-r--r--libs/ardour/region.cc11
-rw-r--r--libs/ardour/session_state.cc2
-rw-r--r--libs/ardour/source.cc3
-rw-r--r--libs/ardour/source_factory.cc9
18 files changed, 233 insertions, 18 deletions
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index 8150f44ae3..83d8b394c3 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -1099,6 +1099,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void duplicate_some_regions (RegionSelection&, float times);
void duplicate_selection (float times);
void region_fill_selection ();
+ void join_regions ();
void region_fill_track ();
void audition_playlist_region_standalone (boost::shared_ptr<ARDOUR::Region>);
diff --git a/gtk2_ardour/editor_actions.cc b/gtk2_ardour/editor_actions.cc
index bf2af13f52..0081a806aa 100644
--- a/gtk2_ardour/editor_actions.cc
+++ b/gtk2_ardour/editor_actions.cc
@@ -1372,6 +1372,7 @@ Editor::register_region_actions ()
reg_sens (_region_actions, "play-selected-regions", _("Play"), sigc::mem_fun(*this, &Editor::play_selected_region));
reg_sens (_region_actions, "bounce-region", _("Bounce"), sigc::mem_fun (*this, &Editor::bounce_region_selection));
+ reg_sens (_region_actions, "join-regions", _("Join"), sigc::mem_fun (*this, &Editor::join_regions));
reg_sens (_region_actions, "analyze-region", _("Spectral Analysis..."), sigc::mem_fun (*this, &Editor::analyze_region_selection));
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc
index 935694a640..5f361ae153 100644
--- a/gtk2_ardour/editor_ops.cc
+++ b/gtk2_ardour/editor_ops.cc
@@ -6401,3 +6401,27 @@ Editor::toggle_region_mute ()
commit_reversible_command ();
}
+void
+Editor::join_regions ()
+{
+ /* foreach track with selected regions, take all selected regions
+ and join them into a new region containing the subregions (as a
+ playlist)
+ */
+
+ typedef set<RouteTimeAxisView*> RTVS;
+ RTVS tracks;
+
+ for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
+
+ if (rtv) {
+ tracks.insert (rtv);
+ }
+ }
+
+ for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
+ (*i)->join_regions ();
+ }
+}
+
diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc
index 8871b7bbe1..449718d15a 100644
--- a/gtk2_ardour/route_time_axis.cc
+++ b/gtk2_ardour/route_time_axis.cc
@@ -2477,3 +2477,24 @@ RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param,
add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
}
+
+static
+void add_region_to_list (RegionView* rv, Playlist::RegionList* l)
+{
+ l->push_back (rv->region());
+}
+
+void
+RouteTimeAxisView::join_regions ()
+{
+ assert (is_track());
+
+ if (!_view) {
+ return;
+ }
+
+ Playlist::RegionList selected_regions;
+
+ _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
+ track()->playlist()->join (selected_regions, "foshizzle");
+}
diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h
index c68dc573ea..d596de3df7 100644
--- a/gtk2_ardour/route_time_axis.h
+++ b/gtk2_ardour/route_time_axis.h
@@ -94,7 +94,7 @@ public:
/* Editing operations */
void cut_copy_clear (Selection&, Editing::CutCopyOp);
bool paste (ARDOUR::framepos_t, float times, Selection&, size_t nth);
-
+ void join_regions ();
void toggle_automation_track (const Evoral::Parameter& param);
/* The editor calls these when mapping an operation across multiple tracks */
diff --git a/libs/ardour/ardour/audio_playlist_source.h b/libs/ardour/ardour/audio_playlist_source.h
index d6047de1fc..868e8c743e 100644
--- a/libs/ardour/ardour/audio_playlist_source.h
+++ b/libs/ardour/ardour/audio_playlist_source.h
@@ -65,6 +65,7 @@ class AudioPlaylistSource : public AudioSource {
framecnt_t _playlist_length;
uint32_t _playlist_channel;
std::string _peak_path;
+ uint32_t _level; /* how recursive is this? */
};
} /* namespace */
diff --git a/libs/ardour/ardour/audiosource.h b/libs/ardour/ardour/audiosource.h
index 5f06d3ee09..d0d34a55c4 100644
--- a/libs/ardour/ardour/audiosource.h
+++ b/libs/ardour/ardour/audiosource.h
@@ -106,10 +106,26 @@ class AudioSource : virtual public Source,
/** @return true if the each source sample s must be clamped to -1 < s < 1 */
virtual bool clamped_at_unity () const = 0;
+ static void allocate_working_buffers ();
+
protected:
static bool _build_missing_peakfiles;
static bool _build_peakfiles;
+ static size_t _working_buffers_size;
+
+ /* these collections of working buffers for supporting
+ playlist's reading from potentially nested/recursive
+ sources assume SINGLE THREADED reads by the butler
+ thread, or a lock around calls that use them.
+ */
+
+ static std::vector<Sample*> _mixdown_buffers;
+ static std::vector<gain_t*> _gain_buffers;
+ static Glib::StaticMutex _level_buffer_lock;
+
+ static void ensure_buffers_for_level (uint32_t);
+
framecnt_t _length;
std::string peakpath;
std::string _captured_for;
@@ -129,7 +145,7 @@ class AudioSource : virtual public Source,
virtual framecnt_t write_unlocked (Sample *dst, framecnt_t cnt) = 0;
virtual std::string peak_path(std::string audio_path) = 0;
virtual std::string find_broken_peakfile (std::string missing_peak_path,
- std::string audio_path) { return std::string(); }
+ std::string audio_path) { return peak_path (audio_path); }
virtual int read_peaks_with_fpp (PeakData *peaks,
framecnt_t npeaks, framepos_t start, framecnt_t cnt,
diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h
index e21199e642..e23ba264fc 100644
--- a/libs/ardour/ardour/playlist.h
+++ b/libs/ardour/ardour/playlist.h
@@ -97,6 +97,8 @@ public:
boost::shared_ptr<Region> region_by_id (const PBD::ID&) const;
+ uint32_t max_source_level () const;
+
void set_region_ownership ();
virtual void clear (bool with_signals=true);
@@ -137,6 +139,8 @@ public:
void partition (framepos_t start, framepos_t end, bool cut = false);
void duplicate (boost::shared_ptr<Region>, framepos_t position, float times);
void nudge_after (framepos_t start, framecnt_t distance, bool forwards);
+ void join (const RegionList&, const std::string&);
+
void shuffle (boost::shared_ptr<Region>, int dir);
void update_after_tempo_map_change ();
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index 17ea1362d8..719c00acf8 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -114,6 +114,7 @@ class Region
layer_t layer () const { return _layer; }
framecnt_t source_length(uint32_t n) const;
+ uint32_t max_source_level () const;
/* these two are valid ONLY during a StateChanged signal handler */
diff --git a/libs/ardour/ardour/source.h b/libs/ardour/ardour/source.h
index aadb7a51b3..4af94d44b8 100644
--- a/libs/ardour/ardour/source.h
+++ b/libs/ardour/ardour/source.h
@@ -106,17 +106,19 @@ class Source : public SessionObject
virtual void dec_use_count ();
int use_count() const { return g_atomic_int_get (&_use_count); }
bool used() const { return use_count() > 0; }
+ uint32_t level() const { return _level; }
protected:
DataType _type;
Flag _flags;
time_t _timestamp;
- framepos_t _timeline_position;
+ framepos_t _timeline_position;
bool _analysed;
mutable Glib::Mutex _lock;
mutable Glib::Mutex _analysis_lock;
Glib::Mutex _playlist_lock;
gint _use_count; /* atomic */
+ uint32_t _level; /* how deeply nested is this source w.r.t a disk file */
private:
void fix_writable_flags ();
diff --git a/libs/ardour/ardour/source_factory.h b/libs/ardour/ardour/source_factory.h
index b8bc5e72b5..427bf10a56 100644
--- a/libs/ardour/ardour/source_factory.h
+++ b/libs/ardour/ardour/source_factory.h
@@ -57,8 +57,7 @@ class SourceFactory {
static boost::shared_ptr<Source> createFromPlaylist
(DataType type, Session& s, boost::shared_ptr<Playlist> p, const std::string& name,
- uint32_t chn, frameoffset_t start, framecnt_t len, bool copy, Source::Flag flags,
- bool announce, bool defer_peaks);
+ uint32_t chn, frameoffset_t start, framecnt_t len, bool copy, bool defer_peaks);
static Glib::Cond* PeaksToBuild;
static Glib::StaticMutex peak_building_lock;
diff --git a/libs/ardour/audio_playlist_source.cc b/libs/ardour/audio_playlist_source.cc
index 568b72129d..7d1e528ee6 100644
--- a/libs/ardour/audio_playlist_source.cc
+++ b/libs/ardour/audio_playlist_source.cc
@@ -24,6 +24,7 @@
#include <cstdio>
#include <glibmm/fileutils.h>
+#include <glibmm/miscutils.h>
#include "pbd/error.h"
#include "pbd/convert.h"
@@ -48,6 +49,7 @@ AudioPlaylistSource::AudioPlaylistSource (Session& s, const std::string& name, b
uint32_t chn, frameoffset_t begin, framecnt_t len, bool copy, Source::Flag flags)
: Source (s, DataType::AUDIO, name)
, AudioSource (s, name)
+ , _playlist (p)
, _playlist_channel (chn)
{
/* PlaylistSources are never writable, renameable, removable or destructive */
@@ -63,7 +65,10 @@ AudioPlaylistSource::AudioPlaylistSource (Session& s, const std::string& name, b
_playlist_length = len;
}
- _peak_path = tempnam (_session.session_directory().peak_path().to_string().c_str(), "apspk");
+ _length = len;
+ _peak_path = Glib::build_filename (_session.session_directory().peak_path().to_string(), name);
+ _level = _playlist->max_source_level () + 1;
+ ensure_buffers_for_level (_level);
}
AudioPlaylistSource::AudioPlaylistSource (Session& s, const XMLNode& node)
@@ -113,11 +118,15 @@ AudioPlaylistSource::set_state (const XMLNode& node, int /* version */)
/* get playlist */
boost::shared_ptr<Playlist> p = _session.playlists->by_id (id);
+ _playlist = boost::dynamic_pointer_cast<AudioPlaylist>(p);
- if (!p) {
+ if (!_playlist) {
throw failed_constructor ();
}
+ pair<framepos_t,framepos_t> extent = _playlist->get_extent();
+ _length = extent.second - extent.first;
+
/* other properties */
if ((prop = node.property (X_("name"))) == 0) {
@@ -149,6 +158,9 @@ AudioPlaylistSource::set_state (const XMLNode& node, int /* version */)
_peak_path = prop->value ();
+ _level = _playlist->max_source_level ();
+ ensure_buffers_for_level (_level);
+
return 0;
}
@@ -172,8 +184,11 @@ AudioPlaylistSource::read_unlocked (Sample* dst, framepos_t start, framecnt_t cn
to_zero = 0;
}
- _playlist->read (dst, 0, 0, start+_playlist_offset, to_read, _playlist_channel);
-
+ {
+ Glib::Mutex::Lock lm (_level_buffer_lock);
+ _playlist->read (dst, _mixdown_buffers[_level-1], _gain_buffers[_level-1], start+_playlist_offset, to_read, _playlist_channel);
+ }
+
if (to_zero) {
memset (dst+to_read, 0, sizeof (Sample) * to_zero);
}
@@ -230,6 +245,9 @@ AudioPlaylistSource::setup_peakfile ()
{
/* the peak data is setup once and once only
*/
+
+ cerr << "looking for peakfile " << _peak_path << endl;
+
if (!Glib::file_test (_peak_path, Glib::FILE_TEST_EXISTS)) {
/* the 2nd argument here will be passed
@@ -237,9 +255,12 @@ AudioPlaylistSource::setup_peakfile ()
since our peak file path is fixed and
not dependent on anything.
*/
-
- return initialize_peakfile (true, string());
- }
+ cerr << "build it!\n";
+ return initialize_peakfile (false, string());
+ } else {
+ cerr << "exists!\n";
+ }
+
return 0;
}
@@ -248,3 +269,4 @@ AudioPlaylistSource::peak_path (string /*audio_path*/)
{
return _peak_path;
}
+
diff --git a/libs/ardour/audiosource.cc b/libs/ardour/audiosource.cc
index ac98837183..ffb8068ea5 100644
--- a/libs/ardour/audiosource.cc
+++ b/libs/ardour/audiosource.cc
@@ -38,6 +38,7 @@
#include "pbd/pthread_utils.h"
#include "ardour/audiosource.h"
+#include "ardour/audio_diskstream.h"
#include "ardour/cycle_timer.h"
#include "ardour/session.h"
#include "ardour/transient_detector.h"
@@ -49,6 +50,10 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
+Glib::StaticMutex AudioSource::_level_buffer_lock = GLIBMM_STATIC_MUTEX_INIT;
+vector<Sample*> AudioSource::_mixdown_buffers;
+vector<gain_t*> AudioSource::_gain_buffers;
+size_t AudioSource::_working_buffers_size = 0;
bool AudioSource::_build_missing_peakfiles = false;
/** true if we want peakfiles (e.g. if we are displaying a GUI) */
@@ -958,3 +963,26 @@ AudioSource::mark_streaming_write_completed ()
PeaksReady (); /* EMIT SIGNAL */
}
}
+
+void
+AudioSource::allocate_working_buffers()
+{
+ assert(AudioDiskstream::disk_io_frames() > 0);
+ _working_buffers_size = AudioDiskstream::disk_io_frames();
+ /* we don't need any buffers allocated until
+ a level 1 audiosource is created, at which
+ time we'll call ::ensure_buffers_for_level()
+ with the right value and do the right thing.
+ */
+}
+
+void
+AudioSource::ensure_buffers_for_level (uint32_t level)
+{
+ Glib::Mutex::Lock lm (_level_buffer_lock);
+
+ while (_mixdown_buffers.size() < level) {
+ _mixdown_buffers.push_back (new Sample[_working_buffers_size]);
+ _gain_buffers.push_back (new gain_t[_working_buffers_size]);
+ }
+}
diff --git a/libs/ardour/playlist.cc b/libs/ardour/playlist.cc
index ea85d9fcb3..5d77310ccb 100644
--- a/libs/ardour/playlist.cc
+++ b/libs/ardour/playlist.cc
@@ -41,6 +41,7 @@
#include "ardour/playlist_factory.h"
#include "ardour/transient_detector.h"
#include "ardour/session_playlists.h"
+#include "ardour/source_factory.h"
#include "i18n.h"
@@ -3084,3 +3085,84 @@ Playlist::find_next_top_layer_position (framepos_t t) const
return max_framepos;
}
+
+void
+Playlist::join (const RegionList& r, const std::string& name)
+{
+ PropertyList plist;
+ uint32_t channels = 0;
+ uint32_t layer = 0;
+ framepos_t earliest_position = max_framepos;
+
+ boost::shared_ptr<Playlist> pl = PlaylistFactory::create (_type, _session, name, true);
+
+ for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
+ earliest_position = min (earliest_position, (*i)->position());
+ }
+
+ for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
+
+ /* copy the region */
+
+ boost::shared_ptr<Region> original_region = (*i);
+ boost::shared_ptr<Region> copied_region = RegionFactory::create (original_region, false);
+
+ /* make position relative to zero */
+
+ pl->add_region (copied_region, original_region->position() - earliest_position);
+
+ /* use the maximum number of channels for any region */
+
+ channels = max (channels, original_region->n_channels());
+
+ /* it will go above the layer of the highest existing region */
+
+ layer = max (layer, original_region->layer());
+ }
+
+ /* now create a new PlaylistSource for each channel in the new playlist */
+
+ SourceList sources;
+ pair<framepos_t,framepos_t> extent = pl->get_extent();
+
+ for (uint32_t chn = 0; chn < channels; ++chn) {
+ sources.push_back (SourceFactory::createFromPlaylist (_type, _session, pl, name, chn, 0, extent.second, false, false));
+ }
+
+ /* now a new region using the list of sources */
+
+ plist.add (Properties::start, 0);
+ plist.add (Properties::length, extent.second);
+ plist.add (Properties::name, name);
+ plist.add (Properties::layer, layer+1);
+
+ boost::shared_ptr<Region> compound_region = RegionFactory::create (sources, plist, true);
+
+ /* remove all the selected regions from the current playlist
+ */
+
+ freeze ();
+
+ for (RegionList::const_iterator i = r.begin(); i != r.end(); ++i) {
+ remove_region (*i);
+ }
+
+ /* add the new region at the right location */
+
+ add_region (compound_region, earliest_position);
+
+ thaw ();
+}
+
+uint32_t
+Playlist::max_source_level () const
+{
+ RegionLock rlock (const_cast<Playlist *> (this));
+ uint32_t lvl = 0;
+
+ for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
+ lvl = max (lvl, (*i)->max_source_level());
+ }
+
+ return lvl;
+}
diff --git a/libs/ardour/region.cc b/libs/ardour/region.cc
index ff9d31fd2d..93223709e7 100644
--- a/libs/ardour/region.cc
+++ b/libs/ardour/region.cc
@@ -1660,3 +1660,14 @@ Region::can_trim () const
return ct;
}
+uint32_t
+Region::max_source_level () const
+{
+ uint32_t lvl = 0;
+
+ for (SourceList::const_iterator i = _sources.begin(); i != _sources.end(); ++i) {
+ lvl = max (lvl, (*i)->level());
+ }
+
+ return lvl;
+}
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index 00523ad933..604fc4bc52 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -69,6 +69,7 @@
#include "ardour/amp.h"
#include "ardour/audio_diskstream.h"
+#include "ardour/audio_playlist_source.h"
#include "ardour/audio_track.h"
#include "ardour/audioengine.h"
#include "ardour/audiofilesource.h"
@@ -220,6 +221,7 @@ Session::first_stage_init (string fullpath, string snapshot_name)
_speakers.reset (new Speakers);
AudioDiskstream::allocate_working_buffers();
+ AudioSource::allocate_working_buffers ();
/* default short fade = 15ms */
diff --git a/libs/ardour/source.cc b/libs/ardour/source.cc
index 409f3e1cdb..00b642b21b 100644
--- a/libs/ardour/source.cc
+++ b/libs/ardour/source.cc
@@ -53,6 +53,7 @@ Source::Source (Session& s, DataType type, const string& name, Flag flags)
, _flags(flags)
, _timeline_position(0)
, _use_count (0)
+ , _level (0)
{
_analysed = false;
_timestamp = 0;
@@ -65,6 +66,7 @@ Source::Source (Session& s, const XMLNode& node)
, _flags (Flag (Writable|CanRename))
, _timeline_position(0)
, _use_count (0)
+ , _level (0)
{
_timestamp = 0;
_analysed = false;
@@ -308,3 +310,4 @@ Source::writable () const
{
return (_flags & Writable) && _session.writable();
}
+
diff --git a/libs/ardour/source_factory.cc b/libs/ardour/source_factory.cc
index 891e431549..1bf3956694 100644
--- a/libs/ardour/source_factory.cc
+++ b/libs/ardour/source_factory.cc
@@ -326,8 +326,7 @@ SourceFactory::createWritable (DataType type, Session& s, const std::string& pat
boost::shared_ptr<Source>
SourceFactory::createFromPlaylist (DataType type, Session& s, boost::shared_ptr<Playlist> p, const std::string& name,
- uint32_t chn, frameoffset_t start, framecnt_t len, bool copy, Source::Flag flags,
- bool announce, bool defer_peaks)
+ uint32_t chn, frameoffset_t start, framecnt_t len, bool copy, bool defer_peaks)
{
if (type == DataType::AUDIO) {
try {
@@ -335,7 +334,7 @@ SourceFactory::createFromPlaylist (DataType type, Session& s, boost::shared_ptr<
boost::shared_ptr<AudioPlaylist> ap = boost::dynamic_pointer_cast<AudioPlaylist>(p);
if (ap) {
- Source* src = new AudioPlaylistSource (s, name, ap, chn, start, len, copy, flags);
+ Source* src = new AudioPlaylistSource (s, name, ap, chn, start, len, copy, Source::Flag (0));
boost::shared_ptr<Source> ret (src);
if (setup_peakfile (ret, defer_peaks)) {
@@ -344,9 +343,7 @@ SourceFactory::createFromPlaylist (DataType type, Session& s, boost::shared_ptr<
ret->check_for_analysis_data_on_disk ();
- if (announce) {
- SourceCreated (ret);
- }
+ /* we never announce these sources */
return ret;
}