mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-08 07:45:00 +01:00
radically rethink export/bounce/freeze code design. probably not 100% done by freeze+unfreeze now work and behave sensibly w.r.t. processors that do routing
git-svn-id: svn://localhost/ardour2/branches/3.0@11701 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
cfaf6ff7e3
commit
f07ca6397f
23 changed files with 202 additions and 118 deletions
|
|
@ -161,7 +161,13 @@ Editor::bounce_region_selection (bool with_processing)
|
||||||
|
|
||||||
InterThreadInfo itt;
|
InterThreadInfo itt;
|
||||||
|
|
||||||
boost::shared_ptr<Region> r = track->bounce_range (region->position(), region->position() + region->length(), itt, with_processing);
|
boost::shared_ptr<Region> r;
|
||||||
|
|
||||||
|
if (with_processing) {
|
||||||
|
r = track->bounce_range (region->position(), region->position() + region->length(), itt, track->main_outs(), false);
|
||||||
|
} else {
|
||||||
|
r = track->bounce_range (region->position(), region->position() + region->length(), itt, boost::shared_ptr<Processor>(), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3345,14 +3345,17 @@ Editor::unfreeze_route ()
|
||||||
void*
|
void*
|
||||||
Editor::_freeze_thread (void* arg)
|
Editor::_freeze_thread (void* arg)
|
||||||
{
|
{
|
||||||
SessionEvent::create_per_thread_pool ("freeze events", 64);
|
|
||||||
|
|
||||||
return static_cast<Editor*>(arg)->freeze_thread ();
|
return static_cast<Editor*>(arg)->freeze_thread ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
Editor::freeze_thread ()
|
Editor::freeze_thread ()
|
||||||
{
|
{
|
||||||
|
/* create event pool because we may need to talk to the session */
|
||||||
|
SessionEvent::create_per_thread_pool ("freeze events", 64);
|
||||||
|
/* create per-thread buffers for process() tree to use */
|
||||||
|
current_interthread_info->process_thread.init ();
|
||||||
|
|
||||||
clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
|
clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
|
||||||
current_interthread_info->done = true;
|
current_interthread_info->done = true;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -3368,22 +3371,23 @@ Editor::freeze_route ()
|
||||||
/* stop transport before we start. this is important */
|
/* stop transport before we start. this is important */
|
||||||
|
|
||||||
_session->request_transport_speed (0.0);
|
_session->request_transport_speed (0.0);
|
||||||
|
|
||||||
|
/* wait for just a little while, because the above call is asynchronous */
|
||||||
|
|
||||||
|
::usleep (250000);
|
||||||
|
|
||||||
if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
|
if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!clicked_routeview->track()->bounceable()) {
|
if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
|
||||||
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_routeview);
|
MessageDialog d (
|
||||||
if (rtv && !rtv->track()->bounceable()) {
|
_("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
|
||||||
MessageDialog d (
|
"This is typically caused by plugins that generate stereo output from mono input or vice versa.")
|
||||||
_("This route cannot be frozen because it has more outputs than inputs. "
|
);
|
||||||
"You can fix this by increasing the number of inputs.")
|
d.set_title (_("Cannot freeze"));
|
||||||
);
|
d.run ();
|
||||||
d.set_title (_("Cannot freeze"));
|
return;
|
||||||
d.run ();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InterThreadInfo itt;
|
InterThreadInfo itt;
|
||||||
|
|
@ -3413,16 +3417,21 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
|
||||||
TrackSelection views = selection->tracks;
|
TrackSelection views = selection->tracks;
|
||||||
|
|
||||||
for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
|
for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
|
||||||
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
|
|
||||||
if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable()) {
|
if (enable_processing) {
|
||||||
MessageDialog d (
|
|
||||||
_("You can't perform this operation because the processing of the signal "
|
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
|
||||||
"will cause one or more of the tracks will end up with a region with more channels than this track has inputs.\n\n"
|
|
||||||
"You can do this without processing, which is a different operation.")
|
if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
|
||||||
);
|
MessageDialog d (
|
||||||
d.set_title (_("Cannot bounce"));
|
_("You can't perform this operation because the processing of the signal "
|
||||||
d.run ();
|
"will cause one or more of the tracks will end up with a region with more channels than this track has inputs.\n\n"
|
||||||
return;
|
"You can do this without processing, which is a different operation.")
|
||||||
|
);
|
||||||
|
d.set_title (_("Cannot bounce"));
|
||||||
|
d.run ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3451,7 +3460,13 @@ Editor::bounce_range_selection (bool replace, bool enable_processing)
|
||||||
playlist->clear_changes ();
|
playlist->clear_changes ();
|
||||||
playlist->clear_owned_changes ();
|
playlist->clear_owned_changes ();
|
||||||
|
|
||||||
boost::shared_ptr<Region> r = rtv->track()->bounce_range (start, start+cnt, itt, enable_processing);
|
boost::shared_ptr<Region> r;
|
||||||
|
|
||||||
|
if (enable_processing) {
|
||||||
|
r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
|
||||||
|
} else {
|
||||||
|
r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
|
||||||
|
}
|
||||||
|
|
||||||
if (!r) {
|
if (!r) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
#include <gtkmm.h>
|
#include <gtkmm.h>
|
||||||
|
|
||||||
#include "ardour/playlist.h"
|
#include "ardour/playlist.h"
|
||||||
|
#include "ardour/timefx_request.h"
|
||||||
|
|
||||||
#include "ardour_dialog.h"
|
#include "ardour_dialog.h"
|
||||||
#include "region_selection.h"
|
#include "region_selection.h"
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#ifndef __ardour_audio_track_h__
|
#ifndef __ardour_audio_track_h__
|
||||||
#define __ardour_audio_track_h__
|
#define __ardour_audio_track_h__
|
||||||
|
|
||||||
|
#include "ardour/interthread_info.h"
|
||||||
#include "ardour/track.h"
|
#include "ardour/track.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
@ -49,20 +50,20 @@ class AudioTrack : public Track
|
||||||
return DataType::AUDIO;
|
return DataType::AUDIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
int export_stuff (BufferSet& bufs, framepos_t start_frame, framecnt_t nframes, bool enable_processing = true);
|
|
||||||
|
|
||||||
void freeze_me (InterThreadInfo&);
|
void freeze_me (InterThreadInfo&);
|
||||||
void unfreeze ();
|
void unfreeze ();
|
||||||
|
|
||||||
|
bool bounceable (boost::shared_ptr<Processor>, bool include_endpoint) const;
|
||||||
boost::shared_ptr<Region> bounce (InterThreadInfo&);
|
boost::shared_ptr<Region> bounce (InterThreadInfo&);
|
||||||
boost::shared_ptr<Region> bounce_range (framepos_t start, framepos_t end, InterThreadInfo&, bool enable_processing);
|
boost::shared_ptr<Region> bounce_range (framepos_t start, framepos_t end, InterThreadInfo&,
|
||||||
|
boost::shared_ptr<Processor> endpoint, bool include_endpoint);
|
||||||
|
int export_stuff (BufferSet& bufs, framepos_t start_frame, framecnt_t nframes,
|
||||||
|
boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export);
|
||||||
|
|
||||||
int set_state (const XMLNode&, int version);
|
int set_state (const XMLNode&, int version);
|
||||||
|
|
||||||
boost::shared_ptr<AudioFileSource> write_source (uint32_t n = 0);
|
boost::shared_ptr<AudioFileSource> write_source (uint32_t n = 0);
|
||||||
|
|
||||||
bool bounceable () const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
boost::shared_ptr<AudioDiskstream> audio_diskstream () const;
|
boost::shared_ptr<AudioDiskstream> audio_diskstream () const;
|
||||||
XMLNode& state (bool full);
|
XMLNode& state (bool full);
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@
|
||||||
#include "ardour/ardour.h"
|
#include "ardour/ardour.h"
|
||||||
#include "ardour/automatable.h"
|
#include "ardour/automatable.h"
|
||||||
#include "ardour/automation_list.h"
|
#include "ardour/automation_list.h"
|
||||||
|
#include "ardour/interthread_info.h"
|
||||||
#include "ardour/logcurve.h"
|
#include "ardour/logcurve.h"
|
||||||
#include "ardour/region.h"
|
#include "ardour/region.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,8 @@ public:
|
||||||
|
|
||||||
static bool role_requires_output_ports (Role r) { return r == Main || r == Send || r == Insert; }
|
static bool role_requires_output_ports (Role r) { return r == Main || r == Send || r == Insert; }
|
||||||
|
|
||||||
|
bool does_routing() const { return true; }
|
||||||
|
|
||||||
/* Delivery to an existing output */
|
/* Delivery to an existing output */
|
||||||
|
|
||||||
Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<Pannable>, boost::shared_ptr<MuteMaster> mm, const std::string& name, Role);
|
Delivery (Session& s, boost::shared_ptr<IO> io, boost::shared_ptr<Pannable>, boost::shared_ptr<MuteMaster> mm, const std::string& name, Role);
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "ardour/interthread_info.h"
|
||||||
#include "ardour/types.h"
|
#include "ardour/types.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,8 @@ class IOProcessor : public Processor
|
||||||
|
|
||||||
bool set_name (const std::string& str);
|
bool set_name (const std::string& str);
|
||||||
|
|
||||||
|
bool does_routing() const { return true; }
|
||||||
|
|
||||||
virtual ChanCount natural_output_streams() const;
|
virtual ChanCount natural_output_streams() const;
|
||||||
virtual ChanCount natural_input_streams () const;
|
virtual ChanCount natural_input_streams () const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#define __ardour_midi_stretch_h__
|
#define __ardour_midi_stretch_h__
|
||||||
|
|
||||||
#include "ardour/filter.h"
|
#include "ardour/filter.h"
|
||||||
|
#include "ardour/timefx_request.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
#ifndef __ardour_midi_track_h__
|
#ifndef __ardour_midi_track_h__
|
||||||
#define __ardour_midi_track_h__
|
#define __ardour_midi_track_h__
|
||||||
|
|
||||||
|
#include "ardour/interthread_info.h"
|
||||||
#include "ardour/track.h"
|
#include "ardour/track.h"
|
||||||
#include "ardour/midi_ring_buffer.h"
|
#include "ardour/midi_ring_buffer.h"
|
||||||
#include "ardour/midi_state_tracker.h"
|
#include "ardour/midi_state_tracker.h"
|
||||||
|
|
@ -54,15 +55,15 @@ public:
|
||||||
return DataType::MIDI;
|
return DataType::MIDI;
|
||||||
}
|
}
|
||||||
|
|
||||||
int export_stuff (BufferSet& bufs, framecnt_t nframes, framepos_t end_frame);
|
|
||||||
|
|
||||||
void freeze_me (InterThreadInfo&);
|
void freeze_me (InterThreadInfo&);
|
||||||
void unfreeze ();
|
void unfreeze ();
|
||||||
|
|
||||||
|
bool bounceable (boost::shared_ptr<Processor>, bool) const { return false; }
|
||||||
boost::shared_ptr<Region> bounce (InterThreadInfo&);
|
boost::shared_ptr<Region> bounce (InterThreadInfo&);
|
||||||
boost::shared_ptr<Region> bounce_range (
|
boost::shared_ptr<Region> bounce_range (framepos_t start, framepos_t end, InterThreadInfo&,
|
||||||
framepos_t start, framepos_t end, InterThreadInfo&, bool enable_processing
|
boost::shared_ptr<Processor> endpoint, bool include_endpoint);
|
||||||
);
|
int export_stuff (BufferSet& bufs, framecnt_t nframes, framepos_t end_frame,
|
||||||
|
boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export);
|
||||||
|
|
||||||
int set_state (const XMLNode&, int version);
|
int set_state (const XMLNode&, int version);
|
||||||
|
|
||||||
|
|
@ -100,10 +101,6 @@ public:
|
||||||
uint16_t get_channel_mask ();
|
uint16_t get_channel_mask ();
|
||||||
boost::shared_ptr<MidiPlaylist> midi_playlist ();
|
boost::shared_ptr<MidiPlaylist> midi_playlist ();
|
||||||
|
|
||||||
bool bounceable () const {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PBD::Signal1<void, boost::weak_ptr<MidiSource> > DataRecorded;
|
PBD::Signal1<void, boost::weak_ptr<MidiSource> > DataRecorded;
|
||||||
boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const;
|
boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ardour/filter.h"
|
#include "ardour/filter.h"
|
||||||
|
#include "ardour/timefx_request.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
class AudioRegion;
|
class AudioRegion;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
class ThreadBuffers;
|
class ThreadBuffers;
|
||||||
|
class BufferSet;
|
||||||
|
|
||||||
class ProcessThread
|
class ProcessThread
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,8 @@ class Processor : public SessionObject, public Automatable, public Latent
|
||||||
|
|
||||||
bool active () const { return _pending_active; }
|
bool active () const { return _pending_active; }
|
||||||
|
|
||||||
|
virtual bool does_routing() const { return false; }
|
||||||
|
|
||||||
bool get_next_ab_is_active () const { return _next_ab_is_active; }
|
bool get_next_ab_is_active () const { return _next_ab_is_active; }
|
||||||
void set_next_ab_is_active (bool yn) { _next_ab_is_active = yn; }
|
void set_next_ab_is_active (bool yn) { _next_ab_is_active = yn; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#define __ardour_rbeffect_h__
|
#define __ardour_rbeffect_h__
|
||||||
|
|
||||||
#include "ardour/filter.h"
|
#include "ardour/filter.h"
|
||||||
|
#include "ardour/timefx_request.h"
|
||||||
|
|
||||||
namespace ARDOUR {
|
namespace ARDOUR {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@
|
||||||
#include "ardour/ardour.h"
|
#include "ardour/ardour.h"
|
||||||
#include "ardour/chan_count.h"
|
#include "ardour/chan_count.h"
|
||||||
#include "ardour/delivery.h"
|
#include "ardour/delivery.h"
|
||||||
|
#include "ardour/interthread_info.h"
|
||||||
#include "ardour/rc_configuration.h"
|
#include "ardour/rc_configuration.h"
|
||||||
#include "ardour/session_configuration.h"
|
#include "ardour/session_configuration.h"
|
||||||
#include "ardour/session_event.h"
|
#include "ardour/session_event.h"
|
||||||
|
|
@ -607,8 +608,8 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
||||||
/* flattening stuff */
|
/* flattening stuff */
|
||||||
|
|
||||||
boost::shared_ptr<Region> write_one_track (AudioTrack&, framepos_t start, framepos_t end,
|
boost::shared_ptr<Region> write_one_track (AudioTrack&, framepos_t start, framepos_t end,
|
||||||
bool overwrite, std::vector<boost::shared_ptr<Source> >&, InterThreadInfo& wot,
|
bool overwrite, std::vector<boost::shared_ptr<Source> >&, InterThreadInfo& wot,
|
||||||
bool enable_processing = true);
|
boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export);
|
||||||
int freeze_all (InterThreadInfo&);
|
int freeze_all (InterThreadInfo&);
|
||||||
|
|
||||||
/* session-wide solo/mute/rec-enable */
|
/* session-wide solo/mute/rec-enable */
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ardour/filter.h"
|
#include "ardour/filter.h"
|
||||||
|
#include "ardour/timefx_request.h"
|
||||||
|
|
||||||
#ifdef USE_RUBBERBAND
|
#ifdef USE_RUBBERBAND
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
#include "ardour/interthread_info.h"
|
||||||
#include "ardour/route.h"
|
#include "ardour/route.h"
|
||||||
#include "ardour/public_diskstream.h"
|
#include "ardour/public_diskstream.h"
|
||||||
|
|
||||||
|
|
@ -87,8 +88,14 @@ class Track : public Route, public PublicDiskstream
|
||||||
virtual void freeze_me (InterThreadInfo&) = 0;
|
virtual void freeze_me (InterThreadInfo&) = 0;
|
||||||
virtual void unfreeze () = 0;
|
virtual void unfreeze () = 0;
|
||||||
|
|
||||||
|
/** @return true if the track can be bounced, or false otherwise.
|
||||||
|
*/
|
||||||
|
virtual bool bounceable (boost::shared_ptr<Processor> endpoint, bool include_endpoint) const = 0;
|
||||||
virtual boost::shared_ptr<Region> bounce (InterThreadInfo&) = 0;
|
virtual boost::shared_ptr<Region> bounce (InterThreadInfo&) = 0;
|
||||||
virtual boost::shared_ptr<Region> bounce_range (framepos_t start, framepos_t end, InterThreadInfo&, bool enable_processing = true) = 0;
|
virtual boost::shared_ptr<Region> bounce_range (framepos_t start, framepos_t end, InterThreadInfo&,
|
||||||
|
boost::shared_ptr<Processor> endpoint, bool include_endpoint) = 0;
|
||||||
|
virtual int export_stuff (BufferSet& bufs, framepos_t start_frame, framecnt_t nframes,
|
||||||
|
boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export) = 0;
|
||||||
|
|
||||||
XMLNode& get_state();
|
XMLNode& get_state();
|
||||||
XMLNode& get_template();
|
XMLNode& get_template();
|
||||||
|
|
@ -104,11 +111,6 @@ class Track : public Route, public PublicDiskstream
|
||||||
|
|
||||||
void set_block_size (pframes_t);
|
void set_block_size (pframes_t);
|
||||||
|
|
||||||
/** @return true if the track can be bounced, or false if it cannot because
|
|
||||||
* it has more outputs than diskstream channels.
|
|
||||||
*/
|
|
||||||
virtual bool bounceable () const = 0;
|
|
||||||
|
|
||||||
/* PublicDiskstream interface */
|
/* PublicDiskstream interface */
|
||||||
boost::shared_ptr<Playlist> playlist ();
|
boost::shared_ptr<Playlist> playlist ();
|
||||||
void request_jack_monitors_input (bool);
|
void request_jack_monitors_input (bool);
|
||||||
|
|
|
||||||
|
|
@ -422,15 +422,6 @@ namespace ARDOUR {
|
||||||
AutoConnectMaster = 0x2
|
AutoConnectMaster = 0x2
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InterThreadInfo {
|
|
||||||
InterThreadInfo () : done (false), cancel (false), progress (0), thread (0) {}
|
|
||||||
|
|
||||||
volatile bool done;
|
|
||||||
volatile bool cancel;
|
|
||||||
volatile float progress;
|
|
||||||
pthread_t thread;
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SampleFormat {
|
enum SampleFormat {
|
||||||
FormatFloat = 0,
|
FormatFloat = 0,
|
||||||
FormatInt24,
|
FormatInt24,
|
||||||
|
|
@ -500,19 +491,6 @@ namespace ARDOUR {
|
||||||
SrcFastest
|
SrcFastest
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TimeFXRequest : public InterThreadInfo {
|
|
||||||
TimeFXRequest()
|
|
||||||
: time_fraction(0), pitch_fraction(0),
|
|
||||||
quick_seek(false), antialias(false), opts(0) {}
|
|
||||||
float time_fraction;
|
|
||||||
float pitch_fraction;
|
|
||||||
/* SoundTouch */
|
|
||||||
bool quick_seek;
|
|
||||||
bool antialias;
|
|
||||||
/* RubberBand */
|
|
||||||
int opts; // really RubberBandStretcher::Options
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::list<framepos_t> AnalysisFeatureList;
|
typedef std::list<framepos_t> AnalysisFeatureList;
|
||||||
|
|
||||||
typedef std::list<boost::shared_ptr<Route> > RouteList;
|
typedef std::list<boost::shared_ptr<Route> > RouteList;
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@
|
||||||
#include "ardour/meter.h"
|
#include "ardour/meter.h"
|
||||||
#include "ardour/playlist_factory.h"
|
#include "ardour/playlist_factory.h"
|
||||||
#include "ardour/plugin_insert.h"
|
#include "ardour/plugin_insert.h"
|
||||||
|
#include "ardour/port_insert.h"
|
||||||
#include "ardour/processor.h"
|
#include "ardour/processor.h"
|
||||||
#include "ardour/region_factory.h"
|
#include "ardour/region_factory.h"
|
||||||
#include "ardour/route_group_specialized.h"
|
#include "ardour/route_group_specialized.h"
|
||||||
|
|
@ -482,7 +483,8 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
AudioTrack::export_stuff (BufferSet& buffers, framepos_t start, framecnt_t nframes, bool enable_processing)
|
AudioTrack::export_stuff (BufferSet& buffers, framepos_t start, framecnt_t nframes,
|
||||||
|
boost::shared_ptr<Processor> endpoint, bool include_endpoint, bool for_export)
|
||||||
{
|
{
|
||||||
boost::scoped_array<gain_t> gain_buffer (new gain_t[nframes]);
|
boost::scoped_array<gain_t> gain_buffer (new gain_t[nframes]);
|
||||||
boost::scoped_array<Sample> mix_buffer (new Sample[nframes]);
|
boost::scoped_array<Sample> mix_buffer (new Sample[nframes]);
|
||||||
|
|
@ -517,41 +519,110 @@ AudioTrack::export_stuff (BufferSet& buffers, framepos_t start, framecnt_t nfram
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no processing is required, there's no need to go any further.
|
// If no processing is required, there's no need to go any further.
|
||||||
if (!enable_processing) {
|
|
||||||
|
if (!endpoint && !include_endpoint) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* note: only run processors during export. other layers in the machinery
|
|
||||||
will already have checked that there are no external port processors.
|
|
||||||
Also, don't run deliveries that write to real output ports, and don't
|
|
||||||
run meters.
|
|
||||||
*/
|
|
||||||
|
|
||||||
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
|
||||||
boost::shared_ptr<Processor> processor = boost::dynamic_pointer_cast<Processor> (*i);
|
|
||||||
boost::shared_ptr<Delivery> delivery = boost::dynamic_pointer_cast<Delivery> (*i);
|
|
||||||
boost::shared_ptr<PeakMeter> meter = boost::dynamic_pointer_cast<PeakMeter> (*i);
|
|
||||||
|
|
||||||
if (processor && (!delivery || !Delivery::role_requires_output_ports (delivery->role())) && !meter) {
|
if (!include_endpoint && (*i) == endpoint) {
|
||||||
processor->run (buffers, start, start+nframes, nframes, true);
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we're not exporting, stop processing if we come across a routing processor.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!for_export && (*i)->does_routing()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* even for export, don't run any processor that does routing.
|
||||||
|
|
||||||
|
oh, and don't bother with the peak meter either.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!(*i)->does_routing() && !boost::dynamic_pointer_cast<PeakMeter>(*i)) {
|
||||||
|
(*i)->run (buffers, start, start+nframes, nframes, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*i) == endpoint) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<Region>
|
bool
|
||||||
AudioTrack::bounce (InterThreadInfo& itt)
|
AudioTrack::bounceable (boost::shared_ptr<Processor> endpoint, bool include_endpoint) const
|
||||||
{
|
{
|
||||||
vector<boost::shared_ptr<Source> > srcs;
|
if (!endpoint && !include_endpoint) {
|
||||||
return _session.write_one_track (*this, _session.current_start_frame(), _session.current_end_frame(), false, srcs, itt);
|
/* no processing - just read from the playlist and create new
|
||||||
|
files: always possible.
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Glib::RWLock::ReaderLock lm (_processor_lock);
|
||||||
|
uint32_t naudio = n_inputs().n_audio();
|
||||||
|
|
||||||
|
for (ProcessorList::const_iterator r = _processors.begin(); r != _processors.end(); ++r) {
|
||||||
|
|
||||||
|
/* if we're not including the endpoint, potentially stop
|
||||||
|
right here before we test matching i/o valences.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!include_endpoint && (*r) == endpoint) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ignore any processors that do routing, because we will not
|
||||||
|
* use them during a bounce/freeze/export operation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((*r)->does_routing()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* does the output from the last considered processor match the
|
||||||
|
* input to this one?
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (naudio != (*r)->input_streams().n_audio()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we're including the endpoint - if we just hit it,
|
||||||
|
then stop.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((*r) == endpoint) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save outputs of this processor to test against inputs
|
||||||
|
of the next one.
|
||||||
|
*/
|
||||||
|
|
||||||
|
naudio = (*r)->output_streams().n_audio();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<Region>
|
boost::shared_ptr<Region>
|
||||||
AudioTrack::bounce_range (framepos_t start, framepos_t end, InterThreadInfo& itt, bool enable_processing)
|
AudioTrack::bounce (InterThreadInfo& itt)
|
||||||
|
{
|
||||||
|
return bounce_range (_session.current_start_frame(), _session.current_end_frame(), itt, main_outs(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::shared_ptr<Region>
|
||||||
|
AudioTrack::bounce_range (framepos_t start, framepos_t end, InterThreadInfo& itt,
|
||||||
|
boost::shared_ptr<Processor> endpoint, bool include_endpoint)
|
||||||
{
|
{
|
||||||
vector<boost::shared_ptr<Source> > srcs;
|
vector<boost::shared_ptr<Source> > srcs;
|
||||||
return _session.write_one_track (*this, start, end, false, srcs, itt, enable_processing);
|
return _session.write_one_track (*this, start, end, false, srcs, itt, endpoint, include_endpoint, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -594,7 +665,8 @@ AudioTrack::freeze_me (InterThreadInfo& itt)
|
||||||
|
|
||||||
boost::shared_ptr<Region> res;
|
boost::shared_ptr<Region> res;
|
||||||
|
|
||||||
if ((res = _session.write_one_track (*this, _session.current_start_frame(), _session.current_end_frame(), true, srcs, itt)) == 0) {
|
if ((res = _session.write_one_track (*this, _session.current_start_frame(), _session.current_end_frame(), true, srcs, itt,
|
||||||
|
main_outs(), false, false)) == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -605,21 +677,20 @@ AudioTrack::freeze_me (InterThreadInfo& itt)
|
||||||
|
|
||||||
for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); ++r) {
|
for (ProcessorList::iterator r = _processors.begin(); r != _processors.end(); ++r) {
|
||||||
|
|
||||||
boost::shared_ptr<Processor> processor;
|
if (!(*r)->does_routing()) {
|
||||||
|
|
||||||
if ((processor = boost::dynamic_pointer_cast<Processor>(*r)) != 0) {
|
FreezeRecordProcessorInfo* frii = new FreezeRecordProcessorInfo ((*r)->get_state(), (*r));
|
||||||
|
|
||||||
FreezeRecordProcessorInfo* frii = new FreezeRecordProcessorInfo ((*r)->get_state(), processor);
|
frii->id = (*r)->id();
|
||||||
|
|
||||||
frii->id = processor->id();
|
|
||||||
|
|
||||||
_freeze_record.processor_info.push_back (frii);
|
_freeze_record.processor_info.push_back (frii);
|
||||||
|
|
||||||
/* now deactivate the processor */
|
/* now deactivate the processor */
|
||||||
|
|
||||||
processor->deactivate ();
|
(*r)->deactivate ();
|
||||||
_session.set_dirty ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_session.set_dirty ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -692,12 +763,6 @@ AudioTrack::write_source (uint32_t n)
|
||||||
return ds->write_source (n);
|
return ds->write_source (n);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
AudioTrack::bounceable () const
|
|
||||||
{
|
|
||||||
return n_inputs().n_audio() >= n_outputs().n_audio();
|
|
||||||
}
|
|
||||||
|
|
||||||
boost::shared_ptr<Diskstream>
|
boost::shared_ptr<Diskstream>
|
||||||
AudioTrack::diskstream_factory (XMLNode const & node)
|
AudioTrack::diskstream_factory (XMLNode const & node)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -113,14 +113,14 @@ PortExportChannel::set_state (XMLNode * node, Session & session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RegionExportChannelFactory::RegionExportChannelFactory (Session * session, AudioRegion const & region, AudioTrack & track, Type type) :
|
RegionExportChannelFactory::RegionExportChannelFactory (Session * session, AudioRegion const & region, AudioTrack & track, Type type)
|
||||||
region (region),
|
: region (region)
|
||||||
track (track),
|
, track (track)
|
||||||
type (type),
|
, type (type)
|
||||||
frames_per_cycle (session->engine().frames_per_cycle ()),
|
, frames_per_cycle (session->engine().frames_per_cycle ())
|
||||||
buffers_up_to_date (false),
|
, buffers_up_to_date (false)
|
||||||
region_start (region.position()),
|
, region_start (region.position())
|
||||||
position (region_start)
|
, position (region_start)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Raw:
|
case Raw:
|
||||||
|
|
@ -190,10 +190,10 @@ RegionExportChannelFactory::update_buffers (framecnt_t frames)
|
||||||
region.read_at (buffers.get_audio (channel).data(), mixdown_buffer.get(), gain_buffer.get(), position, frames, channel);
|
region.read_at (buffers.get_audio (channel).data(), mixdown_buffer.get(), gain_buffer.get(), position, frames, channel);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Processed:
|
case Processed:
|
||||||
track.export_stuff (buffers, position, frames);
|
track.export_stuff (buffers, position, frames, track.main_outs(), true, true);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw ExportFailed ("Unhandled type in ExportChannelFactory::update_buffers");
|
throw ExportFailed ("Unhandled type in ExportChannelFactory::update_buffers");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -478,7 +478,8 @@ MidiTrack::write_out_of_band_data (BufferSet& bufs, framepos_t /*start*/, framep
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
MidiTrack::export_stuff (BufferSet& /*bufs*/, framecnt_t /*nframes*/, framepos_t /*end_frame*/)
|
MidiTrack::export_stuff (BufferSet& /*bufs*/, framecnt_t /*nframes*/, framepos_t /*end_frame*/,
|
||||||
|
boost::shared_ptr<Processor> /*endpoint*/, bool /*include_endpoint*/, bool /*forexport*/)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
@ -492,7 +493,8 @@ MidiTrack::bounce (InterThreadInfo& /*itt*/)
|
||||||
|
|
||||||
|
|
||||||
boost::shared_ptr<Region>
|
boost::shared_ptr<Region>
|
||||||
MidiTrack::bounce_range (framepos_t /*start*/, framepos_t /*end*/, InterThreadInfo& /*itt*/, bool /*enable_processing*/)
|
MidiTrack::bounce_range (framepos_t /*start*/, framepos_t /*end*/, InterThreadInfo& /*itt*/,
|
||||||
|
boost::shared_ptr<Processor> /*endpoint*/, bool /*include_endpoint*/)
|
||||||
{
|
{
|
||||||
std::cerr << "MIDI bounce range currently unsupported" << std::endl;
|
std::cerr << "MIDI bounce range currently unsupported" << std::endl;
|
||||||
return boost::shared_ptr<Region> ();
|
return boost::shared_ptr<Region> ();
|
||||||
|
|
|
||||||
|
|
@ -3901,7 +3901,9 @@ Session::freeze_all (InterThreadInfo& itt)
|
||||||
boost::shared_ptr<Region>
|
boost::shared_ptr<Region>
|
||||||
Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
||||||
bool /*overwrite*/, vector<boost::shared_ptr<Source> >& srcs,
|
bool /*overwrite*/, vector<boost::shared_ptr<Source> >& srcs,
|
||||||
InterThreadInfo& itt, bool enable_processing)
|
InterThreadInfo& itt,
|
||||||
|
boost::shared_ptr<Processor> endpoint, bool include_endpoint,
|
||||||
|
bool for_export)
|
||||||
{
|
{
|
||||||
boost::shared_ptr<Region> result;
|
boost::shared_ptr<Region> result;
|
||||||
boost::shared_ptr<Playlist> playlist;
|
boost::shared_ptr<Playlist> playlist;
|
||||||
|
|
@ -3997,7 +3999,7 @@ Session::write_one_track (AudioTrack& track, framepos_t start, framepos_t end,
|
||||||
|
|
||||||
this_chunk = min (to_do, chunk_size);
|
this_chunk = min (to_do, chunk_size);
|
||||||
|
|
||||||
if (track.export_stuff (buffers, start, this_chunk, enable_processing)) {
|
if (track.export_stuff (buffers, start, this_chunk, endpoint, include_endpoint, for_export)) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,8 @@ class MIDIInvokable : public PBD::Stateful
|
||||||
MIDI::channel_t control_channel;
|
MIDI::channel_t control_channel;
|
||||||
MIDI::byte* data;
|
MIDI::byte* data;
|
||||||
size_t data_size;
|
size_t data_size;
|
||||||
|
bool _parameterized;
|
||||||
|
|
||||||
void midi_sense_note (MIDI::Parser &, MIDI::EventTwoBytes *, bool is_on);
|
void midi_sense_note (MIDI::Parser &, MIDI::EventTwoBytes *, bool is_on);
|
||||||
void midi_sense_note_on (MIDI::Parser &p, MIDI::EventTwoBytes *tb);
|
void midi_sense_note_on (MIDI::Parser &p, MIDI::EventTwoBytes *tb);
|
||||||
void midi_sense_note_off (MIDI::Parser &p, MIDI::EventTwoBytes *tb);
|
void midi_sense_note_off (MIDI::Parser &p, MIDI::EventTwoBytes *tb);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue