De-templatify Evoral::SMF which has no concept of time other than SMF time.
[ardour.git] / libs / evoral / src / SMF.cpp
1 /* This file is part of Evoral.
2  * Copyright (C) 2008 Dave Robillard <http://drobilla.net>
3  * Copyright (C) 2000-2008 Paul Davis
4  * Author: Hans Baier
5  * 
6  * Evoral is free software; you can redistribute it and/or modify it under the
7  * terms of the GNU General Public License as published by the Free Software
8  * Foundation; either version 2 of the License, or (at your option) any later
9  * version.
10  * 
11  * Evoral is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for details.
14  * 
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19
20 #define __STDC_LIMIT_MACROS 1
21 #include <cassert>
22 #include <iostream>
23 #include <stdint.h>
24 #include "evoral/Event.hpp"
25 #include "evoral/SMF.hpp"
26 #include "libsmf/smf.h"
27
28 using namespace std;
29
30 namespace Evoral {
31
32 SMF::~SMF()
33 {       
34         if (_smf) {
35                 smf_delete(_smf);
36                 _smf = 0;
37                 _smf_track = 0;
38         } 
39 }
40
41 uint16_t
42 SMF::num_tracks() const
43 {
44         return _smf->number_of_tracks;
45 }
46
47 uint16_t
48 SMF::ppqn() const
49 {
50         return _smf->ppqn;
51 }
52
53 /** Seek to the specified track (1-based indexing)
54  * \return 0 on success
55  */
56 int
57 SMF::seek_to_track(int track)
58 {
59         _smf_track = smf_get_track_by_number(_smf, track);
60         if (_smf_track != NULL) {
61                 _smf_track->next_event_number = (_smf_track->number_of_events == 0) ? 0 : 1;
62                 return 0;
63         } else {
64                 return -1;
65         }
66 }
67
68 /** Attempt to open the SMF file for reading and/or writing.
69  *
70  * \return  0 on success
71  *         -1 if the file can not be opened or created
72  *         -2 if the file exists but specified track does not exist
73  */
74 int
75 SMF::open(const std::string& path, int track) THROW_FILE_ERROR
76 {
77         assert(track >= 1);
78         if (_smf) { 
79                 smf_delete(_smf);
80         }
81         
82         _path = path;
83         _smf = smf_load(_path.c_str());
84         if (_smf == NULL) {
85                 return -1;
86         }
87
88         _smf_track = smf_get_track_by_number(_smf, track);
89         if (!_smf_track)
90                 return -2;
91
92         cerr << "Track " << track << " # events: " << _smf_track->number_of_events << endl;
93         if (_smf_track->number_of_events == 0) {
94                 _smf_track->next_event_number = 0;
95                 _empty = true;
96         } else {
97                 _smf_track->next_event_number = 1;
98                 _empty = false;
99         }
100         
101         return 0;
102 }
103
104
105 /** Attempt to create a new SMF file for reading and/or writing.
106  *
107  * \return  0 on success
108  *         -1 if the file can not be created
109  *         -2 if the track can not be created
110  */
111 int
112 SMF::create(const std::string& path, int track, uint16_t ppqn) THROW_FILE_ERROR
113 {
114         assert(track >= 1);
115         if (_smf) { 
116                 smf_delete(_smf);
117         }
118         
119         _path = path;
120
121         _smf = smf_new();
122         if (smf_set_ppqn(_smf, ppqn) != 0) {
123                 throw FileError();
124         }
125         
126         if (_smf == NULL) {
127                 return -1;
128         }
129         
130         for (int i = 0; i < track; ++i) {
131                 _smf_track = smf_track_new();
132                 assert(_smf_track);
133                 smf_add_track(_smf, _smf_track);
134         }
135
136         _smf_track = smf_get_track_by_number(_smf, track);
137         if (!_smf_track)
138                 return -2;
139
140         _smf_track->next_event_number = 0;
141         _empty = true;
142         
143         return 0;
144 }
145
146 void
147 SMF::close() THROW_FILE_ERROR
148 {
149         if (_smf) {
150                 if (smf_save(_smf, _path.c_str()) != 0) {
151                         throw FileError();
152                 }
153                 smf_delete(_smf);
154                 _smf = 0;
155                 _smf_track = 0;
156         }
157 }
158
159 void
160 SMF::seek_to_start() const
161 {
162         _smf_track->next_event_number = 1;
163 }
164
165 /** Read an event from the current position in file.
166  *
167  * File position MUST be at the beginning of a delta time, or this will die very messily.
168  * ev.buffer must be of size ev.size, and large enough for the event.  The returned event
169  * will have it's time field set to it's delta time, in SMF tempo-based ticks, using the
170  * rate given by ppqn() (it is the caller's responsibility to calculate a real time).
171  *
172  * \a buf must be a pointer to a buffer allocated with malloc, or a pointer to NULL.
173  * \a size must be the capacity of \a buf.  If it is not large enough, \a buf will
174  * be reallocated and *size will be set to the new size of buf.
175  *
176  * \return event length (including status byte) on success, 0 if event was
177  * skipped (e.g. a meta event), or -1 on EOF (or end of track).
178  */
179 int
180 SMF::read_event(uint32_t* delta_t, uint32_t* size, uint8_t** buf) const
181 {
182         smf_event_t* event;
183         
184         assert(delta_t);
185         assert(size);
186         assert(buf);
187         
188     if ((event = smf_track_get_next_event(_smf_track)) != NULL) {
189         if (smf_event_is_metadata(event)) {
190                 return 0;
191         }
192         *delta_t = event->delta_time_pulses;
193         
194         int event_size = event->midi_buffer_length;
195         assert(event_size > 0);
196                 
197         // Make sure we have enough scratch buffer
198         if (*size < (unsigned)event_size) {
199                 *buf = (uint8_t*)realloc(*buf, event_size);
200         }
201         memcpy(*buf, event->midi_buffer, size_t(event_size));
202         *size = event_size;
203         
204                 /*printf("SMF::read_event:\n");
205                 for (size_t i = 0; i < *size; ++i) {
206                         printf("%X ", (*buf)[i]);
207                 } printf("\n");*/
208         
209         return event_size;
210     } else {
211         return -1;
212     }
213 }
214
215 void
216 SMF::append_event_delta(uint32_t delta_t, uint32_t size, const uint8_t* buf)
217 {
218         if (size == 0) {
219                 return;
220         }
221         
222         /*printf("SMF::append_event_delta:\n");
223         for (size_t i = 0; i < size; ++i) {
224                 printf("%X ", buf[i]);
225         } printf("\n");*/
226
227         smf_event_t* event;
228
229         event = smf_event_new_from_pointer(buf, size);
230         assert(event != NULL);
231         
232         assert(_smf_track);
233         smf_track_add_event_delta_pulses(_smf_track, event, delta_t);
234         _empty = false;
235 }
236
237 void
238 SMF::begin_write()
239 {
240         assert(_smf_track);
241         smf_track_delete(_smf_track);
242         
243         _smf_track = smf_track_new();
244         assert(_smf_track);
245         
246         smf_add_track(_smf, _smf_track);
247         assert(_smf->number_of_tracks == 1);
248 }
249
250 void
251 SMF::end_write() THROW_FILE_ERROR
252 {
253         if (smf_save(_smf, _path.c_str()) != 0)
254                 throw FileError();
255 }
256
257
258 } // namespace Evoral