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