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