// if we don't need to declick, defer to apply_simple_gain
if (initial == target) {
- apply_simple_gain(bufs, nframes, invert_polarity ? target : -target);
+ apply_simple_gain(bufs, nframes, invert_polarity ? -target : target);
}
const jack_nframes_t declick = std::min ((jack_nframes_t)128, nframes);
static void set_short_over_length (jack_nframes_t);
static void set_long_over_length (jack_nframes_t);
- /** Assumes that the port is an audio output port */
- void silence (jack_nframes_t nframes, jack_nframes_t offset) {
- if (!_silent) {
- _buffer.silence(nframes, offset);
- if (offset == 0 && nframes == _buffer.capacity()) {
- _silent = true;
- }
- }
- }
-
protected:
friend class AudioEngine;
* Based on this you can static cast a Buffer* to the desired type. */
DataType type() const { return _type; }
+ bool silent() const { return _silent; }
+
/** Clear (eg zero, or empty) buffer starting at TIME @a offset */
virtual void silence(jack_nframes_t len, jack_nframes_t offset=0) = 0;
protected:
Buffer(DataType type, size_t capacity)
- : _type(type), _capacity(capacity), _size(0)
+ : _type(type), _capacity(capacity), _size(0), _silent(true)
{}
DataType _type;
size_t _capacity;
size_t _size;
+ bool _silent;
private:
// Prevent copies (undefined)
void silence(jack_nframes_t len, jack_nframes_t offset=0)
{
- assert(_capacity > 0);
- assert(offset + len <= _capacity);
- memset(_data + offset, 0, sizeof (Sample) * len);
+ if (!_silent) {
+ assert(_capacity > 0);
+ assert(offset + len <= _capacity);
+ memset(_data + offset, 0, sizeof (Sample) * len);
+ if (offset == 0 && len == _capacity) {
+ _silent = true;
+ }
+ }
}
/** Read @a len frames FROM THE START OF @a src into self at @a offset */
assert(src.type() == _type == DataType::AUDIO);
assert(offset + len <= _capacity);
memcpy(_data + offset, ((AudioBuffer&)src).data(len), sizeof(Sample) * len);
+ _silent = src.silent();
}
/** Accumulate (add)@a len frames FROM THE START OF @a src into self at @a offset */
for (jack_nframes_t n = 0; n < len; ++n) {
dst_raw[n] += src_raw[n];
}
+
+ _silent = (src.silent() && _silent);
}
/** Accumulate (add) @a len frames FROM THE START OF @a src into self at @a offset
for (jack_nframes_t n = 0; n < len; ++n) {
dst_raw[n] += src_raw[n] * gain_coeff;
}
+
+ _silent = ( (src.silent() && _silent) || (_silent && gain_coeff == 0) );
}
void apply_gain(gain_t gain, jack_nframes_t len, jack_nframes_t offset=0) {
for (jack_nframes_t n = 0; n < len; ++n) {
buf[n] *= gain;
}
+
+ _silent = (_silent || gain == 0);
}
/** Set the data contained by this buffer manually (for setting directly to jack buffer).
_capacity = size;
_size = size;
_data = data;
+ _silent = false;
}
const Sample* data(jack_nframes_t nframes, jack_nframes_t offset=0) const
return (MidiBuffer&)get(DataType::MIDI, i);
}
- void read_from(BufferSet& in, jack_nframes_t nframes, jack_nframes_t offset=0)
- {
- throw; // FIXME: implement this with spiffy DataType iterator etc.
- }
+ void read_from(BufferSet& in, jack_nframes_t nframes, jack_nframes_t offset=0);
// ITERATORS
size_t capacity() { return _buffer.capacity(); }
size_t size() { return _buffer.size(); }
-
- /** Assumes that the port is an output port */
- void silence (jack_nframes_t nframes, jack_nframes_t offset) {
- _buffer.silence(nframes, offset);
- }
protected:
friend class AudioEngine;
virtual Buffer& get_buffer() = 0;
- /** Silence/Empty the port, output ports only */
- virtual void silence (jack_nframes_t nframes, jack_nframes_t offset) = 0;
-
-
std::string name() const {
return _name;
}
jack_port_set_latency (_port, nframes);
}
- bool is_silent() const { return _silent; }
-
- void mark_silence (bool yn) {
- _silent = yn;
- }
-
sigc::signal<void,bool> MonitorInputChanged;
sigc::signal<void,bool> ClockSyncChanged;
unsigned short _metering;
bool _last_monitor : 1;
- bool _silent : 1;
};
} // namespace ARDOUR
if (_buffer.capacity() > 0) {
_buffer.clear();
}
- _silent = true;
+ assert(_buffer.silent());
}
_metering = 0;
AudioPort::cycle_start (jack_nframes_t nframes)
{
if (_flags & JackPortIsOutput) {
- // FIXME: do nothing, we can cache the value (but capacity needs to be set)
+ const bool silent = _buffer.silent();
+ // FIXME: do nothing, we can cache the value (but capacity needs to be set for MIDI)
_buffer.set_data((Sample*)jack_port_get_buffer (_port, nframes), nframes);
+ if (silent) {
+ _buffer.silence(nframes);
+ }
} else {
_buffer.set_data((Sample*)jack_port_get_buffer (_port, nframes), nframes);
}
(*i)->reset ();
if ((*i)->flags() & JackPortIsOutput) {
- (*i)->silence (jack_get_buffer_size (_jack), 0);
+ (*i)->get_buffer().silence (jack_get_buffer_size (_jack), 0);
}
}
AudioBuffer::AudioBuffer(size_t capacity)
: Buffer(DataType::AUDIO, capacity)
+ , _owns_data(false)
, _data(NULL)
{
_size = capacity; // For audio buffers, size = capacity (always)
posix_memalign((void**)&_data, 16, sizeof(Sample) * capacity);
#endif
assert(_data);
- clear();
_owns_data = true;
- } else {
- _owns_data = false;
+ clear();
}
}
clear();
assert(_size == 0);
- // FIXME: This is embarrassingly slow. branch branch branch
+ // FIXME: slow
for (size_t i=0; i < src.size(); ++i) {
const MidiEvent& ev = msrc[i];
if (ev.time >= offset && ev.time < offset+nframes) {
push_back(ev);
}
}
+
+ _silent = src.silent();
}
//cerr << "MidiBuffer: pushed, size = " << _size << endl;
+ _silent = false;
+
return true;
}
memset(_events, 0, sizeof(MidiEvent) * _capacity);
memset(_data, 0, sizeof(RawMidi) * _capacity * MAX_EVENT_SIZE);
_size = 0;
+ _silent = true;
}
return _buffers[type.to_index()][0]->capacity();
}
+// FIXME: make 'in' const
+void
+BufferSet::read_from(BufferSet& in, jack_nframes_t nframes, jack_nframes_t offset)
+{
+ assert(available() >= in.count());
+
+ // Copy all buffers 1:1
+ for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
+ BufferSet::iterator o = begin(*t);
+ for (BufferSet::iterator i = in.begin(*t); i != in.end(*t); ++i, ++o) {
+ o->read_from(*i, nframes, offset);
+ }
+ }
+
+ set_count(in.count());
+}
} // namespace ARDOUR
}
// FIXME
- return ensure_io (ChanCount(_default_type, out), ChanCount(_default_type, in), false, this);
+ return ensure_io (ChanCount(_default_type, in), ChanCount(_default_type, out), false, this);
}
int32_t
/* io_lock, not taken: function must be called from Session::process() calltree */
for (PortSet::iterator i = _outputs.begin(); i != _outputs.end(); ++i) {
- i->silence (nframes, offset);
+ i->get_buffer().silence (nframes, offset);
}
}
// Use the panner to distribute audio to output port buffers
if (_panner && !_panner->empty() && !_panner->bypassed()) {
_panner->distribute(bufs, output_buffers(), start_frame, end_frame, nframes, offset);
+ } else {
+ const DataType type = DataType::AUDIO;
+
+ // Copy any audio 1:1 to outputs
+ assert(bufs.count().get(DataType::AUDIO) == output_buffers().count().get(DataType::AUDIO));
+ BufferSet::iterator o = output_buffers().begin(type);
+ for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
+ o->read_from(*i, nframes, offset);
+ }
}
}
const DataType type = DataType::MIDI;
-
- // Just dump any MIDI 1-to-1, we're not at all clever with MIDI routing yet
+
+ // Copy any MIDI 1:1 to outputs
+ assert(bufs.count().get(DataType::MIDI) == output_buffers().count().get(DataType::MIDI));
BufferSet::iterator o = output_buffers().begin(type);
for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
o->read_from(*i, nframes, offset);
jack_nframes_t nframes, jack_nframes_t offset, bool with_redirects, int declick,
bool meter)
{
- // There's no such thing as a MIDI bus for the time being, to avoid diverging from trunk
- // too much until the SoC settles down. We'll do all the MIDI route work here for now
+ /* There's no such thing as a MIDI bus for the time being, to avoid diverging from trunk
+ * too much until the SoC settles down. We'll do all the MIDI route work here for now,
+ * but the long-term goal is to have Route::process_output_buffers handle everything */
- // Main output stage is the only stage we've got.
- // I think it's a pretty good stage though, wouldn't you say?
+ // Run all redirects
+ if (with_redirects) {
+ Glib::RWLock::ReaderLock rm (redirect_lock, Glib::TRY_LOCK);
+ if (rm.locked()) {
+ for (RedirectList::iterator i = _redirects.begin(); i != _redirects.end(); ++i) {
+ (*i)->run (bufs, start_frame, end_frame, nframes, offset);
+ }
+ }
+ }
+ // Main output stage
if (muted()) {
-
IO::silence(nframes, offset);
-
} else {
-
deliver_output(bufs, start_frame, end_frame, nframes, offset);
-
}
-
}
int
dst.accumulate_from(*i, nframes, offset);
}
- //audio_output(0)->mark_silence (false); // FIXME
-
} else {
/* mix all buffers into the output, scaling them all by the gain */
dst.accumulate_with_gain_from(*i, nframes, offset, gain_coeff);
}
- //audio_output(0)->mark_silence (false); // FIXME
}
return;
dst.accumulate_from(*i, nframes, offset);
}
- //audio_output(0)->mark_silence (false); // FIXME
-
return;
}
: _port (p)
, _metering(0)
, _last_monitor(false)
- , _silent(false)
{
if (_port == 0) {
throw failed_constructor();
Port::reset ()
{
_last_monitor = false;
- _silent = false;
}
int
bool post_fader_work = false;
bool mute_declick_applied = false;
gain_t dmg, dsg, dg;
- vector<Sample*>::iterator bufiter;
IO *co;
bool mute_audible;
bool solo_audible;
}
}
- /* ----------------------------------------------------------------------------------------------------
+ /* ---------------------------------------------------------------------------------------------------
PRE-FADER REDIRECTS
-------------------------------------------------------------------------------------------------- */
+ /* FIXME: Somewhere in these loops is where bufs.count() should go from n_inputs() to redirect_max_outs()
+ * (if they differ). Something explicit needs to be done here to make sure the list of redirects will
+ * give us what we need (possibly by inserting transparent 'translators' into the list to make it work) */
+
if (with_redirects) {
Glib::RWLock::ReaderLock rm (redirect_lock, Glib::TRY_LOCK);
if (rm.locked()) {
}
}
+ // FIXME: for now, just hope the redirects list did what it was supposed to
+ bufs.set_count(n_process_buffers());
+
if (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_post_fader) {
Amp::run (bufs, nframes, mute_gain, dmg, _phase_invert);
mute_gain = dmg;
ChanCount
Route::n_process_buffers ()
{
- //return max (n_inputs(), redirect_max_outs);
- return n_inputs(); // FIXME?
+ return max (n_inputs(), redirect_max_outs);
}
void
redirect->set_default_type(_default_type);
- ChanCount potential_max_streams;
-
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(redirect)) != 0) {
pi->set_count (1);
/* generator plugin */
_have_internal_generator = true;
}
-
- potential_max_streams = max(pi->input_streams(), pi->output_streams());
} else if ((porti = boost::dynamic_pointer_cast<PortInsert>(redirect)) != 0) {
the "outputs" of the route should match the inputs of this
route. XXX shouldn't they match the number of active signal
streams at the point of insertion?
-
*/
+ // FIXME: (yes, they should)
porti->ensure_io (n_outputs (), n_inputs(), false, this);
}
-
+
// Ensure peak vector sizes before the plugin is activated
+ ChanCount potential_max_streams = max(redirect->input_streams(), redirect->output_streams());
_meter->setup(potential_max_streams);
_redirects.push_back (redirect);
{
_metering = false;
save_state (_("initial state"));
- RedirectCreated (this); /* EMIT SIGNAL */
+ RedirectCreated (this); /* EMIT SIGNAL */
}
Send::Send (Session& s, const XMLNode& node)
}
save_state (_("initial state"));
- RedirectCreated (this); /* EMIT SIGNAL */
+ RedirectCreated (this); /* EMIT SIGNAL */
}
Send::Send (const Send& other)
sendbufs.read_from(bufs, nframes);
assert(sendbufs.count() == bufs.count());
- assert(sendbufs.count() == _outputs.count());
IO::deliver_output (sendbufs, start_frame, end_frame, nframes, offset);