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 ();
|
~ExportSMFWriter ();
|
||||||
|
|
||||||
int init (std::string const& path, samplepos_t);
|
int init (std::string const& path, samplepos_t);
|
||||||
|
Temporal::Beats duration() const;
|
||||||
|
|
||||||
void process (MidiBuffer const&, sampleoffset_t, samplecnt_t, bool);
|
void process (MidiBuffer const&, sampleoffset_t, samplecnt_t, bool);
|
||||||
|
|
||||||
|
@ -81,6 +81,8 @@ public:
|
|||||||
|
|
||||||
void render (const ReaderLock& lock, Evoral::EventSink<Temporal::Beats>& dst);
|
void render (const ReaderLock& lock, Evoral::EventSink<Temporal::Beats>& dst);
|
||||||
|
|
||||||
|
Temporal::Beats duration() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void close ();
|
void close ();
|
||||||
void flush_midi (const WriterLock& lock);
|
void flush_midi (const WriterLock& lock);
|
||||||
|
@ -95,3 +95,9 @@ ExportSMFWriter::process (MidiBuffer const& buf, sampleoffset_t off, samplecnt_t
|
|||||||
_pos += n_samples;
|
_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)
|
SMFSource::update_length (timepos_t const & dur)
|
||||||
{
|
{
|
||||||
assert (!_length || (_length.time_domain() == dur.time_domain()));
|
assert (!_length || (_length.time_domain() == dur.time_domain()));
|
||||||
Evoral::SMF::set_duration (dur.beats());
|
|
||||||
_length = dur;
|
_length = dur;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Temporal::Beats
|
||||||
|
SMFSource::duration() const
|
||||||
|
{
|
||||||
|
return _length.beats ();
|
||||||
|
}
|
||||||
|
|
||||||
/** Append an event with a timestamp in beats */
|
/** Append an event with a timestamp in beats */
|
||||||
void
|
void
|
||||||
SMFSource::append_event_beats (const WriterLock& lock,
|
SMFSource::append_event_beats (const WriterLock& lock,
|
||||||
@ -643,7 +648,7 @@ SMFSource::mark_midi_streaming_write_completed (const WriterLock& lm, Evoral::Se
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Evoral::SMF::set_duration (duration.beats());
|
update_length (duration.distance());
|
||||||
Evoral::SMF::end_write (_path);
|
Evoral::SMF::end_write (_path);
|
||||||
} catch (std::exception & e) {
|
} catch (std::exception & e) {
|
||||||
error << string_compose (_("Exception while writing %1, file may be corrupt/unusable"), _path) << endmsg;
|
error << string_compose (_("Exception while writing %1, file may be corrupt/unusable"), _path) << endmsg;
|
||||||
|
@ -516,15 +516,24 @@ SMF::end_write (string const & path)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FILE* f = g_fopen (path.c_str(), "w+b");
|
FILE* f = g_fopen (path.c_str(), "w+b");
|
||||||
if (f == 0) {
|
if (f == 0) {
|
||||||
throw FileError (path);
|
throw FileError (path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (smf_save(_smf, f) != 0) {
|
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);
|
fclose(f);
|
||||||
throw FileError (path);
|
throw FileError (path);
|
||||||
}
|
}
|
||||||
@ -532,23 +541,8 @@ SMF::end_write (string const & path)
|
|||||||
fclose(f);
|
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
|
Temporal::Beats
|
||||||
SMF::duration () const
|
SMF::file_duration () const
|
||||||
{
|
{
|
||||||
if (!_smf) {
|
if (!_smf) {
|
||||||
return Temporal::Beats();
|
return Temporal::Beats();
|
||||||
|
@ -27,6 +27,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
|
#include "temporal/beats.h"
|
||||||
|
|
||||||
#include "evoral/visibility.h"
|
#include "evoral/visibility.h"
|
||||||
#include "evoral/types.h"
|
#include "evoral/types.h"
|
||||||
|
|
||||||
@ -39,7 +41,6 @@ typedef smf_tempo_struct smf_tempo_t;
|
|||||||
|
|
||||||
namespace Temporal {
|
namespace Temporal {
|
||||||
class TempoMap;
|
class TempoMap;
|
||||||
class Beats;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Evoral {
|
namespace Evoral {
|
||||||
@ -70,6 +71,8 @@ public:
|
|||||||
SMF();
|
SMF();
|
||||||
virtual ~SMF();
|
virtual ~SMF();
|
||||||
|
|
||||||
|
virtual Temporal::Beats duration() const { return std::numeric_limits<Temporal::Beats>::max(); }
|
||||||
|
|
||||||
static bool test(const std::string& path);
|
static bool test(const std::string& path);
|
||||||
int open (const std::string& path, int track = 1, bool scan = true);
|
int open (const std::string& path, int track = 1, bool scan = true);
|
||||||
// XXX 19200 = 10 * Temporal::ticks_per_beat
|
// XXX 19200 = 10 * Temporal::ticks_per_beat
|
||||||
@ -96,8 +99,7 @@ public:
|
|||||||
|
|
||||||
int smf_format () const;
|
int smf_format () const;
|
||||||
|
|
||||||
void set_duration (Temporal::Beats const &);
|
Temporal::Beats file_duration() const;
|
||||||
Temporal::Beats duration() const;
|
|
||||||
|
|
||||||
int num_channels () const { return _num_channels; }
|
int num_channels () const { return _num_channels; }
|
||||||
typedef std::bitset<16> UsedChannels;
|
typedef std::bitset<16> UsedChannels;
|
||||||
|
Loading…
Reference in New Issue
Block a user