Fix MIDI deinterlace #9422

De-interlace works by first creating 16 SMF Sources, and then
only using sources that are actually required.

However SourceFactory::createWritable by default emits SourceCreated,
which added all the 16 Sources to the Session. Later adding only the
required Sources resulted in duplicate IDs.
This commit is contained in:
Robin Gareus 2023-08-22 19:00:42 +02:00
parent dd4e5dfc96
commit e3297a6a84
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04

View File

@ -204,7 +204,7 @@ static bool
create_mono_sources_for_writing (const vector<string>& new_paths, create_mono_sources_for_writing (const vector<string>& new_paths,
Session& sess, uint32_t samplerate, Session& sess, uint32_t samplerate,
vector<std::shared_ptr<Source> >& newfiles, vector<std::shared_ptr<Source> >& newfiles,
samplepos_t natural_position) samplepos_t natural_position, bool announce)
{ {
for (vector<string>::const_iterator i = new_paths.begin(); i != new_paths.end(); ++i) { for (vector<string>::const_iterator i = new_paths.begin(); i != new_paths.end(); ++i) {
@ -213,7 +213,7 @@ create_mono_sources_for_writing (const vector<string>& new_paths,
try { try {
const DataType type = SMFSource::safe_midi_file_extension (*i) ? DataType::MIDI : DataType::AUDIO; const DataType type = SMFSource::safe_midi_file_extension (*i) ? DataType::MIDI : DataType::AUDIO;
source = SourceFactory::createWritable (type, sess, i->c_str(), samplerate); source = SourceFactory::createWritable (type, sess, i->c_str(), samplerate, announce);
} }
catch (const failed_constructor& err) { catch (const failed_constructor& err) {
@ -530,19 +530,20 @@ Session::deinterlace_midi_region (std::shared_ptr<MidiRegion> mr)
Sources newfiles; Sources newfiles;
try { try {
std::shared_ptr<MidiSource> ms = mr->midi_source(0);
std::shared_ptr<SMFSource> smf = std::dynamic_pointer_cast<SMFSource> (mr->midi_source(0)); //ToDo: handle compound sources? std::shared_ptr<SMFSource> smf = std::dynamic_pointer_cast<SMFSource> (mr->midi_source(0)); //ToDo: handle compound sources?
string source_path = smf->path(); string source_path = smf->path();
/* write_midi_data_to_new_files expects to find raw midi on-disk (SMF*). /* Write_midi_data_to_new_files expects to find raw midi on-disk (SMF*).
* this means that a split looks like a no-op if the file wasn't written to disk yet. * this means that a split looks like a no-op if the file wasn't written to disk yet.
* I've chosen to flush the file to disk, rather than reimplement write_midi_data_to_new_files for a Source */ * I've chosen to flush the file to disk, rather than reimplement
smf->session_saved(); //ToDo: should we just expose flush_midi() instead? * write_midi_data_to_new_files for a Source
*/
smf->session_saved(); //TODO: should we just expose flush_midi() instead?
/* open the SMF file for reading */ /* open the SMF file for reading */
boost::scoped_ptr<Evoral::SMF> smf_reader; boost::scoped_ptr<Evoral::SMF> smf_reader;
smf_reader.reset (new Evoral::SMF()); smf_reader.reset (new Evoral::SMF());
if (smf_reader->open( source_path )) { if (smf_reader->open (source_path)) {
throw Evoral::SMF::FileError (source_path); throw Evoral::SMF::FileError (source_path);
} }
@ -554,7 +555,7 @@ Session::deinterlace_midi_region (std::shared_ptr<MidiRegion> mr)
vector<string> new_paths = get_paths_for_new_sources (false, source_path, 16, smf_names); vector<string> new_paths = get_paths_for_new_sources (false, source_path, 16, smf_names);
/* create source files and write 1 channel of midi data to each of them */ /* create source files and write 1 channel of midi data to each of them */
if (create_mono_sources_for_writing (new_paths, *this, sample_rate(), newfiles, 0) ) { if (create_mono_sources_for_writing (new_paths, *this, sample_rate(), newfiles, 0, false)) {
ImportStatus status; ImportStatus status;
write_midi_data_to_new_files (smf_reader.get(), status, newfiles, true /*split*/); write_midi_data_to_new_files (smf_reader.get(), status, newfiles, true /*split*/);
} else { } else {
@ -566,7 +567,7 @@ Session::deinterlace_midi_region (std::shared_ptr<MidiRegion> mr)
return; return;
} }
/* not all 16 channels will have midi data; delete any sources that turned up empty */ /* not all 16 channels will have midi data; delete any sources that turned up empty */
for (Sources::iterator x = newfiles.begin(); x != newfiles.end(); ) { for (Sources::iterator x = newfiles.begin(); x != newfiles.end(); ) {
std::shared_ptr<SMFSource> smfs; std::shared_ptr<SMFSource> smfs;
if ((smfs = std::dynamic_pointer_cast<SMFSource>(*x)) != 0 && smfs->is_empty()) { if ((smfs = std::dynamic_pointer_cast<SMFSource>(*x)) != 0 && smfs->is_empty()) {
@ -736,7 +737,7 @@ Session::import_files (ImportStatus& status)
fatal << "THIS IS NOT IMPLEMENTED YET, IT SHOULD NEVER GET CALLED!!! DYING!" << endmsg; fatal << "THIS IS NOT IMPLEMENTED YET, IT SHOULD NEVER GET CALLED!!! DYING!" << endmsg;
status.cancel = !map_existing_mono_sources (new_paths, *this, sample_rate(), newfiles, this); status.cancel = !map_existing_mono_sources (new_paths, *this, sample_rate(), newfiles, this);
} else { } else {
status.cancel = !create_mono_sources_for_writing (new_paths, *this, sample_rate(), newfiles, natural_position); status.cancel = !create_mono_sources_for_writing (new_paths, *this, sample_rate(), newfiles, natural_position, true);
} }
// copy on cancel/failure so that any files that were created will be removed below // copy on cancel/failure so that any files that were created will be removed below