13
0

Channel-aware note recording in MidiModel (i.e. multi-channel note input doesn't cause stuck notes).

Fix MIDI regions randomly displaying 100% stuck notes (uninitialized MidiPlaylist::_note_mode).


git-svn-id: svn://localhost/ardour2/branches/3.0@3084 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard 2008-02-18 23:30:27 +00:00
parent fbfb26b45c
commit 466500fdaf
9 changed files with 62 additions and 34 deletions

View File

@ -760,6 +760,9 @@ Editor::add_sources (vector<Glib::ustring> paths, SourceList& sources, nframes64
region_name = region_name_from_path ((*x)->path(), false, true, sources.size(), n);
cout << "REGION NAME: " << region_name << endl;
cout << "SOURCE LENGTH: " << (*x)->length() << endl;
regions.push_back (RegionFactory::create (just_one, 0, (*x)->length(), region_name, 0,
Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External)));

View File

@ -191,9 +191,9 @@ private:
bool is_sorted() const;
#endif
void append_note_on_unlocked(double time, uint8_t note, uint8_t velocity);
void append_note_off_unlocked(double time, uint8_t note);
void append_cc_unlocked(double time, uint8_t number, uint8_t value);
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);
mutable Glib::RWLock _lock;
@ -201,7 +201,7 @@ private:
NoteMode _note_mode;
typedef std::vector<size_t> WriteNotes;
WriteNotes _write_notes;
WriteNotes _write_notes[16];
bool _writing;
bool _edited;

View File

@ -289,12 +289,6 @@ write_midi_data_to_new_files (SMFReader* source, Session::import_status& status,
if (source->read_event(4, ev.buffer(), &size, &delta_t) < 0)
break;
// FIXME: kluuudge
if (ev.channel() != 0) {
cout << "Skipping event with channel " << ev.channel() << endl;
continue;
}
t += delta_t;
ev.time() = t * (double)source->ppqn();
ev.size() = size;

View File

@ -304,6 +304,7 @@ MidiDiskstream::set_destructive (bool yn)
void
MidiDiskstream::set_note_mode (NoteMode m)
{
cout << "MDS: SET NOTE MODE: " << m << endl;
_note_mode = m;
midi_playlist()->set_note_mode(m);
if (_write_source && _write_source->model())

View File

@ -331,7 +331,8 @@ MidiModel::start_write()
//cerr << "MM " << this << " START WRITE, MODE = " << enum_2_string(_note_mode) << endl;
write_lock();
_writing = true;
_write_notes.clear();
for (int i = 0; i < 16; ++i)
_write_notes[i].clear();
write_unlock();
}
@ -362,7 +363,14 @@ MidiModel::end_write(bool delete_stuck)
}
}
_write_notes.clear();
for (int i = 0; i < 16; ++i) {
if (!_write_notes[i].empty()) {
cerr << "WARNING: MidiModel::end_write: Channel " << i << " has "
<< _write_notes[i].size() << " stuck notes" << endl;
}
_write_notes[i].clear();
}
_writing = false;
write_unlock();
}
@ -383,11 +391,11 @@ MidiModel::append(const MidiEvent& ev)
assert(_writing);
if (ev.is_note_on())
append_note_on_unlocked(ev.time(), ev.note(), ev.velocity());
append_note_on_unlocked(ev.channel(), ev.time(), ev.note(), ev.velocity());
else if (ev.is_note_off())
append_note_off_unlocked(ev.time(), ev.note());
append_note_off_unlocked(ev.channel(), ev.time(), ev.note());
else if (ev.is_cc())
append_cc_unlocked(ev.time(), ev.cc_number(), ev.cc_value());
append_cc_unlocked(ev.channel(), ev.time(), ev.cc_number(), ev.cc_value());
else
printf("MM Unknown event type %X\n", ev.type());
@ -396,32 +404,36 @@ MidiModel::append(const MidiEvent& ev)
void
MidiModel::append_note_on_unlocked(double time, uint8_t note_num, uint8_t velocity)
MidiModel::append_note_on_unlocked(uint8_t chan, double time, uint8_t note_num, uint8_t velocity)
{
//cerr << "MidiModel " << this << " note " << (int)note_num << " on @ " << time << endl;
/*cerr << "MidiModel " << this << " chan " << (int)chan <<
" note " << (int)note_num << " on @ " << time << endl;*/
assert(chan < 16);
assert(_writing);
_notes.push_back(boost::shared_ptr<Note>(new Note(time, 0, note_num, velocity)));
if (_note_mode == Sustained) {
//cerr << "MM Sustained: Appending active note on " << (unsigned)(uint8_t)note_num << endl;
_write_notes.push_back(_notes.size() - 1);
} else {
//cerr << "MM Percussive: NOT appending active note on" << endl;
}
_write_notes[chan].push_back(_notes.size() - 1);
}/* else {
cerr << "MM Percussive: NOT appending active note on" << endl;
}*/
}
void
MidiModel::append_note_off_unlocked(double time, uint8_t note_num)
MidiModel::append_note_off_unlocked(uint8_t chan, double time, uint8_t note_num)
{
//cerr << "MidiModel " << this << " note " << (int)note_num << " off @ " << time << endl;
/*cerr << "MidiModel " << this << " chan " << (int)chan <<
" note " << (int)note_num << " off @ " << time << endl;*/
assert(chan < 16);
assert(_writing);
if (_note_mode == Percussive) {
//cerr << "MM Ignoring note off (percussive mode)" << endl;
cerr << "MidiModel Ignoring note off (percussive mode)" << endl;
return;
} else {
//cerr << "MM Attempting to resolve note off " << (unsigned)(uint8_t)note_num << endl;
}
/* FIXME: make _write_notes fixed size (127 noted) for speed */
@ -429,28 +441,42 @@ MidiModel::append_note_off_unlocked(double time, uint8_t note_num)
/* FIXME: note off velocity for that one guy out there who actually has
* keys that send it */
for (WriteNotes::iterator n = _write_notes.begin(); n != _write_notes.end(); ++n) {
bool resolved = false;
for (WriteNotes::iterator n = _write_notes[chan].begin(); n != _write_notes[chan].end(); ++n) {
Note& note = *_notes[*n].get();
//cerr << (unsigned)(uint8_t)note.note() << " ? " << (unsigned)note_num << endl;
if (note.note() == note_num) {
assert(time >= note.time());
note.set_duration(time - note.time());
_write_notes.erase(n);
_write_notes[chan].erase(n);
//cerr << "MM resolved note, duration: " << note.duration() << endl;
resolved = true;
break;
}
}
if (!resolved)
cerr << "MidiModel " << this << " spurious note off chan " << (int)chan
<< ", note " << (int)note_num << " @ " << time << endl;
}
void
MidiModel::append_cc_unlocked(double time, uint8_t number, uint8_t value)
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;*/
assert(chan < 16);
assert(_writing);
if (chan != 0) // FIXME
cerr << "WARNING: CC on non-0 channel, channel information lost!" << endl;
Parameter param(MidiCCAutomation, number);
boost::shared_ptr<AutomationControl> control = Automatable::control(param, true);
//cerr << "MidiModel " << this << "(" << control.get() << ") add CC " << (int)number << " = " << (int)value
// << " @ " << time << endl;
control->list()->fast_simple_add(time, (double)value);
}

View File

@ -42,6 +42,7 @@ using namespace std;
MidiPlaylist::MidiPlaylist (Session& session, const XMLNode& node, bool hidden)
: Playlist (session, node, DataType::MIDI, hidden)
, _note_mode(Sustained)
{
const XMLProperty* prop = node.property("type");
assert(prop && DataType(prop->value()) == DataType::MIDI);

View File

@ -80,6 +80,7 @@ MidiTrack::MidiTrack (Session& sess, string name, Route::Flag flag, TrackMode mo
MidiTrack::MidiTrack (Session& sess, const XMLNode& node)
: Track (sess, node)
, _immediate_events(1024) // FIXME: size?
, _note_mode(Sustained)
{
_set_state(node, false);
@ -690,6 +691,7 @@ MidiTrack::unfreeze ()
void
MidiTrack::set_note_mode (NoteMode m)
{
cout << _name << " SET NOTE MODE " << m << endl;
_note_mode = m;
midi_diskstream()->set_note_mode(m);
}

View File

@ -130,6 +130,7 @@ Session::Session (AudioEngine &eng,
_session_dir (new SessionDirectory(fullpath)),
pending_events (2048),
//midi_requests (128), // the size of this should match the midi request pool size
post_transport_work((PostTransportWork)0),
_send_smpte_update (false),
diskstreams (new DiskstreamList),
routes (new RouteList),

View File

@ -444,14 +444,14 @@ SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
void
SMFSource::append_event_unlocked(const MidiEvent& ev)
{
/*printf("SMF %s - writing event, time = %lf, size = %u, data = ", _path.c_str(), ev.time(), ev.size());
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);
// FIXME: assumes tempo never changes after start