smf_source: implement SMF::UsedChannels, and move midi screening into load_model()

Some MIDI sources (esp immediately after import) are not yet on disk,
 but are only in memory.  So Open() does not properly initalize
 data like UsedChannels and program info
This commit is contained in:
Ben Loftis 2022-02-24 14:30:08 -06:00
parent 9266e47558
commit c83b8396c2
4 changed files with 46 additions and 59 deletions

View file

@ -76,6 +76,9 @@ public:
void prevent_deletion ();
void set_path (const std::string& newpath);
/** Query the smf file for its channel info */
SMF::UsedChannels used_midi_channels();
protected:
void close ();
void flush_midi (const Lock& lock);

View file

@ -52,6 +52,7 @@
#include "ardour/midi_state_tracker.h"
#include "ardour/parameter_types.h"
#include "ardour/session.h"
#include "ardour/segment_descriptor.h"
#include "ardour/smf_source.h"
#include "pbd/i18n.h"
@ -670,6 +671,11 @@ SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload
Evoral::event_id_t event_id;
bool have_event_id;
_num_channels = 0;
_n_note_on_events = 0;
_has_pgm_change = false;
_used_channels.reset ();
// TODO simplify event allocation
std::list< std::pair< Evoral::Event<Temporal::Beats>*, gint > > eventlist;
@ -691,6 +697,23 @@ SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload
continue;
}
/* aggregate information about channels and pgm-changes */
uint8_t type = buf[0] & 0xf0;
uint8_t chan = buf[0] & 0x0f;
if (type >= 0x80 && type <= 0xE0) {
_used_channels.set(chan);
switch (type) {
case MIDI_CMD_NOTE_ON:
++_n_note_on_events;
break;
case MIDI_CMD_PGM_CHANGE:
_has_pgm_change = true;
break;
default:
break;
}
}
if (ret > 0) {
/* not a meta-event */
@ -730,6 +753,8 @@ SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload
}
}
_num_channels = _used_channels.size();
eventlist.sort(compare_eventlist);
std::list< std::pair< Evoral::Event<Temporal::Beats>*, gint > >::iterator it;
@ -749,6 +774,12 @@ SMFSource::load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload
free(buf);
}
Evoral::SMF::UsedChannels
SMFSource::used_midi_channels()
{
return _used_channels;
}
void
SMFSource::destroy_model (const Glib::Threads::Mutex::Lock& lock)
{

View file

@ -125,11 +125,6 @@ SMF::open(const std::string& path, int track)
{
Glib::Threads::Mutex::Lock lm (_smf_lock);
_num_channels = 0;
_n_note_on_events = 0;
_has_pgm_change = false;
_used_channels.clear ();
assert(track >= 1);
if (_smf) {
smf_delete(_smf);
@ -157,57 +152,11 @@ SMF::open(const std::string& path, int track)
fclose(f);
bool type0 = _smf->format==0;
lm.release ();
if (!_empty) {
for (int i = 1; i <= _smf->number_of_tracks; ++i) {
// scan file for used channels.
int ret;
uint32_t delta_t = 0;
uint32_t size = 0;
uint8_t* buf = NULL;
event_id_t event_id = 0;
if (type0) {
seek_to_start (); //type0 files have no 'track' concept, just seek_to_start
} else {
seek_to_track (i);
}
std::set<uint8_t> used;
while ((ret = read_event (&delta_t, &size, &buf, &event_id)) >= 0) {
if (ret == 0) {
continue;
}
if (size == 0) {
break;
}
uint8_t type = buf[0] & 0xf0;
uint8_t chan = buf[0] & 0x0f;
if (type >= 0x80 && type <= 0xE0) {
_used_channels.insert(chan);
switch (type) {
case MIDI_CMD_NOTE_ON:
++_n_note_on_events;
break;
case MIDI_CMD_PGM_CHANGE:
_has_pgm_change = true;
break;
default:
break;
}
}
}
_num_channels += _used_channels.size();
free (buf);
}
seek_to_start();
}
return 0;
}

View file

@ -89,7 +89,9 @@ public:
int smf_format () const;
int num_channels () const { return _num_channels; }
std::set<uint8_t> const& used_channels () const { return _used_channels; }
typedef std::bitset<16> UsedChannels;
UsedChannels const& used_channels () const { return _used_channels; }
void set_used_channels (UsedChannels used) { _used_channels = used; }
uint64_t n_note_on_events () const { return _n_note_on_events; }
bool has_pgm_change () const { return _has_pgm_change; }
@ -134,18 +136,20 @@ public:
Markers const & markers() const { return _markers; }
void load_markers ();
protected:
uint64_t _n_note_on_events;
bool _has_pgm_change;
int _num_channels;
UsedChannels _used_channels;
private:
smf_t* _smf;
smf_track_t* _smf_track;
bool _empty; ///< true iff file contains(non-empty) events
mutable Glib::Threads::Mutex _smf_lock;
int _num_channels;
std::set<uint8_t> _used_channels;
uint64_t _n_note_on_events;
bool _has_pgm_change;
mutable Markers _markers;
};