using namespace PBD;
/** Constructor used for new internal-to-session files. File cannot exist. */
-SMFSource::SMFSource (Session& s, const ustring& path, Source::Flag flags)
+SMFSource::SMFSource (Session& s, const string& path, Source::Flag flags)
: Source(s, DataType::MIDI, path, flags)
- , MidiSource(s, path)
- , FileSource(s, DataType::MIDI, path, flags)
+ , MidiSource(s, path, flags)
+ , FileSource(s, DataType::MIDI, path, string(), flags)
, Evoral::SMF()
, _last_ev_time_beats(0.0)
, _last_ev_time_frames(0)
, _smf_last_read_end (0)
, _smf_last_read_time (0)
{
- if (init(_path, false)) {
- throw failed_constructor ();
- }
+ /* note that origin remains empty */
- if (create(path)) {
+ if (init(_path, false)) {
throw failed_constructor ();
}
-
- load_model(true, true); // FIXME
+
+ /* file is not opened until write */
}
/** Constructor used for existing internal-to-session files. */
throw failed_constructor ();
}
- load_model(true, true); // FIXME
+ _open = true;
}
SMFSource::~SMFSource ()
}
}
+int
+SMFSource::open_for_write ()
+{
+ if (create (_path)) {
+ return -1;
+ }
+ _open = true;
+ return 0;
+}
+
/** All stamps in audio frames */
-nframes_t
-SMFSource::read_unlocked (Evoral::EventSink<nframes_t>& destination, sframes_t const source_start,
- sframes_t start, nframes_t duration,
+framecnt_t
+SMFSource::read_unlocked (Evoral::EventSink<framepos_t>& destination, framepos_t const source_start,
+ framepos_t start, framecnt_t duration,
MidiStateTracker* tracker) const
{
int ret = 0;
uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
+ if (writable() && !_open) {
+ /* nothing to read since nothing has ben written */
+ return duration;
+ }
+
DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: start %1 duration %2\n", start, duration));
_read_data_count = 0;
DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF read_unlocked: seek to %1\n", start));
Evoral::SMF::seek_to_start();
while (time < start_ticks) {
- gint ignored;
+ gint ignored;
ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
if (ret == -1) { // EOF
_smf_last_read_end = start + duration;
while (true) {
- gint ignored; /* XXX don't ignore note id's ??*/
+ gint ignored; /* XXX don't ignore note id's ??*/
ret = read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
if (ret == -1) { // EOF
/* Note that we add on the source start time (in session frames) here so that ev_frame_time
is in session frames.
*/
- const sframes_t ev_frame_time = converter.to(time / (double)ppqn()) + source_start;
+ const framepos_t ev_frame_time = converter.to(time / (double)ppqn()) + source_start;
if (ev_frame_time < start + duration) {
destination.write (ev_frame_time, ev_type, ev_size, ev_buffer);
return duration;
}
-/** All stamps in audio frames */
-nframes_t
-SMFSource::write_unlocked (MidiRingBuffer<nframes_t>& source, sframes_t position, nframes_t duration)
+/** Write data to this source from a MidiRingBuffer.
+ * @param source Buffer to read from.
+ * @param position This source's start position in session frames.
+ */
+framecnt_t
+SMFSource::write_unlocked (MidiRingBuffer<framepos_t>& source, framepos_t position, framecnt_t duration)
{
+ if (!_open && open_for_write()) {
+ error << string_compose (_("cannot open MIDI file %1 for write"), _path) << endmsg;
+ return 0;
+ }
+
+ if (!_writing) {
+ mark_streaming_write_started ();
+ }
+
_write_data_count = 0;
- nframes_t time;
+ framepos_t time;
Evoral::EventType type;
uint32_t size;
_model->start_write();
}
- Evoral::MIDIEvent<nframes_t> ev;
+ Evoral::MIDIEvent<framepos_t> ev;
while (true) {
bool ret = source.peek_time(&time);
break;
}
+ /* convert from session time to time relative to the source start */
assert(time >= position);
time -= position;
ev.set(buf, size, time);
ev.set_event_type(EventTypeMap::instance().midi_event_type(ev.buffer()[0]));
- ev.set_id (Evoral::next_event_id());
+ ev.set_id (Evoral::next_event_id());
if (!(ev.is_channel_event() || ev.is_smf_meta_event() || ev.is_sysex())) {
/*cerr << "SMFSource: WARNING: caller tried to write non SMF-Event of type "
Evoral::SMF::flush();
free(buf);
- ViewDataRangeReady(position + _last_write_end, duration); /* EMIT SIGNAL */
-
return duration;
}
return;
}
- Evoral::event_id_t event_id;
+ Evoral::event_id_t event_id;
- if (ev.id() < 0) {
- event_id = Evoral::next_event_id();
- } else {
- event_id = ev.id();
- }
+ if (ev.id() < 0) {
+ event_id = Evoral::next_event_id();
+ } else {
+ event_id = ev.id();
+ }
if (_model) {
_model->append (ev, event_id);
}
-/** Append an event with a timestamp in frames (nframes_t) */
+/** Append an event with a timestamp in frames (framepos_t) */
void
-SMFSource::append_event_unlocked_frames (const Evoral::Event<nframes_t>& ev, sframes_t position)
+SMFSource::append_event_unlocked_frames (const Evoral::Event<framepos_t>& ev, framepos_t position)
{
assert(_writing);
if (ev.size() == 0) {
cerr << "SMFSource: Warning: Skipping event with non-monotonic time" << endl;
return;
}
-
+
BeatsFramesConverter converter(_session.tempo_map(), position);
- const double ev_time_beats = converter.from(ev.time());
- Evoral::event_id_t event_id;
+ const double ev_time_beats = converter.from(ev.time());
+ Evoral::event_id_t event_id;
- if (ev.id() < 0) {
- event_id = Evoral::next_event_id();
- } else {
- event_id = ev.id();
- }
+ if (ev.id() < 0) {
+ event_id = Evoral::next_event_id();
+ } else {
+ event_id = ev.id();
+ }
if (_model) {
const Evoral::Event<double> beat_ev (ev.event_type(),
- ev_time_beats,
- ev.size(),
- (uint8_t*)ev.buffer());
+ ev_time_beats,
+ ev.size(),
+ (uint8_t*)ev.buffer());
_model->append (beat_ev, event_id);
}
_length_beats = max(_length_beats, ev_time_beats);
- const sframes_t delta_time_frames = ev.time() - _last_ev_time_frames;
- const double delta_time_beats = converter.from(delta_time_frames);
- const uint32_t delta_time_ticks = (uint32_t)(lrint(delta_time_beats * (double)ppqn()));
+ const framepos_t delta_time_frames = ev.time() - _last_ev_time_frames;
+ const double delta_time_beats = converter.from(delta_time_frames);
+ const uint32_t delta_time_ticks = (uint32_t)(lrint(delta_time_beats * (double)ppqn()));
Evoral::SMF::append_event_delta(delta_time_ticks, ev.size(), ev.buffer(), event_id);
_last_ev_time_frames = ev.time();
XMLNode&
SMFSource::get_state ()
{
- return MidiSource::get_state();
+ XMLNode& node = MidiSource::get_state();
+ node.add_property (X_("origin"), _origin);
+ return node;
}
int
}
void
-SMFSource::mark_streaming_midi_write_started (NoteMode mode, sframes_t start_frame)
+SMFSource::mark_streaming_midi_write_started (NoteMode mode)
{
- Glib::Mutex::Lock lm (_lock);
- MidiSource::mark_streaming_midi_write_started (mode, start_frame);
+ /* CALLER MUST HOLD LOCK */
+
+ MidiSource::mark_streaming_midi_write_started (mode);
Evoral::SMF::begin_write ();
_last_ev_time_beats = 0.0;
_last_ev_time_frames = 0;
Evoral::SMF::end_write ();
- /* data in the file now, not removable */
+ /* data in the file now, not removable */
- mark_nonremovable ();
+ mark_nonremovable ();
}
bool
-SMFSource::safe_midi_file_extension (const Glib::ustring& file)
+SMFSource::safe_midi_file_extension (const string& file)
{
- return (file.rfind(".mid") != Glib::ustring::npos);
+ return (file.rfind(".mid") != string::npos);
}
void
return;
}
- if (! _model) {
- _model = boost::shared_ptr<MidiModel>(new MidiModel(this));
+ if (!_model) {
+ _model = boost::shared_ptr<MidiModel> (new MidiModel (shared_from_this ()));
} else {
_model->clear();
}
+ if (writable() && !_open) {
+ return;
+ }
+
_model->start_write();
Evoral::SMF::seek_to_start();
uint32_t size = 0;
uint8_t* buf = NULL;
int ret;
- gint event_id;
- bool have_event_id = false;
+ gint event_id;
+ bool have_event_id = false;
while ((ret = read_event (&delta_t, &size, &buf, &event_id)) >= 0) {
time += delta_t;
- if (ret == 0) {
+ if (ret == 0) {
- /* meta-event : did we get an event ID ?
- */
+ /* meta-event : did we get an event ID ?
+ */
- if (event_id >= 0) {
- have_event_id = true;
- }
+ if (event_id >= 0) {
+ have_event_id = true;
+ }
- continue;
- }
+ continue;
+ }
if (ret > 0) {
- /* not a meta-event */
+ /* not a meta-event */
- ev.set (buf, size, time / (double)ppqn());
+ ev.set (buf, size, time / (double)ppqn());
ev.set_event_type(EventTypeMap::instance().midi_event_type(buf[0]));
- if (!have_event_id) {
- event_id = Evoral::next_event_id();
- }
+ if (!have_event_id) {
+ event_id = Evoral::next_event_id();
+ }
#ifndef NDEBUG
- std::string ss;
+ std::string ss;
- for (uint32_t xx = 0; xx < size; ++xx) {
- char b[8];
- snprintf (b, sizeof (b), "0x%x ", buf[xx]);
- ss += b;
- }
-
- DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF %6 load model delta %1, time %2, size %3 buf %4, type %5\n",
- delta_t, time, size, ss , ev.event_type(), name()));
+ for (uint32_t xx = 0; xx < size; ++xx) {
+ char b[8];
+ snprintf (b, sizeof (b), "0x%x ", buf[xx]);
+ ss += b;
+ }
+
+ DEBUG_TRACE (DEBUG::MidiSourceIO, string_compose ("SMF %6 load model delta %1, time %2, size %3 buf %4, type %5\n",
+ delta_t, time, size, ss , ev.event_type(), name()));
#endif
_model->append (ev, event_id);
- if (ev.size() > scratch_size) {
- scratch_size = ev.size();
- }
+ if (ev.size() > scratch_size) {
+ scratch_size = ev.size();
+ }
- ev.size() = scratch_size; // ensure read_event only allocates if necessary
+ ev.size() = scratch_size; // ensure read_event only allocates if necessary
- _length_beats = max(_length_beats, ev.time());
- }
+ _length_beats = max(_length_beats, ev.time());
+ }
- /* event ID's must immediately precede the event they are for
- */
+ /* event ID's must immediately precede the event they are for
+ */
- have_event_id = false;
+ have_event_id = false;
}
_model->end_write(false);
void
SMFSource::flush_midi ()
{
- if (!writable()) {
- return;
- }
+ if (!writable() || (writable() && !_open)) {
+ return;
+ }
Evoral::SMF::end_write();
- /* data in the file means its no longer removable */
- mark_nonremovable ();
+ /* data in the file means its no longer removable */
+ mark_nonremovable ();
}
void
SMFSource::set_path (const string& p)
{
- FileSource::set_path (p);
- SMF::set_path (_path);
+ FileSource::set_path (p);
+ SMF::set_path (_path);
}