2 * libptformat - a library to read ProTools sessions
4 * Copyright (C) 2015-2019 Damien Zammit
5 * Copyright (C) 2015-2019 Robin Gareus
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30 # include <glib/gstdio.h>
31 # define ptf_open g_fopen
33 # define ptf_open fopen
36 #include "ptformat/ptformat.h"
38 #define BITCODE "0010111100101011"
40 #define ZERO_TICKS 0xe8d4a51000ULL
41 #define MAX_CONTENT_TYPE 0x3000
42 #define MAX_CHANNELS_PER_TRACK 8
49 #define verbose_printf(...) printf("XXX PTFORMAT XXX: " __VA_ARGS__)
51 #define verbose_printf(...)
57 hexdump(uint8_t *data, int length, int level)
59 int i,j,k,end,step=16;
61 for (i = 0; i < length; i += step) {
63 if (end > length) end = length;
64 for (k = 0; k < level; k++)
66 for (j = i; j < end; j++) {
67 printf("%02X ", data[j]);
69 for (j = i; j < end; j++) {
70 if (data[j] < 128 && data[j] > 32)
71 printf("%c", data[j]);
79 PTFFormat::PTFFormat()
91 PTFFormat::~PTFFormat() {
96 PTFFormat::get_content_description(uint16_t ctype) {
99 return std::string("INFO product and version");
101 return std::string("WAV samplerate, size");
103 return std::string("WAV metadata");
105 return std::string("WAV list full");
107 return std::string("region name, number");
109 return std::string("AUDIO region name, number (v5)");
111 return std::string("AUDIO region list (v5)");
113 return std::string("AUDIO region->track entry");
115 return std::string("AUDIO region->track map entries");
117 return std::string("AUDIO region->track full map");
119 return std::string("AUDIO track name, number");
121 return std::string("AUDIO tracks");
123 return std::string("PLUGIN entry");
125 return std::string("PLUGIN full list");
127 return std::string("I/O channel entry");
129 return std::string("I/O channel list");
131 return std::string("INFO sample rate");
133 return std::string("WAV names");
135 return std::string("AUDIO region->track subentry (v8)");
137 return std::string("AUDIO region->track entry (v8)");
139 return std::string("AUDIO region->track map entries (v8)");
141 return std::string("AUDIO region->track full map (v8)");
143 return std::string("MIDI region->track entry");
145 return std::string("MIDI region->track map entries");
147 return std::string("MIDI region->track full map");
149 return std::string("MIDI events block");
151 return std::string("MIDI region name, number (v5)");
153 return std::string("MIDI regions map (v5)");
155 return std::string("INFO path of session");
157 return std::string("Snaps block");
159 return std::string("MIDI track full list");
161 return std::string("MIDI track name, number");
163 return std::string("COMPOUND region element");
165 return std::string("I/O route");
167 return std::string("I/O routing table");
169 return std::string("COMPOUND region group");
171 return std::string("AUDIO region name, number (v10)");
173 return std::string("AUDIO region list (v10)");
175 return std::string("COMPOUND region full map");
177 return std::string("MIDI regions name, number (v10)");
179 return std::string("MIDI regions map (v10)");
181 return std::string("MARKER list");
183 return std::string("UNKNOWN content type");
188 u_endian_read2(unsigned char *buf, bool bigendian)
191 return ((uint16_t)(buf[0]) << 8) | (uint16_t)(buf[1]);
193 return ((uint16_t)(buf[1]) << 8) | (uint16_t)(buf[0]);
198 u_endian_read3(unsigned char *buf, bool bigendian)
201 return ((uint32_t)(buf[0]) << 16) |
202 ((uint32_t)(buf[1]) << 8) |
205 return ((uint32_t)(buf[2]) << 16) |
206 ((uint32_t)(buf[1]) << 8) |
212 u_endian_read4(unsigned char *buf, bool bigendian)
215 return ((uint32_t)(buf[0]) << 24) |
216 ((uint32_t)(buf[1]) << 16) |
217 ((uint32_t)(buf[2]) << 8) |
220 return ((uint32_t)(buf[3]) << 24) |
221 ((uint32_t)(buf[2]) << 16) |
222 ((uint32_t)(buf[1]) << 8) |
228 u_endian_read5(unsigned char *buf, bool bigendian)
231 return ((uint64_t)(buf[0]) << 32) |
232 ((uint64_t)(buf[1]) << 24) |
233 ((uint64_t)(buf[2]) << 16) |
234 ((uint64_t)(buf[3]) << 8) |
237 return ((uint64_t)(buf[4]) << 32) |
238 ((uint64_t)(buf[3]) << 24) |
239 ((uint64_t)(buf[2]) << 16) |
240 ((uint64_t)(buf[1]) << 8) |
246 u_endian_read8(unsigned char *buf, bool bigendian)
249 return ((uint64_t)(buf[0]) << 56) |
250 ((uint64_t)(buf[1]) << 48) |
251 ((uint64_t)(buf[2]) << 40) |
252 ((uint64_t)(buf[3]) << 32) |
253 ((uint64_t)(buf[4]) << 24) |
254 ((uint64_t)(buf[5]) << 16) |
255 ((uint64_t)(buf[6]) << 8) |
258 return ((uint64_t)(buf[7]) << 56) |
259 ((uint64_t)(buf[6]) << 48) |
260 ((uint64_t)(buf[5]) << 40) |
261 ((uint64_t)(buf[4]) << 32) |
262 ((uint64_t)(buf[3]) << 24) |
263 ((uint64_t)(buf[2]) << 16) |
264 ((uint64_t)(buf[1]) << 8) |
270 PTFFormat::cleanup(void) {
280 _midiregions.clear();
287 PTFFormat::foundat(unsigned char *haystack, uint64_t n, const char *needle) {
289 uint64_t i, j, needle_n;
290 needle_n = strlen(needle);
292 for (i = 0; i < n; i++) {
294 for (j = 0; j < needle_n; j++) {
295 if (haystack[i+j] != needle[j]) {
307 PTFFormat::jumpto(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen) {
309 uint64_t k = *currpos;
310 while (k + needlelen < maxoffset) {
311 bool foundall = true;
312 for (i = 0; i < needlelen; i++) {
313 if (buf[k+i] != needle[i]) {
328 PTFFormat::jumpback(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen) {
330 uint64_t k = *currpos;
331 while (k > 0 && k + needlelen < maxoffset) {
332 bool foundall = true;
333 for (i = 0; i < needlelen; i++) {
334 if (buf[k+i] != needle[i]) {
349 PTFFormat::foundin(std::string const& haystack, std::string const& needle) {
350 size_t found = haystack.find(needle);
351 if (found != std::string::npos) {
358 /* Return values: 0 success
359 -1 error decrypting pt session
362 PTFFormat::unxor(std::string const& path) {
364 unsigned char xxor[256];
372 if (! (fp = ptf_open(path.c_str(), "rb"))) {
376 fseek(fp, 0, SEEK_END);
383 if (! (_ptfunxored = (unsigned char*) malloc(_len * sizeof(unsigned char)))) {
384 /* Silently fail -- out of memory*/
390 /* The first 20 bytes are always unencrypted */
391 fseek(fp, 0x00, SEEK_SET);
392 i = fread(_ptfunxored, 1, 0x14, fp);
398 xor_type = _ptfunxored[0x12];
399 xor_value = _ptfunxored[0x13];
402 // xor_type 0x01 = ProTools 5, 6, 7, 8 and 9
403 // xor_type 0x05 = ProTools 10, 11, 12
406 xor_delta = gen_xor_delta(xor_value, 53, false);
409 xor_delta = gen_xor_delta(xor_value, 11, true);
416 /* Generate the xor_key */
417 for (i=0; i < xor_len; i++)
418 xxor[i] = (i * xor_delta) & 0xff;
420 /* hexdump(xxor, xor_len); */
422 /* Read file and decrypt rest of file */
424 fseek(fp, i, SEEK_SET);
425 while (fread(&ct, 1, 1, fp) != 0) {
426 uint8_t xor_index = (xor_type == 0x01) ? i & 0xff : (i >> 12) & 0xff;
427 _ptfunxored[i++] = ct ^ xxor[xor_index];
433 /* Return values: 0 success
434 -1 error decrypting pt session
435 -2 error detecting pt session
436 -3 incompatible pt version
437 -4 error parsing pt session
440 PTFFormat::load(std::string const& ptf, int64_t targetsr) {
450 if (_version < 5 || _version > 12)
453 _targetrate = targetsr;
456 if ((err = parse())) {
457 printf ("PARSE FAILED %d\n", err);
465 PTFFormat::parse_version() {
466 uint32_t seg_len,str_len;
467 uint8_t *data = _ptfunxored + 0x14;
468 uintptr_t data_end = ((uintptr_t)_ptfunxored) + 0x100;
470 bool success = false;
472 if (_ptfunxored[0] != '\x03' && foundat(_ptfunxored, 0x100, BITCODE) != 1) {
476 while( ((uintptr_t)data < data_end) && (success == false) ) {
478 if (data[0] != 0x5a) {
484 /* Skip segment header */
486 if (data[0] == 0 && data[1] == 0) {
491 is_bigendian = false;
493 seg_len = u_endian_read4(&data[0], is_bigendian);
497 if (!(seg_type == 0x04 || seg_type == 0x03) || data[0] != 0x03) {
498 /* Go to next segment */
502 /* Skip 0x03 0x00 0x00 */
505 str_len = (*(uint8_t *)data);
506 if (! (_product = (uint8_t *)malloc((str_len+1) * sizeof(uint8_t)))) {
515 memcpy(_product, data, str_len);
516 _product[str_len] = 0;
520 /* Skip 0x03 0x00 0x00 0x00 */
532 /* If the above does not work, try other heuristics */
533 if ((uintptr_t)data >= data_end - seg_len) {
534 _version = _ptfunxored[0x40];
536 _version = _ptfunxored[0x3d];
539 _version = _ptfunxored[0x3a] + 2;
549 PTFFormat::gen_xor_delta(uint8_t xor_value, uint8_t mul, bool negative) {
551 for (i = 0; i < 256; i++) {
552 if (((i * mul) & 0xff) == xor_value) {
553 return (negative) ? i * (-1) : i;
561 PTFFormat::setrates(void) {
563 if (_sessionrate != 0) {
564 _ratefactor = (float)_targetrate / _sessionrate;
569 PTFFormat::parse_block_at(uint32_t pos, struct block_t *block, struct block_t *parent, int level) {
575 if (_ptfunxored[pos] != ZMARK)
579 max = parent->block_size + parent->offset;
582 b.block_type = u_endian_read2(&_ptfunxored[pos+1], is_bigendian);
583 b.block_size = u_endian_read4(&_ptfunxored[pos+3], is_bigendian);
584 b.content_type = u_endian_read2(&_ptfunxored[pos+7], is_bigendian);
587 if (b.block_size + b.offset > max)
589 if (b.block_type & 0xff00)
592 block->zmark = b.zmark;
593 block->block_type = b.block_type;
594 block->block_size = b.block_size;
595 block->content_type = b.content_type;
596 block->offset = b.offset;
597 block->child.clear();
599 for (i = 1; (i < block->block_size) && (pos + i + childjump < max); i += childjump ? childjump : 1) {
601 struct block_t bchild;
603 if (parse_block_at(p, &bchild, block, level+1)) {
604 block->child.push_back(bchild);
605 childjump = bchild.block_size + 7;
612 PTFFormat::dump_block(struct block_t& b, int level)
616 for (i = 0; i < level; i++) {
619 printf("%s(0x%04x)\n", get_content_description(b.content_type).c_str(), b.content_type);
620 hexdump(&_ptfunxored[b.offset], b.block_size, level);
622 for (vector<PTFFormat::block_t>::iterator c = b.child.begin();
623 c != b.child.end(); ++c) {
624 dump_block(*c, level + 1);
629 PTFFormat::free_block(struct block_t& b)
631 for (vector<PTFFormat::block_t>::iterator c = b.child.begin();
632 c != b.child.end(); ++c) {
640 PTFFormat::free_all_blocks(void)
642 for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
643 b != blocks.end(); ++b) {
651 PTFFormat::dump(void) {
652 for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
653 b != blocks.end(); ++b) {
659 PTFFormat::parseblocks(void) {
664 if (parse_block_at(i, &b, NULL, 0)) {
667 i += b.block_size ? b.block_size + 7 : 1;
672 PTFFormat::parse(void) {
680 if (_sessionrate < 44100 || _sessionrate > 192000)
692 PTFFormat::parseheader(void) {
695 for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
696 b != blocks.end(); ++b) {
697 if (b->content_type == 0x1028) {
698 _sessionrate = u_endian_read4(&_ptfunxored[b->offset+4], is_bigendian);
706 PTFFormat::parsestring (uint32_t pos) {
707 uint32_t length = u_endian_read4(&_ptfunxored[pos], is_bigendian);
709 return std::string((const char *)&_ptfunxored[pos], length);
713 PTFFormat::parseaudio(void) {
715 uint32_t nwavs, i, n;
721 for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
722 b != blocks.end(); ++b) {
723 if (b->content_type == 0x1004) {
725 nwavs = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian);
727 for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
728 c != b->child.end(); ++c) {
729 if (c->content_type == 0x103a) {
731 //nstrings = u_endian_read4(&_ptfunxored[c->offset+1], is_bigendian);
732 pos = c->offset + 11;
734 for (i = n = 0; (pos < c->offset + c->block_size) && (n < nwavs); i++) {
735 wavname = parsestring(pos);
736 pos += wavname.size() + 4;
737 wavtype = std::string((const char*)&_ptfunxored[pos], 4);
739 if (foundin(wavname, std::string(".grp")))
742 if (foundin(wavname, std::string("Audio Files"))) {
745 if (foundin(wavname, std::string("Fade Files"))) {
749 if (!(foundin(wavtype, std::string("WAVE")) ||
750 foundin(wavtype, std::string("EVAW")) ||
751 foundin(wavtype, std::string("AIFF")) ||
752 foundin(wavtype, std::string("FFIA"))) ) {
756 if (wavtype.size() != 0) {
757 if (!(foundin(wavtype, std::string("WAVE")) ||
758 foundin(wavtype, std::string("EVAW")) ||
759 foundin(wavtype, std::string("AIFF")) ||
760 foundin(wavtype, std::string("FFIA"))) ) {
763 } else if (!(foundin(wavname, std::string(".wav")) ||
764 foundin(wavname, std::string(".aif"))) ) {
769 f.filename = wavname;
771 _audiofiles.push_back(f);
778 // Add wav length information
779 for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
780 b != blocks.end(); ++b) {
781 if (b->content_type == 0x1004) {
783 vector<PTFFormat::wav_t>::iterator wav = _audiofiles.begin();
785 for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
786 c != b->child.end(); ++c) {
787 if (c->content_type == 0x1003) {
788 for (vector<PTFFormat::block_t>::iterator d = c->child.begin();
789 d != c->child.end(); ++d) {
790 if (d->content_type == 0x1001) {
791 (*wav).length = u_endian_read8(&_ptfunxored[d->offset+8], is_bigendian);
805 PTFFormat::parse_three_point(uint32_t j, uint64_t& start, uint64_t& offset, uint64_t& length) {
806 uint8_t offsetbytes, lengthbytes, startbytes;
809 offsetbytes = (_ptfunxored[j+4] & 0xf0) >> 4;
810 lengthbytes = (_ptfunxored[j+3] & 0xf0) >> 4;
811 startbytes = (_ptfunxored[j+2] & 0xf0) >> 4;
812 //somethingbytes = (_ptfunxored[j+2] & 0xf);
813 //skipbytes = _ptfunxored[j+1];
815 offsetbytes = (_ptfunxored[j+1] & 0xf0) >> 4; //3
816 lengthbytes = (_ptfunxored[j+2] & 0xf0) >> 4;
817 startbytes = (_ptfunxored[j+3] & 0xf0) >> 4; //1
818 //somethingbytes = (_ptfunxored[j+3] & 0xf);
819 //skipbytes = _ptfunxored[j+4];
822 switch (offsetbytes) {
824 offset = u_endian_read5(&_ptfunxored[j+5], false);
827 offset = (uint64_t)u_endian_read4(&_ptfunxored[j+5], false);
830 offset = (uint64_t)u_endian_read3(&_ptfunxored[j+5], false);
833 offset = (uint64_t)u_endian_read2(&_ptfunxored[j+5], false);
836 offset = (uint64_t)(_ptfunxored[j+5]);
843 switch (lengthbytes) {
845 length = u_endian_read5(&_ptfunxored[j+5], false);
848 length = (uint64_t)u_endian_read4(&_ptfunxored[j+5], false);
851 length = (uint64_t)u_endian_read3(&_ptfunxored[j+5], false);
854 length = (uint64_t)u_endian_read2(&_ptfunxored[j+5], false);
857 length = (uint64_t)(_ptfunxored[j+5]);
864 switch (startbytes) {
866 start = u_endian_read5(&_ptfunxored[j+5], false);
869 start = (uint64_t)u_endian_read4(&_ptfunxored[j+5], false);
872 start = (uint64_t)u_endian_read3(&_ptfunxored[j+5], false);
875 start = (uint64_t)u_endian_read2(&_ptfunxored[j+5], false);
878 start = (uint64_t)(_ptfunxored[j+5]);
887 PTFFormat::parse_region_info(uint32_t j, block_t& blk, region_t& r) {
888 uint64_t findex, start, sampleoffset, length;
890 parse_three_point(j, start, sampleoffset, length);
892 findex = u_endian_read4(&_ptfunxored[blk.offset + blk.block_size], is_bigendian);
894 f.posabsolute = start * _ratefactor;
895 f.length = length * _ratefactor;
898 if (find_wav(findex, found)) {
899 f.filename = found.filename;
902 std::vector<midi_ev_t> m;
903 r.startpos = (int64_t)(start*_ratefactor);
904 r.sampleoffset = (int64_t)(sampleoffset*_ratefactor);
905 r.length = (int64_t)(length*_ratefactor);
911 PTFFormat::parserest(void) {
912 uint32_t i, j, count;
914 uint16_t rindex, rawindex, tindex, mindex;
916 uint16_t ch_map[MAX_CHANNELS_PER_TRACK];
918 bool region_is_fade = false;
919 std::string regionname, trackname, midiregionname;
922 // Parse sources->regions
923 for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
924 b != blocks.end(); ++b) {
925 if (b->content_type == 0x100b || b->content_type == 0x262a) {
926 //nregions = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian);
927 for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
928 c != b->child.end(); ++c) {
929 if (c->content_type == 0x1008 || c->content_type == 0x2629) {
930 vector<PTFFormat::block_t>::iterator d = c->child.begin();
935 regionname = parsestring(j);
936 j += regionname.size() + 4;
940 parse_region_info(j, *d, r);
942 _regions.push_back(r);
951 for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
952 b != blocks.end(); ++b) {
953 if (b->content_type == 0x1015) {
954 //ntracks = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian);
955 for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
956 c != b->child.end(); ++c) {
957 if (c->content_type == 0x1014) {
959 trackname = parsestring(j);
960 j += trackname.size() + 5;
961 nch = u_endian_read4(&_ptfunxored[j], is_bigendian);
963 for (i = 0; i < nch; i++) {
964 ch_map[i] = u_endian_read2(&_ptfunxored[j], is_bigendian);
967 if (!find_track(ch_map[i], ti)) {
968 // Add a dummy region for now
970 track_t t (ch_map[i]);
973 _tracks.push_back(t);
975 //verbose_printf("%s : %d(%d)\n", reg, nch, ch_map[0]);
983 // Reparse from scratch to exclude audio tracks from all tracks to get midi tracks
984 for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
985 b != blocks.end(); ++b) {
986 if (b->content_type == 0x2519) {
989 //ntracks = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian);
990 for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
991 c != b->child.end(); ++c) {
992 if (c->content_type == 0x251a) {
994 trackname = parsestring(j);
995 j += trackname.size() + 4 + 18;
996 //tindex = u_endian_read4(&_ptfunxored[j], is_bigendian);
998 // Add a dummy region for now
1005 // If the current track is not an audio track, insert as midi track
1006 if (!(find_track(tindex, ti) && foundin(trackname, ti.name))) {
1007 _miditracks.push_back(t);
1016 // Parse regions->tracks
1017 for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
1018 b != blocks.end(); ++b) {
1020 if (b->content_type == 0x1012) {
1021 //nregions = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian);
1023 for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
1024 c != b->child.end(); ++c) {
1025 if (c->content_type == 0x1011) {
1026 regionname = parsestring(c->offset + 2);
1027 for (vector<PTFFormat::block_t>::iterator d = c->child.begin();
1028 d != c->child.end(); ++d) {
1029 if (d->content_type == 0x100f) {
1030 for (vector<PTFFormat::block_t>::iterator e = d->child.begin();
1031 e != d->child.end(); ++e) {
1032 if (e->content_type == 0x100e) {
1036 rawindex = u_endian_read4(&_ptfunxored[j], is_bigendian);
1037 if (!find_track(count, ti))
1039 if (!find_region(rawindex, ti.reg))
1041 if (ti.reg.index != 65535) {
1042 _tracks.push_back(ti);
1052 } else if (b->content_type == 0x1054) {
1053 //nregions = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian);
1055 for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
1056 c != b->child.end(); ++c) {
1057 if (c->content_type == 0x1052) {
1058 trackname = parsestring(c->offset + 2);
1059 for (vector<PTFFormat::block_t>::iterator d = c->child.begin();
1060 d != c->child.end(); ++d) {
1061 if (d->content_type == 0x1050) {
1062 region_is_fade = (_ptfunxored[d->offset + 46] == 0x01);
1063 if (region_is_fade) {
1064 verbose_printf("dropped fade region\n");
1067 for (vector<PTFFormat::block_t>::iterator e = d->child.begin();
1068 e != d->child.end(); ++e) {
1069 if (e->content_type == 0x104f) {
1072 rawindex = u_endian_read4(&_ptfunxored[j], is_bigendian);
1074 start = u_endian_read4(&_ptfunxored[j], is_bigendian);
1077 if (!find_track(tindex, ti)) {
1078 verbose_printf("dropped track %d\n", tindex);
1081 if (!find_region(rawindex, ti.reg)) {
1082 verbose_printf("dropped region %d\n", rawindex);
1085 ti.reg.startpos = start * _ratefactor;
1086 if (ti.reg.index != 65535) {
1087 _tracks.push_back(ti);
1099 for (std::vector<track_t>::iterator tr = _tracks.begin();
1100 tr != _tracks.end(); /* noop */) {
1101 if ((*tr).reg.index == 65535) {
1102 tr = _tracks.erase(tr);
1111 mchunk (uint64_t zt, uint64_t ml, std::vector<PTFFormat::midi_ev_t> const& c)
1118 std::vector<PTFFormat::midi_ev_t> chunk;
1122 PTFFormat::parsemidi(void) {
1123 uint32_t i, j, k, n, rindex, tindex, mindex, count, rawindex;
1124 uint64_t n_midi_events, zero_ticks, start, offset, length, start2, stop2;
1125 uint64_t midi_pos, midi_len, max_pos, region_pos;
1126 uint8_t midi_velocity, midi_note;
1127 uint16_t regionnumber = 0;
1128 std::string midiregionname;
1130 std::vector<mchunk> midichunks;
1133 std::string regionname, trackname;
1136 // Parse MIDI events
1137 for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
1138 b != blocks.end(); ++b) {
1139 if (b->content_type == 0x2000) {
1143 // Parse all midi chunks, not 1:1 mapping to regions yet
1144 while (k + 35 < b->block_size + b->offset) {
1146 std::vector<midi_ev_t> midi;
1148 if (!jumpto(&k, _ptfunxored, _len, (const unsigned char *)"MdNLB", 5)) {
1152 n_midi_events = u_endian_read4(&_ptfunxored[k], is_bigendian);
1155 zero_ticks = u_endian_read5(&_ptfunxored[k], is_bigendian);
1156 for (i = 0; i < n_midi_events && k < _len; i++, k += 35) {
1157 midi_pos = u_endian_read5(&_ptfunxored[k], is_bigendian);
1158 midi_pos -= zero_ticks;
1159 midi_note = _ptfunxored[k+8];
1160 midi_len = u_endian_read5(&_ptfunxored[k+9], is_bigendian);
1161 midi_velocity = _ptfunxored[k+17];
1163 if (midi_pos + midi_len > max_pos) {
1164 max_pos = midi_pos + midi_len;
1168 m.length = midi_len;
1170 m.velocity = midi_velocity;
1173 midichunks.push_back(mchunk (zero_ticks, max_pos, midi));
1176 // Put chunks onto regions
1177 } else if ((b->content_type == 0x2002) || (b->content_type == 0x2634)) {
1178 for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
1179 c != b->child.end(); ++c) {
1180 if ((c->content_type == 0x2001) || (c->content_type == 0x2633)) {
1181 for (vector<PTFFormat::block_t>::iterator d = c->child.begin();
1182 d != c->child.end(); ++d) {
1183 if ((d->content_type == 0x1007) || (d->content_type == 0x2628)) {
1185 midiregionname = parsestring(j);
1186 j += 4 + midiregionname.size();
1187 parse_three_point(j, region_pos, zero_ticks, midi_len);
1188 j = d->offset + d->block_size;
1189 rindex = u_endian_read4(&_ptfunxored[j], is_bigendian);
1190 struct mchunk mc = *(midichunks.begin()+rindex);
1192 region_t r (regionnumber++);
1193 r.name = midiregionname;
1194 r.startpos = (int64_t)0xe8d4a51000ULL;
1196 r.length = mc.maxlen;
1199 _midiregions.push_back(r);
1200 //verbose_printf("MIDI %s : r(%d) (%llu, %llu, %llu)\n", str, rindex, zero_ticks, region_pos, midi_len);
1201 //dump_block(*d, 1);
1209 // COMPOUND MIDI regions
1210 for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
1211 b != blocks.end(); ++b) {
1212 if (b->content_type == 0x262c) {
1214 for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
1215 c != b->child.end(); ++c) {
1216 if (c->content_type == 0x262b) {
1217 for (vector<PTFFormat::block_t>::iterator d = c->child.begin();
1218 d != c->child.end(); ++d) {
1219 if (d->content_type == 0x2628) {
1222 regionname = parsestring(j);
1223 j += 4 + regionname.size();
1224 parse_three_point(j, start, offset, length);
1225 j = d->offset + d->block_size + 2;
1226 n = u_endian_read2(&_ptfunxored[j], is_bigendian);
1228 for (vector<PTFFormat::block_t>::iterator e = d->child.begin();
1229 e != d->child.end(); ++e) {
1230 if (e->content_type == 0x2523) {
1231 // FIXME Compound MIDI region
1233 rawindex = u_endian_read4(&_ptfunxored[j], is_bigendian);
1235 start2 = u_endian_read5(&_ptfunxored[j], is_bigendian);
1236 int64_t signedval = (int64_t)start2;
1237 signedval -= ZERO_TICKS;
1238 if (signedval < 0) {
1239 signedval = -signedval;
1243 stop2 = u_endian_read5(&_ptfunxored[j], is_bigendian);
1244 signedval = (int64_t)stop2;
1245 signedval -= ZERO_TICKS;
1246 if (signedval < 0) {
1247 signedval = -signedval;
1251 //nn = u_endian_read4(&_ptfunxored[j], is_bigendian);
1252 //verbose_printf("COMPOUND %s : c(%d) r(%d) ?(%d) ?(%d) (%llu %llu)(%llu %llu %llu)\n", str, mindex, rawindex, n, nn, start2, stop2, start, offset, length);
1257 // Plain MIDI region
1258 struct mchunk mc = *(midichunks.begin()+n);
1261 r.name = midiregionname;
1262 r.startpos = (int64_t)0xe8d4a51000ULL;
1263 r.length = mc.maxlen;
1265 _midiregions.push_back(r);
1266 verbose_printf("%s : MIDI region mr(%d) ?(%d) (%lu %lu %lu)\n", regionname.c_str(), mindex, n, start, offset, length);
1276 // Put midi regions onto midi tracks
1277 for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
1278 b != blocks.end(); ++b) {
1279 if (b->content_type == 0x1058) {
1280 //nregions = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian);
1282 for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
1283 c != b->child.end(); ++c) {
1284 if (c->content_type == 0x1057) {
1285 regionname = parsestring(c->offset + 2);
1286 for (vector<PTFFormat::block_t>::iterator d = c->child.begin();
1287 d != c->child.end(); ++d) {
1288 if (d->content_type == 0x1056) {
1289 for (vector<PTFFormat::block_t>::iterator e = d->child.begin();
1290 e != d->child.end(); ++e) {
1291 if (e->content_type == 0x104f) {
1292 // MIDI region->MIDI track
1295 rawindex = u_endian_read4(&_ptfunxored[j], is_bigendian);
1297 start = u_endian_read5(&_ptfunxored[j], is_bigendian);
1299 if (!find_miditrack(tindex, ti)) {
1300 verbose_printf("dropped midi t(%d) r(%d)\n", tindex, rawindex);
1303 if (!find_midiregion(rawindex, ti.reg)) {
1304 verbose_printf("dropped midiregion\n");
1307 //verbose_printf("MIDI : %s : t(%d) r(%d) %llu(%llu)\n", ti.name.c_str(), tindex, rawindex, start, ti.reg.startpos);
1308 int64_t signedstart = (int64_t)(start - ZERO_TICKS);
1309 if (signedstart < 0)
1310 signedstart = -signedstart;
1311 ti.reg.startpos = (uint64_t)(signedstart * _ratefactor);
1312 if (ti.reg.index != 65535) {
1313 _miditracks.push_back(ti);
1324 for (std::vector<track_t>::iterator tr = _miditracks.begin();
1325 tr != _miditracks.end(); /* noop */) {
1326 if ((*tr).reg.index == 65535) {
1327 tr = _miditracks.erase(tr);