summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2006-08-16 20:36:14 +0000
committerDavid Robillard <d@drobilla.net>2006-08-16 20:36:14 +0000
commit7250433f50236a05fc652fa41c23bf53fbf6a0fd (patch)
tree0371dfe1b6ce5a9eb1769d10505a6ca658ca1a7b /libs
parent5952c48a848926edb02b5d630e36cc461c893964 (diff)
Progress on the disk side of things:
- MidiRingBuffer implementation - MidiDiskstream reading from playlists - MidiPlaylist reading from regions - MidiRegions returning random notes for the time being, but the inter-thread stuff works.. Horrible awful mess, not really commit worthy, but I need to move machines. Nothing to see here.. :) git-svn-id: svn://localhost/ardour2/branches/midi@835 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs')
-rw-r--r--libs/ardour/ardour/audio_track.h4
-rw-r--r--libs/ardour/ardour/buffer.h27
-rw-r--r--libs/ardour/ardour/buffer_set.h6
-rw-r--r--libs/ardour/ardour/midi_diskstream.h23
-rw-r--r--libs/ardour/ardour/midi_playlist.h4
-rw-r--r--libs/ardour/ardour/midi_port.h16
-rw-r--r--libs/ardour/ardour/midi_region.h14
-rw-r--r--libs/ardour/ardour/midi_ring_buffer.h242
-rw-r--r--libs/ardour/ardour/midi_track.h4
-rw-r--r--libs/ardour/ardour/route.h5
-rw-r--r--libs/ardour/ardour/track.h3
-rw-r--r--libs/ardour/ardour/types.h3
-rw-r--r--libs/ardour/audio_diskstream.cc2
-rw-r--r--libs/ardour/audio_track.cc6
-rw-r--r--libs/ardour/buffer.cc93
-rw-r--r--libs/ardour/io.cc9
-rw-r--r--libs/ardour/midi_diskstream.cc537
-rw-r--r--libs/ardour/midi_playlist.cc32
-rw-r--r--libs/ardour/midi_port.cc40
-rw-r--r--libs/ardour/midi_region.cc44
-rw-r--r--libs/ardour/midi_track.cc81
-rw-r--r--libs/ardour/route.cc6
-rw-r--r--libs/ardour/track.cc2
23 files changed, 816 insertions, 387 deletions
diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h
index 54a8c19a22..bca79b0d7d 100644
--- a/libs/ardour/ardour/audio_track.h
+++ b/libs/ardour/ardour/audio_track.h
@@ -64,10 +64,6 @@ class AudioTrack : public Track
protected:
XMLNode& state (bool full);
- void passthru_silence (jack_nframes_t start_frame, jack_nframes_t end_frame,
- jack_nframes_t nframes, jack_nframes_t offset, int declick,
- bool meter);
-
ChanCount n_process_buffers ();
private:
diff --git a/libs/ardour/ardour/buffer.h b/libs/ardour/ardour/buffer.h
index df7f57455b..896d6e7616 100644
--- a/libs/ardour/ardour/buffer.h
+++ b/libs/ardour/ardour/buffer.h
@@ -181,23 +181,36 @@ public:
~MidiBuffer();
- // FIXME: clear events starting at offset in time
- void silence(jack_nframes_t len, jack_nframes_t offset=0) { assert(offset == 0); _size = 0; }
+ void silence(jack_nframes_t dur, jack_nframes_t offset=0);
void read_from(const Buffer& src, jack_nframes_t nframes, jack_nframes_t offset);
- void set_size(size_t size) { _size = size; }
+ bool push_back(const MidiEvent& event);
+
+ const MidiEvent& operator[](size_t i) const { assert(i < _size); return _events[i]; }
+ MidiEvent& operator[](size_t i) { assert(i < _size); return _events[i]; }
+
+ static size_t max_event_size() { return MAX_EVENT_SIZE; }
+
+ //void set_size(size_t size) { _size = size; }
- const RawMidi* data() const { return _data; }
- RawMidi* data() { return _data; }
+ //const RawMidi* data() const { return _data; }
+ //RawMidi* data() { return _data; }
private:
// These are undefined (prevent copies)
MidiBuffer(const MidiBuffer& copy);
MidiBuffer& operator=(const MidiBuffer& copy);
- bool _owns_data;
- RawMidi* _data; ///< Actual buffer contents
+ // FIXME: Jack needs to tell us this
+ static const size_t MAX_EVENT_SIZE = 4; // bytes
+
+ /* We use _size as "number of events", so the size of _data is
+ * (_size * MAX_EVENT_SIZE)
+ */
+
+ MidiEvent* _events; ///< Event structs that point to offsets in _data
+ RawMidi* _data; ///< MIDI, straight up. No time stamps.
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/buffer_set.h b/libs/ardour/ardour/buffer_set.h
index dfb5dd3611..43df729e05 100644
--- a/libs/ardour/ardour/buffer_set.h
+++ b/libs/ardour/ardour/buffer_set.h
@@ -28,6 +28,7 @@ namespace ARDOUR {
class Buffer;
class AudioBuffer;
+class MidiBuffer;
class PortSet;
@@ -77,6 +78,11 @@ public:
{
return (AudioBuffer&)get(DataType::AUDIO, i);
}
+
+ MidiBuffer& get_midi(size_t i)
+ {
+ return (MidiBuffer&)get(DataType::MIDI, i);
+ }
void read_from(BufferSet& in, jack_nframes_t nframes, jack_nframes_t offset=0)
{
diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h
index 901baf3c64..ccff993638 100644
--- a/libs/ardour/ardour/midi_diskstream.h
+++ b/libs/ardour/ardour/midi_diskstream.h
@@ -45,6 +45,8 @@
#include <ardour/utils.h>
#include <ardour/diskstream.h>
#include <ardour/midi_playlist.h>
+#include <ardour/midi_ring_buffer.h>
+
struct tm;
namespace ARDOUR {
@@ -65,8 +67,7 @@ class MidiDiskstream : public Diskstream
float playback_buffer_load() const;
float capture_buffer_load() const;
- RawMidi* playback_buffer () { return _current_playback_buffer; }
- RawMidi* capture_buffer () { return _current_capture_buffer; }
+ void get_playback(MidiBuffer& dst, jack_nframes_t start, jack_nframes_t end);
void set_record_enabled (bool yn);
@@ -124,7 +125,7 @@ class MidiDiskstream : public Diskstream
int do_refill_with_alloc();
- int read (MidiBuffer& dst, jack_nframes_t& start, jack_nframes_t cnt, bool reversed);
+ int read (jack_nframes_t& start, jack_nframes_t cnt, bool reversed);
void finish_capture (bool rec_monitors_input);
void transport_stopped (struct tm&, time_t, bool abort);
@@ -147,17 +148,17 @@ class MidiDiskstream : public Diskstream
void disengage_record_enable ();
// FIXME: This is basically a single ChannelInfo.. abstractify that concept?
- RingBufferNPT<RawMidi>* _playback_buf;
- RingBufferNPT<RawMidi>* _capture_buf;
- RawMidi* _current_playback_buffer;
- RawMidi* _current_capture_buffer;
- RawMidi* _playback_wrap_buffer;
- RawMidi* _capture_wrap_buffer;
+ MidiRingBuffer* _playback_buf;
+ MidiRingBuffer* _capture_buf;
+ //RawMidi* _current_playback_buffer;
+ //RawMidi* _current_capture_buffer;
+ //RawMidi* _playback_wrap_buffer;
+ //RawMidi* _capture_wrap_buffer;
MidiPort* _source_port;
SMFSource* _write_source; ///< aka capturing source
RingBufferNPT<CaptureTransition>* _capture_transition_buf;
- RingBufferNPT<RawMidi>::rw_vector _playback_vector;
- RingBufferNPT<RawMidi>::rw_vector _capture_vector;
+ //RingBufferNPT<RawMidi>::rw_vector _playback_vector;
+ //RingBufferNPT<RawMidi>::rw_vector _capture_vector;
};
}; /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/midi_playlist.h b/libs/ardour/ardour/midi_playlist.h
index 9e9cf250e2..11627b5a07 100644
--- a/libs/ardour/ardour/midi_playlist.h
+++ b/libs/ardour/ardour/midi_playlist.h
@@ -33,7 +33,7 @@ class Session;
class Region;
class MidiRegion;
class Source;
-class MidiBuffer;
+class MidiRingBuffer;
class MidiPlaylist : public ARDOUR::Playlist
{
@@ -56,7 +56,7 @@ public:
MidiPlaylist (const MidiPlaylist&, jack_nframes_t start, jack_nframes_t cnt,
string name, bool hidden = false);
- jack_nframes_t read (MidiBuffer& buf,
+ jack_nframes_t read (MidiRingBuffer& buf,
jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n=0);
int set_state (const XMLNode&);
diff --git a/libs/ardour/ardour/midi_port.h b/libs/ardour/ardour/midi_port.h
index 3c48f0ce9e..f6eafe11bd 100644
--- a/libs/ardour/ardour/midi_port.h
+++ b/libs/ardour/ardour/midi_port.h
@@ -39,19 +39,23 @@ class MidiPort : public Port {
DataType type() const { return DataType(DataType::MIDI); }
- MidiBuffer& get_buffer() {
- return *_buffer;
+ Buffer& get_buffer() {
+ return _buffer;
+ }
+
+ MidiBuffer& get_midi_buffer() {
+ return _buffer;
}
void cycle_start(jack_nframes_t nframes);
void cycle_end();
- size_t capacity() { return _buffer->capacity(); }
- size_t size() { return _buffer->size(); }
+ 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);
+ _buffer.silence(nframes, offset);
}
protected:
@@ -61,7 +65,7 @@ class MidiPort : public Port {
/* engine isn't supposed to access below here */
- MidiBuffer* _buffer;
+ MidiBuffer _buffer;
jack_nframes_t _nframes_this_cycle;
};
diff --git a/libs/ardour/ardour/midi_region.h b/libs/ardour/ardour/midi_region.h
index 0144f52473..745d3fa4a8 100644
--- a/libs/ardour/ardour/midi_region.h
+++ b/libs/ardour/ardour/midi_region.h
@@ -41,7 +41,7 @@ class Playlist;
class Session;
class MidiFilter;
class MidiSource;
-class MidiBuffer;
+class MidiRingBuffer;
class MidiRegion : public Region
{
@@ -57,16 +57,16 @@ class MidiRegion : public Region
MidiSource& midi_source (uint32_t n=0) const;
- jack_nframes_t read_at (MidiBuffer& out,
+ jack_nframes_t read_at (MidiRingBuffer& dst,
jack_nframes_t position,
- jack_nframes_t cnt,
+ jack_nframes_t dur,
uint32_t chan_n = 0,
jack_nframes_t read_frames = 0,
jack_nframes_t skip_frames = 0) const;
- jack_nframes_t master_read_at (MidiBuffer& buf,
+ jack_nframes_t master_read_at (MidiRingBuffer& dst,
jack_nframes_t position,
- jack_nframes_t cnt,
+ jack_nframes_t dur,
uint32_t chan_n=0) const;
XMLNode& state (bool);
@@ -83,9 +83,9 @@ class MidiRegion : public Region
StateManager::State* state_factory (std::string why) const;
Change restore_state (StateManager::State&);
- jack_nframes_t _read_at (const SourceList&, MidiBuffer& buf,
+ jack_nframes_t _read_at (const SourceList&, MidiRingBuffer& dst,
jack_nframes_t position,
- jack_nframes_t cnt,
+ jack_nframes_t dur,
uint32_t chan_n = 0,
jack_nframes_t read_frames = 0,
jack_nframes_t skip_frames = 0) const;
diff --git a/libs/ardour/ardour/midi_ring_buffer.h b/libs/ardour/ardour/midi_ring_buffer.h
new file mode 100644
index 0000000000..53057dbcba
--- /dev/null
+++ b/libs/ardour/ardour/midi_ring_buffer.h
@@ -0,0 +1,242 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef __ardour_midi_ring_buffer_h__
+#define __ardour_midi_ring_buffer_h__
+
+#include <algorithm>
+#include <ardour/types.h>
+#include <pbd/ringbufferNPT.h>
+#include <ardour/buffer.h>
+
+namespace ARDOUR {
+
+/** A MIDI RingBuffer
+ * (necessary because MIDI events are variable sized so a generic RB won't do).
+ *
+ * ALL publically accessible sizes refer to event COUNTS. What actually goes
+ * on in here is none of the callers business :)
+ */
+class MidiRingBuffer {
+public:
+ MidiRingBuffer (size_t size)
+ : _size(size)
+ , _max_event_size(MidiBuffer::max_event_size())
+ , _ev_buf(new MidiEvent[size])
+ , _raw_buf(new RawMidi[size * _max_event_size])
+ {
+ reset ();
+ assert(read_space() == 0);
+ assert(write_space() == size - 1);
+ }
+
+ virtual ~MidiRingBuffer() {
+ delete[] _ev_buf;
+ delete[] _raw_buf;
+ }
+
+ void reset () {
+ /* !!! NOT THREAD SAFE !!! */
+ g_atomic_int_set (&_write_ptr, 0);
+ g_atomic_int_set (&_read_ptr, 0);
+ }
+
+ size_t write_space () {
+ size_t w, r;
+
+ w = g_atomic_int_get (&_write_ptr);
+ r = g_atomic_int_get (&_read_ptr);
+
+ if (w > r) {
+ return ((r - w + _size) % _size) - 1;
+ } else if (w < r) {
+ return (r - w) - 1;
+ } else {
+ return _size - 1;
+ }
+ }
+
+ size_t read_space () {
+ size_t w, r;
+
+ w = g_atomic_int_get (&_write_ptr);
+ r = g_atomic_int_get (&_read_ptr);
+
+ if (w > r) {
+ return w - r;
+ } else {
+ return (w - r + _size) % _size;
+ }
+ }
+
+ size_t capacity() const { return _size; }
+
+ /** Read one event and appends it to @a out. */
+ //size_t read(MidiBuffer& out);
+
+ /** Write one event (@a in) */
+ size_t write(const MidiEvent& in); // deep copies in
+
+ /** Read events all events up to time @a end into @a out, leaving stamps intact.
+ * Any events before @a start will be dropped. */
+ size_t read(MidiBuffer& out, jack_nframes_t start, jack_nframes_t end);
+
+ /** Write all events from @a in, applying @a offset to all time stamps */
+ size_t write(const MidiBuffer& in, jack_nframes_t offset = 0);
+
+ inline void clear_event(size_t index);
+
+private:
+
+ // _event_ indices
+ mutable gint _write_ptr;
+ mutable gint _read_ptr;
+
+ size_t _size; // size (capacity) in events
+ size_t _max_event_size; // ratio of raw_buf size to ev_buf size
+ MidiEvent* _ev_buf; // these point into...
+ RawMidi* _raw_buf; // this
+
+};
+
+/** Just for sanity checking */
+inline void
+MidiRingBuffer::clear_event(size_t index)
+{
+ memset(&_ev_buf[index].buffer, 0, _max_event_size);
+ _ev_buf[index].time = 0;
+ _ev_buf[index].size = 0;
+ _ev_buf[index].buffer = 0;
+
+}
+#if 0
+inline size_t
+MidiRingBuffer::read (MidiBuffer& buf)
+{
+ const size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
+
+ if (read_space() == 0) {
+ return 0;
+ } else {
+ MidiEvent* const read_ev = &_ev_buf[priv_read_ptr];
+ assert(read_ev->size > 0);
+ buf.push_back(*read_ev);
+ printf("MRB - read %xd %d %d with time %u at index %zu\n",
+ read_ev->buffer[0], read_ev->buffer[1], read_ev->buffer[2], read_ev->time,
+ priv_read_ptr);
+ clear_event(priv_read_ptr);
+ g_atomic_int_set(&_read_ptr, (priv_read_ptr + 1) % _size);
+ return 1;
+ }
+}
+#endif
+inline size_t
+MidiRingBuffer::write (const MidiEvent& ev)
+{
+ //static jack_nframes_t last_write_time = 0;
+
+ assert(ev.size > 0);
+
+ size_t priv_write_ptr = g_atomic_int_get(&_write_ptr);
+
+ if (write_space () == 0) {
+ return 0;
+ } else {
+ //assert(ev.time >= last_write_time);
+
+ const size_t raw_index = priv_write_ptr * _max_event_size;
+
+ MidiEvent* const write_ev = &_ev_buf[priv_write_ptr];
+ *write_ev = ev;
+
+ memcpy(&_raw_buf[raw_index], ev.buffer, ev.size);
+ write_ev->buffer = &_raw_buf[raw_index];
+ g_atomic_int_set(&_write_ptr, (priv_write_ptr + 1) % _size);
+
+ printf("MRB - wrote %xd %d %d with time %u at index %zu (raw index %zu)\n",
+ write_ev->buffer[0], write_ev->buffer[1], write_ev->buffer[2], write_ev->time,
+ priv_write_ptr, raw_index);
+
+ assert(write_ev->size = ev.size);
+
+ //last_write_time = ev.time;
+ printf("(W) read space: %zu\n", read_space());
+
+ return 1;
+ }
+}
+
+inline size_t
+MidiRingBuffer::read(MidiBuffer& dst, jack_nframes_t start, jack_nframes_t end)
+{
+ if (read_space() == 0)
+ return 0;
+
+ size_t priv_read_ptr = g_atomic_int_get(&_read_ptr);
+ jack_nframes_t time = _ev_buf[priv_read_ptr].time;
+ size_t count = 0;
+ size_t limit = read_space();
+
+ while (time <= end && limit > 0) {
+ MidiEvent* const read_ev = &_ev_buf[priv_read_ptr];
+ if (time >= start) {
+ dst.push_back(*read_ev);
+ printf("MRB - read %xd %d %d with time %u at index %zu\n",
+ read_ev->buffer[0], read_ev->buffer[1], read_ev->buffer[2], read_ev->time,
+ priv_read_ptr);
+ } else {
+ cerr << "MRB: LOST EVENT!" << endl;
+ }
+
+ clear_event(priv_read_ptr);
+
+ ++count;
+ --limit;
+
+ priv_read_ptr = (priv_read_ptr + 1) % _size;
+
+ assert(read_ev->time <= end);
+ time = _ev_buf[priv_read_ptr].time;
+ }
+
+ g_atomic_int_set(&_read_ptr, priv_read_ptr);
+ printf("(R) read space: %zu\n", read_space());
+
+ return count;
+}
+
+inline size_t
+MidiRingBuffer::write(const MidiBuffer& in, jack_nframes_t offset)
+{
+ size_t num_events = in.size();
+ size_t to_write = std::min(write_space(), num_events);
+
+ // FIXME: double copy :/
+ for (size_t i=0; i < to_write; ++i) {
+ MidiEvent ev = in[i];
+ ev.time += offset;
+ write(ev);
+ }
+
+ return to_write;
+}
+
+} // 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 654eb98e30..409aa171e9 100644
--- a/libs/ardour/ardour/midi_track.h
+++ b/libs/ardour/ardour/midi_track.h
@@ -76,10 +76,6 @@ public:
protected:
XMLNode& state (bool full);
- void passthru_silence (jack_nframes_t start_frame, jack_nframes_t end_frame,
- jack_nframes_t nframes, jack_nframes_t offset, int declick,
- bool meter);
-
ChanCount n_process_buffers ();
private:
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h
index db5cddca39..107abb7b48 100644
--- a/libs/ardour/ardour/route.h
+++ b/libs/ardour/ardour/route.h
@@ -309,10 +309,13 @@ class Route : public IO
bool meter);
protected:
- /* for derived classes */
virtual XMLNode& state(bool);
+ void passthru_silence (jack_nframes_t start_frame, jack_nframes_t end_frame,
+ jack_nframes_t nframes, jack_nframes_t offset, int declick,
+ bool meter);
+
void silence (jack_nframes_t nframes, jack_nframes_t offset);
sigc::connection input_signal_connection;
diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h
index 15a0a28aab..2b317a0299 100644
--- a/libs/ardour/ardour/track.h
+++ b/libs/ardour/ardour/track.h
@@ -95,9 +95,6 @@ class Track : public Route
virtual XMLNode& state (bool full) = 0;
- virtual void passthru_silence (jack_nframes_t start_frame, jack_nframes_t end_frame,
- jack_nframes_t nframes, jack_nframes_t offset, int declick, bool meter) = 0;
-
virtual ChanCount n_process_buffers () = 0;
Diskstream *_diskstream;
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index 00833f6547..d5bfded460 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -50,7 +50,8 @@ namespace ARDOUR {
typedef uint32_t layer_t;
typedef uint64_t microseconds_t;
- typedef jack_midi_event_t RawMidi;
+ typedef jack_midi_event_t MidiEvent;
+ typedef unsigned char RawMidi;
enum IOChange {
NoChange = 0,
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index 784a14bb2b..40c8e3301b 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -968,7 +968,7 @@ AudioDiskstream::seek (jack_nframes_t frame, bool complete_refill)
{
Glib::Mutex::Lock lm (state_lock);
uint32_t n;
- int ret;
+ int ret = -1;
ChannelList::iterator chan;
for (n = 0, chan = channels.begin(); chan != channels.end(); ++chan, ++n) {
diff --git a/libs/ardour/audio_track.cc b/libs/ardour/audio_track.cc
index 52cc7726c9..b12b79858e 100644
--- a/libs/ardour/audio_track.cc
+++ b/libs/ardour/audio_track.cc
@@ -406,12 +406,6 @@ AudioTrack::n_process_buffers ()
return max (_diskstream->n_channels(), redirect_max_outs);
}
-void
-AudioTrack::passthru_silence (jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset, int declick, bool meter)
-{
- process_output_buffers (_session.get_silent_buffers (n_process_buffers()), start_frame, end_frame, nframes, offset, true, declick, meter);
-}
-
int
AudioTrack::no_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t offset,
bool session_state_changing, bool can_record, bool rec_monitors_input)
diff --git a/libs/ardour/buffer.cc b/libs/ardour/buffer.cc
index fa4669cef6..7b99f2a900 100644
--- a/libs/ardour/buffer.cc
+++ b/libs/ardour/buffer.cc
@@ -16,8 +16,11 @@
675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <ardour/buffer.h>
+#include <algorithm>
#include <iostream>
+using std::cerr; using std::endl;
+
+#include <ardour/buffer.h>
namespace ARDOUR {
@@ -62,47 +65,95 @@ AudioBuffer::~AudioBuffer()
// FIXME: mirroring for MIDI buffers?
MidiBuffer::MidiBuffer(size_t capacity)
: Buffer(DataType::MIDI, capacity)
- , _owns_data(true)
+// , _owns_data(true)
+ , _events(NULL)
, _data(NULL)
{
assert(capacity > 0);
- _size = capacity; // For audio buffers, size = capacity (always)
+ _size = 0;
+
#ifdef NO_POSIX_MEMALIGN
- _data = (RawMidi *) malloc(sizeof(RawMidi) * capacity);
+ _events = (MidiEvent *) malloc(sizeof(MidiEvent) * capacity);
+ _data = (RawMidi *) malloc(sizeof(RawMidi) * capacity * MAX_EVENT_SIZE);
#else
- posix_memalign((void**)&_data, 16, sizeof(RawMidi) * capacity);
+ posix_memalign((void**)&_events, 16, sizeof(MidiEvent) * capacity);
+ posix_memalign((void**)&_data, 16, sizeof(RawMidi) * capacity * MAX_EVENT_SIZE);
#endif
assert(_data);
- memset(_data, 0, sizeof(RawMidi) * capacity);
+ assert(_events);
+ silence(_capacity);
}
MidiBuffer::~MidiBuffer()
{
- if (_owns_data)
- free(_data);
+ free(_events);
+ free(_data);
}
-/** Note that offset and nframes refer to sample time, not actual buffer locations */
+/** Read events from @a src starting at time @a offset into the START of this buffer, for
+ * time direction @a nframes. Relative time, where 0 = start of buffer.
+ *
+ * Note that offset and nframes refer to sample time, NOT buffer offsets or event counts.
+ */
void
MidiBuffer::read_from(const Buffer& src, jack_nframes_t nframes, jack_nframes_t offset)
{
- // FIXME: offsets? param semantics?
- assert(src.type() == _type);
assert(src.type() == DataType::MIDI);
- assert(offset == 0);
- MidiBuffer& msrc = (MidiBuffer&)src;
- _size = 0;
- for (size_t i=0; i < msrc.size() && msrc.data()[i].time < nframes; ++i) {
- assert(i < _capacity);
- _data[i] = msrc.data()[i];
- ++_size;
+ const MidiBuffer& msrc = (MidiBuffer&)src;
+
+ assert(_capacity >= src.size());
+
+ clear();
+ assert(_size == 0);
+
+ // FIXME: This is embarrassingly slow. branch branch branch
+ 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);
+ }
}
- assert(_size == msrc.size());
+}
- //if (_size > 0)
- // std::cerr << "MidiBuffer wrote " << _size << " events.\n";
+
+/** Push an event into the buffer.
+ *
+ * Note that the raw MIDI pointed to by ev will be COPIED and unmodified.
+ * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM).
+ * Realtime safe.
+ * @return false if operation failed (not enough room)
+ */
+bool
+MidiBuffer::push_back(const MidiEvent& ev)
+{
+ if (_size == _capacity)
+ return false;
+
+ RawMidi* const write_loc = _data + (_size * MAX_EVENT_SIZE);
+
+ memcpy(write_loc, ev.buffer, ev.size);
+ _events[_size] = ev;
+ _events[_size].buffer = write_loc;
+ ++_size;
+
+ //cerr << "MidiBuffer: pushed, size = " << _size << endl;
+
+ return true;
+}
+
+
+void
+MidiBuffer::silence(jack_nframes_t dur, jack_nframes_t offset)
+{
+ // FIXME use parameters
+ assert(offset == 0);
+ //assert(dur == _capacity);
+
+ memset(_events, 0, sizeof(MidiEvent) * _capacity);
+ memset(_data, 0, sizeof(RawMidi) * _capacity * MAX_EVENT_SIZE);
+ _size = 0;
}
diff --git a/libs/ardour/io.cc b/libs/ardour/io.cc
index fce8c3f1d8..430801310d 100644
--- a/libs/ardour/io.cc
+++ b/libs/ardour/io.cc
@@ -213,15 +213,12 @@ IO::deliver_output (BufferSet& bufs, jack_nframes_t start_frame, jack_nframes_t
return;
}
- const DataType type = DataType::MIDI; // type type type type...
+ const DataType type = DataType::MIDI;
// Just dump any MIDI 1-to-1, we're not at all clever with MIDI routing yet
BufferSet::iterator o = output_buffers().begin(type);
- for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i) {
-
- for (PortSet::iterator i = _inputs.begin(type); i != _inputs.end(type); ++i, ++o) {
- o->read_from(i->get_buffer(), nframes, offset);
- }
+ for (BufferSet::iterator i = bufs.begin(type); i != bufs.end(type); ++i, ++o) {
+ o->read_from(*i, nframes, offset);
}
}
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index 86a95a3cc0..223cfc15f6 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -61,10 +61,10 @@ MidiDiskstream::MidiDiskstream (Session &sess, const string &name, Diskstream::F
: Diskstream(sess, name, flag)
, _playback_buf(0)
, _capture_buf(0)
- , _current_playback_buffer(0)
- , _current_capture_buffer(0)
- , _playback_wrap_buffer(0)
- , _capture_wrap_buffer(0)
+ //, _current_playback_buffer(0)
+ //, _current_capture_buffer(0)
+ //, _playback_wrap_buffer(0)
+ //, _capture_wrap_buffer(0)
, _source_port(0)
, _write_source(0)
, _capture_transition_buf(0)
@@ -86,10 +86,10 @@ MidiDiskstream::MidiDiskstream (Session& sess, const XMLNode& node)
: Diskstream(sess, node)
, _playback_buf(0)
, _capture_buf(0)
- , _current_playback_buffer(0)
- , _current_capture_buffer(0)
- , _playback_wrap_buffer(0)
- , _capture_wrap_buffer(0)
+ //, _current_playback_buffer(0)
+ //, _current_capture_buffer(0)
+ //, _playback_wrap_buffer(0)
+ //, _capture_wrap_buffer(0)
, _source_port(0)
, _write_source(0)
, _capture_transition_buf(0)
@@ -124,10 +124,10 @@ MidiDiskstream::init (Diskstream::Flag f)
set_block_size (_session.get_block_size());
allocate_temporary_buffers ();
- _playback_wrap_buffer = new RawMidi[wrap_buffer_size];
- _capture_wrap_buffer = new RawMidi[wrap_buffer_size];
- _playback_buf = new RingBufferNPT<RawMidi> (_session.diskstream_buffer_size());
- _capture_buf = new RingBufferNPT<RawMidi> (_session.diskstream_buffer_size());
+ //_playback_wrap_buffer = new RawMidi[wrap_buffer_size];
+ //_capture_wrap_buffer = new RawMidi[wrap_buffer_size];
+ _playback_buf = new MidiRingBuffer (_session.diskstream_buffer_size());
+ _capture_buf = new MidiRingBuffer (_session.diskstream_buffer_size());
_capture_transition_buf = new RingBufferNPT<CaptureTransition> (128);
_n_channels = ChanCount(DataType::MIDI, 1);
@@ -435,9 +435,9 @@ MidiDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes,
bool nominally_recording;
bool re = record_enabled ();
bool collect_playback = false;
-
- _current_capture_buffer = 0;
- _current_playback_buffer = 0;
+
+ /*_current_capture_buffer = 0;
+ _current_playback_buffer = 0;*/
/* if we've already processed the frames corresponding to this call,
just return. this allows multiple routes that are taking input
@@ -445,7 +445,7 @@ MidiDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes,
this stuff only happen once. more commonly, it allows both
the AudioTrack that is using this AudioDiskstream *and* the Session
to call process() without problems.
- */
+ */
if (_processed) {
return 0;
@@ -463,58 +463,58 @@ MidiDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes,
/* This lock is held until the end of AudioDiskstream::commit, so these two functions
must always be called as a pair. The only exception is if this function
returns a non-zero value, in which case, ::commit should not be called.
- */
+ */
// If we can't take the state lock return.
if (!state_lock.trylock()) {
return 1;
}
-
+
adjust_capture_position = 0;
if (nominally_recording || (_session.get_record_enabled() && _session.get_punch_in())) {
OverlapType ot;
-
+
ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
switch (ot) {
- case OverlapNone:
- rec_nframes = 0;
- break;
-
- case OverlapInternal:
- /* ---------- recrange
- |---| transrange
- */
- rec_nframes = nframes;
- rec_offset = 0;
- break;
-
- case OverlapStart:
- /* |--------| recrange
- -----| transrange
- */
- rec_nframes = transport_frame + nframes - first_recordable_frame;
- if (rec_nframes) {
+ case OverlapNone:
+ rec_nframes = 0;
+ break;
+
+ case OverlapInternal:
+ /* ---------- recrange
+ |---| transrange
+ */
+ rec_nframes = nframes;
+ rec_offset = 0;
+ break;
+
+ case OverlapStart:
+ /* |--------| recrange
+ -----| transrange
+ */
+ rec_nframes = transport_frame + nframes - first_recordable_frame;
+ if (rec_nframes) {
+ rec_offset = first_recordable_frame - transport_frame;
+ }
+ break;
+
+ case OverlapEnd:
+ /* |--------| recrange
+ |-------- transrange
+ */
+ rec_nframes = last_recordable_frame - transport_frame;
+ rec_offset = 0;
+ break;
+
+ case OverlapExternal:
+ /* |--------| recrange
+ -------------- transrange
+ */
+ rec_nframes = last_recordable_frame - last_recordable_frame;
rec_offset = first_recordable_frame - transport_frame;
- }
- break;
-
- case OverlapEnd:
- /* |--------| recrange
- |-------- transrange
- */
- rec_nframes = last_recordable_frame - transport_frame;
- rec_offset = 0;
- break;
-
- case OverlapExternal:
- /* |--------| recrange
- -------------- transrange
- */
- rec_nframes = last_recordable_frame - last_recordable_frame;
- rec_offset = first_recordable_frame - transport_frame;
- break;
+ break;
}
if (rec_nframes && !was_recording) {
@@ -529,64 +529,20 @@ MidiDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes,
}
if (nominally_recording || rec_nframes) {
- _capture_buf->get_write_vector (&_capture_vector);
-
- if (rec_nframes <= _capture_vector.len[0]) {
-
- _current_capture_buffer = _capture_vector.buf[0];
-
- /* note: grab the entire port buffer, but only copy what we were supposed to for recording, and use
- rec_offset
- */
-
- // FIXME: midi buffer size?
-
- // FIXME: reading from a MIDI port is different, can't just memcpy
- //memcpy (_current_capture_buffer, _io->input(0)->get_buffer (rec_nframes) + offset + rec_offset, sizeof (RawMidi) * rec_nframes);
- assert(_source_port);
-
- /*for (size_t i=0; i < _source_port->size(); ++i) {
- cerr << "DISKSTREAM GOT EVENT(1) " << i << "!!\n";
- }
-
- if (_source_port->size() == 0)
- cerr << "No events :/ (1)\n";
- */
+ assert(_source_port);
- } else {
-
- jack_nframes_t total = _capture_vector.len[0] + _capture_vector.len[1];
-
- if (rec_nframes > total) {
- cerr << "DiskOverrun\n";
- //DiskOverrun (); // FIXME
- goto out;
- }
-
- // FIXME (see above)
- //RawMidi* buf = _io->input (0)->get_buffer (nframes) + offset;
- assert(_source_port);
-
- /*
- for (size_t i=0; i < _source_port->size(); ++i) {
- cerr << "DISKSTREAM GOT EVENT(2) " << i << "!!\n";
- }
- if (_source_port->size() == 0)
- cerr << "No events :/ (2)\n";
- */
+ // Pump entire port buffer into the ring buffer (FIXME!)
+ _capture_buf->write(_source_port->get_midi_buffer(), transport_frame);
- RawMidi* buf = NULL; // FIXME FIXME FIXME (make it compile)
- assert(false);
- jack_nframes_t first = _capture_vector.len[0];
+ /*
+ for (size_t i=0; i < _source_port->size(); ++i) {
+ cerr << "DISKSTREAM GOT EVENT(1) " << i << "!!\n";
+ }
- memcpy (_capture_wrap_buffer, buf, sizeof (RawMidi) * first);
- memcpy (_capture_vector.buf[0], buf, sizeof (RawMidi) * first);
- memcpy (_capture_wrap_buffer+first, buf + first, sizeof (RawMidi) * (rec_nframes - first));
- memcpy (_capture_vector.buf[1], buf + first, sizeof (RawMidi) * (rec_nframes - first));
-
- _current_capture_buffer = _capture_wrap_buffer;
- }
+ if (_source_port->size() == 0)
+ cerr << "No events :/ (1)\n";
+ */
} else {
if (was_recording) {
@@ -594,38 +550,19 @@ MidiDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes,
}
}
-
+
if (rec_nframes) {
-
- // FIXME: filthy hack to fool the GUI into thinking we're doing something
- //if (_write_source)
- // _write_source->ViewDataRangeReady (transport_frame, rec_nframes); /* EMIT SIGNAL */
+ /* XXX XXX XXX XXX XXX XXX XXX XXX */
/* data will be written to disk */
- if (rec_nframes == nframes && rec_offset == 0) {
-
- _current_playback_buffer = _current_capture_buffer;
- playback_distance = nframes;
-
- } else {
-
-
- /* we can't use the capture buffer as the playback buffer, because
- we recorded only a part of the current process' cycle data
- for capture.
- */
-
- collect_playback = true;
- }
-
adjust_capture_position = rec_nframes;
} else if (nominally_recording) {
/* can't do actual capture yet - waiting for latency effects to finish before we start*/
- _current_playback_buffer = _current_capture_buffer;
+ throw; // forget all that jazz!
playback_distance = nframes;
@@ -647,84 +584,22 @@ MidiDiskstream::process (jack_nframes_t transport_frame, jack_nframes_t nframes,
} else {
necessary_samples = nframes;
}
-
- _playback_buf->get_read_vector (&_playback_vector);
-
- if (necessary_samples <= _playback_vector.len[0]) {
-
- _current_playback_buffer = _playback_vector.buf[0];
-
- } else {
- jack_nframes_t total = _playback_vector.len[0] + _playback_vector.len[1];
-
- if (necessary_samples > total) {
- //cerr << "DiskUnderrun\n";
- //DiskUnderrun (); // FIXME
- //goto out;
-
- } else {
-
- memcpy (_playback_wrap_buffer, _playback_vector.buf[0],
- _playback_vector.len[0] * sizeof (RawMidi));
- memcpy (_playback_wrap_buffer + _playback_vector.len[0], _playback_vector.buf[1],
- (necessary_samples - _playback_vector.len[0]) * sizeof (RawMidi));
-
- _current_playback_buffer = _playback_wrap_buffer;
- }
- }
-
-#if 0
- if (rec_nframes == 0 && _actual_speed != 1.0f && _actual_speed != -1.0f) {
-
- uint64_t phase = last_phase;
- jack_nframes_t i = 0;
-
- // Linearly interpolate into the alt buffer
- // using 40.24 fixp maths (swh)
-
- for (c = channels.begin(); c != channels.end(); ++c) {
-
- float fr;
- ChannelInfo& chan (*c);
-
- i = 0;
- phase = last_phase;
-
- for (jack_nframes_t outsample = 0; outsample < nframes; ++outsample) {
- i = phase >> 24;
- fr = (phase & 0xFFFFFF) / 16777216.0f;
- chan.speed_buffer[outsample] =
- chan._current_playback_buffer[i] * (1.0f - fr) +
- chan._current_playback_buffer[i+1] * fr;
- phase += phi;
- }
-
- chan._current_playback_buffer = chan.speed_buffer;
- }
-
- playback_distance = i + 1;
- last_phase = (phase & 0xFFFFFF);
-
- } else {
- playback_distance = nframes;
- }
-#endif
- playback_distance = nframes;
+ // XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
+ // Write into playback buffer here, and whatnot
}
ret = 0;
- out:
_processed = true;
if (ret) {
/* we're exiting with failure, so ::commit will not
be called. unlock the state lock.
- */
-
+ */
+
state_lock.unlock();
}
@@ -746,24 +621,27 @@ MidiDiskstream::commit (jack_nframes_t nframes)
playback_sample += playback_distance;
}
- _playback_buf->increment_read_ptr (playback_distance);
-
- if (adjust_capture_position) {
- _capture_buf->increment_write_ptr (adjust_capture_position);
- }
-
+ /* XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX */
+
+ /*
+ _playback_buf->increment_read_ptr (playback_distance);
+
+ if (adjust_capture_position) {
+ _capture_buf->increment_write_ptr (adjust_capture_position);
+ }
+
if (adjust_capture_position != 0) {
capture_captured += adjust_capture_position;
adjust_capture_position = 0;
}
-
+
if (_slaved) {
need_butler = _playback_buf->write_space() >= _playback_buf->bufsize() / 2;
} else {
need_butler = _playback_buf->write_space() >= disk_io_chunk_frames
|| _capture_buf->read_space() >= disk_io_chunk_frames;
}
-
+ */
state_lock.unlock();
_processed = false;
@@ -792,24 +670,126 @@ int
MidiDiskstream::seek (jack_nframes_t frame, bool complete_refill)
{
Glib::Mutex::Lock lm (state_lock);
- return 0;
+ int ret = -1;
+
+ _playback_buf->reset();
+ _capture_buf->reset();
+
+ playback_sample = frame;
+ file_frame = frame;
+
+ if (complete_refill) {
+ while ((ret = do_refill_with_alloc ()) > 0) ;
+ } else {
+ ret = do_refill_with_alloc ();
+ }
+
+ return ret;
}
int
MidiDiskstream::can_internal_playback_seek (jack_nframes_t distance)
{
- return 0;
+ if (_playback_buf->read_space() < distance) {
+ return false;
+ } else {
+ return true;
+ }
}
int
MidiDiskstream::internal_playback_seek (jack_nframes_t distance)
{
+ first_recordable_frame += distance;
+ playback_sample += distance;
+
return 0;
}
+/** @a start is set to the new frame position (TIME) read up to */
int
-MidiDiskstream::read (MidiBuffer& dst, jack_nframes_t& start, jack_nframes_t cnt, bool reversed)
-{
+MidiDiskstream::read (jack_nframes_t& start, jack_nframes_t dur, bool reversed)
+{
+ jack_nframes_t this_read = 0;
+ bool reloop = false;
+ jack_nframes_t loop_end = 0;
+ jack_nframes_t loop_start = 0;
+ jack_nframes_t loop_length = 0;
+ Location *loc = 0;
+
+ if (!reversed) {
+ /* Make the use of a Location atomic for this read operation.
+
+ Note: Locations don't get deleted, so all we care about
+ when I say "atomic" is that we are always pointing to
+ the same one and using a start/length values obtained
+ just once.
+ */
+
+ if ((loc = loop_location) != 0) {
+ loop_start = loc->start();
+ loop_end = loc->end();
+ loop_length = loop_end - loop_start;
+ }
+
+ /* if we are looping, ensure that the first frame we read is at the correct
+ position within the loop.
+ */
+
+ if (loc && start >= loop_end) {
+ //cerr << "start adjusted from " << start;
+ start = loop_start + ((start - loop_start) % loop_length);
+ //cerr << "to " << start << endl;
+ }
+ //cerr << "start is " << start << " loopstart: " << loop_start << " loopend: " << loop_end << endl;
+ }
+
+ while (dur) {
+
+ /* take any loop into account. we can't read past the end of the loop. */
+
+ if (loc && (loop_end - start < dur)) {
+ this_read = loop_end - start;
+ //cerr << "reloop true: thisread: " << this_read << " dur: " << dur << endl;
+ reloop = true;
+ } else {
+ reloop = false;
+ this_read = dur;
+ }
+
+ if (this_read == 0) {
+ break;
+ }
+
+ this_read = min(dur,this_read);
+
+ if (midi_playlist()->read (*_playback_buf, start, this_read) != this_read) {
+ error << string_compose(_("MidiDiskstream %1: cannot read %2 from playlist at frame %3"), _id, this_read,
+ start) << endmsg;
+ return -1;
+ }
+
+ _read_data_count = _playlist->read_data_count();
+
+ if (reversed) {
+
+ cerr << "Reversed MIDI.. that's just crazy talk." << endl;
+ // Swap note ons with note offs here
+
+ } else {
+
+ /* if we read to the end of the loop, go back to the beginning */
+
+ if (reloop) {
+ start = loop_start;
+ } else {
+ start += this_read;
+ }
+ }
+
+ dur -= this_read;
+ }
+
return 0;
}
@@ -822,8 +802,94 @@ MidiDiskstream::do_refill_with_alloc ()
int
MidiDiskstream::do_refill ()
{
- // yeah, the data's ready. promise.
- return 0;
+ int32_t ret = 0;
+ size_t write_space = _playback_buf->write_space();
+
+ bool reversed = (_visible_speed * _session.transport_speed()) < 0.0f;
+
+ if (write_space == 0) {
+ return 0;
+ }
+
+ /* if there are 2+ chunks of disk i/o possible for
+ this track, let the caller know so that it can arrange
+ for us to be called again, ASAP.
+ */
+
+ // FIXME: using disk_io_chunk_frames as an event count, not good
+ if (_playback_buf->write_space() >= (_slaved?3:2) * disk_io_chunk_frames) {
+ ret = 1;
+ }
+
+ /* if we're running close to normal speed and there isn't enough
+ space to do disk_io_chunk_frames of I/O, then don't bother.
+
+ at higher speeds, just do it because the sync between butler
+ and audio thread may not be good enough.
+ */
+
+ if ((write_space < disk_io_chunk_frames) && fabs (_actual_speed) < 2.0f) {
+ cerr << "No refill 1\n";
+ return 0;
+ }
+
+ /* when slaved, don't try to get too close to the read pointer. this
+ leaves space for the buffer reversal to have something useful to
+ work with.
+ */
+
+ if (_slaved && write_space < (_playback_buf->capacity() / 2)) {
+ cerr << "No refill 2\n";
+ return 0;
+ }
+
+ if (reversed) {
+ cerr << "No refill 3 (reverse)\n";
+ return 0;
+ }
+
+ if (file_frame == max_frames) {
+ cerr << "No refill 4 (EOF)\n";
+
+ /* at end: nothing to do */
+
+ return 0;
+ }
+
+#if 0
+ // or this
+ if (file_frame > max_frames - total_space) {
+
+ /* to close to the end: read what we can, and zero fill the rest */
+
+ zero_fill = total_space - (max_frames - file_frame);
+ total_space = max_frames - file_frame;
+
+ } else {
+ zero_fill = 0;
+ }
+#endif
+
+ // At this point we:
+ assert(_playback_buf->write_space() > 0); // ... have something to write to, and
+ assert(file_frame <= max_frames); // ... something to write
+
+ // So (read it, then) write it:
+
+ jack_nframes_t file_frame_tmp = file_frame;
+ jack_nframes_t to_read = min(disk_io_chunk_frames, (max_frames - file_frame));
+
+ // FIXME: read count?
+ if (read (file_frame_tmp, to_read, reversed)) {
+ ret = -1;
+ goto out;
+ }
+
+ file_frame = file_frame_tmp;
+
+out:
+
+ return ret;
}
/** Flush pending data to disk.
@@ -1338,14 +1404,14 @@ float
MidiDiskstream::playback_buffer_load () const
{
return (float) ((double) _playback_buf->read_space()/
- (double) _playback_buf->bufsize());
+ (double) _playback_buf->capacity());
}
float
MidiDiskstream::capture_buffer_load () const
{
return (float) ((double) _capture_buf->write_space()/
- (double) _capture_buf->bufsize());
+ (double) _capture_buf->capacity());
}
@@ -1354,3 +1420,48 @@ MidiDiskstream::use_pending_capture_data (XMLNode& node)
{
return 0;
}
+
+/** Writes playback events in the given range to dst, translating time stamps
+ * so that an event at start has time = 0
+ */
+void
+MidiDiskstream::get_playback(MidiBuffer& dst, jack_nframes_t start, jack_nframes_t end)
+{
+ assert(end > start);
+ dst.clear();
+ assert(dst.size() == 0);
+/*
+ cerr << "MIDI Diskstream pretending to read" << endl;
+
+ MidiEvent ev;
+ RawMidi data[4];
+
+ const char note = rand()%30 + 30;
+
+ ev.buffer = data;
+ ev.time = 0;
+ ev.size = 3;
+
+ data[0] = 0x90;
+ data[1] = note;
+ data[2] = 120;
+
+ dst.push_back(ev);
+
+ ev.buffer = data;
+ ev.time = (end - start) / 2;
+ ev.size = 3;
+
+ data[0] = 0x80;
+ data[1] = note;
+ data[2] = 64;
+*/
+ _playback_buf->read(dst, start, end);
+
+ // Translate time stamps to be relative to the start of this cycle
+ for (size_t i=0; i < dst.size(); ++i) {
+ assert(dst[i].time >= start);
+ assert(dst[i].time <= end);
+ dst[i].time -= start;
+ }
+}
diff --git a/libs/ardour/midi_playlist.cc b/libs/ardour/midi_playlist.cc
index 582df6f5be..051203e55e 100644
--- a/libs/ardour/midi_playlist.cc
+++ b/libs/ardour/midi_playlist.cc
@@ -30,6 +30,7 @@
#include <ardour/midi_playlist.h>
#include <ardour/midi_region.h>
#include <ardour/session.h>
+#include <ardour/midi_ring_buffer.h>
#include <pbd/error.h>
@@ -118,8 +119,8 @@ MidiPlaylist::MidiPlaylist (const MidiPlaylist& other, string name, bool hidden)
}
}
-MidiPlaylist::MidiPlaylist (const MidiPlaylist& other, jack_nframes_t start, jack_nframes_t cnt, string name, bool hidden)
- : Playlist (other, start, cnt, name, hidden)
+MidiPlaylist::MidiPlaylist (const MidiPlaylist& other, jack_nframes_t start, jack_nframes_t dur, string name, bool hidden)
+ : Playlist (other, start, dur, name, hidden)
{
save_state (_("initial state"));
@@ -168,10 +169,10 @@ struct RegionSortByLayer
}
};
-/** FIXME: semantics of return value? */
+/** Returns the number of frames in time duration read (eg could be large when 0 events are read) */
jack_nframes_t
-MidiPlaylist::read (MidiBuffer& buf, jack_nframes_t start,
- jack_nframes_t cnt, unsigned chan_n)
+MidiPlaylist::read (MidiRingBuffer& dst, jack_nframes_t start,
+ jack_nframes_t dur, unsigned chan_n)
{
/* this function is never called from a realtime thread, so
its OK to block (for short intervals).
@@ -180,11 +181,11 @@ MidiPlaylist::read (MidiBuffer& buf, jack_nframes_t start,
Glib::Mutex::Lock rm (region_lock);
jack_nframes_t ret = 0;
- jack_nframes_t end = start + cnt - 1;
- jack_nframes_t read_frames = 0;
- jack_nframes_t skip_frames = 0;
+ jack_nframes_t end = start + dur - 1;
+ //jack_nframes_t read_frames = 0;
+ //jack_nframes_t skip_frames = 0;
- _read_data_count = 0;
+ //_read_data_count = 0;
vector<MidiRegion*> regs; // relevent regions overlapping start <--> end
@@ -199,13 +200,15 @@ MidiPlaylist::read (MidiBuffer& buf, jack_nframes_t start,
sort(regs.begin(), regs.end(), layer_cmp);
for (vector<MidiRegion*>::iterator i = regs.begin(); i != regs.end(); ++i) {
- (*i)->read_at (buf, start, cnt, chan_n, read_frames, skip_frames);
- ret += (*i)->read_data_count();
+ // FIXME: ensure time is monotonic here
+ (*i)->read_at (dst, start, dur, chan_n, 0, 0);// FIXME read_frames, skip_frames);
+ ret += (*i)->read_data_count();
}
_read_data_count += ret;
- return ret;
+ //return ret; FIXME?
+ return dur;
}
@@ -386,8 +389,7 @@ MidiPlaylist::drop_all_states ()
/* delete every region that is left - these are all things that are part of our "history" */
- for (set
- <Region *>::iterator ar = all_regions.begin(); ar != all_regions.end(); ++ar) {
+ for (set<Region *>::iterator ar = all_regions.begin(); ar != all_regions.end(); ++ar) {
(*ar)->unlock_sources ();
delete *ar;
}
@@ -587,6 +589,8 @@ MidiPlaylist::region_changed (Change what_changed, Region* region)
return false;
}
+ // Feeling rather uninterested today, but thanks for the heads up anyway!
+
Change our_interests = Change (/*MidiRegion::FadeInChanged|
MidiRegion::FadeOutChanged|
MidiRegion::FadeInActiveChanged|
diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc
index 83322dedb6..f4d1912061 100644
--- a/libs/ardour/midi_port.cc
+++ b/libs/ardour/midi_port.cc
@@ -26,7 +26,7 @@ using namespace std;
MidiPort::MidiPort(jack_port_t* p)
: Port(p)
- , _buffer(NULL)
+ , _buffer(4096) // FIXME FIXME FIXME Jack needs to tell us this
, _nframes_this_cycle(0)
{
DataType dt(_type);
@@ -34,22 +34,25 @@ MidiPort::MidiPort(jack_port_t* p)
reset();
- _buffer = new MidiBuffer(4096); // FIXME FIXME FIXME
+
}
MidiPort::~MidiPort()
{
- delete _buffer;
}
void
MidiPort::cycle_start (jack_nframes_t nframes)
{
+ _buffer.clear();
+ assert(_buffer.size() == 0);
+
_nframes_this_cycle = nframes;
if (_flags & JackPortIsOutput) {
- _buffer->set_size(0);
+ _buffer.silence(nframes);
+ assert(_buffer.size() == 0);
return;
}
@@ -60,21 +63,26 @@ MidiPort::cycle_start (jack_nframes_t nframes)
const jack_nframes_t event_count
= jack_midi_port_get_info(jack_buffer, nframes)->event_count;
- assert(event_count < _buffer->capacity());
+ assert(event_count < _buffer.capacity());
+ MidiEvent ev;
+
+ // FIXME: too slow, event struct is copied twice (here and MidiBuffer::push_back)
for (jack_nframes_t i=0; i < event_count; ++i) {
- jack_midi_event_t* const ev = &_buffer->data()[i];
- jack_midi_event_get(ev, jack_buffer, i, nframes);
+ // This will fail to compile if we change MidiEvent to our own class
+ jack_midi_event_get(static_cast<jack_midi_event_t*>(&ev), jack_buffer, i, nframes);
+
+ _buffer.push_back(ev);
// Convert note ons with velocity 0 to proper note offs
// FIXME: Jack MIDI should guarantee this - does it?
//if (ev->buffer[0] == MIDI_CMD_NOTE_ON && ev->buffer[2] == 0)
// ev->buffer[0] = MIDI_CMD_NOTE_OFF;
}
- _buffer->set_size(event_count);
-
- //if (_buffer->size() > 0)
+ assert(_buffer.size() == event_count);
+
+ //if (_buffer.size() > 0)
// cerr << "MIDIPort got " << event_count << " events." << endl;
}
@@ -82,7 +90,7 @@ void
MidiPort::cycle_end()
{
if (_flags & JackPortIsInput) {
- _nframes_this_cycle = 0; // catch any oopses
+ _nframes_this_cycle = 0;
return;
}
@@ -90,13 +98,17 @@ MidiPort::cycle_end()
void* jack_buffer = jack_port_get_buffer(_port, _nframes_this_cycle);
- const jack_nframes_t event_count = _buffer->size();
+ const jack_nframes_t event_count = _buffer.size();
+
+ //if (event_count > 0)
+ // cerr << "MIDIPort writing " << event_count << " events." << endl;
jack_midi_clear_buffer(jack_buffer, _nframes_this_cycle);
for (jack_nframes_t i=0; i < event_count; ++i) {
- const jack_midi_event_t& ev = _buffer->data()[i];
+ const jack_midi_event_t& ev = _buffer[i];
+ assert(ev.time < _nframes_this_cycle);
jack_midi_event_write(jack_buffer, ev.time, ev.buffer, ev.size, _nframes_this_cycle);
}
- _nframes_this_cycle = 0; // catch oopses
+ _nframes_this_cycle = 0;
}
diff --git a/libs/ardour/midi_region.cc b/libs/ardour/midi_region.cc
index 84b03b9aa9..9098bf6f40 100644
--- a/libs/ardour/midi_region.cc
+++ b/libs/ardour/midi_region.cc
@@ -39,6 +39,7 @@
#include <ardour/playlist.h>
#include <ardour/midi_source.h>
#include <ardour/types.h>
+#include <ardour/midi_ring_buffer.h>
#include "i18n.h"
#include <locale.h>
@@ -178,25 +179,51 @@ MidiRegion::get_memento() const
}
jack_nframes_t
-MidiRegion::read_at (MidiBuffer& out, jack_nframes_t position,
- jack_nframes_t cnt,
+MidiRegion::read_at (MidiRingBuffer& out, jack_nframes_t position,
+ jack_nframes_t dur,
uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const
{
- return _read_at (_sources, out, position, cnt, chan_n, read_frames, skip_frames);
+ return _read_at (_sources, out, position, dur, chan_n, read_frames, skip_frames);
}
jack_nframes_t
-MidiRegion::master_read_at (MidiBuffer& out, jack_nframes_t position,
- jack_nframes_t cnt, uint32_t chan_n) const
+MidiRegion::master_read_at (MidiRingBuffer& out, jack_nframes_t position,
+ jack_nframes_t dur, uint32_t chan_n) const
{
- return _read_at (_master_sources, out, position, cnt, chan_n, 0, 0);
+ return _read_at (_master_sources, out, position, dur, chan_n, 0, 0);
}
jack_nframes_t
-MidiRegion::_read_at (const SourceList& srcs, MidiBuffer& buf,
- jack_nframes_t position, jack_nframes_t cnt,
+MidiRegion::_read_at (const SourceList& srcs, MidiRingBuffer& dst,
+ jack_nframes_t position, jack_nframes_t dur,
uint32_t chan_n, jack_nframes_t read_frames, jack_nframes_t skip_frames) const
{
+ MidiEvent ev;
+ RawMidi data[4];
+
+ const char note = rand()%30 + 30;
+
+ ev.buffer = data;
+ ev.time = position;
+ ev.size = 3;
+ data[0] = 0x90;
+ data[1] = note;
+ data[2] = 120;
+ dst.write(ev);
+
+ ev.buffer = data;
+ ev.time = (jack_nframes_t)(position + (9/10.0 * dur));
+ assert(ev.time < position + dur);
+ ev.size = 3;
+ data[0] = 0x80;
+ data[1] = note;
+ data[2] = 64;
+ dst.write(ev);
+
+ _read_data_count += dur;
+
+ return dur;
+#if 0
jack_nframes_t internal_offset;
jack_nframes_t buf_offset;
jack_nframes_t to_read;
@@ -240,6 +267,7 @@ MidiRegion::_read_at (const SourceList& srcs, MidiBuffer& buf,
_read_data_count += src.read_data_count();
return to_read;
+#endif
}
XMLNode&
diff --git a/libs/ardour/midi_track.cc b/libs/ardour/midi_track.cc
index 470759f3ac..91aad5ea80 100644
--- a/libs/ardour/midi_track.cc
+++ b/libs/ardour/midi_track.cc
@@ -32,6 +32,7 @@
#include <ardour/midi_playlist.h>
#include <ardour/panner.h>
#include <ardour/utils.h>
+#include <ardour/buffer_set.h>
#include "i18n.h"
@@ -354,23 +355,18 @@ MidiTrack::n_process_buffers ()
return max (_diskstream->n_channels(), redirect_max_outs);
}
-void
-MidiTrack::passthru_silence (jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset, int declick, bool meter)
-{
- process_output_buffers (_session.get_silent_buffers (n_process_buffers()), start_frame, end_frame, nframes, offset, true, declick, meter);
-}
-
int
MidiTrack::no_roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t offset,
bool session_state_changing, bool can_record, bool rec_monitors_input)
{
if (n_outputs().get(DataType::MIDI) == 0) {
- return 0;
+ //return 0;
+ throw; // FIXME
}
if (!_active) {
silence (nframes, offset);
- return 0;
+ //return 0; // FIXME
}
if (session_state_changing) {
@@ -444,13 +440,9 @@ int
MidiTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t offset, int declick,
bool can_record, bool rec_monitors_input)
{
- //passthru (start_frame, end_frame, nframes, offset, declick, false);
int dret;
- RawMidi* b; // FIXME: this won't work, duh
- //Sample* tmpb;
- jack_nframes_t transport_frame;
MidiDiskstream& diskstream = midi_diskstream();
-
+
{
Glib::RWLock::ReaderLock lm (redirect_lock, Glib::TRY_LOCK);
if (lm.locked()) {
@@ -459,7 +451,7 @@ MidiTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframe
automation_snapshot (start_frame);
}
}
-
+
if (n_outputs().get_total() == 0 && _redirects.empty()) {
return 0;
}
@@ -469,28 +461,27 @@ MidiTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframe
return 0;
}
- transport_frame = _session.transport_frame();
+ jack_nframes_t transport_frame = _session.transport_frame();
if ((nframes = check_initial_delay (nframes, offset, transport_frame)) == 0) {
/* need to do this so that the diskstream sets its
playback distance to zero, thus causing diskstream::commit
to do nothing.
- */
+ */
return diskstream.process (transport_frame, 0, 0, can_record, rec_monitors_input);
}
_silent = false;
- //apply_gain_automation = false;
if ((dret = diskstream.process (transport_frame, nframes, offset, can_record, rec_monitors_input)) != 0) {
-
+
silence (nframes, offset);
return dret;
}
/* special condition applies */
-
+
if (_meter_point == MeterInput) {
just_meter_input (start_frame, end_frame, nframes, offset);
}
@@ -499,53 +490,30 @@ MidiTrack::roll (jack_nframes_t nframes, jack_nframes_t start_frame, jack_nframe
/* not actually recording, but we want to hear the input material anyway,
at least potentially (depending on monitoring options)
- */
+ */
passthru (start_frame, end_frame, nframes, offset, 0, true);
- } else if ((b = diskstream.playback_buffer()) != 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.
- */
+ 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 */
-
+
//const size_t limit = n_process_buffers().get(DataType::AUDIO);
BufferSet& bufs = _session.get_scratch_buffers (n_process_buffers());
-
- //uint32_t n;
- //uint32_t i;
-#if 0
- for (i = 0, n = 1; i < limit; ++i, ++n) {
- memcpy (bufs.get_audio(i).data(nframes), b, sizeof (Sample) * nframes);
- if (n < diskstream.n_channels().get(DataType::AUDIO)) {
- tmpb = diskstream.playback_buffer(n);
- if (tmpb!=0) {
- b = tmpb;
- }
- }
- }
- /* don't waste time with automation if we're recording or we've just stopped (yes it can happen) */
+ diskstream.get_playback(bufs.get_midi(0), start_frame, end_frame);
- if (!diskstream.record_enabled() && _session.transport_rolling()) {
- Glib::Mutex::Lock am (automation_lock, Glib::TRY_LOCK);
-
- if (am.locked() && gain_automation_playback()) {
- apply_gain_automation = _gain_automation_curve.rt_safe_get_vector (start_frame, end_frame, _session.gain_automation_buffer(), nframes);
- }
- }
-#endif
- process_output_buffers (bufs, start_frame, end_frame, nframes, offset, (!_session.get_record_enabled() || !_session.get_do_not_record_plugins()), declick, (_meter_point != MeterInput));
-
- } else {
- /* problem with the diskstream; just be quiet for a bit */
- silence (nframes, offset);
+ process_output_buffers (bufs, start_frame, end_frame, nframes, offset,
+ (!_session.get_record_enabled() || !_session.get_do_not_record_plugins()), declick, (_meter_point != MeterInput));
+
}
return 0;
@@ -584,7 +552,6 @@ MidiTrack::process_output_buffers (BufferSet& bufs,
// Main output stage is the only stage we've got.
// I think it's a pretty good stage though, wouldn't you say?
-
if (muted()) {
IO::silence(nframes, offset);
diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc
index 757c40452f..2ea6c314c1 100644
--- a/libs/ardour/route.cc
+++ b/libs/ardour/route.cc
@@ -680,6 +680,12 @@ Route::passthru (jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nfra
}
void
+Route::passthru_silence (jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset, int declick, bool meter)
+{
+ process_output_buffers (_session.get_silent_buffers (n_process_buffers()), start_frame, end_frame, nframes, offset, true, declick, meter);
+}
+
+void
Route::set_solo (bool yn, void *src)
{
if (_solo_safe) {
diff --git a/libs/ardour/track.cc b/libs/ardour/track.cc
index aa2f12aa65..28816541f1 100644
--- a/libs/ardour/track.cc
+++ b/libs/ardour/track.cc
@@ -224,7 +224,7 @@ Track::set_name (string str, void *src)
if ((ret = IO::set_name (str, src)) == 0) {
_session.save_state ("");
- _session.save_history ("");
+ _session.save_history ("");
}
return ret;
}