1 /*
2  * Copyright (C) 2006-2015 David Robillard <d@drobilla.net>
3  * Copyright (C) 2007-2017 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2008-2009 Hans Baier <hansfbaier@googlemail.com>
5  * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
6  * Copyright (C) 2015-2019 Robin Gareus <robin@gareus.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22 
23 #ifndef __ardour_smf_source_h__
24 #define __ardour_smf_source_h__
25 
26 #include <cstdio>
27 #include <time.h>
28 #include "evoral/SMF.h"
29 #include "ardour/midi_source.h"
30 #include "ardour/file_source.h"
31 
32 namespace Evoral { template<typename T> class Event; }
33 
34 namespace ARDOUR {
35 
36 template<typename T> class MidiRingBuffer;
37 
38 /** Standard Midi File (Type 0) Source */
39 class LIBARDOUR_API SMFSource : public MidiSource, public FileSource, public Evoral::SMF {
40 public:
41 	/** Constructor for new internal-to-session files */
42 	SMFSource (Session& session, const std::string& path, Source::Flag flags);
43 
44 	/** Constructor for existing external-to-session files */
45 	SMFSource (Session& session, const std::string& path);
46 
47 	/** Constructor for existing in-session files */
48 	SMFSource (Session& session, const XMLNode&, bool must_exist = false);
49 
50 	virtual ~SMFSource ();
51 
safe_file_extension(const std::string & path)52 	bool safe_file_extension (const std::string& path) const {
53 		return safe_midi_file_extension(path);
54 	}
55 
56 	void append_event_beats (const Lock& lock, const Evoral::Event<Temporal::Beats>& ev);
57 	void append_event_samples (const Lock& lock, const Evoral::Event<samplepos_t>& ev, samplepos_t source_start);
58 
59 	void mark_streaming_midi_write_started (const Lock& lock, NoteMode mode);
60 	void mark_streaming_write_completed (const Lock& lock);
61 	void mark_midi_streaming_write_completed (const Lock& lock,
62 	                                          Evoral::Sequence<Temporal::Beats>::StuckNoteOption,
63 	                                          Temporal::Beats when = Temporal::Beats());
64 
65 	XMLNode& get_state ();
66 	int set_state (const XMLNode&, int version);
67 
68 	void load_model (const Glib::Threads::Mutex::Lock& lock, bool force_reload=false);
69 	void destroy_model (const Glib::Threads::Mutex::Lock& lock);
70 
71 	static bool safe_midi_file_extension (const std::string& path);
72 	static bool valid_midi_file (const std::string& path);
73 
74 	void prevent_deletion ();
75 	void set_path (const std::string& newpath);
76 
77   protected:
78 	void close ();
79 	void flush_midi (const Lock& lock);
80 
81   private:
82 	bool _open;
83 	Temporal::Beats     _last_ev_time_beats;
84 	samplepos_t         _last_ev_time_samples;
85 	/** end time (start + duration) of last call to read_unlocked */
86 	mutable samplepos_t _smf_last_read_end;
87 	/** time (in SMF ticks, 1 tick per _ppqn) of the last event read by read_unlocked */
88 	mutable samplepos_t _smf_last_read_time;
89 
90 	int open_for_write ();
91 
92 	void ensure_disk_file (const Lock& lock);
93 
94 	samplecnt_t read_unlocked (const Lock&                    lock,
95 	                           Evoral::EventSink<samplepos_t>& dst,
96 	                           samplepos_t                     position,
97 	                           samplepos_t                     start,
98 	                           samplecnt_t                     cnt,
99 	                           Evoral::Range<samplepos_t>*     loop_range,
100 	                           MidiStateTracker*               tracker,
101 	                           MidiChannelFilter*              filter) const;
102 
103 	samplecnt_t write_unlocked (const Lock&                 lock,
104 	                            MidiRingBuffer<samplepos_t>& src,
105 	                            samplepos_t                  position,
106 	                            samplecnt_t                  cnt);
107 
108 };
109 
110 }; /* namespace ARDOUR */
111 
112 #endif /* __ardour_smf_source_h__ */
113 
114