modify how Evoral::SMF (maybe) writes an EOT event into an SMF
every write pass deletes existing tracks, which means it also deletes any existing EOT event. Rather than try to replicate the _length value() that is kept in a Source object in the SMF object, add a virtual method to SMF that returns the _length value (or std::numeric_limits<Beats>::max() if not set). If the _length value is not the max, we will add EOT events to each track (usually just one) right before writing to disk.
This commit is contained in:
parent
a5dac1578e
commit
39661732c3
@ -38,6 +38,7 @@ public:
|
||||
~ExportSMFWriter ();
|
||||
|
||||
int init (std::string const& path, samplepos_t);
|
||||
Temporal::Beats duration() const;
|
||||
|
||||
void process (MidiBuffer const&, sampleoffset_t, samplecnt_t, bool);
|
||||
|
||||
|
@ -81,6 +81,8 @@ public:
|
||||
|
||||
void render (const ReaderLock& lock, Evoral::EventSink<Temporal::Beats>& dst);
|
||||
|
||||
Temporal::Beats duration() const;
|
||||
|
||||
protected:
|
||||
void close ();
|
||||
void flush_midi (const WriterLock& lock);
|
||||
|
@ -95,3 +95,9 @@ ExportSMFWriter::process (MidiBuffer const& buf, sampleoffset_t off, samplecnt_t
|
||||
_pos += n_samples;
|
||||
}
|
||||
}
|
||||
|
||||
Temporal::Beats
|
||||
ExportSMFWriter::duration() const
|
||||
{
|
||||
return std::numeric_limits<Temporal::Beats>::max ();
|
||||
}
|
||||
|
@ -462,10 +462,15 @@ void
|
||||
SMFSource::update_length (timepos_t const & dur)
|
||||
{
|
||||
assert (!_length || (_length.time_domain() == dur.time_domain()));
|
||||
Evoral::SMF::set_duration (dur.beats());
|
||||
_length = dur;
|
||||
}
|
||||
|
||||
Temporal::Beats
|
||||
SMFSource::duration() const
|
||||
{
|
||||
return _length.beats ();
|
||||
}
|
||||
|
||||
/** Append an event with a timestamp in beats */
|
||||
void
|
||||
SMFSource::append_event_beats (const WriterLock& lock,
|
||||
@ -643,7 +648,7 @@ SMFSource::mark_midi_streaming_write_completed (const WriterLock& lm, Evoral::Se
|
||||
}
|
||||
|
||||
try {
|
||||
Evoral::SMF::set_duration (duration.beats());
|
||||
update_length (duration.distance());
|
||||
Evoral::SMF::end_write (_path);
|
||||
} catch (std::exception & e) {
|
||||
error << string_compose (_("Exception while writing %1, file may be corrupt/unusable"), _path) << endmsg;
|
||||
|
@ -516,14 +516,23 @@ SMF::end_write (string const & path)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
FILE* f = g_fopen (path.c_str(), "w+b");
|
||||
if (f == 0) {
|
||||
throw FileError (path);
|
||||
}
|
||||
|
||||
Temporal::Beats b = duration();
|
||||
|
||||
if (b != std::numeric_limits<Temporal::Beats>::max()) {
|
||||
|
||||
int64_t their_pulses = b.to_ticks (_smf->ppqn);
|
||||
|
||||
for (uint16_t n = 0; n < _smf->number_of_tracks; ++n) {
|
||||
smf_track_t* trk = smf_get_track_by_number (_smf, n+1);
|
||||
(void) smf_track_add_eot_pulses (trk, their_pulses);
|
||||
}
|
||||
}
|
||||
|
||||
if (smf_save (_smf, f) != 0) {
|
||||
fclose(f);
|
||||
throw FileError (path);
|
||||
@ -532,23 +541,8 @@ SMF::end_write (string const & path)
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void
|
||||
SMF::set_duration (Temporal::Beats const & b)
|
||||
{
|
||||
if (!_smf) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t their_pulses = b.to_ticks (ppqn());
|
||||
|
||||
for (uint16_t n = 0; n < _smf->number_of_tracks; ++n) {
|
||||
smf_track_t* trk = smf_get_track_by_number (_smf, n+1);
|
||||
(void) smf_track_add_eot_pulses (trk, their_pulses);
|
||||
}
|
||||
}
|
||||
|
||||
Temporal::Beats
|
||||
SMF::duration () const
|
||||
SMF::file_duration () const
|
||||
{
|
||||
if (!_smf) {
|
||||
return Temporal::Beats();
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include "temporal/beats.h"
|
||||
|
||||
#include "evoral/visibility.h"
|
||||
#include "evoral/types.h"
|
||||
|
||||
@ -39,7 +41,6 @@ typedef smf_tempo_struct smf_tempo_t;
|
||||
|
||||
namespace Temporal {
|
||||
class TempoMap;
|
||||
class Beats;
|
||||
}
|
||||
|
||||
namespace Evoral {
|
||||
@ -70,6 +71,8 @@ public:
|
||||
SMF();
|
||||
virtual ~SMF();
|
||||
|
||||
virtual Temporal::Beats duration() const { return std::numeric_limits<Temporal::Beats>::max(); }
|
||||
|
||||
static bool test(const std::string& path);
|
||||
int open (const std::string& path, int track = 1, bool scan = true);
|
||||
// XXX 19200 = 10 * Temporal::ticks_per_beat
|
||||
@ -96,8 +99,7 @@ public:
|
||||
|
||||
int smf_format () const;
|
||||
|
||||
void set_duration (Temporal::Beats const &);
|
||||
Temporal::Beats duration() const;
|
||||
Temporal::Beats file_duration() const;
|
||||
|
||||
int num_channels () const { return _num_channels; }
|
||||
typedef std::bitset<16> UsedChannels;
|
||||
|
Loading…
Reference in New Issue
Block a user