Fix some problems with dragging more than 1 region to a new track.
[ardour.git] / libs / evoral / src / LibSMF.cpp
1 #include "evoral/LibSMF.hpp"
2 #include "evoral/Event.hpp"
3 #include <cassert>
4
5 #include <iostream>
6
7 using namespace std;
8
9 namespace Evoral {
10
11
12 /** Attempt to open the SMF file for reading and writing.
13  *
14  * Currently SMF is always read/write.
15  *
16  * \return  0 on success
17  *         -1 if the file can not be opened
18  */
19 template<typename Time>
20 int
21 LibSMF<Time>::open(const std::string& path)
22 {
23         if (_smf) { 
24                 smf_delete(_smf);
25         }
26         
27         _smf = smf_load(path.c_str());
28         if (!_smf) {
29                 _smf = smf_new();
30                 smf_set_ppqn(_smf, _ppqn);
31                 
32                 if(_smf == NULL) {
33                         return -1;
34                 }
35         }
36                 
37         _smf_track = smf_get_track_by_number(_smf, 1);
38         assert(_smf_track);
39
40         cerr << "number of events: " << _smf_track->number_of_events << endl;
41         
42         _empty = !(_smf_track->number_of_events > 0);
43         
44         return 0;
45 }
46
47 template<typename Time>
48 void
49 LibSMF<Time>::close()
50 {
51         assert(false);
52         if (_smf) {
53                 smf_save(_smf, _path.c_str());
54                 smf_delete(_smf);
55                 _smf = 0;
56                 _smf_track = 0;
57         }
58 }
59
60 template<typename Time>
61 void
62 LibSMF<Time>::seek_to_start() const
63 {
64         smf_rewind(_smf);
65 }
66
67 /** Read an event from the current position in file.
68  *
69  * File position MUST be at the beginning of a delta time, or this will die very messily.
70  * ev.buffer must be of size ev.size, and large enough for the event.  The returned event
71  * will have it's time field set to it's delta time, in SMF tempo-based ticks, using the
72  * rate given by ppqn() (it is the caller's responsibility to calculate a real time).
73  *
74  * \a size should be the capacity of \a buf.  If it is not large enough, \a buf will
75  * be freed and a new buffer allocated in its place, the size of which will be placed
76  * in size.
77  *
78  * Returns event length (including status byte) on success, 0 if event was
79  * skipped (eg a meta event), or -1 on EOF (or end of track).
80  */
81 template<typename Time>
82 int
83 LibSMF<Time>::read_event(uint32_t* delta_t, uint32_t* size, uint8_t** buf) const
84 {
85         smf_event_t *event;
86         
87         assert(delta_t);
88         assert(size);
89         assert(buf);
90         
91     if ((event = smf_get_next_event(_smf)) != NULL) {
92         if (smf_event_is_metadata(event)) {
93                 return 0;
94         }
95         *delta_t = event->delta_time_pulses;
96         
97         int event_size = event->midi_buffer_length;
98         assert(event_size > 0);
99                 
100         // Make sure we have enough scratch buffer
101         if (*size < (unsigned)event_size) {
102                 *buf = (uint8_t*)realloc(*buf, event_size);
103         }
104         memcpy(*buf, event->midi_buffer, size_t(event_size));
105         *size = event_size;
106         
107         return event_size;
108     } else {
109         return -1;
110     }
111 }
112
113 template<typename Time>
114 void
115 LibSMF<Time>::append_event_unlocked(uint32_t delta_t, const Event<Time>& ev)
116 {
117         assert(ev.size() > 0);
118         
119         smf_event_t *event;
120
121         event = smf_event_new_from_pointer((void *) ev.buffer(), int(ev.size()));
122         assert(event != NULL);
123         
124         memcpy(event->midi_buffer, ev.buffer(), ev.size());
125         
126         assert(_smf_track);
127         smf_track_add_event_delta_pulses (_smf_track, event, int(delta_t));
128         _last_ev_time = ev.time();
129         
130         if (ev.size() > 0) {
131                 _empty = false;
132         }
133 }
134
135 template<typename Time>
136 void
137 LibSMF<Time>::begin_write(FrameTime start_frame)
138 {
139         assert(_smf_track);
140         smf_track_delete(_smf_track);
141         
142         _smf_track = smf_track_new();
143         assert(_smf_track);
144         
145         smf_add_track(_smf, _smf_track);
146         assert(_smf->number_of_tracks == 1);
147         
148         _last_ev_time = 0;
149 }
150
151 template<typename Time>
152 void
153 LibSMF<Time>::end_write()
154 {
155         smf_save(_smf, _path.c_str());
156 }
157
158 template class LibSMF<double>;
159
160 } // namespace Evoral