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:
parent
fbfb26b45c
commit
466500fdaf
@ -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)));
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user