13
0

* recording/playing/saving/loading program changes basically seems to work now

git-svn-id: svn://localhost/ardour2/branches/3.0@3288 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Hans Baier 2008-04-26 00:12:54 +00:00
parent d9de6f2c4c
commit 0fc3087d7d
3 changed files with 112 additions and 27 deletions

View File

@ -110,7 +110,7 @@ public:
inline Notes& notes() { return _notes; }
inline const Notes& notes() const { return _notes; }
typedef std::vector<MIDI::Event> PgmChanges;
typedef std::vector< boost::shared_ptr<MIDI::Event> > PgmChanges;
inline PgmChanges& pgm_changes() { return _pgm_changes; }
inline const PgmChanges& pgm_changes() const { return _pgm_changes; }
@ -219,6 +219,7 @@ private:
void append_note_on_unlocked(uint8_t chan, double time, uint8_t note, uint8_t velocity);
void append_note_off_unlocked(uint8_t chan, double time, uint8_t note);
void append_cc_unlocked(uint8_t chan, double time, uint8_t number, uint8_t value);
void append_pgm_change_unlocked(uint8_t chan, double time, uint8_t number);
mutable Glib::RWLock _lock;

View File

@ -122,7 +122,7 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
if (_note_iter != model.notes().end()) {
_event = MIDI::Event((*_note_iter)->on_event(), false);
_active_notes.push(*_note_iter);
cerr << " new const iterator: size active notes: " << _active_notes.size() << " is empty: " << _active_notes.empty() << endl;
//cerr << " new const iterator: size active notes: " << _active_notes.size() << " is empty: " << _active_notes.empty() << endl;
++_note_iter;
}
@ -133,16 +133,16 @@ MidiModel::const_iterator::const_iterator(const MidiModel& model, double t)
_pgm_change_iter = model.pgm_changes().end();
// find first program change which begins after t
for (vector<MIDI::Event>::const_iterator i = model.pgm_changes().begin(); i != model.pgm_changes().end(); ++i) {
if (i->time() >= t) {
for (PgmChanges::const_iterator i = model.pgm_changes().begin(); i != model.pgm_changes().end(); ++i) {
if ((*i)->time() >= t) {
_pgm_change_iter = i;
break;
}
}
if(_pgm_change_iter != model.pgm_changes().end()) {
if(_pgm_change_iter->time() <= _event.time()) {
_event = MIDI::Event((*_pgm_change_iter), true);
if((*_pgm_change_iter)->time() <= _event.time()) {
_event = MIDI::Event(*(*_pgm_change_iter), false);
}
}
@ -174,7 +174,15 @@ MidiModel::const_iterator::operator++()
if (_is_end)
throw std::logic_error("Attempt to iterate past end of MidiModel");
assert(_event.is_note() || _event.is_cc());
cerr << "const_iterator::operator++: _event type:" << hex << "0x" << int(_event.type())
<< " buffer: 0x" << int(_event.buffer()[0]) << " 0x" << int(_event.buffer()[1])
<< " 0x" << int(_event.buffer()[2]) << endl;
if(! (_event.is_note() || _event.is_cc() || _event.is_pgm_change())) {
cerr << "FAILED pgm change vector size: " << _model->pgm_changes().size() << endl;
cerr << "FAILED event buffer: " << hex << int(_event.buffer()[0]) << int(_event.buffer()[1]) << int(_event.buffer()[2]) << endl;
}
assert(_event.is_note() || _event.is_cc() || _event.is_pgm_change());
// TODO: This code crashes at the marked section
/*
@ -237,9 +245,12 @@ MidiModel::const_iterator::operator++()
type = CC;
*/
if(_pgm_change_iter != _model->pgm_changes().end()) {
if(_pgm_change_iter->time() <= t) {
if((*_pgm_change_iter)->time() <= t) {
type = PGM_CHANGE;
t = _pgm_change_iter->time();
t = (*_pgm_change_iter)->time();
cerr << "operator++ got PGM CHANGE with time " << t << " and type " << hex
<< int((*_pgm_change_iter)->type()) << " and channel " << int((*_pgm_change_iter)->channel())
<< " and program " << int((*_pgm_change_iter)->pgm_number()) << endl;
}
}
@ -257,7 +268,8 @@ MidiModel::const_iterator::operator++()
_model->control_to_midi_event(_event, *_control_iter);
} else if (type == PGM_CHANGE) {
cerr << "********** MIDI Iterator = program change" << endl;
_event = MIDI::Event(*_pgm_change_iter, true);
_event = MIDI::Event(*(*_pgm_change_iter), false);
++_pgm_change_iter;
} else {
cerr << "********** MIDI Iterator = END" << endl;
_is_end = true;
@ -327,16 +339,16 @@ MidiModel::MidiModel(MidiSource *s, size_t size)
size_t
MidiModel::read(MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes_t stamp_offset, nframes_t negative_stamp_offset) const
{
cerr << this << " MM::read @ " << start << " frames: " << nframes << " -> " << stamp_offset << endl;
cerr << this << " MM # notes: " << n_notes() << endl;
//cerr << this << " MM::read @ " << start << " frames: " << nframes << " -> " << stamp_offset << endl;
//cerr << this << " MM # notes: " << n_notes() << endl;
size_t read_events = 0;
if (start != _next_read) {
_read_iter = const_iterator(*this, (double)start);
cerr << "Repositioning iterator from " << _next_read << " to " << start << endl;
//cerr << "Repositioning iterator from " << _next_read << " to " << start << endl;
} else {
cerr << "Using cached iterator at " << _next_read << endl;
//cerr << "Using cached iterator at " << _next_read << endl;
}
_next_read = start + nframes;
@ -344,11 +356,13 @@ MidiModel::read(MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes
while (_read_iter != end() && _read_iter->time() < start + nframes) {
assert(_read_iter->size() > 0);
dst.write(_read_iter->time() + stamp_offset - negative_stamp_offset, _read_iter->size(), _read_iter->buffer());
cerr << this << " MM::read event @ " << _read_iter->time()
cerr << this << " MidiModel::read event @ " << _read_iter->time()
<< " type: " << hex << int(_read_iter->type()) << dec
<< " note: " << int(_read_iter->note())
<< " velocity: " << int(_read_iter->velocity())
<< endl;
++_read_iter;
++read_events;
}
@ -451,18 +465,23 @@ MidiModel::append(const MIDI::Event& ev)
{
write_lock();
_edited = true;
cerr << "MidiModel::append event type: " << hex << "0x" << int(ev.type()) << endl;
assert(_notes.empty() || ev.time() >= _notes.back()->time());
assert(_writing);
if (ev.is_note_on())
if (ev.is_note_on()) {
append_note_on_unlocked(ev.channel(), ev.time(), ev.note(), ev.velocity());
else if (ev.is_note_off())
} else if (ev.is_note_off()) {
append_note_off_unlocked(ev.channel(), ev.time(), ev.note());
else if (ev.is_cc())
} else if (ev.is_cc()) {
append_cc_unlocked(ev.channel(), ev.time(), ev.cc_number(), ev.cc_value());
else
} else if (ev.is_pgm_change()) {
append_pgm_change_unlocked(ev.channel(), ev.time(), ev.pgm_number());
} else {
printf("MM Unknown event type %X\n", ev.type());
}
write_unlock();
}
@ -532,8 +551,8 @@ MidiModel::append_note_off_unlocked(uint8_t chan, double time, uint8_t note_num)
void
MidiModel::append_cc_unlocked(uint8_t chan, double time, uint8_t number, uint8_t value)
{
cerr << "MidiModel " << this << " chan " << (int)chan <<
" CC " << (int)number << " = " << (int)value << " @ " << time << endl;
//cerr << "MidiModel " << this << " chan " << (int)chan <<
// " CC " << (int)number << " = " << (int)value << " @ " << time << endl;
assert(chan < 16);
assert(_writing);
@ -545,6 +564,25 @@ MidiModel::append_cc_unlocked(uint8_t chan, double time, uint8_t number, uint8_t
control->list()->fast_simple_add(time, (double)value);
}
void
MidiModel::append_pgm_change_unlocked(uint8_t chan, double time, uint8_t number)
{
cerr << "MidiModel::append_pgm_change_unlocked: channel " << int(chan) << " time: " << time << " program number: " << int(number) <<endl;
assert(chan < 16);
assert(_writing);
_edited = true;
boost::shared_ptr<MIDI::Event> event_ptr(new MIDI::Event(time, 3, 0, true));
event_ptr->set_type(MIDI_CMD_PGM_CHANGE);
event_ptr->set_channel(chan);
event_ptr->set_pgm_number(number);
_pgm_changes.push_back(event_ptr);
cerr << "MidiModel::append_pgm_change_unlocked: appended pgm change" << endl;
for(PgmChanges::iterator i = _pgm_changes.begin(); i != _pgm_changes.end(); ++i) {
cerr << "_pgm_changes contents: channel " << int((*i)->channel()) << dec << " time: " << int((*i)->time()) << hex << " program number: " << int(int((*i)->pgm_number())) <<endl;
}
//<< int(_pgm_changes.) << " time: " << time << " program number: " << int(number) <<endl;
}
void
MidiModel::add_note_unlocked(const boost::shared_ptr<Note> note)
@ -820,10 +858,18 @@ MidiModel::DeltaCommand::get_state ()
}
struct EventTimeComparator {
typedef const MIDI::Event* value_type;
inline bool operator()(const MIDI::Event* a,
const MIDI::Event* b) const {
return a->time() >= b->time();
}
};
bool
MidiModel::write_to(boost::shared_ptr<MidiSource> source)
{
//cerr << "Writing model to " << source->name() << endl;
cerr << "Writing model to " << source->name() << endl;
/* This could be done using a temporary MidiRingBuffer and using
* MidiModel::read and MidiSource::write, but this is more efficient
@ -845,9 +891,39 @@ MidiModel::write_to(boost::shared_ptr<MidiSource> source)
read_lock();
LaterNoteEndComparator cmp;
ActiveNotes active_notes(cmp);
//LaterNoteEndComparator cmp;
//ActiveNotes active_notes(cmp);
EventTimeComparator comp;
typedef std::priority_queue<
MIDI::Event*,
std::deque<MIDI::Event*>,
EventTimeComparator> MidiEvents;
MidiEvents events(comp);
for (Notes::const_iterator n = _notes.begin(); n != _notes.end(); ++n) {
events.push(&(*n)->on_event());
events.push(&(*n)->off_event());
}
for (PgmChanges::const_iterator p = _pgm_changes.begin(); p != _pgm_changes.end(); ++p) {
events.push((*p).get());
}
while(!events.empty()) {
source->append_event_unlocked(Frames, *events.top());
cerr << "MidiModel::write_to appending event with time:" << dec << int(events.top()->time()) << hex
<< " buffer: 0x" << int(events.top()->buffer()[0]) << " 0x" << int(events.top()->buffer()[1])
<< " 0x" << int(events.top()->buffer()[2]) << endl;
events.pop();
}
/* Why sort manyally, when a priority queue does the job for us,
* or am I missing something???
*
// Foreach note
for (Notes::const_iterator n = _notes.begin(); n != _notes.end(); ++n) {
@ -862,6 +938,13 @@ MidiModel::write_to(boost::shared_ptr<MidiSource> source)
break;
}
}
// Write program changes preceding this note on
if(p != _pgm_changes.end() && ((*p)->time() <= (*n)->time())) {
const MIDI::Event& pgm_change_event = *(*p);
source->append_event_unlocked(Frames, pgm_change_event);
++p;
}
// Write this note on
source->append_event_unlocked(Frames, (*n)->on_event());
@ -874,7 +957,8 @@ MidiModel::write_to(boost::shared_ptr<MidiSource> source)
source->append_event_unlocked(Frames, active_notes.top()->off_event());
active_notes.pop();
}
*/
_edited = false;
read_unlock();

View File

@ -451,12 +451,12 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
void
SMFSource::append_event_unlocked(EventTimeUnit unit, const MIDI::Event& ev)
{
/*printf("%s - append chan = %u, time = %lf, size = %u, data = ", _path.c_str(),
printf("%s - append chan = %u, time = %lf, size = %u, data = ", _path.c_str(),
(unsigned)ev.channel(), ev.time(), ev.size());
for (size_t i=0; i < ev.size(); ++i) {
printf("%X ", ev.buffer()[i]);
}
printf("\n");*/
printf("\n");
assert(ev.time() >= 0);
assert(ev.time() >= _last_ev_time);