summaryrefslogtreecommitdiff
path: root/libs/ardour/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/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/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
10 files changed, 164 insertions, 102 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
{