optimize some performance bottlenecks; remove jack_nframes_t that crept back into...
[ardour.git] / libs / ardour / buffer.cc
index 85b9317f78ee8f83434781a1fff556f1a9fcb111..7635ea2199e044f30ad0ddfdbf5fd156cfe15a8b 100644 (file)
     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>
+
+#ifdef __x86_64__
+static const int CPU_CACHE_ALIGN = 64;
+#else
+static const int CPU_CACHE_ALIGN = 16; /* arguably 32 on most arches, but it matters less */
+#endif
 
 namespace ARDOUR {
 
@@ -36,6 +45,7 @@ Buffer::create(DataType type, size_t capacity)
 
 AudioBuffer::AudioBuffer(size_t capacity)
        : Buffer(DataType::AUDIO, capacity)
+       , _owns_data(false)
        , _data(NULL)
 {
        _size = capacity; // For audio buffers, size = capacity (always)
@@ -43,13 +53,11 @@ AudioBuffer::AudioBuffer(size_t capacity)
 #ifdef NO_POSIX_MEMALIGN
                _data =  (Sample *) malloc(sizeof(Sample) * capacity);
 #else
-               posix_memalign((void**)&_data, 16, sizeof(Sample) * capacity);
+               posix_memalign((void**)&_data, CPU_CACHE_ALIGN, sizeof(Sample) * capacity);
 #endif 
                assert(_data);
-               clear();
                _owns_data = true;
-       } else {
-               _owns_data = false;
+               clear();
        }
 }
 
@@ -62,47 +70,100 @@ 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, CPU_CACHE_ALIGN, sizeof(MidiEvent) * capacity);
+       posix_memalign((void**)&_data, CPU_CACHE_ALIGN, 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)
+MidiBuffer::read_from(const Buffer& src, nframes_t nframes, 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: slow
+       for (size_t i=0; i < src.size(); ++i) {
+               const MidiEvent& ev = msrc[i];
+               if (ev.time >= offset && ev.time < offset+nframes) {
+                       push_back(ev);
+               }
        }
-       assert(_size == msrc.size());
 
-       if (_size > 0)
-               std::cerr << "MidiBuffer wrote " << _size << " events.\n";
+       _silent = src.silent();
+}
+
+
+/** 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;
+
+       _silent = false;
+
+       return true;
+}
+
+
+void
+MidiBuffer::silence(nframes_t dur, 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;
+       _silent = true;
 }