X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fmidi_buffer.cc;h=cbf7603c96020f54a80e84cfaa121a4473608de3;hb=706d6e8ff06b32f2b7cefcb09fd81051c3f80735;hp=f724aac1000bf4bec5c0b2c76fc4504bf0976646;hpb=166ef64e3db4ab72b7b1e7455234e2b9ceddf6d8;p=ardour.git diff --git a/libs/ardour/midi_buffer.cc b/libs/ardour/midi_buffer.cc index f724aac100..cbf7603c96 100644 --- a/libs/ardour/midi_buffer.cc +++ b/libs/ardour/midi_buffer.cc @@ -1,39 +1,32 @@ /* - Copyright (C) 2006-2007 Paul Davis + Copyright (C) 2006-2007 Paul Davis Author: Dave Robillard - + 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. */ #include -#include - -#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 +#include "pbd/malign.h" +#include "ardour/midi_buffer.h" using namespace std; using namespace ARDOUR; - // FIXME: mirroring for MIDI buffers? MidiBuffer::MidiBuffer(size_t capacity) : Buffer(DataType::MIDI, capacity) - , _size(0) , _data(0) { if (capacity) { @@ -41,7 +34,7 @@ MidiBuffer::MidiBuffer(size_t capacity) silence(_capacity); } } - + MidiBuffer::~MidiBuffer() { free(_data); @@ -60,12 +53,8 @@ MidiBuffer::resize(size_t size) _size = 0; _capacity = size; + cache_aligned_malloc ((void**) &_data, _capacity); -#ifdef NO_POSIX_MEMALIGN - _data = (uint8_t*)malloc(_capacity); -#else - posix_memalign((void**)&_data, CPU_CACHE_ALIGN, _capacity); -#endif assert(_data); } @@ -84,39 +73,42 @@ MidiBuffer::copy(const MidiBuffer& copy) * Note that offset and nframes refer to sample time, NOT buffer offsets or event counts. */ void -MidiBuffer::read_from(const Buffer& src, nframes_t nframes, nframes_t offset) +MidiBuffer::read_from (const Buffer& src, nframes_t nframes, nframes_t dst_offset, nframes_t src_offset) { - assert(src.type() == DataType::MIDI); - assert(&src != this); + assert (src.type() == DataType::MIDI); + assert (&src != this); + + const MidiBuffer& msrc = (MidiBuffer&) src; - const MidiBuffer& msrc = (MidiBuffer&)src; - - assert(_capacity >= msrc.size()); + assert (_capacity >= msrc.size()); - if (offset == 0) { - clear(); - assert(_size == 0); + if (dst_offset == 0) { + clear (); + assert (_size == 0); } - + + /* XXX use dst_offset somehow */ + for (MidiBuffer::const_iterator i = msrc.begin(); i != msrc.end(); ++i) { const Evoral::MIDIEvent ev(*i, false); - /*cout << this << " MidiBuffer::read_from event type: " << int(ev.type()) - << " time: " << ev.time() << " size: " << ev.size() - << " status: " << (int)*ev.buffer() << " buffer size: " << _size << endl;*/ - if (ev.time() < offset) { - //cout << "MidiBuffer::read_from skipped event before " << offset << endl; - } else if (ev.time() < (nframes + offset)) { - //cout << "MidiBuffer::read_from appending event" << endl; - push_back(ev); - } else { - //cerr << "MidiBuffer::read_from skipped event after " - // << nframes << " + " << offset << endl; + if (ev.time() >= src_offset && ev.time() < (nframes+src_offset)) { + push_back (ev); } } _silent = src.silent(); } +void +MidiBuffer::merge_from (const Buffer& src, nframes_t /*nframes*/, nframes_t /*dst_offset*/, nframes_t /*src_offset*/) +{ + const MidiBuffer* mbuf = dynamic_cast(&src); + assert (mbuf); + assert (mbuf != this); + + /* XXX use nframes, and possible offsets */ + merge_in_place (*mbuf); +} /** Push an event into the buffer. * @@ -129,18 +121,52 @@ bool MidiBuffer::push_back(const Evoral::MIDIEvent& ev) { const size_t stamp_size = sizeof(TimeType); + /*cerr << "MidiBuffer: pushing event @ " << ev.time() + << " size = " << ev.size() << endl;*/ + if (_size + stamp_size + ev.size() >= _capacity) { cerr << "MidiBuffer::push_back failed (buffer is full)" << endl; return false; } + if (!Evoral::midi_event_is_valid(ev.buffer(), ev.size())) { + cerr << "WARNING: MidiBuffer ignoring illegal MIDI event" << endl; + return false; + } + + push_back(ev.time(), ev.size(), ev.buffer()); + + return true; +} + + +/** Push an event into the buffer. + * @return false if operation failed (not enough room) + */ +bool +MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data) +{ + const size_t stamp_size = sizeof(TimeType); + /*cerr << "MidiBuffer: pushing event @ " << ev.time() + << " size = " << ev.size() << endl;*/ + + if (_size + stamp_size + size >= _capacity) { + cerr << "MidiBuffer::push_back failed (buffer is full)" << endl; + return false; + } + + if (!Evoral::midi_event_is_valid(data, size)) { + cerr << "WARNING: MidiBuffer ignoring illegal MIDI event" << endl; + return false; + } + uint8_t* const write_loc = _data + _size; - *((TimeType*)write_loc) = ev.time(); - memcpy(write_loc + stamp_size, ev.buffer(), ev.size()); + *((TimeType*)write_loc) = time; + memcpy(write_loc + stamp_size, data, size); - _size += stamp_size + ev.size(); + _size += stamp_size + size; _silent = false; - + return true; } @@ -161,13 +187,18 @@ MidiBuffer::push_back(const jack_midi_event_t& ev) return false; } + if (!Evoral::midi_event_is_valid(ev.buffer, ev.size)) { + cerr << "WARNING: MidiBuffer ignoring illegal MIDI event" << endl; + return false; + } + uint8_t* const write_loc = _data + _size; *((TimeType*)write_loc) = ev.time; memcpy(write_loc + stamp_size, ev.buffer, ev.size); _size += stamp_size + ev.size; _silent = false; - + return true; } @@ -187,22 +218,26 @@ MidiBuffer::reserve(TimeType time, size_t size) return 0; } - uint8_t* const write_loc = _data + _size; + // write timestamp + uint8_t* write_loc = _data + _size; *((TimeType*)write_loc) = time; + // move write_loc to begin of MIDI buffer data to write to + write_loc += stamp_size; + _size += stamp_size + size; _silent = false; - + return write_loc; } void -MidiBuffer::silence(nframes_t dur, nframes_t offset) +MidiBuffer::silence (nframes_t /*nframes*/, nframes_t /*offset*/) { - // FIXME use parameters - if (offset != 0) - cerr << "WARNING: MidiBuffer::silence w/ offset != 0 (not implemented)" << endl; + /* XXX iterate over existing events, find all in range given by offset & nframes, + and delete them. + */ _size = 0; _silent = true; @@ -225,8 +260,97 @@ MidiBuffer::merge_in_place(const MidiBuffer &other) cerr << "MidiBuffer::merge failed (no space)" << endl; return false; } - - cerr << "FIXME: MIDI BUFFER IN-PLACE MERGE" << endl; + +#ifndef NDEBUG + size_t test_orig_us_size = _size; + size_t test_orig_them_size = other._size; + TimeType test_time = 0; + size_t test_us_count = 0; + size_t test_them_count = 0; + for (iterator i = begin(); i != end(); ++i) { + assert(Evoral::midi_event_is_valid((*i).buffer(), (*i).size())); + assert((*i).time() >= test_time); + test_time = (*i).time(); + ++test_us_count; + } + test_time = 0; + for (const_iterator i = other.begin(); i != other.end(); ++i) { + assert(Evoral::midi_event_is_valid((*i).buffer(), (*i).size())); + assert((*i).time() >= test_time); + test_time = (*i).time(); + ++test_them_count; + } +#endif + + const_iterator them = other.begin(); + iterator us = begin(); + + while (them != other.end()) { + + size_t sz = 0; + ssize_t src = -1; + + /* gather up total size of events that are earlier than + the event referenced by "us" + */ + + while (them != other.end() && (*them).time() <= (*us).time()) { + if (src == -1) { + src = them.offset; + } + sz += sizeof (TimeType) + (*them).size(); + ++them; + } + + if (us != end()) + cerr << "us @ " << (*us).time() << endl; + if (them != other.end()) + cerr << "them @ " << (*them).time() << endl; + + if (sz) { + assert(src >= 0); + /* move existing */ + memmove (_data + us.offset + sz, _data + us.offset, _size - us.offset); + /* increase _size */ + _size += sz; + assert(_size <= _capacity); + /* insert new stuff */ + memcpy (_data + us.offset, other._data + src, sz); + /* update iterator to our own events. this is a miserable hack */ + us.offset += sz; + } else { + + /* advance past our own events to get to the correct insertion + point for the next event(s) from "other" + */ + + while (us != end() && (*us).time() < (*them).time()) { + ++us; + } + } + + if (!(us != end())) { + /* just append the rest of other */ + memcpy (_data + us.offset, other._data + them.offset, other._size - them.offset); + _size += other._size - them.offset; + break; + } + } + +#ifndef NDEBUG + assert(_size == test_orig_us_size + test_orig_them_size); + size_t test_final_count = 0; + test_time = 0; + for (iterator i = begin(); i != end(); ++i) { + cerr << "CHECK " << test_final_count << " / " << test_us_count + test_them_count << endl; + assert(Evoral::midi_event_is_valid((*i).buffer(), (*i).size())); + assert((*i).time() >= test_time); + test_time = (*i).time(); + ++test_final_count; + } + assert(test_final_count = test_us_count + test_them_count); +#endif + return true; } @@ -238,16 +362,41 @@ bool MidiBuffer::merge(const MidiBuffer& a, const MidiBuffer& b) { _size = 0; - + if (this == &a) { - merge_in_place(b); + return merge_in_place(b); + } else if (this == &b) { + return merge_in_place(a); + } + + const_iterator ai = a.begin(); + const_iterator bi = b.begin(); + + resize(a.size() + b.size()); + while (ai != a.end() && bi != b.end()) { + if ((*ai).time() < (*bi).time()) { + memcpy(_data + _size, (*ai).buffer(), (*ai).size()); + _size += (*ai).size(); + ++ai; + } else { + memcpy(_data + _size, (*bi).buffer(), (*bi).size()); + _size += (*bi).size(); + ++bi; + } } - if (this == &b) { - merge_in_place(a); + while (ai != a.end()) { + memcpy(_data + _size, (*ai).buffer(), (*ai).size()); + _size += (*ai).size(); + ++ai; } - - cerr << "FIXME: MIDI BUFFER MERGE" << endl; + + while (bi != b.end()) { + memcpy(_data + _size, (*bi).buffer(), (*bi).size()); + _size += (*bi).size(); + ++bi; + } + return true; }