summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2013-03-27 21:50:18 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2013-03-27 21:50:18 -0400
commit4abbabdcf9c6d6d98ba261d91846577a2fa2f05e (patch)
tree5a7134ccc9508a6f1da25ef3dc6d432bdc25a04f /libs/ardour
parent78aa7a13fd5e5abac70637ce6641b7d2e73dd541 (diff)
Squashed commit of the following:
commit fdbae82077db53add90df7448a06869dac89acc6 Author: Paul Davis <paul@linuxaudiosystems.com> Date: Wed Mar 27 21:45:28 2013 -0400 mammoth changes in basic signal flow, total redesign of MIDI channel filtering and more. commit 59343a8283698e02bc0f622313b29e98f449e4c8 Author: Paul Davis <paul@linuxaudiosystems.com> Date: Wed Mar 27 01:58:53 2013 -0400 initial working version after changes to MIDI channel filtering. may affect metering input too. testing not yet finished this commit merges many deep changes in ardour's internal architecture, combined with a total redesign of how MIDI channel filtering works. data in a track used to flow from JACK port buffers to diskstream's ringbuffers and was then copied from the ringbuffers into a BufferSet for use during Route::process_output_buffers(). The butler thread would handle the movement of data between the ringbuffers and disk. with this commit, data now flows from JACK port buffers into the BufferSet used for Route processing, and is copied from the BufferSet into the diskstream's ringbuffers (the butler thread continues to handle interactions with disk as usual). this change allowed a dramatic consolidation of code and simplification of most aspects of Track/Route::roll() and Track/Route::no_roll(). in particular, see Route::fill_buffers_with_input() which now concisely describes how we move data from JACK port buffers into the BufferSet for all Route types (including Tracks). this work was initially motivated by changing MIDI channel filtering so that we can process capture and playback independently. there is now a very clean pathway for this - see MidiTrack::roll() (NOTE: This needs implementing in the no-roll case too - a TODO item). the channel selector for MIDI tracks has been moved out of the track header and is now accessible via the context menu. more work is likely here, to make it (more) obvious to the user when filtering is going on.
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/ardour/audio_buffer.h38
-rw-r--r--libs/ardour/ardour/audio_diskstream.h2
-rw-r--r--libs/ardour/ardour/diskstream.h3
-rw-r--r--libs/ardour/ardour/meter.h2
-rw-r--r--libs/ardour/ardour/midi_buffer.h65
-rw-r--r--libs/ardour/ardour/midi_diskstream.h25
-rw-r--r--libs/ardour/ardour/midi_ring_buffer.h57
-rw-r--r--libs/ardour/ardour/midi_track.h61
-rw-r--r--libs/ardour/ardour/route.h12
-rw-r--r--libs/ardour/ardour/track.h1
-rw-r--r--libs/ardour/audio_buffer.cc11
-rw-r--r--libs/ardour/audio_diskstream.cc48
-rw-r--r--libs/ardour/audio_track.cc128
-rw-r--r--libs/ardour/meter.cc12
-rw-r--r--libs/ardour/midi_diskstream.cc68
-rw-r--r--libs/ardour/midi_port.cc1
-rw-r--r--libs/ardour/midi_ring_buffer.cc17
-rw-r--r--libs/ardour/midi_track.cc206
-rw-r--r--libs/ardour/return.cc2
-rw-r--r--libs/ardour/route.cc147
-rw-r--r--libs/ardour/send.cc2
-rw-r--r--libs/ardour/session_process.cc2
-rw-r--r--libs/ardour/track.cc27
23 files changed, 578 insertions, 359 deletions
diff --git a/libs/ardour/ardour/audio_buffer.h b/libs/ardour/ardour/audio_buffer.h
index 5c04a7f43a..42aba607f9 100644
--- a/libs/ardour/ardour/audio_buffer.h
+++ b/libs/ardour/ardour/audio_buffer.h
@@ -46,6 +46,28 @@ public:
}
/** Read @a len frames @a src starting at @a src_offset into self starting at @ dst_offset*/
+ void read_from (const Sample* src, framecnt_t len, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
+ assert(src != 0);
+ assert(_capacity > 0);
+ assert(len <= _capacity);
+ memcpy(_data + dst_offset, src + src_offset, sizeof(Sample) * len);
+ _silent = false;
+ _written = true;
+ }
+
+ void read_from_with_gain (const Sample* src, framecnt_t len, gain_t gain, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
+ assert(src != 0);
+ assert(_capacity > 0);
+ assert(len <= _capacity);
+ src += src_offset;
+ for (framecnt_t n = 0; n < len; ++n) {
+ _data[dst_offset+n] = src[n] * gain;
+ }
+ _silent = false;
+ _written = true;
+ }
+
+ /** Read @a len frames @a src starting at @a src_offset into self starting at @ dst_offset*/
void read_from (const Buffer& src, framecnt_t len, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
assert(&src != this);
assert(_capacity > 0);
@@ -82,6 +104,20 @@ public:
_written = true;
}
+ /** Acumulate (add) @a len frames @a src starting at @a src_offset into self starting at @a dst_offset */
+ void accumulate_from (const Sample* src, framecnt_t len, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
+ assert(_capacity > 0);
+ assert(len <= _capacity);
+
+ Sample* const dst_raw = _data + dst_offset;
+ const Sample* const src_raw = src + src_offset;
+
+ mix_buffers_no_gain(dst_raw, src_raw, len);
+
+ _silent = false;
+ _written = true;
+ }
+
/** Acumulate (add) @a len frames @a src starting at @a src_offset into self starting at @dst_offset
* scaling by @a gain_coeff */
void accumulate_with_gain_from (const AudioBuffer& src, framecnt_t len, gain_t gain_coeff, framecnt_t dst_offset = 0, framecnt_t src_offset = 0) {
@@ -171,6 +207,8 @@ public:
return _data + offset;
}
+ bool check_silence (pframes_t, pframes_t&) const;
+
void prepare () { _written = false; _silent = false; }
bool written() const { return _written; }
void set_written(bool w) { _written = w; }
diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h
index 455e89392b..cbc6b93fe0 100644
--- a/libs/ardour/ardour/audio_diskstream.h
+++ b/libs/ardour/ardour/audio_diskstream.h
@@ -151,7 +151,7 @@ class AudioDiskstream : public Diskstream
protected:
friend class AudioTrack;
- int process (framepos_t transport_frame, pframes_t nframes, framecnt_t &);
+ int process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_disk_signal);
bool commit (framecnt_t);
private:
diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h
index 81eb588d1a..85ca03caff 100644
--- a/libs/ardour/ardour/diskstream.h
+++ b/libs/ardour/ardour/diskstream.h
@@ -49,6 +49,7 @@ class Source;
class Session;
class Track;
class Location;
+class BufferSet;
/** Parent class for classes which can stream data to and from disk.
* These are used by Tracks to get playback and put recorded data.
@@ -191,7 +192,7 @@ class Diskstream : public SessionObject, public PublicDiskstream
protected:
friend class Track;
- virtual int process (framepos_t transport_frame, pframes_t nframes, framecnt_t &) = 0;
+ virtual int process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_disk_signal) = 0;
virtual bool commit (framecnt_t) = 0;
//private:
diff --git a/libs/ardour/ardour/meter.h b/libs/ardour/ardour/meter.h
index 773b04f386..eea240f821 100644
--- a/libs/ardour/ardour/meter.h
+++ b/libs/ardour/ardour/meter.h
@@ -44,7 +44,7 @@ class Metering {
*/
class PeakMeter : public Processor {
public:
- PeakMeter(Session& s) : Processor(s, "Meter") {}
+ PeakMeter(Session& s, const std::string& name);
void meter();
void reset ();
diff --git a/libs/ardour/ardour/midi_buffer.h b/libs/ardour/ardour/midi_buffer.h
index 183ca7eea9..5ef5e4c845 100644
--- a/libs/ardour/ardour/midi_buffer.h
+++ b/libs/ardour/ardour/midi_buffer.h
@@ -55,38 +55,50 @@ public:
template<typename BufferType, typename EventType>
class iterator_base {
public:
- iterator_base<BufferType, EventType>(BufferType& b, framecnt_t o) : buffer(b), offset(o) {}
+ iterator_base<BufferType, EventType>(BufferType& b, framecnt_t o)
+ : buffer(&b), offset(o) {}
+ iterator_base<BufferType, EventType>(const iterator_base<BufferType,EventType>& o)
+ : buffer (o.buffer), offset(o.offset) {}
+
+ inline iterator_base<BufferType,EventType> operator= (const iterator_base<BufferType,EventType>& o) {
+ if (&o != this) {
+ buffer = o.buffer;
+ offset = o.offset;
+ }
+ return *this;
+ }
+
inline EventType operator*() const {
- uint8_t* ev_start = buffer._data + offset + sizeof(TimeType);
+ uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType);
int event_size = Evoral::midi_event_size(ev_start);
assert(event_size >= 0);
return EventType(EventTypeMap::instance().midi_event_type(*ev_start),
- *((TimeType*)(buffer._data + offset)),
+ *((TimeType*)(buffer->_data + offset)),
event_size, ev_start);
}
inline EventType operator*() {
- uint8_t* ev_start = buffer._data + offset + sizeof(TimeType);
+ uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType);
int event_size = Evoral::midi_event_size(ev_start);
assert(event_size >= 0);
return EventType(EventTypeMap::instance().midi_event_type(*ev_start),
- *((TimeType*)(buffer._data + offset)),
+ *((TimeType*)(buffer->_data + offset)),
event_size, ev_start);
}
inline iterator_base<BufferType, EventType>& operator++() {
- uint8_t* ev_start = buffer._data + offset + sizeof(TimeType);
+ uint8_t* ev_start = buffer->_data + offset + sizeof(TimeType);
int event_size = Evoral::midi_event_size(ev_start);
assert(event_size >= 0);
offset += sizeof(TimeType) + event_size;
return *this;
}
inline bool operator!=(const iterator_base<BufferType, EventType>& other) const {
- return (&buffer != &other.buffer) || (offset != other.offset);
+ return (buffer != other.buffer) || (offset != other.offset);
}
inline bool operator==(const iterator_base<BufferType, EventType>& other) const {
- return (&buffer == &other.buffer) && (offset == other.offset);
+ return (buffer == other.buffer) && (offset == other.offset);
}
- BufferType& buffer;
+ BufferType* buffer;
size_t offset;
};
@@ -99,6 +111,41 @@ public:
const_iterator begin() const { return const_iterator(*this, 0); }
const_iterator end() const { return const_iterator(*this, _size); }
+ iterator erase(const iterator& i) {
+ assert (i.buffer == this);
+ uint8_t* ev_start = _data + i.offset + sizeof (TimeType);
+ int event_size = Evoral::midi_event_size (ev_start);
+
+ if (event_size < 0) {
+ /* unknown size, sysex: return end() */
+ return end();
+ }
+
+ size_t total_data_deleted = sizeof(TimeType) + event_size;
+
+ if (i.offset + total_data_deleted >= _size) {
+ _size = 0;
+ return end();
+ }
+
+ /* we need to avoid the temporary malloc that memmove would do,
+ so copy by hand. remember: this is small amounts of data ...
+ */
+ size_t a, b;
+ for (a = i.offset, b = i.offset + total_data_deleted; b < _size; ++b, ++a) {
+ _data[a] = _data[b];
+ }
+
+ _size -= total_data_deleted;
+
+ /* all subsequent iterators are now invalid, and the one we
+ * return should refer to the event we copied, which was after
+ * the one we just erased.
+ */
+
+ return iterator (*this, i.offset);
+ }
+
uint8_t* data() const { return _data; }
/**
diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h
index 309c275434..d6ad71863a 100644
--- a/libs/ardour/ardour/midi_diskstream.h
+++ b/libs/ardour/ardour/midi_diskstream.h
@@ -89,29 +89,6 @@ class MidiDiskstream : public Diskstream
void set_note_mode (NoteMode m);
- uint16_t get_channel_mask() {
- uint16_t playback_mask = _playback_buf->get_channel_mask();
-#ifndef NDEBUG
- uint16_t capture_mask = _capture_buf->get_channel_mask();
- assert(playback_mask == capture_mask);
-#endif
- return playback_mask;
- }
-
- void set_channel_mode(ChannelMode mode, uint16_t mask) {
- _playback_buf->set_channel_mode(mode, mask);
- _capture_buf->set_channel_mode(mode, mask);
- }
-
- ChannelMode get_channel_mode() {
- ChannelMode playback_mode = _playback_buf->get_channel_mode();
-#ifndef NDEBUG
- ChannelMode capture_mode = _capture_buf->get_channel_mode();
- assert(playback_mode == capture_mode);
-#endif
- return playback_mode;
- }
-
/** Emitted when some MIDI data has been received for recording.
* Parameter is the source that it is destined for.
* A caller can get a copy of the data with get_gui_feed_buffer ()
@@ -147,7 +124,7 @@ class MidiDiskstream : public Diskstream
protected:
friend class MidiTrack;
- int process (framepos_t transport_frame, pframes_t nframes, framecnt_t &);
+ int process (BufferSet&, framepos_t transport_frame, pframes_t nframes, framecnt_t &, bool need_diskstream);
bool commit (framecnt_t nframes);
static framecnt_t midi_readahead;
diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h
index b3e532bdbe..d5c9947b9a 100644
--- a/libs/ardour/ardour/midi_ring_buffer.h
+++ b/libs/ardour/ardour/midi_ring_buffer.h
@@ -45,38 +45,16 @@ public:
/** @param size Size in bytes.
*/
MidiRingBuffer(size_t size)
- : Evoral::EventRingBuffer<T>(size)
- , _channel_mask(0x0000FFFF)
- {}
+ : Evoral::EventRingBuffer<T>(size) {}
inline bool read_prefix(T* time, Evoral::EventType* type, uint32_t* size);
inline bool read_contents(uint32_t size, uint8_t* buf);
size_t read(MidiBuffer& dst, framepos_t start, framepos_t end, framecnt_t offset=0, bool stop_on_overflow_in_destination=false);
- inline uint32_t write(T time, Evoral::EventType type, uint32_t size, const uint8_t* buf);
void dump(std::ostream& dst);
void flush (framepos_t start, framepos_t end);
- /** Set the channel filtering mode.
- * @param mask If mode is FilterChannels, each bit represents a midi channel:
- * bit 0 = channel 0, bit 1 = channel 1 etc. the read and write methods will only
- * process events whose channel bit is 1.
- * If mode is ForceChannel, mask is simply a channel number which all events will
- * be forced to while reading.
- */
- void set_channel_mode(ChannelMode mode, uint16_t mask) {
- g_atomic_int_set(&_channel_mask, (uint32_t(mode) << 16) | uint32_t(mask));
- }
-
- ChannelMode get_channel_mode() const {
- return static_cast<ChannelMode>((g_atomic_int_get(&_channel_mask) & 0xFFFF0000) >> 16);
- }
-
- uint16_t get_channel_mask() const {
- return g_atomic_int_get(&_channel_mask) & 0x0000FFFF;
- }
-
void reset_tracker ();
void loop_resolve (MidiBuffer& dst, framepos_t);
@@ -99,7 +77,6 @@ protected:
}
private:
- volatile uint32_t _channel_mask; // 16 bits mode, 16 bits mask
MidiStateTracker _tracker;
};
@@ -137,38 +114,6 @@ MidiRingBuffer<T>::read_contents(uint32_t size, uint8_t* buf)
return PBD::RingBufferNPT<uint8_t>::read(buf, size) == size;
}
-template<typename T>
-inline uint32_t
-MidiRingBuffer<T>::write(T time, Evoral::EventType type, uint32_t size, const uint8_t* buf)
-{
- assert(size > 0);
- uint8_t status = buf[0];
-
- // Ignore event if it doesn't match channel filter
- if (is_channel_event(status)) {
- ChannelMode mode = get_channel_mode();
- if (mode == FilterChannels) {
- const uint8_t channel = status & 0x0F;
- if (!(get_channel_mask() & (1L << channel))) {
- return 0;
- }
- } else if (mode == ForceChannel) {
- uint8_t* tmpbuf = (uint8_t*) malloc(size);
- assert(tmpbuf);
- memcpy(tmpbuf, buf, size);
-
- tmpbuf[0] = (tmpbuf[0] & 0xF0) | (get_channel_mask() & 0x0F);
-
- uint32_t bytes_written = Evoral::EventRingBuffer<T>::write(time, type, size, tmpbuf);
- free(tmpbuf);
- return bytes_written;
- }
- }
-
- return Evoral::EventRingBuffer<T>::write(time, type, size, buf);
-}
-
-
} // namespace ARDOUR
#endif // __ardour_midi_ring_buffer_h__
diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h
index 8134f5312a..be209bc0f6 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -102,11 +102,39 @@ public:
PBD::Signal1<void,bool> StepEditStatusChange;
boost::shared_ptr<SMFSource> write_source (uint32_t n = 0);
- void set_channel_mode (ChannelMode, uint16_t);
- ChannelMode get_channel_mode ();
- uint16_t get_channel_mask ();
+
+ /** Channel filtering mode.
+ * @param mask If mode is FilterChannels, each bit represents a midi channel:
+ * bit 0 = channel 0, bit 1 = channel 1 etc. the read and write methods will only
+ * process events whose channel bit is 1.
+ * If mode is ForceChannel, mask is simply a channel number which all events will
+ * be forced to while reading.
+ */
+ void set_capture_channel_mode (ChannelMode mode, uint16_t mask);
+ void set_playback_channel_mode (ChannelMode mode, uint16_t mask);
+ void set_playback_channel_mask (uint16_t mask);
+ void set_capture_channel_mask (uint16_t mask);
+
+ ChannelMode get_playback_channel_mode() const {
+ return static_cast<ChannelMode>((g_atomic_int_get(&_playback_channel_mask) & 0xffff0000) >> 16);
+ }
+ uint16_t get_playback_channel_mask() const {
+ return g_atomic_int_get(&_playback_channel_mask) & 0x0000ffff;
+ }
+ ChannelMode get_capture_channel_mode() const {
+ return static_cast<ChannelMode>((g_atomic_int_get(&_capture_channel_mask) & 0xffff0000) >> 16);
+ }
+ uint16_t get_capture_channel_mask() const {
+ return g_atomic_int_get(&_capture_channel_mask) & 0x0000ffff;
+ }
+
boost::shared_ptr<MidiPlaylist> midi_playlist ();
+ PBD::Signal0<void> PlaybackChannelMaskChanged;
+ PBD::Signal0<void> PlaybackChannelModeChanged;
+ PBD::Signal0<void> CaptureChannelMaskChanged;
+ PBD::Signal0<void> CaptureChannelModeChanged;
+
PBD::Signal1<void, boost::weak_ptr<MidiSource> > DataRecorded;
boost::shared_ptr<MidiBuffer> get_gui_feed_buffer () const;
@@ -123,6 +151,13 @@ protected:
void act_on_mute ();
private:
+ MidiRingBuffer<framepos_t> _immediate_events;
+ MidiRingBuffer<framepos_t> _step_edit_ring_buffer;
+ NoteMode _note_mode;
+ bool _step_editing;
+ bool _input_active;
+ uint32_t _playback_channel_mask; // 16 bits mode, 16 bits mask
+ uint32_t _capture_channel_mask; // 16 bits mode, 16 bits mask
virtual boost::shared_ptr<Diskstream> diskstream_factory (XMLNode const &);
@@ -133,11 +168,6 @@ private:
void set_state_part_two ();
void set_state_part_three ();
- MidiRingBuffer<framepos_t> _immediate_events;
- MidiRingBuffer<framepos_t> _step_edit_ring_buffer;
- NoteMode _note_mode;
- bool _step_editing;
- bool _input_active;
int no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool state_changing);
void push_midi_input_to_step_edit_ringbuffer (framecnt_t nframes);
@@ -147,6 +177,21 @@ private:
void track_input_active (IOChange, void*);
void map_input_active (bool);
+
+ void filter_channels (BufferSet& bufs, ChannelMode mode, uint32_t mask);
+
+ void _set_playback_channel_mode(ChannelMode mode, uint16_t mask) {
+ g_atomic_int_set(&_playback_channel_mask, (uint32_t(mode) << 16) | uint32_t(mask));
+ }
+ void _set_playback_channel_mask (uint16_t mask) {
+ g_atomic_int_set(&_playback_channel_mask, (uint32_t(get_playback_channel_mode()) << 16) | uint32_t(mask));
+ }
+ void _set_capture_channel_mode(ChannelMode mode, uint16_t mask) {
+ g_atomic_int_set(&_capture_channel_mask, (uint32_t(mode) << 16) | uint32_t(mask));
+ }
+ void _set_capture_channel_mask (uint16_t mask) {
+ g_atomic_int_set(&_capture_channel_mask, (uint32_t(get_capture_channel_mode()) << 16) | uint32_t(mask));
+ }
};
} /* namespace ARDOUR*/
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index 1a42999e6b..c25b6be950 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -436,6 +436,12 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
bool has_external_redirects() const;
+ /* can only be executed by a route for which is_monitor() is true
+ (i.e. the monitor out)
+ */
+ void monitor_run (framepos_t start_frame, framepos_t end_frame,
+ pframes_t nframes, int declick);
+
protected:
friend class Session;
@@ -448,11 +454,13 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
protected:
virtual framecnt_t check_initial_delay (framecnt_t nframes, framepos_t&) { return nframes; }
- void passthru (framepos_t start_frame, framepos_t end_frame,
+ void fill_buffers_with_input (BufferSet& bufs, boost::shared_ptr<IO> io, pframes_t nframes);
+
+ void passthru (BufferSet&, framepos_t start_frame, framepos_t end_frame,
pframes_t nframes, int declick);
virtual void write_out_of_band_data (BufferSet& /* bufs */, framepos_t /* start_frame */, framepos_t /* end_frame */,
- framecnt_t /* nframes */) {}
+ framecnt_t /* nframes */) {}
virtual void process_output_buffers (BufferSet& bufs,
framepos_t start_frame, framepos_t end_frame,
diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h
index 8493d5e4ae..7159261b51 100644
--- a/libs/ardour/ardour/track.h
+++ b/libs/ardour/ardour/track.h
@@ -33,6 +33,7 @@ class RouteGroup;
class Source;
class Region;
class Diskstream;
+class IO;
class Track : public Route, public PublicDiskstream
{
diff --git a/libs/ardour/audio_buffer.cc b/libs/ardour/audio_buffer.cc
index 8b2d5c744f..1fd0337dd1 100644
--- a/libs/ardour/audio_buffer.cc
+++ b/libs/ardour/audio_buffer.cc
@@ -67,4 +67,13 @@ AudioBuffer::resize (size_t size)
cache_aligned_malloc ((void**) &_data, sizeof (Sample) * _capacity);
}
-
+bool
+AudioBuffer::check_silence (pframes_t nframes, pframes_t& n) const
+{
+ for (n = 0; n < _size && n < nframes; ++n) {
+ if (_data[n] != Sample (0)) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index dc9f427e87..24687c766f 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -408,7 +408,7 @@ AudioDiskstream::prepare_record_status(framepos_t capture_start_frame)
* that someone can read playback_distance worth of data from.
*/
int
-AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance)
+AudioDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance, bool need_disk_signal)
{
uint32_t n;
boost::shared_ptr<ChannelList> c = channels.reader();
@@ -494,9 +494,9 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecn
assert(ap);
assert(rec_nframes <= (framecnt_t) ap->get_audio_buffer(nframes).capacity());
- Sample *buf = ap->get_audio_buffer (nframes).data (rec_offset);
+ Sample *buf = bufs.get_audio (n).data(rec_offset);
memcpy (chaninfo->current_capture_buffer, buf, sizeof (Sample) * rec_nframes);
-
+
} else {
framecnt_t total = chaninfo->capture_vector.len[0] + chaninfo->capture_vector.len[1];
@@ -509,7 +509,7 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecn
boost::shared_ptr<AudioPort> const ap = _io->audio (n);
assert(ap);
- Sample* buf = ap->get_audio_buffer(nframes).data (rec_offset);
+ Sample *buf = bufs.get_audio (n).data(rec_offset);
framecnt_t first = chaninfo->capture_vector.len[0];
memcpy (chaninfo->capture_wrap_buffer, buf, sizeof (Sample) * first);
@@ -657,6 +657,46 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecn
_speed = _target_speed;
}
+ if (need_disk_signal) {
+
+ /* copy data over to buffer set */
+
+ size_t n_buffers = bufs.count().n_audio();
+ size_t n_chans = c->size();
+ gain_t scaling = 1.0f;
+
+ if (n_chans > n_buffers) {
+ scaling = ((float) n_buffers)/n_chans;
+ }
+
+ for (n = 0, chan = c->begin(); chan != c->end(); ++chan, ++n) {
+
+ AudioBuffer& buf (bufs.get_audio (n%n_buffers));
+ ChannelInfo* chaninfo (*chan);
+
+ if (n < n_chans) {
+ if (scaling != 1.0f) {
+ buf.read_from_with_gain (chaninfo->current_playback_buffer, nframes, scaling);
+ } else {
+ buf.read_from (chaninfo->current_playback_buffer, nframes);
+ }
+ } else {
+ if (scaling != 1.0f) {
+ buf.accumulate_with_gain_from (chaninfo->current_playback_buffer, nframes, scaling);
+ } else {
+ buf.accumulate_from (chaninfo->current_playback_buffer, nframes);
+ }
+ }
+ }
+
+ /* leave the MIDI count alone */
+ ChanCount cnt (DataType::AUDIO, n_chans);
+ cnt.set (DataType::MIDI, bufs.count().n_midi());
+ bufs.set_count (cnt);
+
+ /* extra buffers will already be silent, so leave them alone */
+ }
+
return 0;
}
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index 90439f46e9..070a7453fb 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -316,8 +316,6 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
return 0;
}
- Sample* b;
- Sample* tmpb;
framepos_t transport_frame;
boost::shared_ptr<AudioDiskstream> diskstream = audio_diskstream();
@@ -342,7 +340,9 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
to do nothing.
*/
- dret = diskstream->process (transport_frame, 0, playback_distance);
+ BufferSet bufs; /* empty set, no matter - nothing will happen */
+
+ dret = diskstream->process (bufs, transport_frame, 0, playback_distance, false);
need_butler = diskstream->commit (playback_distance);
return dret;
}
@@ -350,126 +350,22 @@ AudioTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_fram
_silent = false;
_amp->apply_gain_automation(false);
- if ((dret = diskstream->process (transport_frame, nframes, playback_distance)) != 0) {
- need_butler = diskstream->commit (playback_distance);
- silence (nframes);
- return dret;
- }
-
- /* special condition applies */
+ BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers ());
+ fill_buffers_with_input (bufs, _input, nframes);
+
if (_meter_point == MeterInput) {
- _input->process_input (_meter, start_frame, end_frame, nframes);
+ _meter->run (bufs, start_frame, end_frame, nframes, true);
}
- if (monitoring_state() == MonitoringInput) {
-
- passthru (start_frame, end_frame, nframes, false);
-
- } else if ((b = diskstream->playback_buffer(0)) != 0) {
-
- /*
- XXX is it true that the earlier test on n_outputs()
- means that we can avoid checking it again here? i think
- so, because changing the i/o configuration of an IO
- requires holding the AudioEngine lock, which we hold
- while in the process() tree.
- */
-
-
- /* copy the diskstream data to all output buffers */
-
- size_t limit = input_streams ().n_audio();
- BufferSet& bufs = _session.get_scratch_buffers ();
- const size_t blimit = bufs.count().n_audio();
-
- uint32_t n;
- uint32_t i;
-
- if (limit > blimit) {
-
- /* example case: auditioner configured for stereo output,
- but loaded with an 8 channel file. there are only
- 2 passthrough buffers, but n_process_buffers() will
- return 8.
-
- arbitrary decision: map all channels in the diskstream
- to the outputs available.
- */
-
- float scaling = limit/blimit;
-
- for (i = 0, n = 1; i < blimit; ++i, ++n) {
-
- /* first time through just copy a channel into
- the output buffer.
- */
-
- Sample* bb = bufs.get_audio (i).data();
-
- for (pframes_t xx = 0; xx < nframes; ++xx) {
- bb[xx] = b[xx] * scaling;
- }
-
- if (n < diskstream->n_channels().n_audio()) {
- tmpb = diskstream->playback_buffer(n);
- if (tmpb!=0) {
- b = tmpb;
- }
- }
- }
-
- for (;i < limit; ++i, ++n) {
-
- /* for all remaining channels, sum with existing
- data in the output buffers
- */
-
- bufs.get_audio (i%blimit).accumulate_with_gain_from (b, nframes, 0, scaling);
-
- if (n < diskstream->n_channels().n_audio()) {
- tmpb = diskstream->playback_buffer(n);
- if (tmpb!=0) {
- b = tmpb;
- }
- }
-
- }
-
- limit = blimit;
-
- } else {
- for (i = 0, n = 1; i < limit; ++i, ++n) {
- memcpy (bufs.get_audio (i).data(), b, sizeof (Sample) * nframes);
- if (n < diskstream->n_channels().n_audio()) {
- tmpb = diskstream->playback_buffer(n);
- if (tmpb!=0) {
- b = tmpb;
- }
- }
- }
-
- /* try to leave any MIDI buffers alone */
-
- ChanCount chn;
- chn.set_audio (limit);
- chn.set_midi (_input->n_ports().n_midi());
- bufs.set_count (chn);
- }
-
- /* final argument: don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
-
- process_output_buffers (
- bufs, start_frame, end_frame, nframes,
- declick,
- (!diskstream->record_enabled() && _session.transport_rolling())
- );
-
- } else {
- /* problem with the diskstream; just be quiet for a bit */
+ if ((dret = diskstream->process (bufs, transport_frame, nframes, playback_distance, (monitoring_state() == MonitoringDisk))) != 0) {
+ need_butler = diskstream->commit (playback_distance);
silence (nframes);
+ return dret;
}
+ process_output_buffers (bufs, start_frame, end_frame, nframes, declick, (!diskstream->record_enabled() && _session.transport_rolling()));
+
need_butler = diskstream->commit (playback_distance);
return 0;
diff --git a/libs/ardour/meter.cc b/libs/ardour/meter.cc
index 3b49c97d27..38c5bb63de 100644
--- a/libs/ardour/meter.cc
+++ b/libs/ardour/meter.cc
@@ -19,6 +19,8 @@
#include <algorithm>
#include <cmath>
+#include "pbd/compose.h"
+
#include "ardour/audio_buffer.h"
#include "ardour/buffer_set.h"
#include "ardour/dB.h"
@@ -33,6 +35,12 @@ using namespace ARDOUR;
PBD::Signal0<void> Metering::Meter;
+PeakMeter::PeakMeter (Session& s, const std::string& name)
+ : Processor (s, string_compose ("meter-%1", name))
+{
+}
+
+
/** Get peaks from @a bufs
* Input acceptance is lenient - the first n buffers from @a bufs will
* be metered, where n was set by the last call to setup(), excess meters will
@@ -55,7 +63,9 @@ PeakMeter::run (BufferSet& bufs, framepos_t /*start_frame*/, framepos_t /*end_fr
// Meter MIDI in to the first n_midi peaks
for (uint32_t i = 0; i < n_midi; ++i, ++n) {
float val = 0.0f;
- for (MidiBuffer::iterator e = bufs.get_midi(i).begin(); e != bufs.get_midi(i).end(); ++e) {
+ MidiBuffer& buf (bufs.get_midi(i));
+
+ for (MidiBuffer::iterator e = buf.begin(); e != buf.end(); ++e) {
const Evoral::MIDIEvent<framepos_t> ev(*e, false);
if (ev.is_note_on()) {
const float this_vel = log(ev.buffer()[2] / 127.0 * (M_E*M_E-M_E) + M_E) - 1.0;
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index cf54bef82e..9c11e818ac 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -26,6 +26,7 @@
#include <fcntl.h>
#include <cstdlib>
#include <ctime>
+#include <strings.h> // for ffs(3)
#include <sys/stat.h>
#include <sys/mman.h>
@@ -320,7 +321,7 @@ get_location_times(const Location* location,
}
int
-MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance)
+MidiDiskstream::process (BufferSet& bufs, framepos_t transport_frame, pframes_t nframes, framecnt_t& playback_distance, bool need_disk_signal)
{
framecnt_t rec_offset = 0;
framecnt_t rec_nframes = 0;
@@ -389,8 +390,11 @@ MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt
// Pump entire port buffer into the ring buffer (FIXME: split cycles?)
MidiBuffer& buf = sp->get_midi_buffer(nframes);
+ ChannelMode mode = AllChannels; // _track->get_capture_channel_mode ();
+ uint32_t mask = 0xffff; // _track->get_capture_channel_mask ();
+
for (MidiBuffer::iterator i = buf.begin(); i != buf.end(); ++i) {
- const Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
+ Evoral::MIDIEvent<MidiBuffer::TimeType> ev(*i, false);
#ifndef NDEBUG
if (DEBUG::MidiIO & PBD::debug_bits) {
const uint8_t* __data = ev.buffer();
@@ -416,8 +420,31 @@ MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt
probabl be implemented in the source instead of here.
*/
const framecnt_t loop_offset = _num_captured_loops * loop_length;
- _capture_buf->write(transport_frame + loop_offset + ev.time(),
- ev.type(), ev.size(), ev.buffer());
+
+ switch (mode) {
+ case AllChannels:
+ _capture_buf->write(transport_frame + loop_offset + ev.time(),
+ ev.type(), ev.size(), ev.buffer());
+ break;
+ case FilterChannels:
+ if (ev.is_channel_event()) {
+ if ((1<<ev.channel()) & mask) {
+ _capture_buf->write(transport_frame + loop_offset + ev.time(),
+ ev.type(), ev.size(), ev.buffer());
+ }
+ } else {
+ _capture_buf->write(transport_frame + loop_offset + ev.time(),
+ ev.type(), ev.size(), ev.buffer());
+ }
+ break;
+ case ForceChannel:
+ if (ev.is_channel_event()) {
+ ev.set_channel (ffs(mask) - 1);
+ }
+ _capture_buf->write(transport_frame + loop_offset + ev.time(),
+ ev.type(), ev.size(), ev.buffer());
+ break;
+ }
}
g_atomic_int_add(&_frames_pending_write, nframes);
@@ -475,6 +502,18 @@ MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt
}
+ if (need_disk_signal) {
+ /* copy the diskstream data to all output buffers */
+
+ MidiBuffer& mbuf (bufs.get_midi (0));
+ get_playback (mbuf, nframes);
+
+ /* leave the audio count alone */
+ ChanCount cnt (DataType::MIDI, 1);
+ cnt.set (DataType::AUDIO, bufs.count().n_audio());
+ bufs.set_count (cnt);
+ }
+
return 0;
}
@@ -1078,10 +1117,6 @@ MidiDiskstream::get_state ()
char buf[64];
LocaleGuard lg (X_("POSIX"));
- node.add_property("channel-mode", enum_2_string(get_channel_mode()));
- snprintf (buf, sizeof(buf), "0x%x", get_channel_mask());
- node.add_property("channel-mask", buf);
-
if (_write_source && _session.get_record_enabled()) {
XMLNode* cs_child = new XMLNode (X_("CapturingSources"));
@@ -1111,7 +1146,6 @@ MidiDiskstream::get_state ()
int
MidiDiskstream::set_state (const XMLNode& node, int version)
{
- const XMLProperty* prop;
XMLNodeList nlist = node.children();
XMLNodeIterator niter;
XMLNode* capture_pending_node = 0;
@@ -1131,26 +1165,10 @@ MidiDiskstream::set_state (const XMLNode& node, int version)
return -1;
}
- ChannelMode channel_mode = AllChannels;
- if ((prop = node.property ("channel-mode")) != 0) {
- channel_mode = ChannelMode (string_2_enum(prop->value(), channel_mode));
- }
-
- unsigned int channel_mask = 0xFFFF;
- if ((prop = node.property ("channel-mask")) != 0) {
- sscanf (prop->value().c_str(), "0x%x", &channel_mask);
- if (channel_mask & (~0xFFFF)) {
- warning << _("MidiDiskstream: XML property channel-mask out of range") << endmsg;
- }
- }
-
-
if (capture_pending_node) {
use_pending_capture_data (*capture_pending_node);
}
- set_channel_mode (channel_mode, channel_mask);
-
in_set_state = false;
return 0;
diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc
index 51d364a3d9..72150f8cfc 100644
--- a/libs/ardour/midi_port.cc
+++ b/libs/ardour/midi_port.cc
@@ -108,7 +108,6 @@ MidiPort::get_midi_buffer (pframes_t nframes)
return *_buffer;
}
-
void
MidiPort::cycle_end (pframes_t /*nframes*/)
{
diff --git a/libs/ardour/midi_ring_buffer.cc b/libs/ardour/midi_ring_buffer.cc
index db3a4cb109..e4ae3f3ffe 100644
--- a/libs/ardour/midi_ring_buffer.cc
+++ b/libs/ardour/midi_ring_buffer.cc
@@ -17,6 +17,7 @@
*/
#include "pbd/compose.h"
+#include "pbd/enumwriter.h"
#include "pbd/error.h"
#include "ardour/debug.h"
@@ -81,17 +82,6 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
bool r = this->peek (&status, sizeof(uint8_t));
assert (r); // If this failed, buffer is corrupt, all hope is lost
- // Ignore event if it doesn't match channel filter
- if (is_channel_event(status) && get_channel_mode() == FilterChannels) {
- const uint8_t channel = status & 0x0F;
- if (!(get_channel_mask() & (1L << channel))) {
- DEBUG_TRACE (DEBUG::MidiDiskstreamIO, string_compose ("MRB skipping event (%3 bytes) due to channel mask (mask = %1 chn = %2)\n",
- get_channel_mask(), (int) channel, ev_size));
- this->increment_read_ptr (ev_size); // Advance read pointer to next event
- continue;
- }
- }
-
/* lets see if we are going to be able to write this event into dst.
*/
uint8_t* write_loc = dst.reserve (ev_time, ev_size);
@@ -130,10 +120,7 @@ MidiRingBuffer<T>::read(MidiBuffer& dst, framepos_t start, framepos_t end, frame
} else if (is_note_off(write_loc[0])) {
_tracker.remove (write_loc[1], write_loc[0] & 0xf);
}
-
- if (is_channel_event(status) && get_channel_mode() == ForceChannel) {
- write_loc[0] = (write_loc[0] & 0xF0) | (get_channel_mask() & 0x0F);
- }
+
++count;
} else {
cerr << "WARNING: error reading event contents from MIDI ring" << endl;
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index 65a42836a3..0f1b2b52af 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -17,6 +17,8 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <strings.h> // for ffs(3)
+
#include "pbd/enumwriter.h"
#include "pbd/convert.h"
#include "evoral/midi_util.h"
@@ -55,6 +57,8 @@ MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mo
, _note_mode(Sustained)
, _step_editing (false)
, _input_active (true)
+ , _playback_channel_mask(0x0000ffff)
+ , _capture_channel_mask(0x0000ffff)
{
}
@@ -158,6 +162,38 @@ MidiTrack::set_state (const XMLNode& node, int version)
set_input_active (string_is_affirmative (prop->value()));
}
+ ChannelMode playback_channel_mode = AllChannels;
+ ChannelMode capture_channel_mode = AllChannels;
+
+ if ((prop = node.property ("playback-channel-mode")) != 0) {
+ playback_channel_mode = ChannelMode (string_2_enum(prop->value(), playback_channel_mode));
+ }
+ if ((prop = node.property ("capture-channel-mode")) != 0) {
+ playback_channel_mode = ChannelMode (string_2_enum(prop->value(), capture_channel_mode));
+ }
+ if ((prop = node.property ("channel-mode")) != 0) {
+ /* 3.0 behaviour where capture and playback modes were not separated */
+ playback_channel_mode = ChannelMode (string_2_enum(prop->value(), playback_channel_mode));
+ capture_channel_mode = playback_channel_mode;
+ }
+
+ unsigned int playback_channel_mask = 0xffff;
+ unsigned int capture_channel_mask = 0xffff;
+
+ if ((prop = node.property ("playback-channel-mask")) != 0) {
+ sscanf (prop->value().c_str(), "0x%x", &playback_channel_mask);
+ }
+ if ((prop = node.property ("capture-channel-mask")) != 0) {
+ sscanf (prop->value().c_str(), "0x%x", &capture_channel_mask);
+ }
+ if ((prop = node.property ("channel-mask")) != 0) {
+ sscanf (prop->value().c_str(), "0x%x", &playback_channel_mask);
+ capture_channel_mask = playback_channel_mask;
+ }
+
+ set_playback_channel_mode (playback_channel_mode, playback_channel_mask);
+ set_capture_channel_mode (capture_channel_mode, capture_channel_mask);
+
pending_state = const_cast<XMLNode*> (&node);
if (_session.state_of_the_state() & Session::Loading) {
@@ -196,6 +232,13 @@ MidiTrack::state(bool full_state)
root.add_child_nocopy (*freeze_node);
}
+ root.add_property("playback_channel-mode", enum_2_string(get_playback_channel_mode()));
+ root.add_property("capture_channel-mode", enum_2_string(get_capture_channel_mode()));
+ snprintf (buf, sizeof(buf), "0x%x", get_playback_channel_mask());
+ root.add_property("playback-channel-mask", buf);
+ snprintf (buf, sizeof(buf), "0x%x", get_capture_channel_mask());
+ root.add_property("capture-channel-mask", buf);
+
root.add_property ("note-mode", enum_2_string (_note_mode));
root.add_property ("step-editing", (_step_editing ? "yes" : "no"));
root.add_property ("input-active", (_input_active ? "yes" : "no"));
@@ -300,25 +343,36 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
playback distance to zero, thus causing diskstream::commit
to do nothing.
*/
- dret = diskstream->process (transport_frame, 0, playback_distance);
+ BufferSet bufs; /* empty set - is OK, since nothing will happen */
+
+ dret = diskstream->process (bufs, transport_frame, 0, playback_distance, false);
need_butler = diskstream->commit (playback_distance);
return dret;
}
+ BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+ fill_buffers_with_input (bufs, _input, nframes);
+
+ if (_meter_point == MeterInput) {
+ _meter->run (bufs, start_frame, end_frame, nframes, true);
+ }
+
+ /* filter captured data before the diskstream sees it */
+
+ filter_channels (bufs, get_capture_channel_mode(), get_capture_channel_mask());
_silent = false;
- if ((dret = diskstream->process (transport_frame, nframes, playback_distance)) != 0) {
+ if ((dret = diskstream->process (bufs, transport_frame, nframes, playback_distance, (monitoring_state() == MonitoringDisk))) != 0) {
need_butler = diskstream->commit (playback_distance);
silence (nframes);
return dret;
}
- /* special condition applies */
-
- if (_meter_point == MeterInput) {
- _input->process_input (_meter, start_frame, end_frame, nframes);
- }
+ /* filter playback data before we do anything else */
+
+ filter_channels (bufs, get_playback_channel_mode(), get_playback_channel_mask ());
if (monitoring_state() == MonitoringInput) {
@@ -334,47 +388,17 @@ MidiTrack::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame
diskstream->flush_playback (start_frame, end_frame);
- passthru (start_frame, end_frame, nframes, 0);
-
- } else {
-
- /*
- XXX is it true that the earlier test on n_outputs()
- means that we can avoid checking it again here? i think
- so, because changing the i/o configuration of an IO
- requires holding the AudioEngine lock, which we hold
- while in the process() tree.
- */
-
-
- /* copy the diskstream data to all output buffers */
-
- BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
- MidiBuffer& mbuf (bufs.get_midi (0));
-
- /* we are a MIDI track, so we always start the chain with a
- * single-MIDI-channel diskstream
- */
- ChanCount c;
- c.set_audio (0);
- c.set_midi (1);
- bufs.set_count (c);
-
- assert (nframes > 0);
-
- diskstream->get_playback (mbuf, nframes);
-
- /* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */
-
- write_out_of_band_data (bufs, start_frame, end_frame, nframes);
-
- /* final argument: don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
+ }
- process_output_buffers (
- bufs, start_frame, end_frame, nframes,
- declick, (!diskstream->record_enabled() && !_session.transport_stopped())
- );
- }
+
+ /* append immediate messages to the first MIDI buffer (thus sending it to the first output port) */
+
+ write_out_of_band_data (bufs, start_frame, end_frame, nframes);
+
+ /* final argument: don't waste time with automation if we're not recording or rolling */
+
+ process_output_buffers (bufs, start_frame, end_frame, nframes,
+ declick, (!diskstream->record_enabled() && !_session.transport_stopped()));
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
boost::shared_ptr<Delivery> d = boost::dynamic_pointer_cast<Delivery> (*i);
@@ -457,6 +481,43 @@ MidiTrack::push_midi_input_to_step_edit_ringbuffer (framecnt_t nframes)
}
}
+void
+MidiTrack::filter_channels (BufferSet& bufs, ChannelMode mode, uint32_t mask)
+{
+ if (mode == AllChannels) {
+ return;
+ }
+
+ MidiBuffer& buf (bufs.get_midi (0));
+
+ for (MidiBuffer::iterator e = buf.begin(); e != buf.end(); ) {
+
+ Evoral::MIDIEvent<framepos_t> ev(*e, false);
+
+ if (ev.is_channel_event()) {
+ switch (mode) {
+ case FilterChannels:
+ if (0 == ((1<<ev.channel()) & mask)) {
+ e = buf.erase (e);
+ } else {
+ ++e;
+ }
+ break;
+ case ForceChannel:
+ ev.set_channel (ffs (mask) - 1);
+ ++e;
+ break;
+ case AllChannels:
+ /* handled by the opening if() */
+ ++e;
+ break;
+ }
+ } else {
+ ++e;
+ }
+ }
+}
+
void
MidiTrack::write_out_of_band_data (BufferSet& bufs, framepos_t /*start*/, framepos_t /*end*/, framecnt_t nframes)
{
@@ -637,21 +698,53 @@ MidiTrack::write_source (uint32_t)
}
void
-MidiTrack::set_channel_mode (ChannelMode mode, uint16_t mask)
+MidiTrack::set_playback_channel_mode(ChannelMode mode, uint16_t mask)
{
- midi_diskstream()->set_channel_mode (mode, mask);
+ ChannelMode old = get_playback_channel_mode ();
+ uint16_t old_mask = get_playback_channel_mask ();
+
+ if (old != mode || mask != old_mask) {
+ _set_playback_channel_mode (mode, mask);
+ PlaybackChannelModeChanged ();
+ _session.set_dirty ();
+ }
}
-ChannelMode
-MidiTrack::get_channel_mode ()
+void
+MidiTrack::set_capture_channel_mode(ChannelMode mode, uint16_t mask)
{
- return midi_diskstream()->get_channel_mode ();
+ ChannelMode old = get_capture_channel_mode ();
+ uint16_t old_mask = get_capture_channel_mask ();
+
+ if (old != mode || mask != old_mask) {
+ _set_capture_channel_mode (mode, mask);
+ CaptureChannelModeChanged ();
+ _session.set_dirty ();
+ }
}
-uint16_t
-MidiTrack::get_channel_mask ()
+void
+MidiTrack::set_playback_channel_mask (uint16_t mask)
{
- return midi_diskstream()->get_channel_mask ();
+ uint16_t old = get_playback_channel_mask();
+
+ if (old != mask) {
+ _set_playback_channel_mask (mask);
+ PlaybackChannelMaskChanged ();
+ _session.set_dirty ();
+ }
+}
+
+void
+MidiTrack::set_capture_channel_mask (uint16_t mask)
+{
+ uint16_t old = get_capture_channel_mask();
+
+ if (old != mask) {
+ _set_capture_channel_mask (mask);
+ CaptureChannelMaskChanged ();
+ _session.set_dirty ();
+ }
}
boost::shared_ptr<MidiPlaylist>
@@ -739,7 +832,7 @@ MidiTrack::act_on_mute ()
if (muted()) {
/* only send messages for channels we are using */
- uint16_t mask = get_channel_mask();
+ uint16_t mask = get_playback_channel_mask();
for (uint8_t channel = 0; channel <= 0xF; channel++) {
@@ -792,3 +885,4 @@ MidiTrack::monitoring_state () const
}
return ms;
}
+
diff --git a/libs/ardour/return.cc b/libs/ardour/return.cc
index 519f3ca494..921be6a53a 100644
--- a/libs/ardour/return.cc
+++ b/libs/ardour/return.cc
@@ -50,7 +50,7 @@ Return::Return (Session& s, bool internal)
/* never muted */
_amp.reset (new Amp (_session));
- _meter.reset (new PeakMeter (_session));
+ _meter.reset (new PeakMeter (_session, name()));
}
Return::~Return ()
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 1a90553be2..9f933e0a4a 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -37,6 +37,7 @@
#include "ardour/amp.h"
#include "ardour/audio_buffer.h"
+#include "ardour/audio_port.h"
#include "ardour/audioengine.h"
#include "ardour/buffer.h"
#include "ardour/buffer_set.h"
@@ -46,6 +47,8 @@
#include "ardour/internal_return.h"
#include "ardour/internal_send.h"
#include "ardour/meter.h"
+#include "ardour/midi_buffer.h"
+#include "ardour/midi_port.h"
#include "ardour/monitor_processor.h"
#include "ardour/pannable.h"
#include "ardour/panner_shell.h"
@@ -139,7 +142,7 @@ Route::init ()
they will be added to _processors by setup_invisible_processors ()
*/
- _meter.reset (new PeakMeter (_session));
+ _meter.reset (new PeakMeter (_session, _name));
_meter->set_display_to_user (false);
_meter->activate ();
@@ -454,8 +457,8 @@ Route::process_output_buffers (BufferSet& bufs,
on a transition between monitoring states we get a de-clicking gain
change in the _main_outs delivery.
*/
- _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
+ _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
/* -------------------------------------------------------------------------------------------
GLOBAL DECLICK (for transport changes etc.)
@@ -561,39 +564,26 @@ Route::n_process_buffers ()
}
void
-Route::passthru (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
+Route::monitor_run (framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
{
- BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+ assert (is_monitor());
+ BufferSet& bufs (_session.get_scratch_buffers (n_process_buffers()));
+ passthru (bufs, start_frame, end_frame, nframes, declick);
+}
+void
+Route::passthru (BufferSet& bufs, framepos_t start_frame, framepos_t end_frame, pframes_t nframes, int declick)
+{
_silent = false;
- assert (bufs.available() >= input_streams());
-
- if (_input->n_ports() == ChanCount::ZERO) {
- silence_unlocked (nframes);
- }
-
- bufs.set_count (input_streams());
-
if (is_monitor() && _session.listening() && !_session.is_auditioning()) {
/* control/monitor bus ignores input ports when something is
feeding the listen "stream". data will "arrive" into the
route from the intreturn processor element.
*/
- bufs.silence (nframes, 0);
-
- } else {
-
- for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
- BufferSet::iterator o = bufs.begin(*t);
- PortSet& ports (_input->ports());
-
- for (PortSet::iterator i = ports.begin(*t); i != ports.end(*t); ++i, ++o) {
- o->read_from (i->get_buffer(nframes), nframes);
- }
- }
+ bufs.silence (nframes, 0);
}
write_out_of_band_data (bufs, start_frame, end_frame, nframes);
@@ -2985,6 +2975,7 @@ int
Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing)
{
Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
+
if (!lm.locked()) {
return 0;
}
@@ -2997,6 +2988,7 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
silence_unlocked (nframes);
return 0;
}
+
if (session_state_changing) {
if (_session.transport_speed() != 0.0f) {
/* we're rolling but some state is changing (e.g. our diskstream contents)
@@ -3012,8 +3004,16 @@ Route::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
*/
}
+ BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+ fill_buffers_with_input (bufs, _input, nframes);
+
+ if (_meter_point == MeterInput) {
+ _meter->run (bufs, start_frame, end_frame, nframes, true);
+ }
+
_amp->apply_gain_automation (false);
- passthru (start_frame, end_frame, nframes, 0);
+ passthru (bufs, start_frame, end_frame, nframes, 0);
return 0;
}
@@ -3043,7 +3043,15 @@ Route::roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, in
_silent = false;
- passthru (start_frame, end_frame, nframes, declick);
+ BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+ fill_buffers_with_input (bufs, _input, nframes);
+
+ if (_meter_point == MeterInput) {
+ _meter->run (bufs, start_frame, end_frame, nframes, true);
+ }
+
+ passthru (bufs, start_frame, end_frame, nframes, declick);
return 0;
}
@@ -4148,3 +4156,90 @@ Route::non_realtime_locate (framepos_t pos)
}
}
}
+
+void
+Route::fill_buffers_with_input (BufferSet& bufs, boost::shared_ptr<IO> io, pframes_t nframes)
+{
+ size_t n_buffers;
+ size_t i;
+
+ /* MIDI
+ *
+ * We don't currently mix MIDI input together, so we don't need the
+ * complex logic of the audio case.
+ */
+
+ n_buffers = bufs.count().n_midi ();
+
+ for (i = 0; i < n_buffers; ++i) {
+
+ boost::shared_ptr<MidiPort> source_port = io->midi (i);
+ MidiBuffer& buf (bufs.get_midi (i));
+
+ if (source_port) {
+ buf.copy (source_port->get_midi_buffer(nframes));
+ } else {
+ buf.silence (nframes);
+ }
+ }
+
+ /* AUDIO */
+
+ n_buffers = bufs.count().n_audio();
+
+ size_t n_ports = io->n_ports().n_audio();
+ float scaling = 1.0f;
+
+ if (n_ports > n_buffers) {
+ scaling = ((float) n_buffers) / n_ports;
+ }
+
+ for (i = 0; i < n_ports; ++i) {
+
+ /* if there are more ports than buffers, map them onto buffers
+ * in a round-robin fashion
+ */
+
+ boost::shared_ptr<AudioPort> source_port = io->audio (i);
+ AudioBuffer& buf (bufs.get_audio (i%n_buffers));
+
+
+ if (i < n_buffers) {
+
+ /* first time through just copy a channel into
+ the output buffer.
+ */
+
+ buf.read_from (source_port->get_audio_buffer (nframes), nframes);
+
+ if (scaling != 1.0f) {
+ buf.apply_gain (scaling, nframes);
+ }
+
+ } else {
+
+ /* on subsequent times around, merge data from
+ * the port with what is already there
+ */
+
+ if (scaling != 1.0f) {
+ buf.accumulate_with_gain_from (source_port->get_audio_buffer (nframes), nframes, 0, scaling);
+ } else {
+ buf.accumulate_from (source_port->get_audio_buffer (nframes), nframes);
+ }
+ }
+ }
+
+ /* silence any remaining buffers */
+
+ for (; i < n_buffers; ++i) {
+ AudioBuffer& buf (bufs.get_audio (i));
+ buf.silence (nframes);
+ }
+
+ /* establish the initial setup of the buffer set, reflecting what was
+ copied into it.
+ */
+
+ bufs.set_count (io->n_ports());
+}
diff --git a/libs/ardour/send.cc b/libs/ardour/send.cc
index fb5c6b7b0c..107cf9862b 100644
--- a/libs/ardour/send.cc
+++ b/libs/ardour/send.cc
@@ -83,7 +83,7 @@ Send::Send (Session& s, boost::shared_ptr<Pannable> p, boost::shared_ptr<MuteMas
boost_debug_shared_ptr_mark_interesting (this, "send");
_amp.reset (new Amp (_session));
- _meter.reset (new PeakMeter (_session));
+ _meter.reset (new PeakMeter (_session, name()));
add_control (_amp->gain_control ());
}
diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc
index 9a4fabeb64..cd7daaf185 100644
--- a/libs/ardour/session_process.cc
+++ b/libs/ardour/session_process.cc
@@ -873,7 +873,7 @@ Session::process_audition (pframes_t nframes)
/* if using a monitor section, run it because otherwise we don't hear anything */
if (auditioner->needs_monitor()) {
- _monitor_out->passthru (_transport_frame, _transport_frame + nframes, nframes, false);
+ _monitor_out->monitor_run (_transport_frame, _transport_frame + nframes, nframes, false);
}
/* handle pending events */
diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc
index 52a960fce6..1effaa45b8 100644
--- a/libs/ardour/track.cc
+++ b/libs/ardour/track.cc
@@ -330,16 +330,21 @@ int
Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame, bool session_state_changing)
{
Glib::Threads::RWLock::ReaderLock lm (_processor_lock, Glib::Threads::TRY_LOCK);
+
if (!lm.locked()) {
return 0;
}
bool can_record = _session.actively_recording ();
+ /* no outputs? nothing to do ... what happens if we have sends etc. ? */
+
if (n_outputs().n_total() == 0) {
return 0;
}
+ /* not active ... do the minimum possible by just outputting silence */
+
if (!_active) {
silence (nframes);
return 0;
@@ -393,14 +398,9 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
}
}
- if (!_have_internal_generator && metering_state() == MeteringInput) {
- _input->process_input (_meter, start_frame, end_frame, nframes);
- }
-
_amp->apply_gain_automation (false);
/* if have_internal_generator, or .. */
- //_input->process_input (_meter, start_frame, end_frame, nframes);
if (be_silent) {
@@ -408,10 +408,15 @@ Track::no_roll (pframes_t nframes, framepos_t start_frame, framepos_t end_frame,
} else {
- /* we're sending signal, but we may still want to meter the input.
- */
+ BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
+
+ fill_buffers_with_input (bufs, _input, nframes);
- passthru (start_frame, end_frame, nframes, false);
+ if (_meter_point == MeterInput) {
+ _meter->run (bufs, start_frame, end_frame, nframes, true);
+ }
+
+ passthru (bufs, start_frame, end_frame, nframes, false);
}
for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
@@ -447,7 +452,10 @@ Track::silent_roll (pframes_t nframes, framepos_t /*start_frame*/, framepos_t /*
silence (nframes);
framecnt_t playback_distance;
- int const dret = _diskstream->process (_session.transport_frame(), nframes, playback_distance);
+
+ BufferSet& bufs (_session.get_silent_buffers (n_process_buffers()));
+
+ int const dret = _diskstream->process (bufs, _session.transport_frame(), nframes, playback_distance, false);
need_butler = _diskstream->commit (playback_distance);
return dret;
}
@@ -934,3 +942,4 @@ Track::metering_state () const
{
return _diskstream->record_enabled() ? MeteringInput : MeteringRoute;
}
+