Channel-aware note recording in MidiModel (i.e. multi-channel note input doesn't...
authorDavid Robillard <d@drobilla.net>
Mon, 18 Feb 2008 23:30:27 +0000 (23:30 +0000)
committerDavid Robillard <d@drobilla.net>
Mon, 18 Feb 2008 23:30:27 +0000 (23:30 +0000)
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

gtk2_ardour/editor_audio_import.cc
libs/ardour/ardour/midi_model.h
libs/ardour/import.cc
libs/ardour/midi_diskstream.cc
libs/ardour/midi_model.cc
libs/ardour/midi_playlist.cc
libs/ardour/midi_track.cc
libs/ardour/session.cc
libs/ardour/smf_source.cc

index 535b65a195c34284d32f8d5db2b5f3afc8c83670..3e1cf4f6485cf4dd88448b4e2083173b8ed90989 100644 (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)));
 
index 8e7d7867225546f10f77b0dae92c3d50c6906115..61b39c914299d4016a0a92771f2d4555a99a0b49 100644 (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;
 
index d4a1bc72e7c9d89fcf60d02f41f03e1d3a33ffdf..b028e1c1a7cdf03dcd702c1a5c4080162341e2f5 100644 (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;
index 921824c615927b16246af54c0b0c660254c28586..7c3bc73fb82c49cb4f76f5b9eba2ff7b5277b3cb 100644 (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())
index 51793a4189ab8a706f382a8bfcee30fc38ada38a..b2c7369eddde6e1f14d400998e34af9c6c3f2b44 100644 (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);
 }
 
index 9720384130701ca22cf55a22b331644cd011b7c2..d8e59efd4aa3caff86a2f84e4a77539adf6c81ba 100644 (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);
index 8e41df84ef4c4ed3e6ef7651c2b17f756d8f2923..e1fa109342489f1e4b83b54aa44e3f86ede9c96a 100644 (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);
 }
index a7c693fb2d698f620a28b1e19269281c426ca08c..52cfc093cc7a02a9bce9989fb1865bb077c24861 100644 (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),
index 59ad7269dbd6b3271955b166059b2a1679a3cda8..4903cf384f2229e6b0b01bf4d8efa0377b596d9c 100644 (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