33 #include <glib/gstdio.h>
34 #include <glibmm/miscutils.h>
35 #include <glibmm/fileutils.h>
40 #include "ardour/debug.h"
64 , _last_ev_time_beats(0.0)
65 , _last_ev_time_frames(0)
66 , _smf_last_read_end (0)
67 , _smf_last_read_time (0)
71 if (
init (_path,
false)) {
75 assert (!Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
100 , _last_ev_time_beats(0.0)
101 , _last_ev_time_frames(0)
102 , _smf_last_read_end (0)
103 , _smf_last_read_time (0)
107 if (
init (_path,
true)) {
111 assert (Glib::file_test (_path, Glib::FILE_TEST_EXISTS));
114 if (_flags & Writable) {
132 , _last_ev_time_beats(0.0)
133 , _last_ev_time_frames(0)
134 , _smf_last_read_end (0)
135 , _smf_last_read_time (0)
163 _path = Glib::build_filename (sdirs.front(),
_path);
173 assert (Glib::file_test (
_path, Glib::FILE_TEST_EXISTS));
191 ::g_unlink (
_path.c_str());
232 uint32_t ev_delta_t = 0;
233 uint32_t ev_type = 0;
234 uint32_t ev_size = 0;
235 uint8_t* ev_buffer = 0;
237 size_t scratch_size = 0;
241 const uint64_t start_ticks = converter.
from(start).
to_ticks();
247 while (time < start_ticks) {
250 ret =
read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
267 ret =
read_event(&ev_delta_t, &ev_size, &ev_buffer, &ignored);
282 ev_delta_t, time, ev_buffer[0], ev_type));
284 assert(time >= start_ticks);
291 if (ev_frame_time < start + duration) {
292 if (!filter || !filter->
filter(ev_buffer, ev_size)) {
293 destination.
write (ev_frame_time, ev_type, ev_size, ev_buffer);
295 tracker->
track(ev_buffer);
302 if (ev_size > scratch_size) {
303 scratch_size = ev_size;
305 ev_size = scratch_size;
325 size_t buf_capacity = 4;
326 uint8_t* buf = (uint8_t*)malloc(buf_capacity);
336 if (!(ret = source.
peek ((uint8_t*)&time, sizeof (time)))) {
349 if (!(ret = source.
read_prefix (&time, &type, &size))) {
350 error <<
_(
"Unable to read event prefix, corrupt MIDI ring") <<
endmsg;
355 if (size > buf_capacity) {
357 buf = (uint8_t*)realloc(buf, size);
363 error <<
_(
"Event has time and size but no body, corrupt MIDI ring") <<
endmsg;
368 if (time < position) {
369 error <<
_(
"Event time is before MIDI source position") <<
endmsg;
374 ev.
set(buf, size, time);
415 warning <<
string_compose(
_(
"Skipping event with unordered beat time %1 < %2 (off by %3 beats, %4 ticks)"),
431 _model->append (ev, event_id);
437 const uint32_t delta_time_ticks = delta_time_beats.
to_ticks(
ppqn());
440 _last_ev_time_beats = time;
479 const_cast<uint8_t*
>(ev.
buffer()));
480 _model->append (beat_ev, event_id);
486 const Evoral::Beats delta_time_beats = ev_time_beats - last_time_beats;
487 const uint32_t delta_time_ticks = delta_time_beats.
to_ticks(
ppqn());
552 _model->set_edited(
false);
566 return (SMF::test (file) );
574 static regex_t compiled_pattern;
575 static bool compile =
true;
576 const int nmatches = 2;
577 regmatch_t matches[nmatches];
579 if (Glib::file_test (file, Glib::FILE_TEST_EXISTS)) {
580 if (!Glib::file_test (file, Glib::FILE_TEST_IS_REGULAR)) {
586 if (compile && regcomp (&compiled_pattern,
"\\.[mM][iI][dD][iI]?$", REG_EXTENDED)) {
592 if (regexec (&compiled_pattern, file.c_str(), nmatches, matches, 0)) {
602 return ( a.first->time() < b.first->time() );
612 if (
_model && !force_reload) {
634 uint32_t scratch_size = 0;
636 uint32_t delta_t = 0;
644 std::list< std::pair< Evoral::Event<Evoral::Beats>*, gint > > eventlist;
646 for (
unsigned i = 1; i <=
num_tracks(); ++i) {
650 have_event_id =
false;
652 while ((ret =
read_event (&delta_t, &size, &buf, &event_id)) >= 0) {
659 have_event_id =
true;
667 if (!have_event_id) {
675 for (uint32_t xx = 0; xx < size; ++xx) {
677 snprintf (b,
sizeof (b),
"0x%x ", buf[xx]);
682 delta_t, time, size, ss , event_type,
name()));
685 eventlist.push_back(make_pair (
687 event_type, event_time,
692 scratch_size = std::max(size, scratch_size);
699 have_event_id =
false;
705 std::list< std::pair< Evoral::Event<Evoral::Beats>*, gint > >::iterator it;
706 for (it=eventlist.begin(); it!=eventlist.end(); ++it) {
707 _model->append (*it->first, it->second);
712 _model->set_edited (
false);
EventType event_type() const
ARDOUR::Session & _session
virtual uint32_t write(Time time, EventType type, uint32_t size, const uint8_t *buf)=0
int read_event(uint32_t *delta_t, uint32_t *size, uint8_t **buf) const
virtual void mark_streaming_midi_write_started(const Lock &lock, NoteMode mode)
framecnt_t read_unlocked(const Lock &lock, Evoral::EventSink< framepos_t > &dst, framepos_t position, framepos_t start, framecnt_t cnt, MidiStateTracker *tracker, MidiChannelFilter *filter) const
framepos_t _smf_last_read_end
Glib::Threads::Mutex::Lock Lock
bool read_contents(uint32_t size, uint8_t *buf)
bool is_smf_meta_event() const
bool is_channel_event() const
void end_write() THROW_FILE_ERROR
void mark_midi_streaming_write_completed(const Lock &lock, Evoral::Sequence< Evoral::Beats >::StuckNoteOption, Evoral::Beats when=Evoral::Beats())
framepos_t _capture_length
void set_id(event_id_t n)
void track(const MidiBuffer::const_iterator &from, const MidiBuffer::const_iterator &to)
LIBPBD_API Transmitter error
LIBPBD_API Transmitter warning
std::ostream & endmsg(std::ostream &ostr)
int open(const std::string &path) THROW_FILE_ERROR
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > start
framepos_t _smf_last_read_time
void ensure_disk_file(const Lock &lock)
static Beats ticks_at_rate(uint64_t ticks, uint32_t ppqn)
uint16_t num_tracks() const
uint64_t to_ticks() const
int set_state(const XMLNode &, int version)
static bool valid_midi_file(const std::string &path)
int set_state(const XMLNode &, int version)
void set_event_type(EventType t)
SMFSource(Session &session, const std::string &path, Source::Flag flags)
Evoral::Beats _length_beats
int seek_to_track(int track)
LIBEVORAL_API event_id_t next_event_id()
#define DEBUG_TRACE(bits, str)
Evoral::Beats from(framepos_t frames) const
void destroy_model(const Glib::Threads::Mutex::Lock &lock)
static bool compare_eventlist(const std::pair< Evoral::Event< Evoral::Beats > *, gint > &a, const std::pair< Evoral::Event< Evoral::Beats > *, gint > &b)
void set_path(const std::string &newpath)
bool sync_to_source(const Glib::Threads::Mutex::Lock &source_lock)
int create(const std::string &path, int track=1, uint16_t ppqn=19200) THROW_FILE_ERROR
bool read_prefix(T *time, Evoral::EventType *type, uint32_t *size)
void filter(BufferSet &bufs)
static int loading_state_version
void flush_midi(const Lock &lock)
void mark_streaming_write_completed(const Lock &lock)
virtual int init(const std::string &idstr, bool must_exist)
void append_event_beats(const Lock &lock, const Evoral::Event< Evoral::Beats > &ev)
void set(const uint8_t *buf, uint32_t size, Time t)
static bool safe_midi_file_extension(const std::string &path)
XMLProperty * add_property(const char *name, const std::string &value)
virtual void mark_streaming_write_started(const Lock &lock)
framecnt_t write_unlocked(const Lock &lock, MidiRingBuffer< framepos_t > &src, framepos_t position, framecnt_t cnt)
void load_model(const Glib::Threads::Mutex::Lock &lock, bool force_reload=false)
LIBARDOUR_API uint64_t MidiSourceIO
void seek_to_start() const
LIBARDOUR_API PBD::PropertyDescriptor< framepos_t > position
std::vector< std::string > source_search_path(DataType) const
int set_state(const XMLNode &, int version)
virtual void set_path(const std::string &)
void append_event_delta(uint32_t delta_t, const Event< Time > &ev)
LIBEVORAL_API uint64_t Beats
Evoral::Beats _last_ev_time_beats
const uint8_t * buffer() const
static const framecnt_t max_framecnt
bool peek(uint8_t *, size_t size)
virtual void mark_midi_streaming_write_completed(const Lock &lock, Evoral::Sequence< Evoral::Beats >::StuckNoteOption stuck_option, Evoral::Beats when=Evoral::Beats())
int set_state(const XMLNode &, int version)
AutomationType midi_parameter_type(uint8_t status)
boost::shared_ptr< MidiModel > _model
LIBARDOUR_API bool init(bool with_vst, bool try_optimization, const char *localedir)
void mark_streaming_midi_write_started(const Lock &lock, NoteMode mode)
framepos_t _last_ev_time_frames
std::string string_compose(const std::string &fmt, const T1 &o1)
void append_event_frames(const Lock &lock, const Evoral::Event< framepos_t > &ev, framepos_t source_start)
void invalidate(const Glib::Threads::Mutex::Lock &lock, std::set< Evoral::Sequence< Evoral::Beats >::WeakNotePtr > *notes=NULL)