MIDI Import: Support for separating the channels of a Type1 midifile track(s)

This commit is contained in:
Ben Loftis 2021-11-13 15:51:20 -06:00
parent 0733b2d9e2
commit 58033262ae

View File

@ -141,7 +141,7 @@ open_importable_source (const string& path, samplecnt_t samplerate, ARDOUR::SrcQ
vector<string>
Session::get_paths_for_new_sources (bool /*allow_replacing*/, const string& import_file_path, uint32_t channels,
vector<string> const & smf_track_names)
vector<string> const & smf_names)
{
vector<string> new_paths;
@ -154,14 +154,9 @@ Session::get_paths_for_new_sources (bool /*allow_replacing*/, const string& impo
switch (type) {
case DataType::MIDI:
assert (smf_track_names.empty() || smf_track_names.size() == channels);
if (channels > 1) {
string mchn_name;
if (smf_track_names.empty() || smf_track_names[n].empty()) {
mchn_name = string_compose ("%1-t%2", basename, n);
} else {
mchn_name = string_compose ("%1-%2", basename, smf_track_names[n]);
}
assert (smf_names.size() == channels);
string mchn_name = string_compose ("%1.%2", basename, smf_names[n]);
filepath = new_midi_source_path (mchn_name);
} else {
filepath = new_midi_source_path (basename);
@ -367,30 +362,34 @@ write_audio_data_to_new_files (ImportableSource* source, ImportStatus& status,
static void
write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
vector<boost::shared_ptr<Source> >& newfiles,
bool split_type0)
bool split_midi_channels)
{
uint32_t buf_size = 4;
uint8_t* buf = (uint8_t*) malloc (buf_size);
status.progress = 0.0f;
uint16_t num_tracks;
bool type0 = source->is_type0 () && split_type0;
const std::set<uint8_t>& chn = source->channels ();
if (type0) {
num_tracks = source->channels().size();
} else {
num_tracks = source->num_tracks();
}
assert (newfiles.size() == num_tracks);
bool type0 = source->smf_format()==0;
int total_files = newfiles.size();
try {
vector<boost::shared_ptr<Source> >::iterator s = newfiles.begin();
std::set<uint8_t>::const_iterator cur_chan = chn.begin();
for (unsigned i = 1; i <= num_tracks; ++i) {
int cur_chan = 0;
for (int i = 0; i < total_files; ++i) {
int cur_track = i+1; //first Track of a type-1 file is metadata only. Start importing sourcefiles at Track index 1
if (split_midi_channels) { //if splitting channels we will need to fill 16x sources. empties will be disposed-of later
cur_track = 1 + (int) floor((float)i/16.f); //calculate the Track needed for this sourcefile (offset by 1)
}
boost::shared_ptr<SMFSource> smfs = boost::dynamic_pointer_cast<SMFSource> (*s);
if (!smfs) {
continue; //should never happen. The calling code should provide exactly the number of tracks&channels we need
}
Glib::Threads::Mutex::Lock source_lock(smfs->mutex());
@ -398,7 +397,7 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
if (type0) {
source->seek_to_start ();
} else {
source->seek_to_track (i);
source->seek_to_track (cur_track);
}
uint64_t t = 0;
@ -427,12 +426,12 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
continue;
}
// type-0 files separate by channel
if (type0) {
/* if requested by user, each sourcefile gets only a single channel's data */
if (split_midi_channels) {
uint8_t type = buf[0] & 0xf0;
uint8_t chan = buf[0] & 0x0f;
if (type >= 0x80 && type <= 0xE0) {
if (chan != *cur_chan) {
if (chan != cur_chan) {
continue;
}
}
@ -468,12 +467,14 @@ write_midi_data_to_new_files (Evoral::SMF* source, ImportStatus& status,
break;
}
} else {
info << string_compose (_("Track %1 of %2 contained no usable MIDI data"), i, num_tracks) << endmsg;
info << string_compose (_("Track %1 of %2 contained no usable MIDI data"), i, total_files) << endmsg;
}
++s; // next source
if (type0) {
++cur_chan;
++cur_chan;
if (cur_chan > 15) {
cur_chan=0;
}
}
@ -509,7 +510,7 @@ Session::import_files (ImportStatus& status)
Sources all_new_sources;
boost::shared_ptr<AudioFileSource> afs;
boost::shared_ptr<SMFSource> smfs;
uint32_t channels = 0;
uint32_t num_channels = 0;
vector<string> smf_names;
status.sources.clear ();
@ -524,7 +525,7 @@ Session::import_files (ImportStatus& status)
if (type == DataType::AUDIO) {
try {
source = open_importable_source (*p, sample_rate(), status.quality);
channels = source->channels();
num_channels = source->channels();
} catch (const failed_constructor& err) {
error << string_compose(_("Import: cannot open input sound file \"%1\""), (*p)) << endmsg;
status.done = status.cancel = true;
@ -539,18 +540,53 @@ Session::import_files (ImportStatus& status)
throw Evoral::SMF::FileError (*p);
}
if (smf_reader->is_type0 () && status.split_midi_channels) {
channels = smf_reader->channels().size();
if (smf_reader->smf_format()==0) {
/* Type0: we should prepare filenames for up to 16 channels in the file; we will throw out the empty ones later */
if (status.split_midi_channels) {
num_channels = 16;
for (uint32_t i = 0; i<num_channels; i++) {
smf_names.push_back( string_compose ("ch%1", 1+i ) ); //chanX
}
} else {
num_channels = 1;
smf_names.push_back("");
}
} else {
channels = smf_reader->num_tracks();
/* we should prepare filenames for up to 16 channels in each Track; we will throw out the empty ones later*/
num_channels = status.split_midi_channels ? smf_reader->num_tracks()*16 : smf_reader->num_tracks();
switch (status.midi_track_name_source) {
case SMFTrackNumber:
if (status.split_midi_channels) {
for (uint32_t i = 0; i<num_channels; i++) {
smf_names.push_back( string_compose ("t%1.ch%2", 1+i/16, 1+i%16 ) ); //trackX.chanX
}
} else {
for (uint32_t i = 0; i<num_channels;i++) {
smf_names.push_back( string_compose ("t%1", i+1 ) ); //trackX
}
}
break;
case SMFTrackName:
smf_reader->track_names (smf_names);
if (status.split_midi_channels) {
vector<string> temp;
smf_reader->track_names (temp);
for (uint32_t i = 0; i<num_channels;i++) {
smf_names.push_back( string_compose ("%1.ch%2", temp[i/16], 1+i%16 ) ); //trackname.chanX
}
} else {
smf_reader->track_names (smf_names);
}
break;
case SMFInstrumentName:
smf_reader->instrument_names (smf_names);
if (status.split_midi_channels) {
vector<string> temp;
smf_reader->instrument_names (temp);
for (uint32_t i = 0; i<num_channels;i++) {
smf_names.push_back( string_compose ("%1.ch%2", temp[i/16], 1+i%16 ) ); //instrument.chanX
}
} else {
smf_reader->instrument_names (smf_names);
}
break;
}
}
@ -561,12 +597,12 @@ Session::import_files (ImportStatus& status)
}
}
if (channels == 0) {
if (num_channels == 0) {
error << _("Import: file contains no channels.") << endmsg;
continue;
}
vector<string> new_paths = get_paths_for_new_sources (status.replace_existing_source, *p, channels, smf_names);
vector<string> new_paths = get_paths_for_new_sources (status.replace_existing_source, *p, num_channels, smf_names);
Sources newfiles;
samplepos_t natural_position = source ? source->natural_position() : 0;