* implemented editing velocities (http://tracker.ardour.org/view.php?id=2148)
[ardour.git] / libs / ardour / smf_source.cc
1 /*
2     Copyright (C) 2006 Paul Davis 
3         Written by Dave Robillard, 2006
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include <vector>
22
23 #include <sys/time.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #include <errno.h>
27
28 #include <pbd/mountpoint.h>
29 #include <pbd/pathscanner.h>
30 #include <pbd/stl_delete.h>
31 #include <pbd/strsplit.h>
32
33 #include <glibmm/miscutils.h>
34
35 #include <ardour/smf_source.h>
36 #include <ardour/session.h>
37 #include <ardour/midi_ring_buffer.h>
38 #include <ardour/midi_util.h>
39 #include <ardour/tempo.h>
40 #include <ardour/audioengine.h>
41 #include <ardour/smf_reader.h>
42
43 #include "i18n.h"
44
45 using namespace ARDOUR;
46
47 string SMFSource::_search_path;
48
49 /*sigc::signal<void,struct tm*, time_t> SMFSource::HeaderPositionOffsetChanged;
50 bool                                  SMFSource::header_position_negative;
51 uint64_t                              SMFSource::header_position_offset;
52 */
53
54 SMFSource::SMFSource (Session& s, std::string path, Flag flags)
55         : MidiSource (s, region_name_from_path(path, false))
56         , _channel(0)
57         , _flags (Flag(flags | Writable)) // FIXME: this needs to be writable for now
58         , _allow_remove_if_empty(true)
59         , _fd (0)
60         , _last_ev_time(0)
61         , _track_size(4) // 4 bytes for the ever-present EOT event
62         , _header_size(22)
63 {
64         /* constructor used for new internal-to-session files. file cannot exist */
65
66         if (init (path, false)) {
67                 throw failed_constructor ();
68         }
69         
70         if (open()) {
71                 throw failed_constructor ();
72         }
73
74         cerr << "SMF Source path: " << path << endl;
75         
76         assert(_name.find("/") == string::npos);
77 }
78
79 SMFSource::SMFSource (Session& s, const XMLNode& node)
80         : MidiSource (s, node)
81         , _channel(0)
82         , _flags (Flag (Writable|CanRename))
83         , _allow_remove_if_empty(true)
84         , _fd (0)
85         , _last_ev_time(0)
86         , _track_size(4) // 4 bytes for the ever-present EOT event
87         , _header_size(22)
88 {
89         /* constructor used for existing internal-to-session files. file must exist */
90
91         if (set_state (node)) {
92                 throw failed_constructor ();
93         }
94         
95         if (init (_name, true)) {
96                 throw failed_constructor ();
97         }
98         
99         if (open()) {
100                 throw failed_constructor ();
101         }
102         
103         assert(_name.find("/") == string::npos);
104 }
105
106 SMFSource::~SMFSource ()
107 {
108         if (removable()) {
109                 unlink (_path.c_str());
110         }
111 }
112
113 bool
114 SMFSource::removable () const
115 {
116         return (_flags & Removable) && ((_flags & RemoveAtDestroy) || 
117                                       ((_flags & RemovableIfEmpty) && is_empty()));
118 }
119
120 int
121 SMFSource::init (string pathstr, bool must_exist)
122 {
123         bool is_new = false;
124
125         if (!find (pathstr, must_exist, is_new)) {
126                 cerr << "cannot find " << pathstr << " with me = " << must_exist << endl;
127                 return -1;
128         }
129
130         if (is_new && must_exist) {
131                 return -1;
132         }
133
134         assert(_name.find("/") == string::npos);
135         return 0;
136 }
137
138 int
139 SMFSource::open()
140 {
141         //cerr << "Opening SMF file " << path() << " writeable: " << writable() << endl;
142
143         assert(writable()); // FIXME;
144
145         _fd = fopen(path().c_str(), "r+");
146
147         // File already exists
148         if (_fd) {
149                 fseek(_fd, _header_size - 4, 0);
150                 uint32_t track_size_be = 0;
151                 fread(&track_size_be, 4, 1, _fd);
152                 _track_size = GUINT32_FROM_BE(track_size_be);
153                 //cerr << "SMF - read track size " << _track_size << endl;
154
155         // We're making a new file
156         } else {
157                 _fd = fopen(path().c_str(), "w+");
158                 _track_size = 4;
159
160                 // Write a tentative header just to pad things out so writing happens in the right spot
161                 flush_header();
162                 write_footer();
163                 seek_to_end();
164         }
165
166         return (_fd == 0) ? -1 : 0;
167 }
168
169 void
170 SMFSource::seek_to_end()
171 {
172         fseek(_fd, -4, SEEK_END);
173 }
174
175 int
176 SMFSource::flush_header ()
177 {
178         // FIXME: write timeline position somehow?
179         
180         //cerr << "SMF Flushing header\n";
181
182         assert(_fd);
183
184         const uint16_t type     = GUINT16_TO_BE(0);     // SMF Type 0 (single track)
185         const uint16_t ntracks  = GUINT16_TO_BE(1);     // Number of tracks (always 1 for Type 0)
186         const uint16_t division = GUINT16_TO_BE(_ppqn); // Pulses per quarter note (beat)
187
188         char data[6];
189         memcpy(data, &type, 2);
190         memcpy(data+2, &ntracks, 2);
191         memcpy(data+4, &division, 2);
192
193         _fd = freopen(path().c_str(), "r+", _fd);
194         assert(_fd);
195         fseek(_fd, 0, SEEK_SET);
196         write_chunk("MThd", 6, data);
197         write_chunk_header("MTrk", _track_size); 
198
199         fflush(_fd);
200
201         return 0;
202 }
203
204 int
205 SMFSource::flush_footer()
206 {
207         fseek(_fd, 0, SEEK_END);
208         write_footer();
209
210         return 0;
211 }
212
213 void
214 SMFSource::write_footer()
215 {
216         //cerr << "SMF " << name() << " writing EOT at byte " << ftell(_fd) << endl;
217         
218         write_var_len(0);
219         char eot[3] = { 0xFF, 0x2F, 0x00 }; // end-of-track meta-event
220         fwrite(eot, 1, 3, _fd);
221         fflush(_fd);
222 }
223
224 /** Returns the offset of the first event in the file with a time past @a start,
225  * relative to the start of the source.
226  *
227  * Returns -1 if not found.
228  */
229 /*
230 long
231 SMFSource::find_first_event_after(nframes_t start)
232 {
233         // FIXME: obviously this is slooow
234         
235         fseek(_fd, _header_size, 0);
236
237         while ( ! feof(_fd) ) {
238                 const uint32_t delta_time = read_var_len();
239
240                 if (delta_time > start)
241                         return delta_time;
242         }
243
244         return -1;
245 }
246 */
247
248 /** Read an event from the current position in file.
249  *
250  * File position MUST be at the beginning of a delta time, or this will die very messily.
251  * ev.buffer must be of size ev.size, and large enough for the event.  The returned event
252  * will have it's time field set to it's delta time, in SMF tempo-based ticks, using the
253  * rate given by ppqn() (it is the caller's responsibility to calculate a real time).
254  *
255  * \a size should be the capacity of \a buf.  If it is not large enough, \a buf will
256  * be freed and a new buffer allocated in its place, the size of which will be placed
257  * in size.
258  *
259  * Returns event length (including status byte) on success, 0 if event was
260  * skipped (eg a meta event), or -1 on EOF (or end of track).
261  */
262 int
263 SMFSource::read_event(uint32_t* delta_t, uint32_t* size, Byte** buf) const
264 {
265         if (feof(_fd)) {
266                 return -1;
267         }
268
269         assert(delta_t);
270         assert(size);
271         assert(buf);
272
273         try {
274                 *delta_t = SMFReader::read_var_len(_fd);
275         } catch (...) {
276                 return -1; // Premature EOF
277         }
278         
279         if (feof(_fd)) {
280                 return -1; // Premature EOF
281         }
282
283         const int status = fgetc(_fd);
284
285         if (status == EOF) {
286                 return -1; // Premature EOF
287         }
288
289         //printf("Status @ %X = %X\n", (unsigned)ftell(_fd) - 1, status);
290
291         if (status == 0xFF) {
292                 if (feof(_fd)) {
293                         return -1; // Premature EOF
294                 }
295                 const int type = fgetc(_fd);
296                 if ((unsigned char)type == 0x2F) {
297                         return -1; // hit end of track
298                 } else {
299                         *size = 0;
300                         return 0;
301                 }
302         }
303         
304         const int event_size = midi_event_size((unsigned char)status) + 1;
305         if (event_size <= 0) {
306                 *size = 0;
307                 return 0;
308         }
309         
310         // Make sure we have enough scratch buffer
311         if (*size < (unsigned)event_size)
312                 *buf = (Byte*)realloc(*buf, event_size);
313         
314         *size = event_size;
315
316         /*if (ev.buffer == NULL)
317                 ev.buffer = (Byte*)malloc(sizeof(Byte) * ev.size);*/
318
319         (*buf)[0] = (unsigned char)status;
320         if (event_size > 1)
321                 fread((*buf) + 1, 1, *size - 1, _fd);
322
323         printf("%s read event: delta = %u, size = %u, data = ", _name.c_str(), *delta_t, *size);
324         for (size_t i=0; i < *size; ++i) {
325                 printf("%X ", (*buf)[i]);
326         }
327         printf("\n");
328         
329         return (int)*size;
330 }
331
332 /** All stamps in audio frames */
333 nframes_t
334 SMFSource::read_unlocked (MidiRingBuffer& dst, nframes_t start, nframes_t cnt, nframes_t stamp_offset) const
335 {
336         cerr << "SMF read_unlocked " << name() << " read " << start << ", count=" << cnt << ", offset=" << stamp_offset << endl;
337
338         // 64 bits ought to be enough for anybody
339         uint64_t time = 0; // in SMF ticks, 1 tick per _ppqn
340
341         _read_data_count = 0;
342
343         // Output parameters for read_event (which will allocate scratch in buffer as needed)
344         uint32_t ev_delta_t = 0;
345         uint32_t ev_size = 0;
346         Byte*    ev_buffer = 0;
347
348         size_t scratch_size = 0; // keep track of scratch to minimize reallocs
349
350         // FIXME: don't seek to start and search every read (brutal!)
351         fseek(_fd, _header_size, SEEK_SET);
352         
353         // FIXME: assumes tempo never changes after start
354         const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
355                         _session.engine().frame_rate(),
356                         _session.tempo_map().meter_at(_timeline_position));
357         
358         const uint64_t start_ticks = (uint64_t)((start / frames_per_beat) * _ppqn);
359
360         while (!feof(_fd)) {
361                 int ret = read_event(&ev_delta_t, &ev_size, &ev_buffer);
362                 if (ret == -1) { // EOF
363                         //cerr << "SMF - EOF\n";
364                         break;
365                 }
366
367                 if (ret == 0) { // meta-event (skipped)
368                         //cerr << "SMF - META\n";
369                         time += ev_delta_t; // just accumulate delta time and ignore event
370                         continue;
371                 }
372
373                 time += ev_delta_t; // accumulate delta time
374
375                 if (time >= start_ticks) {
376                         const nframes_t ev_frame_time = (nframes_t)(
377                                         ((time / (double)_ppqn) * frames_per_beat)) + stamp_offset;
378
379                         if (ev_frame_time <= start + cnt)
380                                 dst.write(ev_frame_time, ev_size, ev_buffer);
381                         else
382                                 break;
383                 }
384
385                 _read_data_count += ev_size;
386
387                 if (ev_size > scratch_size)
388                         scratch_size = ev_size;
389                 else
390                         ev_size = scratch_size; // minimize realloc in read_event
391         }
392         
393         return cnt;
394 }
395
396 /** All stamps in audio frames */
397 nframes_t
398 SMFSource::write_unlocked (MidiRingBuffer& src, nframes_t cnt)
399 {
400         _write_data_count = 0;
401                 
402         double time;
403         size_t size;
404
405         size_t buf_capacity = 4;
406         Byte* buf = (Byte*)malloc(buf_capacity);
407         
408         if (_model && ! _model->writing())
409                 _model->start_write();
410
411         while (true) {
412                 bool ret = src.full_peek(sizeof(double), (Byte*)&time);
413                 if (!ret || time - _timeline_position > _length + cnt)
414                         break;
415
416                 ret = src.read_prefix(&time, &size);
417                 if (!ret)
418                         break;
419
420                 if (size > buf_capacity) {
421                         buf_capacity = size;
422                         buf = (Byte*)realloc(buf, size);
423                 }
424
425                 ret = src.read_contents(size, buf);
426                 if (!ret) {
427                         cerr << "ERROR: Read time/size but not buffer, corrupt MIDI ring buffer" << endl;
428                         break;
429                 }
430                 
431                 assert(time >= _timeline_position);
432                 time -= _timeline_position;
433
434                 const MIDI::Event ev(time, size, buf);
435                 append_event_unlocked(Frames, ev);
436
437                 if (_model)
438                         _model->append(ev);
439         }
440
441         fflush(_fd);
442         free(buf);
443
444         const nframes_t oldlen = _length;
445         update_length(oldlen, cnt);
446
447         ViewDataRangeReady (_timeline_position + oldlen, cnt); /* EMIT SIGNAL */
448         
449         return cnt;
450 }
451                 
452
453 void
454 SMFSource::append_event_unlocked(EventTimeUnit unit, const MIDI::Event& ev)
455 {
456         /*printf("%s - append chan = %u, time = %lf, size = %u, data = ", _path.c_str(),
457                         (unsigned)ev.channel(), ev.time(), ev.size());
458         for (size_t i=0; i < ev.size(); ++i) {
459                 printf("%X ", ev.buffer()[i]);
460         }
461         printf("\n");*/
462
463         assert(ev.time() >= 0);
464         assert(ev.time() >= _last_ev_time);
465         
466         uint32_t delta_time = 0;
467         
468         if (unit == Frames) {
469                 // FIXME: assumes tempo never changes after start
470                 const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
471                                 _session.engine().frame_rate(),
472                                 _session.tempo_map().meter_at(_timeline_position));
473
474                 delta_time = (uint32_t)((ev.time() - _last_ev_time) / frames_per_beat * _ppqn);
475         } else {
476                 assert(unit == Beats);
477                 delta_time = (uint32_t)((ev.time() - _last_ev_time) * _ppqn);
478         }
479
480         const size_t stamp_size = write_var_len(delta_time);
481         fwrite(ev.buffer(), 1, ev.size(), _fd);
482
483         _track_size += stamp_size + ev.size();
484         _write_data_count += ev.size();
485
486         _last_ev_time = ev.time();
487 }
488
489
490 XMLNode&
491 SMFSource::get_state ()
492 {
493         XMLNode& root (MidiSource::get_state());
494         char buf[16];
495         snprintf (buf, sizeof (buf), "0x%x", (int)_flags);
496         root.add_property ("flags", buf);
497         return root;
498 }
499
500 int
501 SMFSource::set_state (const XMLNode& node)
502 {
503         const XMLProperty* prop;
504
505         if (MidiSource::set_state (node)) {
506                 return -1;
507         }
508
509         if ((prop = node.property (X_("flags"))) != 0) {
510
511                 int ival;
512                 sscanf (prop->value().c_str(), "0x%x", &ival);
513                 _flags = Flag (ival);
514
515         } else {
516
517                 _flags = Flag (0);
518
519         }
520
521         assert(_name.find("/") == string::npos);
522
523         return 0;
524 }
525
526 void
527 SMFSource::mark_for_remove ()
528 {
529         if (!writable()) {
530                 return;
531         }
532         _flags = Flag (_flags | RemoveAtDestroy);
533 }
534
535 void
536 SMFSource::mark_streaming_midi_write_started (NoteMode mode, nframes_t start_frame)
537 {
538         MidiSource::mark_streaming_midi_write_started (mode, start_frame);
539         _last_ev_time = 0;
540 }
541
542 void
543 SMFSource::mark_streaming_write_completed ()
544 {
545         MidiSource::mark_streaming_write_completed();
546
547         if (!writable()) {
548                 return;
549         }
550         
551         flush_header();
552         flush_footer();
553
554 #if 0
555         Glib::Mutex::Lock lm (_lock);
556
557
558         next_peak_clear_should_notify = true;
559
560         if (_peaks_built || pending_peak_builds.empty()) {
561                 _peaks_built = true;
562                  PeaksReady (); /* EMIT SIGNAL */
563         }
564 #endif
565 }
566
567 void
568 SMFSource::mark_take (string id)
569 {
570         if (writable()) {
571                 _take_id = id;
572         }
573 }
574
575 int
576 SMFSource::move_to_trash (const string trash_dir_name)
577 {
578         string newpath;
579
580         if (!writable()) {
581                 return -1;
582         }
583
584         /* don't move the file across filesystems, just
585            stick it in the 'trash_dir_name' directory
586            on whichever filesystem it was already on.
587         */
588
589         newpath = Glib::path_get_dirname (_path);
590         newpath = Glib::path_get_dirname (newpath);
591
592         newpath += '/';
593         newpath += trash_dir_name;
594         newpath += '/';
595         newpath += Glib::path_get_basename (_path);
596
597         if (access (newpath.c_str(), F_OK) == 0) {
598
599                 /* the new path already exists, try versioning */
600                 
601                 char buf[PATH_MAX+1];
602                 int version = 1;
603                 string newpath_v;
604
605                 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
606                 newpath_v = buf;
607
608                 while (access (newpath_v.c_str(), F_OK) == 0 && version < 999) {
609                         snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
610                         newpath_v = buf;
611                 }
612                 
613                 if (version == 999) {
614                         PBD::error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
615                                           newpath)
616                               << endmsg;
617                 } else {
618                         newpath = newpath_v;
619                 }
620
621         } else {
622
623                 /* it doesn't exist, or we can't read it or something */
624
625         }
626
627         if (::rename (_path.c_str(), newpath.c_str()) != 0) {
628                 PBD::error << string_compose (_("cannot rename midi file source from %1 to %2 (%3)"),
629                                   _path, newpath, strerror (errno))
630                       << endmsg;
631                 return -1;
632         }
633 #if 0
634         if (::unlink (peakpath.c_str()) != 0) {
635                 PBD::error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
636                                   peakpath, _path, strerror (errno))
637                       << endmsg;
638                 /* try to back out */
639                 rename (newpath.c_str(), _path.c_str());
640                 return -1;
641         }
642             
643         _path = newpath;
644         peakpath = "";
645 #endif  
646         /* file can not be removed twice, since the operation is not idempotent */
647
648         _flags = Flag (_flags & ~(RemoveAtDestroy|Removable|RemovableIfEmpty));
649
650         return 0;
651 }
652
653 bool
654 SMFSource::safe_file_extension(const Glib::ustring& file)
655 {
656         return (file.rfind(".mid") != Glib::ustring::npos);
657 }
658
659 // FIXME: Merge this with audiofilesource somehow (make a generic filesource?)
660 bool
661 SMFSource::find (string pathstr, bool must_exist, bool& isnew)
662 {
663         string::size_type pos;
664         bool ret = false;
665
666         isnew = false;
667
668         /* clean up PATH:CHANNEL notation so that we are looking for the correct path */
669
670         if ((pos = pathstr.find_last_of (':')) == string::npos) {
671                 pathstr = pathstr;
672         } else {
673                 pathstr = pathstr.substr (0, pos);
674         }
675
676         if (pathstr[0] != '/') {
677
678                 /* non-absolute pathname: find pathstr in search path */
679
680                 vector<string> dirs;
681                 int cnt;
682                 string fullpath;
683                 string keeppath;
684
685                 if (_search_path.length() == 0) {
686                         PBD::error << _("FileSource: search path not set") << endmsg;
687                         goto out;
688                 }
689
690                 split (_search_path, dirs, ':');
691
692                 cnt = 0;
693                 
694                 for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
695
696                         fullpath = *i;
697                         if (fullpath[fullpath.length()-1] != '/') {
698                                 fullpath += '/';
699                         }
700                         fullpath += pathstr;
701                         
702                         if (access (fullpath.c_str(), R_OK) == 0) {
703                                 keeppath = fullpath;
704                                 ++cnt;
705                         } 
706                 }
707
708                 if (cnt > 1) {
709
710                         PBD::error << string_compose (_("FileSource: \"%1\" is ambigous when searching %2\n\t"), pathstr, _search_path) << endmsg;
711                         goto out;
712
713                 } else if (cnt == 0) {
714
715                         if (must_exist) {
716                                 PBD::error << string_compose(_("Filesource: cannot find required file (%1): while searching %2"), pathstr, _search_path) << endmsg;
717                                 goto out;
718                         } else {
719                                 isnew = true;
720                         }
721                 }
722                 
723                 _name = pathstr;
724                 _path = keeppath;
725                 ret = true;
726
727         } else {
728                 
729                 /* external files and/or very very old style sessions include full paths */
730                 
731                 _path = pathstr;
732                 _name = pathstr.substr (pathstr.find_last_of ('/') + 1);
733                 
734                 if (access (_path.c_str(), R_OK) != 0) {
735
736                         /* file does not exist or we cannot read it */
737
738                         if (must_exist) {
739                                 PBD::error << string_compose(_("Filesource: cannot find required file (%1): %2"), _path, strerror (errno)) << endmsg;
740                                 goto out;
741                         }
742                         
743                         if (errno != ENOENT) {
744                                 PBD::error << string_compose(_("Filesource: cannot check for existing file (%1): %2"), _path, strerror (errno)) << endmsg;
745                                 goto out;
746                         }
747                         
748                         /* a new file */
749
750                         isnew = true;
751                         ret = true;
752
753                 } else {
754                         
755                         /* already exists */
756
757                         ret = true;
758                 }
759         }
760         
761   out:
762         return ret;
763 }
764
765 void
766 SMFSource::set_search_path (string p)
767 {
768         _search_path = p;
769 }
770
771
772 void
773 SMFSource::set_allow_remove_if_empty (bool yn)
774 {
775         if (writable()) {
776                 _allow_remove_if_empty = yn;
777         }
778 }
779
780 int
781 SMFSource::set_source_name (string newname, bool destructive)
782 {
783         //Glib::Mutex::Lock lm (_lock); FIXME
784         string oldpath = _path;
785         string newpath = Session::change_midi_path_by_name (oldpath, _name, newname, destructive);
786
787         if (newpath.empty()) {
788                 PBD::error << string_compose (_("programming error: %1"), "cannot generate a changed midi path") << endmsg;
789                 return -1;
790         }
791
792         if (rename (oldpath.c_str(), newpath.c_str()) != 0) {
793                 PBD::error << string_compose (_("cannot rename midi file for %1 to %2"), _name, newpath) << endmsg;
794                 return -1;
795         }
796
797         _name = Glib::path_get_basename (newpath);
798         _path = newpath;
799
800         return 0;//rename_peakfile (peak_path (_path));
801 }
802
803 bool
804 SMFSource::is_empty () const
805 {
806         bool ret = (_track_size > 4);
807
808         //cerr << name() << " IS EMPTY: " << ret << endl;
809
810         return ret;
811 }
812
813
814 void
815 SMFSource::write_chunk_header(const char id[4], uint32_t length)
816 {
817         const uint32_t length_be = GUINT32_TO_BE(length);
818
819         fwrite(id, 1, 4, _fd);
820         fwrite(&length_be, 4, 1, _fd);
821 }
822
823 void
824 SMFSource::write_chunk(const char id[4], uint32_t length, void* data)
825 {
826         write_chunk_header(id, length);
827         
828         fwrite(data, 1, length, _fd);
829 }
830
831 /** Returns the size (in bytes) of the value written. */
832 size_t
833 SMFSource::write_var_len(uint32_t value)
834 {
835         size_t ret = 0;
836
837         uint32_t buffer = value & 0x7F;
838
839         while ( (value >>= 7) ) {
840                 buffer <<= 8;
841                 buffer |= ((value & 0x7F) | 0x80);
842         }
843
844         while (true) {
845                 //printf("Writing var len byte %X\n", (unsigned char)buffer);
846                 ++ret;
847                 fputc(buffer, _fd);
848                 if (buffer & 0x80)
849                         buffer >>= 8;
850                 else
851                         break;
852         }
853
854         return ret;
855 }
856
857 void
858 SMFSource::load_model(bool lock, bool force_reload)
859 {
860         if (_writing)
861                 return;
862
863         if (lock)
864                 Glib::Mutex::Lock lm (_lock);
865
866         if (_model && !force_reload && !_model->empty()) {
867                 //cerr << _name << " NOT reloading model " << _model.get() << " (" << _model->n_notes()
868                 //      << " notes)" << endl;
869                 return;
870         } else {
871                 cerr << _name << " loading model" << endl;
872         }
873
874         if (! _model) {
875                 _model = boost::shared_ptr<MidiModel>(new MidiModel(_session));
876                 cerr << _name << " loaded new model " << _model.get() << endl;
877         } else {
878                 cerr << _name << " reloading model " << _model.get()
879                         << " (" << _model->n_notes() << " notes)" <<endl;
880                 _model->clear();
881         }
882
883         _model->start_write();
884
885         fseek(_fd, _header_size, 0);
886
887         uint64_t time = 0; /* in SMF ticks */
888         MIDI::Event ev;
889         
890         size_t scratch_size = 0; // keep track of scratch and minimize reallocs
891         
892         // FIXME: assumes tempo never changes after start
893         const double frames_per_beat = _session.tempo_map().tempo_at(_timeline_position).frames_per_beat(
894                         _session.engine().frame_rate(),
895                         _session.tempo_map().meter_at(_timeline_position));
896         
897         uint32_t delta_t = 0;
898         int ret;
899         while ((ret = read_event(&delta_t, &ev.size(), &ev.buffer())) >= 0) {
900                 
901                 time += delta_t;
902                 
903                 if (ret > 0) { // didn't skip (meta) event
904                         // make ev.time absolute time in frames
905                         ev.time() = (double)time * frames_per_beat / (double)_ppqn;
906
907                         _model->append(ev);
908                 }
909
910                 if (ev.size() > scratch_size)
911                         scratch_size = ev.size();
912                 else
913                         ev.size() = scratch_size;
914         }
915         
916         _model->end_write(false);
917
918         free(ev.buffer());
919 }
920
921
922 void
923 SMFSource::destroy_model()
924 {
925         //cerr << _name << " destroying model " << _model.get() << endl;
926         _model.reset();
927 }
928