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:
Paul Davis 2012-03-15 21:40:17 +00:00
parent cfaf6ff7e3
commit f07ca6397f
23 changed files with 202 additions and 118 deletions

View file

@ -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);
}
} }
} }

View file

@ -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;

View file

@ -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"

View file

@ -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);

View file

@ -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"

View file

@ -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);

View file

@ -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 {

View file

@ -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;

View file

@ -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 {

View file

@ -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;

View file

@ -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;

View file

@ -9,6 +9,7 @@
namespace ARDOUR { namespace ARDOUR {
class ThreadBuffers; class ThreadBuffers;
class BufferSet;
class ProcessThread class ProcessThread
{ {

View file

@ -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; }

View file

@ -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 {

View file

@ -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 */

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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)
{ {

View file

@ -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");
} }

View file

@ -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> ();

View file

@ -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;
} }

View file

@ -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);