summaryrefslogtreecommitdiff
path: root/libs/ptformat
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2019-06-21 21:51:43 +1000
committerDamien Zammit <damien@zamaudio.com>2019-06-22 17:26:05 +1000
commitf5524ddf379c928faaf1de93b7b55d83d0958c8b (patch)
treef7ab26da3eca3ee626b1e102ece6e829211fff8a /libs/ptformat
parent632ab8c42187b1ec913191e0398fe7b5b958c33e (diff)
ptformat: Update lib from legacy parser to new parser 6240b87
Diffstat (limited to 'libs/ptformat')
-rw-r--r--libs/ptformat/MSVCptformat/ptformat.vcproj4
-rw-r--r--libs/ptformat/ptfformat.cc2512
-rw-r--r--libs/ptformat/ptformat.cc1350
-rw-r--r--libs/ptformat/ptformat/ptfformat.h195
-rw-r--r--libs/ptformat/ptformat/ptformat.h282
-rw-r--r--libs/ptformat/wscript4
6 files changed, 1636 insertions, 2711 deletions
diff --git a/libs/ptformat/MSVCptformat/ptformat.vcproj b/libs/ptformat/MSVCptformat/ptformat.vcproj
index f8b440ba61..65e20a1eba 100644
--- a/libs/ptformat/MSVCptformat/ptformat.vcproj
+++ b/libs/ptformat/MSVCptformat/ptformat.vcproj
@@ -262,7 +262,7 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
- RelativePath="..\ptfformat.cc"
+ RelativePath="..\ptformat.cc"
>
</File>
</Filter>
@@ -272,7 +272,7 @@
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
- RelativePath="..\ptformat\ptfformat.h"
+ RelativePath="..\ptformat\ptformat.h"
>
</File>
<File
diff --git a/libs/ptformat/ptfformat.cc b/libs/ptformat/ptfformat.cc
deleted file mode 100644
index aca6f10a7e..0000000000
--- a/libs/ptformat/ptfformat.cc
+++ /dev/null
@@ -1,2512 +0,0 @@
-/*
- * libptformat - a library to read ProTools sessions
- *
- * Copyright (C) 2015 Damien Zammit
- * Copyright (C) 2015 Robin Gareus
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string>
-#include <string.h>
-#include <assert.h>
-
-#include <glib/gstdio.h>
-
-#include "ptformat/ptfformat.h"
-
-#if 0
-#define verbose_printf(...) printf(__VA_ARGS__)
-#else
-#define verbose_printf(...)
-#endif
-
-using namespace std;
-
-static bool wavidx_compare(PTFFormat::wav_t& w1, PTFFormat::wav_t& w2) {
- return w1.index < w2.index;
-}
-
-static bool wavname_compare(PTFFormat::wav_t& w1, PTFFormat::wav_t& w2) {
- return (strcasecmp(w1.filename.c_str(), w2.filename.c_str()) < 0);
-}
-
-static bool regidx_compare(PTFFormat::region_t& r1, PTFFormat::region_t& r2) {
- return r1.index < r2.index;
-}
-
-static bool regname_compare(PTFFormat::region_t& r1, PTFFormat::region_t& r2) {
- return (strcasecmp(r1.name.c_str(), r2.name.c_str()) < 0);
-}
-
-static void
-hexdump(uint8_t *data, int len)
-{
- int i,j,end,step=16;
-
- for (i = 0; i < len; i += step) {
- printf("0x%02X: ", i);
- end = i + step;
- if (end > len) end = len;
- for (j = i; j < end; j++) {
- printf("0x%02X ", data[j]);
- }
- for (j = i; j < end; j++) {
- if (data[j] < 128 && data[j] > 32)
- printf("%c", data[j]);
- else
- printf(".");
- }
- printf("\n");
- }
-}
-
-PTFFormat::PTFFormat() : version(0), product(NULL), ptfunxored(NULL) {
-}
-
-PTFFormat::~PTFFormat() {
- cleanup();
-}
-
-uint16_t
-PTFFormat::u_endian_read2(unsigned char *buf, bool bigendian)
-{
- if (bigendian) {
- return ((uint16_t)(buf[0]) << 8) | (uint16_t)(buf[1]);
- } else {
- return ((uint16_t)(buf[1]) << 8) | (uint16_t)(buf[0]);
- }
-}
-
-uint32_t
-PTFFormat::u_endian_read3(unsigned char *buf, bool bigendian)
-{
- if (bigendian) {
- return ((uint32_t)(buf[0]) << 16) |
- ((uint32_t)(buf[1]) << 8) |
- (uint32_t)(buf[2]);
- } else {
- return ((uint32_t)(buf[2]) << 16) |
- ((uint32_t)(buf[1]) << 8) |
- (uint32_t)(buf[0]);
- }
-}
-
-uint32_t
-PTFFormat::u_endian_read4(unsigned char *buf, bool bigendian)
-{
- if (bigendian) {
- return ((uint32_t)(buf[0]) << 24) |
- ((uint32_t)(buf[1]) << 16) |
- ((uint32_t)(buf[2]) << 8) |
- (uint32_t)(buf[3]);
- } else {
- return ((uint32_t)(buf[3]) << 24) |
- ((uint32_t)(buf[2]) << 16) |
- ((uint32_t)(buf[1]) << 8) |
- (uint32_t)(buf[0]);
- }
-}
-
-uint64_t
-PTFFormat::u_endian_read5(unsigned char *buf, bool bigendian)
-{
- if (bigendian) {
- return ((uint64_t)(buf[0]) << 32) |
- ((uint64_t)(buf[1]) << 24) |
- ((uint64_t)(buf[2]) << 16) |
- ((uint64_t)(buf[3]) << 8) |
- (uint64_t)(buf[4]);
- } else {
- return ((uint64_t)(buf[4]) << 32) |
- ((uint64_t)(buf[3]) << 24) |
- ((uint64_t)(buf[2]) << 16) |
- ((uint64_t)(buf[1]) << 8) |
- (uint64_t)(buf[0]);
- }
-}
-
-void
-PTFFormat::cleanup(void) {
- if (ptfunxored) {
- free(ptfunxored);
- ptfunxored = NULL;
- }
- audiofiles.clear();
- regions.clear();
- midiregions.clear();
- compounds.clear();
- tracks.clear();
- miditracks.clear();
- version = 0;
- product = NULL;
-}
-
-int64_t
-PTFFormat::foundat(unsigned char *haystack, uint64_t n, const char *needle) {
- int64_t found = 0;
- uint64_t i, j, needle_n;
- needle_n = strlen(needle);
-
- for (i = 0; i < n; i++) {
- found = i;
- for (j = 0; j < needle_n; j++) {
- if (haystack[i+j] != needle[j]) {
- found = -1;
- break;
- }
- }
- if (found > 0)
- return found;
- }
- return -1;
-}
-
-bool
-PTFFormat::jumpto(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen) {
- uint64_t i;
- uint64_t k = *currpos;
- while (k + needlelen < maxoffset) {
- bool foundall = true;
- for (i = 0; i < needlelen; i++) {
- if (buf[k+i] != needle[i]) {
- foundall = false;
- break;
- }
- }
- if (foundall) {
- *currpos = k;
- return true;
- }
- k++;
- }
- return false;
-}
-
-bool
-PTFFormat::jumpback(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen) {
- uint64_t i;
- uint64_t k = *currpos;
- while (k > 0 && k + needlelen < maxoffset) {
- bool foundall = true;
- for (i = 0; i < needlelen; i++) {
- if (buf[k+i] != needle[i]) {
- foundall = false;
- break;
- }
- }
- if (foundall) {
- *currpos = k;
- return true;
- }
- k--;
- }
- return false;
-}
-
-bool
-PTFFormat::foundin(std::string haystack, std::string needle) {
- size_t found = haystack.find(needle);
- if (found != std::string::npos) {
- return true;
- } else {
- return false;
- }
-}
-
-/* Return values: 0 success
- -1 could not decrypt pt session
-*/
-int
-PTFFormat::unxor(std::string path) {
- FILE *fp;
- unsigned char xxor[256];
- unsigned char ct;
- uint64_t i;
- uint8_t xor_type;
- uint8_t xor_value;
- uint8_t xor_delta;
- uint16_t xor_len;
-
- if (! (fp = g_fopen(path.c_str(), "rb"))) {
- return -1;
- }
-
- fseek(fp, 0, SEEK_END);
- len = ftell(fp);
- if (len < 0x14) {
- fclose(fp);
- return -1;
- }
-
- if (! (ptfunxored = (unsigned char*) malloc(len * sizeof(unsigned char)))) {
- /* Silently fail -- out of memory*/
- fclose(fp);
- ptfunxored = 0;
- return -1;
- }
-
- /* The first 20 bytes are always unencrypted */
- fseek(fp, 0x00, SEEK_SET);
- i = fread(ptfunxored, 1, 0x14, fp);
- if (i < 0x14) {
- fclose(fp);
- return -1;
- }
-
- xor_type = ptfunxored[0x12];
- xor_value = ptfunxored[0x13];
- xor_len = 256;
-
- // xor_type 0x01 = ProTools 5, 6, 7, 8 and 9
- // xor_type 0x05 = ProTools 10, 11, 12
- switch(xor_type) {
- case 0x01:
- xor_delta = gen_xor_delta(xor_value, 53, false);
- break;
- case 0x05:
- xor_delta = gen_xor_delta(xor_value, 11, true);
- break;
- default:
- fclose(fp);
- return -1;
- }
-
- /* Generate the xor_key */
- for (i=0; i < xor_len; i++)
- xxor[i] = (i * xor_delta) & 0xff;
-
- /* hexdump(xxor, xor_len); */
-
- /* Read file and decrypt rest of file */
- i = 0x14;
- fseek(fp, i, SEEK_SET);
- while (fread(&ct, 1, 1, fp) != 0) {
- uint8_t xor_index = (xor_type == 0x01) ? i & 0xff : (i >> 12) & 0xff;
- ptfunxored[i++] = ct ^ xxor[xor_index];
- }
- fclose(fp);
- return 0;
-}
-
-/* Return values: 0 success
- -1 could not parse pt session
-*/
-int
-PTFFormat::load(std::string ptf, int64_t targetsr) {
- cleanup();
- path = ptf;
-
- if (unxor(path))
- return -1;
-
- if (parse_version())
- return -1;
-
- if (version < 5 || version > 12)
- return -1;
-
- targetrate = targetsr;
-
- if (parse())
- return -1;
-
- return 0;
-}
-
-bool
-PTFFormat::parse_version() {
- uint32_t seg_len,str_len;
- uint8_t *data = ptfunxored + 0x14;
- uintptr_t data_end = ((uintptr_t)ptfunxored) + 0x100;
- uint8_t seg_type;
- bool success = false;
-
- while( ((uintptr_t)data < data_end) && (success == false) ) {
-
- if (data[0] != 0x5a) {
- success = false;
- break;
- }
-
- seg_type = data[1];
- /* Skip segment header */
- data += 3;
- if (data[0] == 0 && data[1] == 0) {
- /* BE */
- is_bigendian = true;
- } else {
- /* LE */
- is_bigendian = false;
- }
- seg_len = u_endian_read4(&data[0], is_bigendian);
-
- /* Skip seg_len */
- data += 4;
- if (!(seg_type == 0x04 || seg_type == 0x03) || data[0] != 0x03) {
- /* Go to next segment */
- data += seg_len;
- continue;
- }
- /* Skip 0x03 0x00 0x00 */
- data += 3;
- seg_len -= 3;
- str_len = (*(uint8_t *)data);
- if (! (product = (uint8_t *)malloc((str_len+1) * sizeof(uint8_t)))) {
- success = false;
- break;
- }
-
- /* Skip str_len */
- data += 4;
- seg_len -= 4;
-
- memcpy(product, data, str_len);
- product[str_len] = 0;
- data += str_len;
- seg_len -= str_len;
-
- /* Skip 0x03 0x00 0x00 0x00 */
- data += 4;
- seg_len -= 4;
-
- version = data[0];
- if (version == 0) {
- version = data[3];
- }
- data += seg_len;
- success = true;
- }
-
- /* If the above does not work, try other heuristics */
- if ((uintptr_t)data >= data_end - seg_len) {
- version = ptfunxored[0x40];
- if (version == 0) {
- version = ptfunxored[0x3d];
- }
- if (version == 0) {
- version = ptfunxored[0x3a] + 2;
- }
- if (version != 0) {
- success = true;
- }
- }
- return (!success);
-}
-
-uint8_t
-PTFFormat::gen_xor_delta(uint8_t xor_value, uint8_t mul, bool negative) {
- uint16_t i;
- for (i = 0; i < 256; i++) {
- if (((i * mul) & 0xff) == xor_value) {
- return (negative) ? i * (-1) : i;
- }
- }
- // Should not occur
- return 0;
-}
-
-int
-PTFFormat::parse(void) {
- if (version == 5) {
- parse5header();
- setrates();
- if (sessionrate < 44100 || sessionrate > 192000)
- return -1;
- parseaudio5();
- parserest5();
- parsemidi();
- } else if (version == 7) {
- parse7header();
- setrates();
- if (sessionrate < 44100 || sessionrate > 192000)
- return -1;
- parseaudio();
- parserest89();
- parsemidi();
- } else if (version == 8) {
- parse8header();
- setrates();
- if (sessionrate < 44100 || sessionrate > 192000)
- return -1;
- parseaudio();
- parserest89();
- parsemidi();
- } else if (version == 9) {
- parse9header();
- setrates();
- if (sessionrate < 44100 || sessionrate > 192000)
- return -1;
- parseaudio();
- parserest89();
- parsemidi();
- } else if (version == 10 || version == 11 || version == 12) {
- parse10header();
- setrates();
- if (sessionrate < 44100 || sessionrate > 192000)
- return -1;
- parseaudio();
- parserest12();
- parsemidi12();
- } else {
- // Should not occur
- return -1;
- }
- return 0;
-}
-
-void
-PTFFormat::setrates(void) {
- ratefactor = 1.f;
- if (sessionrate != 0) {
- ratefactor = (float)targetrate / sessionrate;
- }
-}
-
-void
-PTFFormat::parse5header(void) {
- uint32_t k;
-
- // Find session sample rate
- k = 0x100;
-
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x00\x02", 3)) {
- jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x03", 2);
- k--;
- }
-
- sessionrate = u_endian_read3(&ptfunxored[k+12], is_bigendian);
-}
-
-void
-PTFFormat::parse7header(void) {
- uint32_t k;
-
- // Find session sample rate
- k = 0x100;
-
- jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x00\x05", 3);
-
- sessionrate = u_endian_read3(&ptfunxored[k+12], is_bigendian);
-}
-
-void
-PTFFormat::parse8header(void) {
- uint32_t k;
-
- // Find session sample rate
- k = 0;
-
- jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x05", 2);
-
- sessionrate = u_endian_read3(&ptfunxored[k+11], is_bigendian);
-}
-
-void
-PTFFormat::parse9header(void) {
- uint32_t k;
-
- // Find session sample rate
- k = 0x100;
-
- jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x06", 2);
-
- sessionrate = u_endian_read3(&ptfunxored[k+11], is_bigendian);
-}
-
-void
-PTFFormat::parse10header(void) {
- uint32_t k;
-
- // Find session sample rate
- k = 0x100;
-
- jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x09", 2);
-
- sessionrate = u_endian_read3(&ptfunxored[k+11], is_bigendian);
-}
-
-void
-PTFFormat::parserest5(void) {
- uint32_t i, j, k;
- uint64_t regionspertrack, lengthofname, numberofregions;
- uint64_t startbytes, lengthbytes, offsetbytes, somethingbytes, skipbytes;
- uint16_t tracknumber = 0;
- uint16_t findex;
- uint16_t rindex;
- unsigned char tag1[3];
- unsigned char tag2[3];
- unsigned char tag3[3];
-
- if (is_bigendian) {
- tag1[0] = tag2[0] = tag3[0] = '\x5a';
- tag1[1] = tag2[1] = tag3[1] = '\x00';
- tag1[2] = '\x01';
- tag2[2] = '\x02';
- tag3[2] = '\x03';
- } else {
- tag1[0] = tag2[0] = tag3[0] = '\x5a';
- tag1[1] = '\x01';
- tag2[1] = '\x02';
- tag3[1] = '\x03';
- tag1[2] = tag2[2] = tag3[2] = '\x00';
- }
-
- // Find Source->Region info
- k = upto;
- for (i = 0; i < 2; i++) {
- jumpto(&k, ptfunxored, len, tag3, 3);
- k++;
- }
- jumpto(&k, ptfunxored, len, tag2, 3);
-
- numberofregions = u_endian_read4(&ptfunxored[k-13], is_bigendian);
-
- i = k;
- while (numberofregions > 0 && i < len) {
- jumpto(&i, ptfunxored, len, tag2, 3);
-
- uint32_t lengthofname = u_endian_read4(&ptfunxored[i+9], is_bigendian);
-
- char name[256] = {0};
- for (j = 0; j < lengthofname; j++) {
- name[j] = ptfunxored[i+13+j];
- }
- name[j] = '\0';
- j += i+13;
- //uint8_t disabled = ptfunxored[j];
-
- if (is_bigendian) {
- offsetbytes = (ptfunxored[j+4] & 0xf0) >> 4;
- lengthbytes = (ptfunxored[j+3] & 0xf0) >> 4;
- startbytes = (ptfunxored[j+2] & 0xf0) >> 4;
- somethingbytes = (ptfunxored[j+2] & 0xf);
- skipbytes = ptfunxored[j+1];
- } else {
- offsetbytes = (ptfunxored[j+1] & 0xf0) >> 4; //3
- lengthbytes = (ptfunxored[j+2] & 0xf0) >> 4;
- startbytes = (ptfunxored[j+3] & 0xf0) >> 4; //1
- somethingbytes = (ptfunxored[j+3] & 0xf);
- skipbytes = ptfunxored[j+4];
- }
- findex = u_endian_read4(&ptfunxored[j+5
- +startbytes
- +lengthbytes
- +offsetbytes
- +somethingbytes
- +skipbytes], is_bigendian);
-
- uint32_t sampleoffset = 0;
- switch (offsetbytes) {
- case 4:
- sampleoffset = u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- sampleoffset = u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- sampleoffset = (uint32_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- sampleoffset = (uint32_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=offsetbytes;
- uint32_t length = 0;
- switch (lengthbytes) {
- case 4:
- length = u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- length = u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- length = (uint32_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- length = (uint32_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=lengthbytes;
- uint32_t start = 0;
- switch (startbytes) {
- case 4:
- start = u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- start = u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- start = (uint32_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- start = (uint32_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=startbytes;
-
- std::string filename = string(name);
- wav_t f = {
- "",
- (uint16_t)findex,
- (int64_t)(start*ratefactor),
- (int64_t)(length*ratefactor),
- };
-
- vector<wav_t>::iterator begin = actualwavs.begin();
- vector<wav_t>::iterator finish = actualwavs.end();
- vector<wav_t>::iterator found;
- if ((found = std::find(begin, finish, f)) != finish) {
- f.filename = (*found).filename;
- }
- std::vector<midi_ev_t> m;
- region_t r = {
- name,
- rindex,
- (int64_t)(start*ratefactor),
- (int64_t)(sampleoffset*ratefactor),
- (int64_t)(length*ratefactor),
- f,
- m
- };
- regions.push_back(r);
- rindex++;
- i = j + 1;
- numberofregions--;
- }
-
- // Find Region->Track info
- /*
- k = 0;
- for (i = 0; i < 4; i++) {
- jumpto(&k, ptfunxored, len, tag3, 3);
- k++;
- }
- */
- k = j = i;
- while (j < len) {
- if (jumpto(&j, ptfunxored, j+13+3, tag1, 3)) {
- j++;
- if (jumpto(&j, ptfunxored, j+13+3, tag1, 3)) {
- j++;
- if (jumpto(&j, ptfunxored, j+13+3, tag1, 3)) {
- if ((j == k+26) && (ptfunxored[j-13] == '\x5a') && (ptfunxored[j-26] == '\x5a')) {
- k = j;
- break;
- }
- }
- }
- }
- k++;
- j = k;
- }
-
- if (ptfunxored[k+13] == '\x5a') {
- k++;
- }
-
- // Start parsing track info
- rindex = 0;
- while (k < len) {
- if ( (ptfunxored[k ] == 0xff) &&
- (ptfunxored[k+1] == 0xff)) {
- break;
- }
- jumpto(&k, ptfunxored, len, tag1, 3);
-
- lengthofname = u_endian_read4(&ptfunxored[k+9], is_bigendian);
- if (ptfunxored[k+13] == 0x5a) {
- k++;
- break;
- }
- char name[256] = {0};
- for (j = 0; j < lengthofname; j++) {
- name[j] = ptfunxored[k+13+j];
- }
- name[j] = '\0';
- regionspertrack = u_endian_read4(&ptfunxored[k+13+j], is_bigendian);
- for (i = 0; i < regionspertrack; i++) {
- jumpto(&k, ptfunxored, len, tag3, 3);
- j = k + 15;
- if (is_bigendian) {
- offsetbytes = (ptfunxored[j+1] & 0xf0) >> 4;
- //somethingbytes = (ptfunxored[j+2] & 0xf);
- lengthbytes = (ptfunxored[j+3] & 0xf0) >> 4;
- startbytes = (ptfunxored[j+4] & 0xf0) >> 4;
- } else {
- offsetbytes = (ptfunxored[j+4] & 0xf0) >> 4;
- //somethingbytes = (ptfunxored[j+3] & 0xf);
- lengthbytes = (ptfunxored[j+2] & 0xf0) >> 4;
- startbytes = (ptfunxored[j+1] & 0xf0) >> 4;
- }
- rindex = u_endian_read4(&ptfunxored[k+11], is_bigendian);
- uint32_t start = 0;
- switch (startbytes) {
- case 4:
- start = u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- start = u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- start = (uint32_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- start = (uint32_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=startbytes;
- uint32_t length = 0;
- switch (lengthbytes) {
- case 4:
- length = u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- length = u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- length = (uint32_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- length = (uint32_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=lengthbytes;
- uint32_t sampleoffset = 0;
- switch (offsetbytes) {
- case 4:
- sampleoffset = u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- sampleoffset = u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- sampleoffset = (uint32_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- sampleoffset = (uint32_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=offsetbytes;
-
- track_t tr;
- tr.name = name;
-
- region_t r;
- r.index = rindex;
-
- vector<region_t>::iterator begin = regions.begin();
- vector<region_t>::iterator finish = regions.end();
- vector<region_t>::iterator found;
- if ((found = std::find(begin, finish, r)) != finish) {
- tr.reg = (*found);
- }
-
- tr.reg.startpos = (int64_t)(start*ratefactor);
- tr.reg.sampleoffset = (int64_t)(sampleoffset*ratefactor);
- tr.reg.length = (int64_t)(length*ratefactor);
- vector<track_t>::iterator ti;
- vector<track_t>::iterator bt = tracks.begin();
- vector<track_t>::iterator et = tracks.end();
- if ((ti = std::find(bt, et, tr)) != et) {
- tracknumber = (*ti).index;
- } else {
- ++tracknumber;
- }
- track_t t = {
- name,
- (uint16_t)tracknumber,
- uint8_t(0),
- tr.reg
- };
- //if (tr.reg.length > 0) {
- tracks.push_back(t);
- //}
- k++;
- }
- k++;
- }
-}
-
-void
-PTFFormat::resort(std::vector<wav_t>& ws) {
- int j = 0;
- std::sort(ws.begin(), ws.end());
- for (std::vector<wav_t>::iterator i = ws.begin(); i != ws.end(); ++i) {
- (*i).index = j;
- j++;
- }
-}
-
-void
-PTFFormat::resort(std::vector<region_t>& rs) {
- int j = 0;
- //std::sort(rs.begin(), rs.end());
- for (std::vector<region_t>::iterator i = rs.begin(); i != rs.end(); ++i) {
- (*i).index = j;
- j++;
- }
-}
-
-void
-PTFFormat::filter(std::vector<region_t>& rs) {
- for (std::vector<region_t>::iterator i = rs.begin(); i != rs.end(); ++i) {
- if (i->length == 0)
- rs.erase(i);
- }
-}
-
-void
-PTFFormat::parseaudio5(void) {
- uint32_t i,k,l;
- uint64_t lengthofname, wavnumber;
- uint32_t numberofwavs;
- unsigned char tag6_LE[3], tag5_BE[3];
- unsigned char tag2_LE[3], tag2_BE[3];
-
- // Find start of wav file list
- k = 0;
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xff\xff\xff\xff", 4))
- return;
- numberofwavs = u_endian_read4(&ptfunxored[k-18], is_bigendian);
-
- // Find actual wav names
- char wavname[256];
- i = k;
- jumpto(&i, ptfunxored, len, (const unsigned char *)"Files", 5);
-
- wavnumber = 0;
- i+=16;
- char ext[5];
- while (i < len && numberofwavs > 0) {
- i++;
- if ( ((ptfunxored[i ] == 0x5a) &&
- (ptfunxored[i+1] == 0x00) &&
- (ptfunxored[i+2] == 0x05)) ||
- ((ptfunxored[i ] == 0x5a) &&
- (ptfunxored[i+1] == 0x06))) {
- break;
- }
- lengthofname = u_endian_read4(&ptfunxored[i-3], is_bigendian);
- i++;
- l = 0;
- while (l < lengthofname) {
- wavname[l] = ptfunxored[i+l];
- l++;
- }
- i+=lengthofname;
- ext[0] = ptfunxored[i++];
- ext[1] = ptfunxored[i++];
- ext[2] = ptfunxored[i++];
- ext[3] = ptfunxored[i++];
- ext[4] = '\0';
-
- wavname[l] = 0;
- if (foundin(wavname, ".L") || foundin(wavname, ".R")) {
- extension = string("");
- } else if (foundin(wavname, ".wav") || foundin(ext, "WAVE")) {
- extension = string(".wav");
- } else if (foundin(wavname, ".aif") || foundin(ext, "AIFF")) {
- extension = string(".aif");
- } else {
- extension = string("");
- }
-
- std::string wave = string(wavname);
-
- if (foundin(wave, string(".grp"))) {
- continue;
- }
- if (foundin(wave, string("Fade Files"))) {
- i += 7;
- continue;
- }
-
- wav_t f = { wave, (uint16_t)(wavnumber++), 0, 0 };
-
- actualwavs.push_back(f);
- audiofiles.push_back(f);
- //printf("done\n");
- numberofwavs--;
- i += 7;
- }
-
- i -= 7;
-
- tag5_BE[0] = tag6_LE[0] = tag2_BE[0] = tag2_LE[0] = '\x5a';
- tag5_BE[1] = '\x00';
- tag6_LE[1] = '\x06';
- tag2_BE[1] = '\x00';
- tag2_LE[1] = '\x02';
- tag5_BE[2] = '\x05';
- tag6_LE[2] = '\x00';
- tag2_BE[2] = '\x02';
- tag2_LE[2] = '\x00';
-
- // Loop through all the sources
- for (vector<wav_t>::iterator w = audiofiles.begin(); w != audiofiles.end(); ++w) {
- // Jump to start of source metadata for this source
- if (is_bigendian) {
- if (!jumpto(&i, ptfunxored, len, tag5_BE, 3))
- return;
- if (!jumpto(&i, ptfunxored, len, tag2_BE, 3))
- return;
- w->length = u_endian_read4(&ptfunxored[i+19], true);
- } else {
- if (!jumpto(&i, ptfunxored, len, tag6_LE, 3))
- return;
- if (!jumpto(&i, ptfunxored, len, tag2_LE, 3))
- return;
- w->length = u_endian_read4(&ptfunxored[i+15], false);
- }
- }
- upto = i;
-}
-
-struct mchunk {
- mchunk (uint64_t zt, uint64_t ml, std::vector<PTFFormat::midi_ev_t> const& c)
- : zero (zt)
- , maxlen (ml)
- , chunk (c)
- {}
- uint64_t zero;
- uint64_t maxlen;
- std::vector<PTFFormat::midi_ev_t> chunk;
-};
-
-void
-PTFFormat::parsemidi(void) {
- uint32_t i, k;
- uint64_t tr, n_midi_events, zero_ticks;
- uint64_t midi_pos, midi_len, max_pos, region_pos;
- uint8_t midi_velocity, midi_note;
- uint16_t ridx;
- uint16_t nmiditracks, regionnumber = 0;
- uint32_t nregions, mr;
-
- std::vector<mchunk> midichunks;
- midi_ev_t m;
-
- // Find MdNLB
- k = 0;
-
- // Parse all midi chunks, not 1:1 mapping to regions yet
- while (k + 35 < len) {
- max_pos = 0;
- std::vector<midi_ev_t> midi;
-
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"MdNLB", 5)) {
- break;
- }
- k += 11;
- n_midi_events = ptfunxored[k] | ptfunxored[k+1] << 8 |
- ptfunxored[k+2] << 16 | ptfunxored[k+3] << 24;
-
- k += 4;
- zero_ticks = u_endian_read5(&ptfunxored[k], is_bigendian);
- for (i = 0; i < n_midi_events && k < len; i++, k += 35) {
- midi_pos = u_endian_read5(&ptfunxored[k], is_bigendian);
- midi_pos -= zero_ticks;
- midi_note = ptfunxored[k+8];
- midi_len = u_endian_read5(&ptfunxored[k+9], is_bigendian);
- midi_velocity = ptfunxored[k+17];
-
- if (midi_pos + midi_len > max_pos) {
- max_pos = midi_pos + midi_len;
- }
-
- m.pos = midi_pos;
- m.length = midi_len;
- m.note = midi_note;
- m.velocity = midi_velocity;
-#if 1
-// stop gap measure to prevent crashes in ardour,
-// remove when decryption is fully solved for .ptx
- if ((m.velocity & 0x80) || (m.note & 0x80) ||
- (m.pos & 0xff00000000LL) || (m.length & 0xff00000000LL)) {
- continue;
- }
-#endif
- midi.push_back(m);
- }
- midichunks.push_back(mchunk (zero_ticks, max_pos, midi));
- }
-
- // Map midi chunks to regions
- while (k < len) {
- char midiregionname[256];
- uint8_t namelen;
-
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"MdTEL", 5)) {
- break;
- }
-
- k += 41;
-
- nregions = u_endian_read2(&ptfunxored[k], is_bigendian);
-
- for (mr = 0; mr < nregions; mr++) {
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x0c", 2)) {
- break;
- }
-
- k += 9;
-
- namelen = ptfunxored[k];
- for (i = 0; i < namelen; i++) {
- midiregionname[i] = ptfunxored[k+4+i];
- }
- midiregionname[namelen] = '\0';
- k += 4 + namelen;
-
- k += 5;
- /*
- region_pos = (uint64_t)ptfunxored[k] |
- (uint64_t)ptfunxored[k+1] << 8 |
- (uint64_t)ptfunxored[k+2] << 16 |
- (uint64_t)ptfunxored[k+3] << 24 |
- (uint64_t)ptfunxored[k+4] << 32;
- */
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xfe\xff\xff\xff", 4)) {
- break;
- }
-
- k += 40;
-
- ridx = ptfunxored[k];
- ridx |= ptfunxored[k+1] << 8;
-
- struct mchunk mc = *(midichunks.begin()+ridx);
-
- wav_t w = { std::string(""), 0, 0, 0 };
- region_t r = {
- midiregionname,
- regionnumber++,
- //(int64_t)mc.zero,
- (int64_t)0xe8d4a51000ULL,
- (int64_t)(0),
- //(int64_t)(max_pos*sessionrate*60/(960000*120)),
- (int64_t)mc.maxlen,
- w,
- mc.chunk,
- };
- midiregions.push_back(r);
- }
- }
-
- // Put midi regions on midi tracks
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x03", 2)) {
- return;
- }
-
- nmiditracks = u_endian_read2(&ptfunxored[k-4], is_bigendian);
-
- for (tr = 0; tr < nmiditracks; tr++) {
- char miditrackname[256];
- uint8_t namelen;
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x03", 2)) {
- return;
- }
-
- namelen = ptfunxored[k+9];
- for (i = 0; i < namelen; i++) {
- miditrackname[i] = ptfunxored[k+13+i];
- }
- miditrackname[namelen] = '\0';
- k += 13 + namelen;
- nregions = u_endian_read2(&ptfunxored[k], is_bigendian);
-
- for (i = 0; (i < nregions) && (k < len); i++) {
- k += 24;
-
- ridx = u_endian_read2(&ptfunxored[k], is_bigendian);
-
- k += 5;
-
- region_pos = u_endian_read5(&ptfunxored[k], is_bigendian);
-
- k += 20;
-
- track_t mtr;
- mtr.name = string(miditrackname);
- mtr.index = tr;
- mtr.playlist = 0;
- // Find the midi region with index 'ridx'
- std::vector<region_t>::iterator begin = midiregions.begin();
- std::vector<region_t>::iterator finish = midiregions.end();
- std::vector<region_t>::iterator mregion;
- wav_t w = { std::string(""), 0, 0, 0 };
- std::vector<midi_ev_t> m;
- region_t r = { std::string(""), ridx, 0, 0, 0, w, m};
- if ((mregion = std::find(begin, finish, r)) != finish) {
- mtr.reg = *mregion;
- mtr.reg.startpos = labs(region_pos - mtr.reg.startpos);
- miditracks.push_back(mtr);
- }
- }
- }
-}
-
-void
-PTFFormat::parsemidi12(void) {
- uint32_t i, k;
- uint64_t tr, n_midi_events, zero_ticks;
- uint64_t midi_pos, midi_len, max_pos, region_pos;
- uint8_t midi_velocity, midi_note;
- uint16_t ridx;
- uint16_t nmiditracks, regionnumber = 0;
- uint32_t nregions, mr;
-
- std::vector<mchunk> midichunks;
- midi_ev_t m;
-
- k = 0;
-
- // Parse all midi chunks, not 1:1 mapping to regions yet
- while (k + 35 < len) {
- max_pos = 0;
- std::vector<midi_ev_t> midi;
-
- // Find MdNLB
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"MdNLB", 5)) {
- break;
- }
-
- k += 11;
- n_midi_events = u_endian_read4(&ptfunxored[k], is_bigendian);
-
- k += 4;
- zero_ticks = u_endian_read5(&ptfunxored[k], is_bigendian);
- for (i = 0; i < n_midi_events && k < len; i++, k += 35) {
- midi_pos = u_endian_read5(&ptfunxored[k], is_bigendian);
- midi_pos -= zero_ticks;
- midi_note = ptfunxored[k+8];
- midi_len = u_endian_read5(&ptfunxored[k+9], is_bigendian);
- midi_velocity = ptfunxored[k+17];
-
- if (midi_pos + midi_len > max_pos) {
- max_pos = midi_pos + midi_len;
- }
-
- m.pos = midi_pos;
- m.length = midi_len;
- m.note = midi_note;
- m.velocity = midi_velocity;
-#if 1
-// stop gap measure to prevent crashes in ardour,
-// remove when decryption is fully solved for .ptx
- if ((m.velocity & 0x80) || (m.note & 0x80) ||
- (m.pos & 0xff00000000LL) || (m.length & 0xff00000000LL)) {
- continue;
- }
-#endif
- midi.push_back(m);
- }
- midichunks.push_back(mchunk (zero_ticks, max_pos, midi));
- }
-
- // Map midi chunks to regions
- while (k < len) {
- char midiregionname[256];
- uint8_t namelen;
-
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"MdTEL", 5)) {
- break;
- }
-
- k += 41;
-
- nregions = u_endian_read2(&ptfunxored[k], is_bigendian);
-
- for (mr = 0; mr < nregions; mr++) {
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x01", 2)) {
- break;
- }
- k += 18;
-
- namelen = ptfunxored[k];
- for (i = 0; i < namelen; i++) {
- midiregionname[i] = ptfunxored[k+4+i];
- }
- midiregionname[namelen] = '\0';
- k += 4 + namelen;
-
- k += 5;
- /*
- region_pos = (uint64_t)ptfunxored[k] |
- (uint64_t)ptfunxored[k+1] << 8 |
- (uint64_t)ptfunxored[k+2] << 16 |
- (uint64_t)ptfunxored[k+3] << 24 |
- (uint64_t)ptfunxored[k+4] << 32;
- */
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xfe\xff\x00\x00", 4)) {
- break;
- }
-
- k += 37;
-
- ridx = u_endian_read2(&ptfunxored[k], is_bigendian);
-
- k += 3;
- struct mchunk mc = *(midichunks.begin()+ridx);
-
- wav_t w = { std::string(""), 0, 0, 0 };
- region_t r = {
- midiregionname,
- regionnumber++,
- //(int64_t)mc.zero,
- (int64_t)0xe8d4a51000ULL,
- (int64_t)(0),
- //(int64_t)(max_pos*sessionrate*60/(960000*120)),
- (int64_t)mc.maxlen,
- w,
- mc.chunk,
- };
- midiregions.push_back(r);
- }
- }
-
- // Put midi regions on midi tracks
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x03", 2)) {
- return;
- }
-
- nmiditracks = u_endian_read2(&ptfunxored[k-4], is_bigendian);
-
- for (tr = 0; tr < nmiditracks; tr++) {
- char miditrackname[256];
- uint8_t namelen;
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x03", 2)) {
- return;
- }
-
- namelen = ptfunxored[k+9];
- for (i = 0; i < namelen; i++) {
- miditrackname[i] = ptfunxored[k+13+i];
- }
- miditrackname[namelen] = '\0';
- k += 13 + namelen;
- nregions = u_endian_read2(&ptfunxored[k], is_bigendian);
-
- k += 13;
-
- for (i = 0; (i < nregions) && (k < len); i++) {
- while (k < len) {
- if ( (ptfunxored[k] == 0x5a) &&
- (ptfunxored[k+1] & 0x08)) {
- break;
- }
- k++;
- }
- k += 11;
-
- ridx = u_endian_read2(&ptfunxored[k], is_bigendian);
-
- k += 5;
-
- region_pos = u_endian_read5(&ptfunxored[k], is_bigendian);
-
- track_t mtr;
- mtr.name = string(miditrackname);
- mtr.index = tr;
- mtr.playlist = 0;
- // Find the midi region with index 'ridx'
- std::vector<region_t>::iterator begin = midiregions.begin();
- std::vector<region_t>::iterator finish = midiregions.end();
- std::vector<region_t>::iterator mregion;
- wav_t w = { std::string(""), 0, 0, 0 };
- std::vector<midi_ev_t> m;
- region_t r = { std::string(""), ridx, 0, 0, 0, w, m};
- if ((mregion = std::find(begin, finish, r)) != finish) {
- mtr.reg = *mregion;
- mtr.reg.startpos = labs(region_pos - mtr.reg.startpos);
- miditracks.push_back(mtr);
- }
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xff\xff\xff\xff\xff\xff\xff\xff", 8)) {
- return;
- }
- }
- }
-}
-
-void
-PTFFormat::parseaudio(void) {
- uint32_t i,j,k,l;
- std::string wave;
-
- k = 0;
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"Audio Files", 11))
- return;
-
- // Find end of wav file list
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xff\xff\xff\xff", 4))
- return;
-
- // Find number of wave files
- uint16_t numberofwavs;
- j = k;
- if (!jumpback(&j, ptfunxored, len, (const unsigned char *)"\x5a\x01", 2))
- return;
-
- numberofwavs = u_endian_read4(&ptfunxored[j-4], is_bigendian);
- //printf("%d wavs\n", numberofwavs);
-
- // Find actual wav names
- char wavname[256];
- j = k - 2;
- for (i = 0; i < numberofwavs; i++) {
- while (j > 0) {
- if ( ((ptfunxored[j ] == 'W') || (ptfunxored[j ] == 'A') || ptfunxored[j ] == '\0') &&
- ((ptfunxored[j-1] == 'A') || (ptfunxored[j-1] == 'I') || ptfunxored[j-1] == '\0') &&
- ((ptfunxored[j-2] == 'V') || (ptfunxored[j-2] == 'F') || ptfunxored[j-2] == '\0')) {
- break;
- }
- j--;
- }
- j -= 4;
- l = 0;
- while (ptfunxored[j] != '\0') {
- wavname[l] = ptfunxored[j];
- l++;
- j--;
- }
- wavname[l] = '\0';
-
- // Must be at least "vaw.z\0"
- if (l < 6) {
- i--;
- continue;
- }
-
- // and skip "zWAVE" or "zAIFF"
- if ( ( (wavname[1] == 'W') &&
- (wavname[2] == 'A') &&
- (wavname[3] == 'V') &&
- (wavname[4] == 'E')) ||
- ( (wavname[1] == 'A') &&
- (wavname[2] == 'I') &&
- (wavname[3] == 'F') &&
- (wavname[4] == 'F'))) {
- wave = string(&wavname[5]);
- } else {
- wave = string(wavname);
- }
- //uint8_t playlist = ptfunxored[j-8];
-
- std::reverse(wave.begin(), wave.end());
- wav_t f = { wave, (uint16_t)(numberofwavs - i - 1), 0, 0 };
-
- if (foundin(wave, string("Audio Files")) ||
- foundin(wave, string("Fade Files"))) {
- i--;
- continue;
- }
-
- actualwavs.push_back(f);
- audiofiles.push_back(f);
-
- //printf(" %d:%s \n", numberofwavs - i - 1, wave.c_str());
- }
- std::reverse(audiofiles.begin(), audiofiles.end());
- std::reverse(actualwavs.begin(), actualwavs.end());
- //resort(audiofiles);
- //resort(actualwavs);
-
- // Jump to end of wav file list
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xff\xff\xff\xff", 4))
- return;
-
- // Loop through all the sources
- for (vector<wav_t>::iterator w = audiofiles.begin(); w != audiofiles.end(); ++w) {
- // Jump to start of source metadata for this source
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x07", 2))
- return;
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x02", 2))
- return;
- k++;
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x02", 2))
- return;
-
- w->length = u_endian_read4(&ptfunxored[k-25], false);
- }
-}
-
-void
-PTFFormat::parserest89(void) {
- uint32_t i,j,k;
- uint8_t startbytes = 0;
- uint8_t lengthbytes = 0;
- uint8_t offsetbytes = 0;
- uint8_t somethingbytes = 0;
- uint8_t skipbytes = 0;
-
- // Find Regions
- k = 0;
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"Snap", 4)) {
- return;
- }
-
- uint16_t rindex = 0;
- uint32_t findex = 0;
- for (i = k; i < len-70; i++) {
- if ( (ptfunxored[i ] == 0x5a) &&
- (ptfunxored[i+1] == 0x0a)) {
- break;
- }
- if ( (ptfunxored[i ] == 0x5a) &&
- (ptfunxored[i+1] == 0x0c)) {
-
- uint8_t lengthofname = ptfunxored[i+9];
-
- char name[256] = {0};
- for (j = 0; j < lengthofname; j++) {
- name[j] = ptfunxored[i+13+j];
- }
- name[j] = '\0';
- j += i+13;
- //uint8_t disabled = ptfunxored[j];
-
- offsetbytes = (ptfunxored[j+1] & 0xf0) >> 4;
- lengthbytes = (ptfunxored[j+2] & 0xf0) >> 4;
- startbytes = (ptfunxored[j+3] & 0xf0) >> 4;
- somethingbytes = (ptfunxored[j+3] & 0xf);
- skipbytes = ptfunxored[j+4];
- findex = ptfunxored[j+5
- +startbytes
- +lengthbytes
- +offsetbytes
- +somethingbytes
- +skipbytes
- +40];
- /*rindex = ptfunxored[j+5
- +startbytes
- +lengthbytes
- +offsetbytes
- +somethingbytes
- +skipbytes
- +24];
- */
- uint32_t sampleoffset = 0;
- switch (offsetbytes) {
- case 4:
- sampleoffset = u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- sampleoffset = u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- sampleoffset = (uint32_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- sampleoffset = (uint32_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=offsetbytes;
- uint32_t length = 0;
- switch (lengthbytes) {
- case 4:
- length = u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- length = u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- length = (uint32_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- length = (uint32_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=lengthbytes;
- uint32_t start = 0;
- switch (startbytes) {
- case 4:
- start = u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- start = u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- start = (uint32_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- start = (uint32_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=startbytes;
- /*
- uint32_t something = 0;
- switch (somethingbytes) {
- case 4:
- something |= (uint32_t)(ptfunxored[j+8] << 24);
- case 3:
- something |= (uint32_t)(ptfunxored[j+7] << 16);
- case 2:
- something |= (uint32_t)(ptfunxored[j+6] << 8);
- case 1:
- something |= (uint32_t)(ptfunxored[j+5]);
- default:
- break;
- }
- j+=somethingbytes;
- */
- std::string filename = string(name);
- wav_t f = {
- filename,
- (uint16_t)findex,
- (int64_t)(start*ratefactor),
- (int64_t)(length*ratefactor),
- };
-
- //printf("something=%d\n", something);
-
- vector<wav_t>::iterator begin = actualwavs.begin();
- vector<wav_t>::iterator finish = actualwavs.end();
- vector<wav_t>::iterator found;
- // Add file to list only if it is an actual wav
- if ((found = std::find(begin, finish, f)) != finish) {
- f.filename = (*found).filename;
- // Also add plain wav as region
- std::vector<midi_ev_t> m;
- region_t r = {
- name,
- rindex,
- (int64_t)(start*ratefactor),
- (int64_t)(sampleoffset*ratefactor),
- (int64_t)(length*ratefactor),
- f,
- m
- };
- regions.push_back(r);
- // Region only
- } else {
- if (foundin(filename, string(".grp"))) {
- continue;
- }
- std::vector<midi_ev_t> m;
- region_t r = {
- name,
- rindex,
- (int64_t)(start*ratefactor),
- (int64_t)(sampleoffset*ratefactor),
- (int64_t)(length*ratefactor),
- f,
- m
- };
- regions.push_back(r);
- }
- rindex++;
- }
- }
-
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x03", 2)) {
- return;
- }
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x02", 2)) {
- return;
- }
- k++;
-
- // Tracks
- uint32_t offset;
- uint32_t tracknumber = 0;
- uint32_t regionspertrack = 0;
- for (;k < len; k++) {
- if ( (ptfunxored[k ] == 0x5a) &&
- (ptfunxored[k+1] == 0x04)) {
- break;
- }
- if ( (ptfunxored[k ] == 0x5a) &&
- (ptfunxored[k+1] == 0x02)) {
-
- uint8_t lengthofname = 0;
- lengthofname = ptfunxored[k+9];
- if (lengthofname == 0x5a) {
- continue;
- }
- track_t tr;
-
- regionspertrack = (uint8_t)(ptfunxored[k+13+lengthofname]);
-
- //printf("regions/track=%d\n", regionspertrack);
- char name[256] = {0};
- for (j = 0; j < lengthofname; j++) {
- name[j] = ptfunxored[j+k+13];
- }
- name[j] = '\0';
- tr.name = string(name);
- tr.index = tracknumber++;
-
- for (j = k; regionspertrack > 0 && j < len; j++) {
- jumpto(&j, ptfunxored, len, (const unsigned char *)"\x5a\x07", 2);
- tr.reg.index = (uint16_t)(ptfunxored[j+11] & 0xff)
- | (uint16_t)((ptfunxored[j+12] << 8) & 0xff00);
- vector<region_t>::iterator begin = regions.begin();
- vector<region_t>::iterator finish = regions.end();
- vector<region_t>::iterator found;
- if ((found = std::find(begin, finish, tr.reg)) != finish) {
- tr.reg = (*found);
- }
- i = j+16;
- offset = u_endian_read4(&ptfunxored[i], is_bigendian);
- tr.reg.startpos = (int64_t)(offset*ratefactor);
- if (tr.reg.length > 0) {
- tracks.push_back(tr);
- }
- regionspertrack--;
- }
- }
- }
-}
-
-void
-PTFFormat::parserest12(void) {
- uint32_t i,j,k,l,m,n;
- uint8_t startbytes = 0;
- uint8_t lengthbytes = 0;
- uint8_t offsetbytes = 0;
- uint8_t somethingbytes = 0;
- uint8_t skipbytes = 0;
- uint32_t maxregions = 0;
- uint32_t findex = 0;
- uint32_t findex2 = 0;
- uint32_t findex3 = 0;
- uint16_t rindex = 0;
- vector<region_t> groups;
- uint16_t groupcount, compoundcount, groupmax;
- uint16_t gindex, gindex2;
-
- m = 0;
- n = 0;
- vector<compound_t> groupmap;
- // Find region group total
- k = 0;
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"Custom 1\0\0\x5a", 11))
- goto nocustom;
-
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xff\xff\xff\xff", 4))
- return;
-
- if (!jumpback(&k, ptfunxored, len, (const unsigned char *)"\x5a", 1))
- return;
-
- jumpto(&k, ptfunxored, k+0x2000, (const unsigned char *)"\x5a\x03", 2);
- k++;
-
- groupcount = 0;
- for (i = k; i < len; i++) {
- if (!jumpto(&i, ptfunxored, len, (const unsigned char *)"\x5a\x03", 2))
- break;
- groupcount++;
- }
- verbose_printf("groupcount=%d\n", groupcount);
-
- // Find start of group names -> group indexes
- k = 0;
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"Custom 1\0\0\x5a", 11))
- return;
-
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\xff\xff\xff\xff", 4))
- return;
-
- if (!jumpback(&k, ptfunxored, len, (const unsigned char *)"\x5a", 1))
- return;
- k++;
-
- // Skip total number of groups
- for (i = 0; i < groupcount; i++) {
- while (k < len) {
- if ( (ptfunxored[k ] == 0x5a) &&
- ((ptfunxored[k+1] == 0x03) || (ptfunxored[k+1] == 0x0a))) {
- break;
- }
- k++;
- }
- k++;
- }
-
- while (k < len) {
- if ( (ptfunxored[k ] == 0x5a) &&
- (ptfunxored[k+1] & 0x02)) {
- break;
- }
- k++;
- }
- k++;
-
- while (k < len) {
- if ( (ptfunxored[k ] == 0x5a) &&
- (ptfunxored[k+1] & 0x02)) {
- break;
- }
- k++;
- }
- k++;
-
- verbose_printf("start of groups k=0x%x\n", k);
- // Loop over all groups and associate the compound index/name
- for (i = 0; i < groupcount; i++) {
- while (k < len) {
- if ( (ptfunxored[k ] == 0x5a) &&
- (ptfunxored[k+1] & 0x02)) {
- break;
- }
- k++;
- }
- if (k > len)
- break;
- gindex = u_endian_read2(&ptfunxored[k+9], is_bigendian);
- gindex2 = u_endian_read2(&ptfunxored[k+3], is_bigendian);
-
- uint8_t lengthofname = ptfunxored[k+13];
- char name[256] = {0};
- for (l = 0; l < lengthofname; l++) {
- name[l] = ptfunxored[k+17+l];
- }
- name[l] = '\0';
-
- if (strlen(name) == 0) {
- i--;
- k++;
- continue;
- }
- compound_t c = {
- (uint16_t)i, // curr_index
- gindex, // unknown1
- 0, // level
- 0, // ontopof_index
- gindex2, // next_index
- string(name)
- };
- groupmap.push_back(c);
- k++;
- }
-
- // Sort lookup table by group index
- //std::sort(glookup.begin(), glookup.end(), regidx_compare);
-
- // print compounds as flattened tree
- j = 0;
- for (std::vector<compound_t>::iterator i = groupmap.begin(); i != groupmap.end(); ++i) {
- verbose_printf("g(%u) uk(%u) ni(%u) %s\n", i->curr_index, i->unknown1, i->next_index, i->name.c_str());
- j++;
- }
-
-nocustom:
- // Find region groups
- k = 0;
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"Snap", 4))
- return;
-
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\x5a\x06", 2))
- return;
- k++;
-
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16))
- return;
- k++;
-
- if (!jumpto(&k, ptfunxored, len, (const unsigned char *)"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16))
- return;
- k++;
-
- // Hack to find actual start of region group information
- while (k < len) {
- if ((ptfunxored[k+13] == 0x5a) && (ptfunxored[k+14] & 0xf)) {
- k += 13;
- continue;
- } else {
- if ((ptfunxored[k+9] == 0x5a) && (ptfunxored[k+10] & 0xf)) {
- k += 9;
- continue;
- }
- }
- if ((ptfunxored[k] == 0x5a) && (ptfunxored[k+1] & 0xf))
- break;
- k++;
- }
- verbose_printf("hack region groups k=0x%x\n", k);
-
- compoundcount = 0;
- j = k;
- groupmax = groupcount == 0 ? 0 : u_endian_read2(&ptfunxored[j+3], is_bigendian);
- groupcount = 0;
- for (i = k; (groupcount < groupmax) && (i < len-70); i++) {
- if ( (ptfunxored[i ] == 0x5a) &&
- (ptfunxored[i+1] == 0x03)) {
- break;
- }
- if ( (ptfunxored[i ] == 0x5a) &&
- ((ptfunxored[i+1] == 0x01) || (ptfunxored[i+1] == 0x02))) {
-
- //findex = ptfunxored[i-48] | ptfunxored[i-47] << 8;
- //rindex = ptfunxored[i+3] | ptfunxored[i+4] << 8;
-
- uint8_t lengthofname = ptfunxored[i+9];
- if (ptfunxored[i+13] == 0x5a) {
- continue;
- }
- char name[256] = {0};
- for (j = 0; j < lengthofname; j++) {
- name[j] = ptfunxored[i+13+j];
- }
- name[j] = '\0';
- j += i+13;
-
- offsetbytes = (ptfunxored[j+1] & 0xf0) >> 4;
- lengthbytes = (ptfunxored[j+2] & 0xf0) >> 4;
- startbytes = (ptfunxored[j+3] & 0xf0) >> 4;
- somethingbytes = (ptfunxored[j+3] & 0xf);
- skipbytes = ptfunxored[j+4];
- uint16_t regionsingroup = ptfunxored[j+5
- +startbytes
- +lengthbytes
- +offsetbytes
- +somethingbytes
- +skipbytes
- +12]
- | ptfunxored[j+5
- +startbytes
- +lengthbytes
- +offsetbytes
- +somethingbytes
- +skipbytes
- +13] << 8;
-
- findex = ptfunxored[j+5
- +startbytes
- +lengthbytes
- +offsetbytes
- +somethingbytes
- +skipbytes
- +37]
- | ptfunxored[j+5
- +startbytes
- +lengthbytes
- +offsetbytes
- +somethingbytes
- +skipbytes
- +38] << 8;
-
- uint64_t sampleoffset = 0;
- switch (offsetbytes) {
- case 5:
- sampleoffset = u_endian_read5(&ptfunxored[j+5], false);
- break;
- case 4:
- sampleoffset = (uint64_t)u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- sampleoffset = (uint64_t)u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- sampleoffset = (uint64_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- sampleoffset = (uint64_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=offsetbytes;
- uint64_t length = 0;
- switch (lengthbytes) {
- case 5:
- length = u_endian_read5(&ptfunxored[j+5], false);
- break;
- case 4:
- length = (uint64_t)u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- length = (uint64_t)u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- length = (uint64_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- length = (uint64_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=lengthbytes;
- uint64_t start = 0;
- switch (startbytes) {
- case 5:
- start = u_endian_read5(&ptfunxored[j+5], false);
- break;
- case 4:
- start = (uint64_t)u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- start = (uint64_t)u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- start = (uint64_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- start = (uint64_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=startbytes;
-
- if (offsetbytes == 5)
- sampleoffset -= 1000000000000ULL;
- if (startbytes == 5)
- start -= 1000000000000ULL;
-
- std::string filename = string(name);
- wav_t f = {
- filename,
- (uint16_t)findex,
- (int64_t)(start*ratefactor),
- (int64_t)(length*ratefactor),
- };
-
- if (strlen(name) == 0) {
- continue;
- }
- if (length == 0) {
- continue;
- }
- //if (foundin(filename, string(".grp")) && !regionsingroup && !findex) {
- // // Empty region group
- // verbose_printf(" EMPTY: %s\n", name);
- // continue;
- if (regionsingroup) {
- // Active region grouping
- // Iterate parsing all the regions in the group
- verbose_printf("\nGROUP\t%d %s\n", groupcount, name);
- m = j;
- n = j+16;
-
- for (l = 0; l < regionsingroup; l++) {
- if (!jumpto(&n, ptfunxored, len, (const unsigned char *)"\x5a\x02", 2)) {
- return;
- }
- n++;
- }
- n--;
- //printf("n=0x%x\n", n+112);
- //findex = ptfunxored[n+112] | (ptfunxored[n+113] << 8);
- findex = u_endian_read2(&ptfunxored[i-11], is_bigendian);
- findex2 = u_endian_read2(&ptfunxored[n+108], is_bigendian);
- //findex2= rindex; //XXX
- // Find wav with correct findex
- vector<wav_t>::iterator wave = actualwavs.end();
- for (vector<wav_t>::iterator aw = actualwavs.begin();
- aw != actualwavs.end(); ++aw) {
- if (aw->index == findex) {
- wave = aw;
- }
- }
- if (wave == actualwavs.end())
- return;
-
- if (!jumpto(&n, ptfunxored, len, (const unsigned char *)"\x5a\x02", 2))
- return;
- n += 37;
- //rindex = ptfunxored[n] | (ptfunxored[n+1] << 8);
- for (l = 0; l < regionsingroup; l++) {
- if (!jumpto(&m, ptfunxored, len, (const unsigned char *)"\x5a\x02", 2))
- return;
-
- m += 37;
- rindex = u_endian_read2(&ptfunxored[m], is_bigendian);
-
- m += 12;
- sampleoffset = 0;
- switch (offsetbytes) {
- case 5:
- sampleoffset = u_endian_read5(&ptfunxored[m], false);
- break;
- case 4:
- sampleoffset = (uint64_t)u_endian_read4(&ptfunxored[m], false);
- break;
- case 3:
- sampleoffset = (uint64_t)u_endian_read3(&ptfunxored[m], false);
- break;
- case 2:
- sampleoffset = (uint64_t)u_endian_read2(&ptfunxored[m], false);
- break;
- case 1:
- sampleoffset = (uint64_t)(ptfunxored[m]);
- break;
- default:
- break;
- }
- m+=offsetbytes+3;
- start = 0;
- switch (offsetbytes) {
- case 5:
- start = u_endian_read5(&ptfunxored[m], false);
- break;
- case 4:
- start = (uint64_t)u_endian_read4(&ptfunxored[m], false);
- break;
- case 3:
- start = (uint64_t)u_endian_read3(&ptfunxored[m], false);
- break;
- case 2:
- start = (uint64_t)u_endian_read2(&ptfunxored[m], false);
- break;
- case 1:
- start = (uint64_t)(ptfunxored[m]);
- break;
- default:
- break;
- }
- m+=offsetbytes+3;
- length = 0;
- switch (lengthbytes) {
- case 5:
- length = u_endian_read5(&ptfunxored[m], false);
- break;
- case 4:
- length = (uint64_t)u_endian_read4(&ptfunxored[m], false);
- break;
- case 3:
- length = (uint64_t)u_endian_read3(&ptfunxored[m], false);
- break;
- case 2:
- length = (uint64_t)u_endian_read2(&ptfunxored[m], false);
- break;
- case 1:
- length = (uint64_t)(ptfunxored[m]);
- break;
- default:
- break;
- }
- m+=8;
- findex3 = ptfunxored[m] | (ptfunxored[m+1] << 8);
- sampleoffset -= 1000000000000ULL;
- start -= 1000000000000ULL;
-
- /*
- // Find wav with correct findex
- vector<wav_t>::iterator wave = actualwavs.end();
- for (vector<wav_t>::iterator aw = actualwavs.begin();
- aw != actualwavs.end(); ++aw) {
- if (aw->index == (glookup.begin()+findex2)->startpos) {
- wave = aw;
- }
- }
- if (wave == actualwavs.end())
- return;
- // findex is the true source
- std::vector<midi_ev_t> md;
- region_t r = {
- name,
- (uint16_t)rindex,
- (int64_t)findex, //(start*ratefactor),
- (int64_t)findex2, //(sampleoffset*ratefactor),
- (int64_t)findex3, //(length*ratefactor),
- *wave,
- md
- };
- groups.push_back(r);
- */
- vector<compound_t>::iterator g = groupmap.begin()+findex2;
- if (g >= groupmap.end())
- continue;
- compound_t c;
- c.name = string(g->name);
- c.curr_index = compoundcount;
- c.level = findex;
- c.ontopof_index = findex3;
- c.next_index = g->next_index;
- c.unknown1 = g->unknown1;
- compounds.push_back(c);
- verbose_printf("COMPOUND\tc(%d) %s (%d %d) -> c(%u) %s\n", c.curr_index, c.name.c_str(), c.level, c.ontopof_index, c.next_index, name);
- compoundcount++;
- }
- groupcount++;
- }
- }
- }
- j = 0;
-
- // Start pure regions
- k = m != 0 ? m : k - 1;
- if (!jumpto(&k, ptfunxored, k+64, (const unsigned char *)"\x5a\x05", 2))
- jumpto(&k, ptfunxored, k+0x400, (const unsigned char *)"\x5a\x02", 2);
-
- verbose_printf("pure regions k=0x%x\n", k);
-
- maxregions = u_endian_read4(&ptfunxored[k-4], is_bigendian);
-
- verbose_printf("maxregions=%u\n", maxregions);
- rindex = 0;
- for (i = k; rindex < maxregions && i < len; i++) {
- if ( (ptfunxored[i ] == 0xff) &&
- (ptfunxored[i+1] == 0x5a) &&
- (ptfunxored[i+2] == 0x01)) {
- break;
- }
- //if ( (ptfunxored[i ] == 0x5a) &&
- // (ptfunxored[i+1] == 0x03)) {
- // break;
- //}
- if ( (ptfunxored[i ] == 0x5a) &&
- ((ptfunxored[i+1] == 0x01) || (ptfunxored[i+1] == 0x02))) {
-
- //findex = ptfunxored[i-48] | ptfunxored[i-47] << 8;
- //rindex = ptfunxored[i+3] | ptfunxored[i+4] << 8;
-
- uint8_t lengthofname = ptfunxored[i+9];
- if (ptfunxored[i+13] == 0x5a) {
- continue;
- }
- char name[256] = {0};
- for (j = 0; j < lengthofname; j++) {
- name[j] = ptfunxored[i+13+j];
- }
- name[j] = '\0';
- j += i+13;
-
- offsetbytes = (ptfunxored[j+1] & 0xf0) >> 4;
- lengthbytes = (ptfunxored[j+2] & 0xf0) >> 4;
- startbytes = (ptfunxored[j+3] & 0xf0) >> 4;
- somethingbytes = (ptfunxored[j+3] & 0xf);
- skipbytes = ptfunxored[j+4];
- findex = ptfunxored[j+5
- +startbytes
- +lengthbytes
- +offsetbytes
- +somethingbytes
- +skipbytes
- +37]
- | ptfunxored[j+5
- +startbytes
- +lengthbytes
- +offsetbytes
- +somethingbytes
- +skipbytes
- +38] << 8;
-
- uint64_t sampleoffset = 0;
- switch (offsetbytes) {
- case 5:
- sampleoffset = u_endian_read5(&ptfunxored[j+5], false);
- break;
- case 4:
- sampleoffset = (uint64_t)u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- sampleoffset = (uint64_t)u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- sampleoffset = (uint64_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- sampleoffset = (uint64_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=offsetbytes;
- uint64_t length = 0;
- switch (lengthbytes) {
- case 5:
- length = u_endian_read5(&ptfunxored[j+5], false);
- break;
- case 4:
- length = (uint64_t)u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- length = (uint64_t)u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- length = (uint64_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- length = (uint64_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=lengthbytes;
- uint64_t start = 0;
- switch (startbytes) {
- case 5:
- start = u_endian_read5(&ptfunxored[j+5], false);
- break;
- case 4:
- start = (uint64_t)u_endian_read4(&ptfunxored[j+5], false);
- break;
- case 3:
- start = (uint64_t)u_endian_read3(&ptfunxored[j+5], false);
- break;
- case 2:
- start = (uint64_t)u_endian_read2(&ptfunxored[j+5], false);
- break;
- case 1:
- start = (uint64_t)(ptfunxored[j+5]);
- break;
- default:
- break;
- }
- j+=startbytes;
-
- if (offsetbytes == 5)
- sampleoffset -= 1000000000000ULL;
- if (startbytes == 5)
- start -= 1000000000000ULL;
-
- std::string filename = string(name);
- wav_t f = {
- filename,
- (uint16_t)findex,
- (int64_t)(start*ratefactor),
- (int64_t)(length*ratefactor),
- };
-
- if (strlen(name) == 0) {
- continue;
- }
- if (length == 0) {
- continue;
- }
- // Regular region mapping to a source
- uint32_t n = j;
- if (!jumpto(&n, ptfunxored, len, (const unsigned char *)"\x5a\x01", 2))
- return;
- //printf("XXX=%d\n", ptfunxored[n+12] | ptfunxored[n+13]<<8);
-
- // Find wav with correct findex
- vector<wav_t>::iterator wave = actualwavs.end();
- for (vector<wav_t>::iterator aw = actualwavs.begin();
- aw != actualwavs.end(); ++aw) {
- if (aw->index == findex) {
- wave = aw;
- }
- }
- if (wave == actualwavs.end()) {
- verbose_printf("missing source with findex\n");
- continue;
- }
- //verbose_printf("\n+r(%d) w(%d) REGION: %s st(%lx)x%u of(%lx)x%u ln(%lx)x%u\n", rindex, findex, name, start, startbytes, sampleoffset, offsetbytes, length, lengthbytes);
- verbose_printf("REGION\tg(NA)\tr(%d)\tw(%d) %s(%s)\n", rindex, findex, name, wave->filename.c_str());
- std::vector<midi_ev_t> md;
- region_t r = {
- name,
- rindex,
- (int64_t)(start*ratefactor),
- (int64_t)(sampleoffset*ratefactor),
- (int64_t)(length*ratefactor),
- *wave,
- md
- };
- regions.push_back(r);
- rindex++;
- }
- }
-
- // print compounds
- vector<uint16_t> rootnodes;
- bool found = false;
-
- j = 0;
- for (vector<compound_t>::iterator cmp = compounds.begin();
- cmp != compounds.end(); ++cmp) {
- found = false;
- for (vector<compound_t>::iterator tmp = compounds.begin();
- tmp != compounds.end(); ++tmp) {
- if (tmp == cmp)
- continue;
- if (tmp->ontopof_index == cmp->curr_index)
- found = true;
- }
- // Collect a vector of all the root nodes (no others point to)
- if (!found)
- rootnodes.push_back(cmp->curr_index);
- }
-
- for (vector<uint16_t>::iterator rt = rootnodes.begin();
- rt != rootnodes.end(); ++rt) {
- vector<compound_t>::iterator cmp = compounds.begin()+(*rt);
- // Now we are at a root node, follow to leaf
- if (cmp >= compounds.end())
- continue;
-
- verbose_printf("----\n");
-
- for (; cmp < compounds.end() && cmp->curr_index != cmp->next_index;
- cmp = compounds.begin()+cmp->next_index) {
-
- // Find region
- vector<region_t>::iterator r = regions.end();
- for (vector<region_t>::iterator rs = regions.begin();
- rs != regions.end(); rs++) {
- if (rs->index == cmp->unknown1 + cmp->level) {
- r = rs;
- }
- }
- if (r == regions.end())
- continue;
- verbose_printf("\t->cidx(%u) pl(%u)+ridx(%u) cflags(0x%x) ?(%u) grp(%s) reg(%s)\n", cmp->curr_index, cmp->level, cmp->unknown1, cmp->ontopof_index, cmp->next_index, cmp->name.c_str(), r->name.c_str());
- }
- // Find region
- vector<region_t>::iterator r = regions.end();
- for (vector<region_t>::iterator rs = regions.begin();
- rs != regions.end(); rs++) {
- if (rs->index == cmp->unknown1 + cmp->level) {
- r = rs;
- }
- }
- if (r == regions.end())
- continue;
- verbose_printf("\tLEAF->cidx(%u) pl(%u)+ridx(%u) cflags(0x%x) ?(%u) grp(%s) reg(%s)\n", cmp->curr_index, cmp->level, cmp->unknown1, cmp->ontopof_index, cmp->next_index, cmp->name.c_str(), r->name.c_str());
- }
-
- // Start grouped regions
-
- // Print region groups mapped to sources
- for (vector<region_t>::iterator a = groups.begin(); a != groups.end(); ++a) {
- // Find wav with findex
- vector<wav_t>::iterator wav = audiofiles.end();
- for (vector<wav_t>::iterator ws = audiofiles.begin();
- ws != audiofiles.end(); ws++) {
- if (ws->index == a->startpos) {
- wav = ws;
- }
- }
- if (wav == audiofiles.end())
- continue;
-
- // Find wav with findex2
- vector<wav_t>::iterator wav2 = audiofiles.end();
- for (vector<wav_t>::iterator ws = audiofiles.begin();
- ws != audiofiles.end(); ws++) {
- if (ws->index == a->sampleoffset) {
- wav2 = ws;
- }
- }
- if (wav2 == audiofiles.end())
- continue;
-
- verbose_printf("Group: %s -> %s OR %s\n", a->name.c_str(), wav->filename.c_str(), wav2->filename.c_str());
- }
-
- //filter(regions);
- //resort(regions);
-
- // Tracks
- uint32_t offset;
- uint32_t tracknumber = 0;
- uint32_t regionspertrack = 0;
-
- // Total tracks
- j = k;
- if (!jumpto(&j, ptfunxored, len, (const unsigned char *)"\x5a\x03\x00", 3))
- return;
- //maxtracks = u_endian_read4(&ptfunxored[j-4]);
-
- // Jump to start of region -> track mappings
- if (jumpto(&k, ptfunxored, k + regions.size() * 0x400, (const unsigned char *)"\x5a\x08", 2)) {
- if (!jumpback(&k, ptfunxored, len, (const unsigned char *)"\x5a\x02", 2))
- return;
- } else if (jumpto(&k, ptfunxored, k + regions.size() * 0x400, (const unsigned char *)"\x5a\x0a", 2)) {
- if (!jumpback(&k, ptfunxored, len, (const unsigned char *)"\x5a\x01", 2))
- return;
- } else {
- return;
- }
- verbose_printf("tracks k=0x%x\n", k);
-
- for (;k < len; k++) {
- if ( (ptfunxored[k ] == 0x5a) &&
- (ptfunxored[k+1] & 0x04)) {
- break;
- }
- if ( (ptfunxored[k ] == 0x5a) &&
- (ptfunxored[k+1] & 0x02)) {
-
- uint8_t lengthofname = 0;
- lengthofname = ptfunxored[k+9];
- if (lengthofname == 0x5a) {
- continue;
- }
- track_t tr;
-
- regionspertrack = (uint8_t)(ptfunxored[k+13+lengthofname]);
-
- //printf("regions/track=%d\n", regionspertrack);
- char name[256] = {0};
- for (j = 0; j < lengthofname; j++) {
- name[j] = ptfunxored[j+k+13];
- }
- name[j] = '\0';
- tr.name = string(name);
- tr.index = tracknumber++;
-
- for (j = k+18+lengthofname; regionspertrack > 0 && j < len; j++) {
- jumpto(&j, ptfunxored, len, (const unsigned char *)"\x5a", 1);
- bool isgroup = ptfunxored[j+27] > 0;
- if (isgroup) {
- tr.reg.name = string("");
- tr.reg.length = 0;
- //tr.reg.index = 0xffff;
- verbose_printf("TRACK: t(%d) g(%d) G(%s) -> T(%s)\n",
- tracknumber, tr.reg.index, tr.reg.name.c_str(), tr.name.c_str());
- } else {
- tr.reg.index = ((uint16_t)(ptfunxored[j+11]) & 0xff)
- | (((uint16_t)(ptfunxored[j+12]) << 8) & 0xff00);
- vector<region_t>::iterator begin = regions.begin();
- vector<region_t>::iterator finish = regions.end();
- vector<region_t>::iterator found;
- if ((found = std::find(begin, finish, tr.reg)) != finish) {
- tr.reg = *found;
- }
- verbose_printf("TRACK: t(%d) r(%d) R(%s) -> T(%s)\n",
- tracknumber, tr.reg.index, tr.reg.name.c_str(), tr.name.c_str());
- }
- i = j+16;
- offset = u_endian_read4(&ptfunxored[i], is_bigendian);
- tr.reg.startpos = (int64_t)(offset*ratefactor);
- if (tr.reg.length > 0) {
- tracks.push_back(tr);
- }
- regionspertrack--;
-
- jumpto(&j, ptfunxored, len, (const unsigned char *)"\xff\xff\xff\xff\xff\xff\xff\xff", 8);
- j += 12;
- }
- }
- }
-}
diff --git a/libs/ptformat/ptformat.cc b/libs/ptformat/ptformat.cc
new file mode 100644
index 0000000000..b6b13b745f
--- /dev/null
+++ b/libs/ptformat/ptformat.cc
@@ -0,0 +1,1350 @@
+/*
+ * libptformat - a library to read ProTools sessions
+ *
+ * Copyright (C) 2015-2019 Damien Zammit
+ * Copyright (C) 2015-2019 Robin Gareus
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <string.h>
+#include <assert.h>
+
+#ifdef HAVE_GLIB
+# include <glib/gstdio.h>
+# define ptf_open g_fopen
+#else
+# define ptf_open fopen
+#endif
+
+#include "ptformat/ptformat.h"
+
+#define BITCODE "0010111100101011"
+#define ZMARK '\x5a'
+#define ZERO_TICKS 0xe8d4a51000ULL
+#define MAX_CONTENT_TYPE 0x3000
+#define MAX_CHANNELS_PER_TRACK 8
+
+#if 0
+#define DEBUG
+#endif
+
+#ifdef DEBUG
+#define verbose_printf(...) printf("XXX PTFORMAT XXX: " __VA_ARGS__)
+#else
+#define verbose_printf(...)
+#endif
+
+using namespace std;
+
+static void
+hexdump(uint8_t *data, int length, int level)
+{
+ int i,j,k,end,step=16;
+
+ for (i = 0; i < length; i += step) {
+ end = i + step;
+ if (end > length) end = length;
+ for (k = 0; k < level; k++)
+ printf(" ");
+ for (j = i; j < end; j++) {
+ printf("%02X ", data[j]);
+ }
+ for (j = i; j < end; j++) {
+ if (data[j] < 128 && data[j] > 32)
+ printf("%c", data[j]);
+ else
+ printf(".");
+ }
+ printf("\n");
+ }
+}
+
+PTFFormat::PTFFormat()
+ : _ptfunxored(0)
+ , _len(0)
+ , _sessionrate(0)
+ , _version(0)
+ , _product(NULL)
+ , _targetrate (0)
+ , _ratefactor (1.0)
+ , is_bigendian(false)
+{
+}
+
+PTFFormat::~PTFFormat() {
+ cleanup();
+}
+
+const std::string
+PTFFormat::get_content_description(uint16_t ctype) {
+ switch(ctype) {
+ case 0x0030:
+ return std::string("INFO product and version");
+ case 0x1001:
+ return std::string("WAV samplerate, size");
+ case 0x1003:
+ return std::string("WAV metadata");
+ case 0x1004:
+ return std::string("WAV list full");
+ case 0x1007:
+ return std::string("region name, number");
+ case 0x1008:
+ return std::string("AUDIO region name, number (v5)");
+ case 0x100b:
+ return std::string("AUDIO region list (v5)");
+ case 0x100f:
+ return std::string("AUDIO region->track entry");
+ case 0x1011:
+ return std::string("AUDIO region->track map entries");
+ case 0x1012:
+ return std::string("AUDIO region->track full map");
+ case 0x1014:
+ return std::string("AUDIO track name, number");
+ case 0x1015:
+ return std::string("AUDIO tracks");
+ case 0x1017:
+ return std::string("PLUGIN entry");
+ case 0x1018:
+ return std::string("PLUGIN full list");
+ case 0x1021:
+ return std::string("I/O channel entry");
+ case 0x1022:
+ return std::string("I/O channel list");
+ case 0x1028:
+ return std::string("INFO sample rate");
+ case 0x103a:
+ return std::string("WAV names");
+ case 0x104f:
+ return std::string("AUDIO region->track subentry (v8)");
+ case 0x1050:
+ return std::string("AUDIO region->track entry (v8)");
+ case 0x1052:
+ return std::string("AUDIO region->track map entries (v8)");
+ case 0x1054:
+ return std::string("AUDIO region->track full map (v8)");
+ case 0x1056:
+ return std::string("MIDI region->track entry");
+ case 0x1057:
+ return std::string("MIDI region->track map entries");
+ case 0x1058:
+ return std::string("MIDI region->track full map");
+ case 0x2000:
+ return std::string("MIDI events block");
+ case 0x2001:
+ return std::string("MIDI region name, number (v5)");
+ case 0x2002:
+ return std::string("MIDI regions map (v5)");
+ case 0x2067:
+ return std::string("INFO path of session");
+ case 0x2511:
+ return std::string("Snaps block");
+ case 0x2519:
+ return std::string("MIDI track full list");
+ case 0x251a:
+ return std::string("MIDI track name, number");
+ case 0x2523:
+ return std::string("COMPOUND region element");
+ case 0x2602:
+ return std::string("I/O route");
+ case 0x2603:
+ return std::string("I/O routing table");
+ case 0x2628:
+ return std::string("COMPOUND region group");
+ case 0x2629:
+ return std::string("AUDIO region name, number (v10)");
+ case 0x262a:
+ return std::string("AUDIO region list (v10)");
+ case 0x262c:
+ return std::string("COMPOUND region full map");
+ case 0x2633:
+ return std::string("MIDI regions name, number (v10)");
+ case 0x2634:
+ return std::string("MIDI regions map (v10)");
+ case 0x271a:
+ return std::string("MARKER list");
+ default:
+ return std::string("UNKNOWN content type");
+ }
+}
+
+uint16_t
+PTFFormat::u_endian_read2(unsigned char *buf, bool bigendian)
+{
+ if (bigendian) {
+ return ((uint16_t)(buf[0]) << 8) | (uint16_t)(buf[1]);
+ } else {
+ return ((uint16_t)(buf[1]) << 8) | (uint16_t)(buf[0]);
+ }
+}
+
+uint32_t
+PTFFormat::u_endian_read3(unsigned char *buf, bool bigendian)
+{
+ if (bigendian) {
+ return ((uint32_t)(buf[0]) << 16) |
+ ((uint32_t)(buf[1]) << 8) |
+ (uint32_t)(buf[2]);
+ } else {
+ return ((uint32_t)(buf[2]) << 16) |
+ ((uint32_t)(buf[1]) << 8) |
+ (uint32_t)(buf[0]);
+ }
+}
+
+uint32_t
+PTFFormat::u_endian_read4(unsigned char *buf, bool bigendian)
+{
+ if (bigendian) {
+ return ((uint32_t)(buf[0]) << 24) |
+ ((uint32_t)(buf[1]) << 16) |
+ ((uint32_t)(buf[2]) << 8) |
+ (uint32_t)(buf[3]);
+ } else {
+ return ((uint32_t)(buf[3]) << 24) |
+ ((uint32_t)(buf[2]) << 16) |
+ ((uint32_t)(buf[1]) << 8) |
+ (uint32_t)(buf[0]);
+ }
+}
+
+uint64_t
+PTFFormat::u_endian_read5(unsigned char *buf, bool bigendian)
+{
+ if (bigendian) {
+ return ((uint64_t)(buf[0]) << 32) |
+ ((uint64_t)(buf[1]) << 24) |
+ ((uint64_t)(buf[2]) << 16) |
+ ((uint64_t)(buf[3]) << 8) |
+ (uint64_t)(buf[4]);
+ } else {
+ return ((uint64_t)(buf[4]) << 32) |
+ ((uint64_t)(buf[3]) << 24) |
+ ((uint64_t)(buf[2]) << 16) |
+ ((uint64_t)(buf[1]) << 8) |
+ (uint64_t)(buf[0]);
+ }
+}
+
+uint64_t
+PTFFormat::u_endian_read8(unsigned char *buf, bool bigendian)
+{
+ if (bigendian) {
+ return ((uint64_t)(buf[0]) << 56) |
+ ((uint64_t)(buf[1]) << 48) |
+ ((uint64_t)(buf[2]) << 40) |
+ ((uint64_t)(buf[3]) << 32) |
+ ((uint64_t)(buf[4]) << 24) |
+ ((uint64_t)(buf[5]) << 16) |
+ ((uint64_t)(buf[6]) << 8) |
+ (uint64_t)(buf[7]);
+ } else {
+ return ((uint64_t)(buf[7]) << 56) |
+ ((uint64_t)(buf[6]) << 48) |
+ ((uint64_t)(buf[5]) << 40) |
+ ((uint64_t)(buf[4]) << 32) |
+ ((uint64_t)(buf[3]) << 24) |
+ ((uint64_t)(buf[2]) << 16) |
+ ((uint64_t)(buf[1]) << 8) |
+ (uint64_t)(buf[0]);
+ }
+}
+
+void
+PTFFormat::cleanup(void) {
+ _len = 0;
+ _sessionrate = 0;
+ _version = 0;
+ free(_ptfunxored);
+ _ptfunxored = NULL;
+ free (_product);
+ _product = NULL;
+ _audiofiles.clear();
+ _regions.clear();
+ _midiregions.clear();
+ _tracks.clear();
+ _miditracks.clear();
+ free_all_blocks();
+}
+
+int64_t
+PTFFormat::foundat(unsigned char *haystack, uint64_t n, const char *needle) {
+ int64_t found = 0;
+ uint64_t i, j, needle_n;
+ needle_n = strlen(needle);
+
+ for (i = 0; i < n; i++) {
+ found = i;
+ for (j = 0; j < needle_n; j++) {
+ if (haystack[i+j] != needle[j]) {
+ found = -1;
+ break;
+ }
+ }
+ if (found > 0)
+ return found;
+ }
+ return -1;
+}
+
+bool
+PTFFormat::jumpto(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen) {
+ uint64_t i;
+ uint64_t k = *currpos;
+ while (k + needlelen < maxoffset) {
+ bool foundall = true;
+ for (i = 0; i < needlelen; i++) {
+ if (buf[k+i] != needle[i]) {
+ foundall = false;
+ break;
+ }
+ }
+ if (foundall) {
+ *currpos = k;
+ return true;
+ }
+ k++;
+ }
+ return false;
+}
+
+bool
+PTFFormat::jumpback(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen) {
+ uint64_t i;
+ uint64_t k = *currpos;
+ while (k > 0 && k + needlelen < maxoffset) {
+ bool foundall = true;
+ for (i = 0; i < needlelen; i++) {
+ if (buf[k+i] != needle[i]) {
+ foundall = false;
+ break;
+ }
+ }
+ if (foundall) {
+ *currpos = k;
+ return true;
+ }
+ k--;
+ }
+ return false;
+}
+
+bool
+PTFFormat::foundin(std::string const& haystack, std::string const& needle) {
+ size_t found = haystack.find(needle);
+ if (found != std::string::npos) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/* Return values: 0 success
+ -1 error decrypting pt session
+*/
+int
+PTFFormat::unxor(std::string const& path) {
+ FILE *fp;
+ unsigned char xxor[256];
+ unsigned char ct;
+ uint64_t i;
+ uint8_t xor_type;
+ uint8_t xor_value;
+ uint8_t xor_delta;
+ uint16_t xor_len;
+
+ if (! (fp = ptf_open(path.c_str(), "rb"))) {
+ return -1;
+ }
+
+ fseek(fp, 0, SEEK_END);
+ _len = ftell(fp);
+ if (_len < 0x14) {
+ fclose(fp);
+ return -1;
+ }
+
+ if (! (_ptfunxored = (unsigned char*) malloc(_len * sizeof(unsigned char)))) {
+ /* Silently fail -- out of memory*/
+ fclose(fp);
+ _ptfunxored = 0;
+ return -1;
+ }
+
+ /* The first 20 bytes are always unencrypted */
+ fseek(fp, 0x00, SEEK_SET);
+ i = fread(_ptfunxored, 1, 0x14, fp);
+ if (i < 0x14) {
+ fclose(fp);
+ return -1;
+ }
+
+ xor_type = _ptfunxored[0x12];
+ xor_value = _ptfunxored[0x13];
+ xor_len = 256;
+
+ // xor_type 0x01 = ProTools 5, 6, 7, 8 and 9
+ // xor_type 0x05 = ProTools 10, 11, 12
+ switch(xor_type) {
+ case 0x01:
+ xor_delta = gen_xor_delta(xor_value, 53, false);
+ break;
+ case 0x05:
+ xor_delta = gen_xor_delta(xor_value, 11, true);
+ break;
+ default:
+ fclose(fp);
+ return -1;
+ }
+
+ /* Generate the xor_key */
+ for (i=0; i < xor_len; i++)
+ xxor[i] = (i * xor_delta) & 0xff;
+
+ /* hexdump(xxor, xor_len); */
+
+ /* Read file and decrypt rest of file */
+ i = 0x14;
+ fseek(fp, i, SEEK_SET);
+ while (fread(&ct, 1, 1, fp) != 0) {
+ uint8_t xor_index = (xor_type == 0x01) ? i & 0xff : (i >> 12) & 0xff;
+ _ptfunxored[i++] = ct ^ xxor[xor_index];
+ }
+ fclose(fp);
+ return 0;
+}
+
+/* Return values: 0 success
+ -1 error decrypting pt session
+ -2 error detecting pt session
+ -3 incompatible pt version
+ -4 error parsing pt session
+*/
+int
+PTFFormat::load(std::string const& ptf, int64_t targetsr) {
+ cleanup();
+ _path = ptf;
+
+ if (unxor(_path))
+ return -1;
+
+ if (parse_version())
+ return -2;
+
+ if (_version < 5 || _version > 12)
+ return -3;
+
+ _targetrate = targetsr;
+
+ int err = 0;
+ if ((err = parse())) {
+ printf ("PARSE FAILED %d\n", err);
+ return -4;
+ }
+
+ return 0;
+}
+
+bool
+PTFFormat::parse_version() {
+ uint32_t seg_len,str_len;
+ uint8_t *data = _ptfunxored + 0x14;
+ uintptr_t data_end = ((uintptr_t)_ptfunxored) + 0x100;
+ uint8_t seg_type;
+ bool success = false;
+
+ if (_ptfunxored[0] != '\x03' && foundat(_ptfunxored, 0x100, BITCODE) != 1) {
+ return false;
+ }
+
+ while( ((uintptr_t)data < data_end) && (success == false) ) {
+
+ if (data[0] != 0x5a) {
+ success = false;
+ break;
+ }
+
+ seg_type = data[1];
+ /* Skip segment header */
+ data += 3;
+ if (data[0] == 0 && data[1] == 0) {
+ /* BE */
+ is_bigendian = true;
+ } else {
+ /* LE */
+ is_bigendian = false;
+ }
+ seg_len = u_endian_read4(&data[0], is_bigendian);
+
+ /* Skip seg_len */
+ data += 4;
+ if (!(seg_type == 0x04 || seg_type == 0x03) || data[0] != 0x03) {
+ /* Go to next segment */
+ data += seg_len;
+ continue;
+ }
+ /* Skip 0x03 0x00 0x00 */
+ data += 3;
+ seg_len -= 3;
+ str_len = (*(uint8_t *)data);
+ if (! (_product = (uint8_t *)malloc((str_len+1) * sizeof(uint8_t)))) {
+ success = false;
+ break;
+ }
+
+ /* Skip str_len */
+ data += 4;
+ seg_len -= 4;
+
+ memcpy(_product, data, str_len);
+ _product[str_len] = 0;
+ data += str_len;
+ seg_len -= str_len;
+
+ /* Skip 0x03 0x00 0x00 0x00 */
+ data += 4;
+ seg_len -= 4;
+
+ _version = data[0];
+ if (_version == 0) {
+ _version = data[3];
+ }
+ data += seg_len;
+ success = true;
+ }
+
+ /* If the above does not work, try other heuristics */
+ if ((uintptr_t)data >= data_end - seg_len) {
+ _version = _ptfunxored[0x40];
+ if (_version == 0) {
+ _version = _ptfunxored[0x3d];
+ }
+ if (_version == 0) {
+ _version = _ptfunxored[0x3a] + 2;
+ }
+ if (_version != 0) {
+ success = true;
+ }
+ }
+ return (!success);
+}
+
+uint8_t
+PTFFormat::gen_xor_delta(uint8_t xor_value, uint8_t mul, bool negative) {
+ uint16_t i;
+ for (i = 0; i < 256; i++) {
+ if (((i * mul) & 0xff) == xor_value) {
+ return (negative) ? i * (-1) : i;
+ }
+ }
+ // Should not occur
+ return 0;
+}
+
+void
+PTFFormat::setrates(void) {
+ _ratefactor = 1.f;
+ if (_sessionrate != 0) {
+ _ratefactor = (float)_targetrate / _sessionrate;
+ }
+}
+
+bool
+PTFFormat::parse_block_at(uint32_t pos, struct block_t *block, struct block_t *parent, int level) {
+ struct block_t b;
+ int childjump = 0;
+ uint32_t i;
+ uint32_t max = _len;
+
+ if (_ptfunxored[pos] != ZMARK)
+ return false;
+
+ if (parent)
+ max = parent->block_size + parent->offset;
+
+ b.zmark = ZMARK;
+ b.block_type = u_endian_read2(&_ptfunxored[pos+1], is_bigendian);
+ b.block_size = u_endian_read4(&_ptfunxored[pos+3], is_bigendian);
+ b.content_type = u_endian_read2(&_ptfunxored[pos+7], is_bigendian);
+ b.offset = pos + 7;
+
+ if (b.block_size + b.offset > max)
+ return false;
+ if (b.block_type & 0xff00)
+ return false;
+
+ block->zmark = b.zmark;
+ block->block_type = b.block_type;
+ block->block_size = b.block_size;
+ block->content_type = b.content_type;
+ block->offset = b.offset;
+ memset(&block->child, 0, sizeof(block->child));
+
+ for (i = 1; (i < block->block_size) && (pos + i + childjump < max); i += childjump ? childjump : 1) {
+ int p = pos + i;
+ struct block_t bchild;
+ childjump = 0;
+ if (parse_block_at(p, &bchild, block, level+1)) {
+ block->child.push_back(bchild);
+ childjump = bchild.block_size + 7;
+ }
+ }
+ return true;
+}
+
+void
+PTFFormat::dump_block(struct block_t& b, int level)
+{
+ int i;
+
+ for (i = 0; i < level; i++) {
+ printf(" ");
+ }
+ printf("%s(0x%04x)\n", get_content_description(b.content_type).c_str(), b.content_type);
+ hexdump(&_ptfunxored[b.offset], b.block_size, level);
+
+ for (vector<PTFFormat::block_t>::iterator c = b.child.begin();
+ c != b.child.end(); ++c) {
+ dump_block(*c, level + 1);
+ }
+}
+
+void
+PTFFormat::free_block(struct block_t& b)
+{
+ for (vector<PTFFormat::block_t>::iterator c = b.child.begin();
+ c != b.child.end(); ++c) {
+ free_block(*c);
+ }
+
+ b.child.clear();
+}
+
+void
+PTFFormat::free_all_blocks(void)
+{
+ for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
+ b != blocks.end(); ++b) {
+ free_block(*b);
+ }
+
+ blocks.clear();
+}
+
+void
+PTFFormat::dump(void) {
+ for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
+ b != blocks.end(); ++b) {
+ dump_block(*b, 0);
+ }
+}
+
+void
+PTFFormat::parseblocks(void) {
+ uint32_t i = 20;
+
+ while (i < _len) {
+ struct block_t b;
+ if (parse_block_at(i, &b, NULL, 0)) {
+ blocks.push_back(b);
+ }
+ i += b.block_size ? b.block_size + 7 : 1;
+ }
+}
+
+int
+PTFFormat::parse(void) {
+ parseblocks();
+#ifdef DEBUG
+ dump();
+#endif
+ if (!parseheader())
+ return -1;
+ setrates();
+ if (_sessionrate < 44100 || _sessionrate > 192000)
+ return -2;
+ if (!parseaudio())
+ return -3;
+ if (!parserest())
+ return -4;
+ if (!parsemidi())
+ return -5;
+ return 0;
+}
+
+bool
+PTFFormat::parseheader(void) {
+ bool found = false;
+
+ for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
+ b != blocks.end(); ++b) {
+ if (b->content_type == 0x1028) {
+ _sessionrate = u_endian_read4(&_ptfunxored[b->offset+4], is_bigendian);
+ found = true;
+ }
+ }
+ return found;
+}
+
+char *
+PTFFormat::parsestring(uint32_t pos) {
+ uint32_t length = u_endian_read4(&_ptfunxored[pos], is_bigendian);
+ pos += 4;
+ return strndup((const char *)&_ptfunxored[pos], length);
+}
+
+bool
+PTFFormat::parseaudio(void) {
+ bool found = false;
+ uint32_t nwavs, i, n;
+ uint32_t pos = 0;
+ char *str;
+ std::string wavtype;
+ std::string wavname;
+
+ // Parse wav names
+ for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
+ b != blocks.end(); ++b) {
+ if (b->content_type == 0x1004) {
+
+ nwavs = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian);
+
+ for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
+ c != b->child.end(); ++c) {
+ if (c->content_type == 0x103a) {
+ found = true;
+ //nstrings = u_endian_read4(&_ptfunxored[c->offset+1], is_bigendian);
+ pos = c->offset + 11;
+ // Found wav list
+ for (i = n = 0; (pos < c->offset + c->block_size) && (n < nwavs); i++) {
+ str = parsestring(pos);
+ wavname = std::string(str);
+ free(str);
+ pos += wavname.size() + 4;
+ str = strndup((const char *)&_ptfunxored[pos], 4);
+ wavtype = std::string(str);
+ free(str);
+ pos += 9;
+ if (foundin(wavname, std::string(".grp")))
+ continue;
+
+ if (foundin(wavname, std::string("Audio Files"))) {
+ continue;
+ }
+ if (foundin(wavname, std::string("Fade Files"))) {
+ continue;
+ }
+ if (_version < 10) {
+ if (!(foundin(wavtype, std::string("WAVE")) ||
+ foundin(wavtype, std::string("EVAW")) ||
+ foundin(wavtype, std::string("AIFF")) ||
+ foundin(wavtype, std::string("FFIA"))) ) {
+ continue;
+ }
+ } else {
+ if (wavtype.size() != 0) {
+ if (!(foundin(wavtype, std::string("WAVE")) ||
+ foundin(wavtype, std::string("EVAW")) ||
+ foundin(wavtype, std::string("AIFF")) ||
+ foundin(wavtype, std::string("FFIA"))) ) {
+ continue;
+ }
+ } else if (!(foundin(wavname, std::string(".wav")) ||
+ foundin(wavname, std::string(".aif"))) ) {
+ continue;
+ }
+ }
+ wav_t f (n);
+ f.filename = wavname;
+ n++;
+ _audiofiles.push_back(f);
+ }
+ }
+ }
+ }
+ }
+
+ // Add wav length information
+ for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
+ b != blocks.end(); ++b) {
+ if (b->content_type == 0x1004) {
+
+ vector<PTFFormat::wav_t>::iterator wav = _audiofiles.begin();
+
+ for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
+ c != b->child.end(); ++c) {
+ if (c->content_type == 0x1003) {
+ for (vector<PTFFormat::block_t>::iterator d = c->child.begin();
+ d != c->child.end(); ++d) {
+ if (d->content_type == 0x1001) {
+ (*wav).length = u_endian_read8(&_ptfunxored[d->offset+8], is_bigendian);
+ wav++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return found;
+}
+
+
+void
+PTFFormat::parse_three_point(uint32_t j, uint64_t& start, uint64_t& offset, uint64_t& length) {
+ uint8_t offsetbytes, lengthbytes, startbytes;
+
+ if (is_bigendian) {
+ offsetbytes = (_ptfunxored[j+4] & 0xf0) >> 4;
+ lengthbytes = (_ptfunxored[j+3] & 0xf0) >> 4;
+ startbytes = (_ptfunxored[j+2] & 0xf0) >> 4;
+ //somethingbytes = (_ptfunxored[j+2] & 0xf);
+ //skipbytes = _ptfunxored[j+1];
+ } else {
+ offsetbytes = (_ptfunxored[j+1] & 0xf0) >> 4; //3
+ lengthbytes = (_ptfunxored[j+2] & 0xf0) >> 4;
+ startbytes = (_ptfunxored[j+3] & 0xf0) >> 4; //1
+ //somethingbytes = (_ptfunxored[j+3] & 0xf);
+ //skipbytes = _ptfunxored[j+4];
+ }
+
+ switch (offsetbytes) {
+ case 5:
+ offset = u_endian_read5(&_ptfunxored[j+5], false);
+ break;
+ case 4:
+ offset = (uint64_t)u_endian_read4(&_ptfunxored[j+5], false);
+ break;
+ case 3:
+ offset = (uint64_t)u_endian_read3(&_ptfunxored[j+5], false);
+ break;
+ case 2:
+ offset = (uint64_t)u_endian_read2(&_ptfunxored[j+5], false);
+ break;
+ case 1:
+ offset = (uint64_t)(_ptfunxored[j+5]);
+ break;
+ default:
+ offset = 0;
+ break;
+ }
+ j+=offsetbytes;
+ switch (lengthbytes) {
+ case 5:
+ length = u_endian_read5(&_ptfunxored[j+5], false);
+ break;
+ case 4:
+ length = (uint64_t)u_endian_read4(&_ptfunxored[j+5], false);
+ break;
+ case 3:
+ length = (uint64_t)u_endian_read3(&_ptfunxored[j+5], false);
+ break;
+ case 2:
+ length = (uint64_t)u_endian_read2(&_ptfunxored[j+5], false);
+ break;
+ case 1:
+ length = (uint64_t)(_ptfunxored[j+5]);
+ break;
+ default:
+ length = 0;
+ break;
+ }
+ j+=lengthbytes;
+ switch (startbytes) {
+ case 5:
+ start = u_endian_read5(&_ptfunxored[j+5], false);
+ break;
+ case 4:
+ start = (uint64_t)u_endian_read4(&_ptfunxored[j+5], false);
+ break;
+ case 3:
+ start = (uint64_t)u_endian_read3(&_ptfunxored[j+5], false);
+ break;
+ case 2:
+ start = (uint64_t)u_endian_read2(&_ptfunxored[j+5], false);
+ break;
+ case 1:
+ start = (uint64_t)(_ptfunxored[j+5]);
+ break;
+ default:
+ start = 0;
+ break;
+ }
+}
+
+void
+PTFFormat::parse_region_info(uint32_t j, block_t& blk, region_t& r) {
+ uint64_t findex, start, sampleoffset, length;
+
+ parse_three_point(j, start, sampleoffset, length);
+
+ findex = u_endian_read4(&_ptfunxored[blk.offset + blk.block_size], is_bigendian);
+ wav_t f (findex);
+ f.posabsolute = start * _ratefactor;
+ f.length = length * _ratefactor;
+
+ wav_t found;
+ if (find_wav(findex, found)) {
+ f.filename = found.filename;
+ }
+
+ std::vector<midi_ev_t> m;
+ r.startpos = (int64_t)(start*_ratefactor);
+ r.sampleoffset = (int64_t)(sampleoffset*_ratefactor);
+ r.length = (int64_t)(length*_ratefactor);
+ r.wave = f;
+ r.midi = m;
+}
+
+bool
+PTFFormat::parserest(void) {
+ uint32_t i, j, count;
+ uint64_t start;
+ uint16_t rindex, rawindex, tindex, mindex;
+ uint32_t nch;
+ uint16_t ch_map[MAX_CHANNELS_PER_TRACK];
+ bool found = false;
+ char *reg;
+ std::string regionname, trackname, midiregionname;
+ rindex = 0;
+
+ // Parse sources->regions
+ for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
+ b != blocks.end(); ++b) {
+ if (b->content_type == 0x100b || b->content_type == 0x262a) {
+ //nregions = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian);
+ for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
+ c != b->child.end(); ++c) {
+ if (c->content_type == 0x1008 || c->content_type == 0x2629) {
+ vector<PTFFormat::block_t>::iterator d = c->child.begin();
+ region_t r;
+
+ found = true;
+ j = c->offset + 11;
+ reg = parsestring(j);
+ regionname = std::string(reg);
+ free(reg);
+ j += regionname.size() + 4;
+
+ r.name = regionname;
+ r.index = rindex;
+ parse_region_info(j, *d, r);
+
+ _regions.push_back(r);
+ rindex++;
+ }
+ }
+ found = true;
+ }
+ }
+
+ // Parse tracks
+ for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
+ b != blocks.end(); ++b) {
+ if (b->content_type == 0x1015) {
+ //ntracks = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian);
+ for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
+ c != b->child.end(); ++c) {
+ if (c->content_type == 0x1014) {
+ j = c->offset + 2;
+ reg = parsestring(j);
+ trackname = std::string(reg);
+ j += trackname.size() + 5;
+ nch = u_endian_read4(&_ptfunxored[j], is_bigendian);
+ j += 4;
+ for (i = 0; i < nch; i++) {
+ ch_map[i] = u_endian_read2(&_ptfunxored[j], is_bigendian);
+
+ track_t ti;
+ if (!find_track(ch_map[i], ti)) {
+ // Add a dummy region for now
+ region_t r (65535);
+ track_t t (ch_map[i]);
+ t.name = trackname;
+ t.reg = r;
+ _tracks.push_back(t);
+ }
+ //verbose_printf("%s : %d(%d)\n", reg, nch, ch_map[0]);
+ j += 2;
+ }
+ free(reg);
+ }
+ }
+ }
+ }
+
+ // Reparse from scratch to exclude audio tracks from all tracks to get midi tracks
+ for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
+ b != blocks.end(); ++b) {
+ if (b->content_type == 0x2519) {
+ tindex = 0;
+ mindex = 0;
+ //ntracks = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian);
+ for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
+ c != b->child.end(); ++c) {
+ if (c->content_type == 0x251a) {
+ j = c->offset + 4;
+ reg = parsestring(j);
+ trackname = std::string(reg);
+ free(reg);
+ j += trackname.size() + 4 + 18;
+ //tindex = u_endian_read4(&_ptfunxored[j], is_bigendian);
+
+ // Add a dummy region for now
+ region_t r (65535);
+ track_t t (mindex);
+ t.name = trackname;
+ t.reg = r;
+
+ track_t ti;
+ // If the current track is not an audio track, insert as midi track
+ if (!(find_track(tindex, ti) && foundin(trackname, ti.name))) {
+ _miditracks.push_back(t);
+ mindex++;
+ }
+ tindex++;
+ }
+ }
+ }
+ }
+
+ // Parse regions->tracks
+ for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
+ b != blocks.end(); ++b) {
+ tindex = 0;
+ if (b->content_type == 0x1012) {
+ //nregions = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian);
+ count = 0;
+ for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
+ c != b->child.end(); ++c) {
+ if (c->content_type == 0x1011) {
+ reg = parsestring(c->offset + 2);
+ regionname = std::string(reg);
+ free(reg);
+ for (vector<PTFFormat::block_t>::iterator d = c->child.begin();
+ d != c->child.end(); ++d) {
+ if (d->content_type == 0x100f) {
+ for (vector<PTFFormat::block_t>::iterator e = d->child.begin();
+ e != d->child.end(); ++e) {
+ if (e->content_type == 0x100e) {
+ // Region->track
+ track_t ti;
+ j = e->offset + 4;
+ rawindex = u_endian_read4(&_ptfunxored[j], is_bigendian);
+ if (!find_track(count, ti))
+ continue;
+ if (!find_region(rawindex, ti.reg))
+ continue;
+ if (ti.reg.index != 65535) {
+ _tracks.push_back(ti);
+ }
+ }
+ }
+ }
+ }
+ found = true;
+ count++;
+ }
+ }
+ } else if (b->content_type == 0x1054) {
+ //nregions = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian);
+ count = 0;
+ for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
+ c != b->child.end(); ++c) {
+ if (c->content_type == 0x1052) {
+ reg = parsestring(c->offset + 2);
+ regionname = std::string(reg);
+ free(reg);
+ for (vector<PTFFormat::block_t>::iterator d = c->child.begin();
+ d != c->child.end(); ++d) {
+ if (d->content_type == 0x1050) {
+ for (vector<PTFFormat::block_t>::iterator e = d->child.begin();
+ e != d->child.end(); ++e) {
+ if (e->content_type == 0x104f) {
+ // Region->track
+ j = e->offset + 4;
+ rawindex = u_endian_read4(&_ptfunxored[j], is_bigendian);
+ j += 4 + 1;
+ start = u_endian_read4(&_ptfunxored[j], is_bigendian);
+ tindex = count;
+ track_t ti;
+ if (!find_track(tindex, ti)) {
+ verbose_printf("dropped track %d\n", tindex);
+ continue;
+ }
+ if (!find_region(rawindex, ti.reg)) {
+ verbose_printf("dropped region %d\n", rawindex);
+ continue;
+ }
+ ti.reg.startpos = start;
+ if (ti.reg.index != 65535) {
+ _tracks.push_back(ti);
+ }
+ }
+ }
+ }
+ }
+ found = true;
+ count++;
+ }
+ }
+ }
+ }
+ for (std::vector<track_t>::iterator tr = _tracks.begin();
+ tr != _tracks.end(); /* noop */) {
+ if ((*tr).reg.index == 65535) {
+ tr = _tracks.erase(tr);
+ } else {
+ tr++;
+ }
+ }
+ return found;
+}
+
+struct mchunk {
+ mchunk (uint64_t zt, uint64_t ml, std::vector<PTFFormat::midi_ev_t> const& c)
+ : zero (zt)
+ , maxlen (ml)
+ , chunk (c)
+ {}
+ uint64_t zero;
+ uint64_t maxlen;
+ std::vector<PTFFormat::midi_ev_t> chunk;
+};
+
+bool
+PTFFormat::parsemidi(void) {
+ uint32_t i, j, k, n, rindex, tindex, mindex, count, rawindex;
+ uint64_t n_midi_events, zero_ticks, start, offset, length, start2, stop2;
+ uint64_t midi_pos, midi_len, max_pos, region_pos;
+ uint8_t midi_velocity, midi_note;
+ uint16_t regionnumber = 0;
+ std::string midiregionname;
+
+ std::vector<mchunk> midichunks;
+ midi_ev_t m;
+
+ char *str;
+ std::string regionname, trackname;
+ rindex = 0;
+
+ // Parse MIDI events
+ for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
+ b != blocks.end(); ++b) {
+ if (b->content_type == 0x2000) {
+
+ k = b->offset;
+
+ // Parse all midi chunks, not 1:1 mapping to regions yet
+ while (k + 35 < b->block_size + b->offset) {
+ max_pos = 0;
+ std::vector<midi_ev_t> midi;
+
+ if (!jumpto(&k, _ptfunxored, _len, (const unsigned char *)"MdNLB", 5)) {
+ break;
+ }
+ k += 11;
+ n_midi_events = u_endian_read4(&_ptfunxored[k], is_bigendian);
+
+ k += 4;
+ zero_ticks = u_endian_read5(&_ptfunxored[k], is_bigendian);
+ for (i = 0; i < n_midi_events && k < _len; i++, k += 35) {
+ midi_pos = u_endian_read5(&_ptfunxored[k], is_bigendian);
+ midi_pos -= zero_ticks;
+ midi_note = _ptfunxored[k+8];
+ midi_len = u_endian_read5(&_ptfunxored[k+9], is_bigendian);
+ midi_velocity = _ptfunxored[k+17];
+
+ if (midi_pos + midi_len > max_pos) {
+ max_pos = midi_pos + midi_len;
+ }
+
+ m.pos = midi_pos;
+ m.length = midi_len;
+ m.note = midi_note;
+ m.velocity = midi_velocity;
+ midi.push_back(m);
+ }
+ midichunks.push_back(mchunk (zero_ticks, max_pos, midi));
+ }
+
+ // Put chunks onto regions
+ } else if ((b->content_type == 0x2002) || (b->content_type == 0x2634)) {
+ for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
+ c != b->child.end(); ++c) {
+ if ((c->content_type == 0x2001) || (c->content_type == 0x2633)) {
+ for (vector<PTFFormat::block_t>::iterator d = c->child.begin();
+ d != c->child.end(); ++d) {
+ if ((d->content_type == 0x1007) || (d->content_type == 0x2628)) {
+ j = d->offset + 2;
+ str = parsestring(j);
+ midiregionname = std::string(str);
+ j += 4 + midiregionname.size();
+ parse_three_point(j, region_pos, zero_ticks, midi_len);
+ j = d->offset + d->block_size;
+ rindex = u_endian_read4(&_ptfunxored[j], is_bigendian);
+ struct mchunk mc = *(midichunks.begin()+rindex);
+
+ region_t r (regionnumber++);
+ r.name = midiregionname;
+ r.startpos = (int64_t)0xe8d4a51000ULL;
+ r.sampleoffset = 0;
+ r.length = mc.maxlen;
+ r.midi = mc.chunk;
+
+ _midiregions.push_back(r);
+ //verbose_printf("MIDI %s : r(%d) (%llu, %llu, %llu)\n", str, rindex, zero_ticks, region_pos, midi_len);
+ //dump_block(*d, 1);
+ free(str);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // COMPOUND MIDI regions
+ for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
+ b != blocks.end(); ++b) {
+ if (b->content_type == 0x262c) {
+ mindex = 0;
+ for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
+ c != b->child.end(); ++c) {
+ if (c->content_type == 0x262b) {
+ for (vector<PTFFormat::block_t>::iterator d = c->child.begin();
+ d != c->child.end(); ++d) {
+ if (d->content_type == 0x2628) {
+ count = 0;
+ j = d->offset + 2;
+ str = parsestring(j);
+ regionname = std::string(str);
+ j += 4 + regionname.size();
+ parse_three_point(j, start, offset, length);
+ j = d->offset + d->block_size + 2;
+ n = u_endian_read2(&_ptfunxored[j], is_bigendian);
+
+ for (vector<PTFFormat::block_t>::iterator e = d->child.begin();
+ e != d->child.end(); ++e) {
+ if (e->content_type == 0x2523) {
+ // FIXME Compound MIDI region
+ j = e->offset + 39;
+ rawindex = u_endian_read4(&_ptfunxored[j], is_bigendian);
+ j += 12;
+ start2 = u_endian_read5(&_ptfunxored[j], is_bigendian);
+ int64_t signedval = (int64_t)start2;
+ signedval -= ZERO_TICKS;
+ if (signedval < 0) {
+ signedval = -signedval;
+ }
+ start2 = signedval;
+ j += 8;
+ stop2 = u_endian_read5(&_ptfunxored[j], is_bigendian);
+ signedval = (int64_t)stop2;
+ signedval -= ZERO_TICKS;
+ if (signedval < 0) {
+ signedval = -signedval;
+ }
+ stop2 = signedval;
+ j += 16;
+ //nn = u_endian_read4(&_ptfunxored[j], is_bigendian);
+ //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);
+ count++;
+ }
+ }
+ if (!count) {
+ // Plain MIDI region
+ struct mchunk mc = *(midichunks.begin()+n);
+
+ region_t r (n);
+ r.name = midiregionname;
+ r.startpos = (int64_t)0xe8d4a51000ULL;
+ r.length = mc.maxlen;
+ r.midi = mc.chunk;
+ _midiregions.push_back(r);
+ verbose_printf("%s : MIDI region mr(%d) ?(%d) (%llu %llu %llu)\n", str, mindex, n, start, offset, length);
+ mindex++;
+ }
+ free(str);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Put midi regions onto midi tracks
+ for (vector<PTFFormat::block_t>::iterator b = blocks.begin();
+ b != blocks.end(); ++b) {
+ if (b->content_type == 0x1058) {
+ //nregions = u_endian_read4(&_ptfunxored[b->offset+2], is_bigendian);
+ count = 0;
+ for (vector<PTFFormat::block_t>::iterator c = b->child.begin();
+ c != b->child.end(); ++c) {
+ if (c->content_type == 0x1057) {
+ str = parsestring(c->offset + 2);
+ regionname = std::string(str);
+ free(str);
+ for (vector<PTFFormat::block_t>::iterator d = c->child.begin();
+ d != c->child.end(); ++d) {
+ if (d->content_type == 0x1056) {
+ for (vector<PTFFormat::block_t>::iterator e = d->child.begin();
+ e != d->child.end(); ++e) {
+ if (e->content_type == 0x104f) {
+ // MIDI region->MIDI track
+ track_t ti;
+ j = e->offset + 4;
+ rawindex = u_endian_read4(&_ptfunxored[j], is_bigendian);
+ j += 4 + 1;
+ start = u_endian_read5(&_ptfunxored[j], is_bigendian);
+ tindex = count;
+ if (!find_miditrack(tindex, ti)) {
+ verbose_printf("dropped midi t(%d) r(%d)\n", tindex, rawindex);
+ continue;
+ }
+ if (!find_midiregion(rawindex, ti.reg)) {
+ verbose_printf("dropped midiregion\n");
+ continue;
+ }
+ //verbose_printf("MIDI : %s : t(%d) r(%d) %llu(%llu)\n", ti.name.c_str(), tindex, rawindex, start, ti.reg.startpos);
+ int64_t signedstart = (int64_t)(start - ZERO_TICKS);
+ if (signedstart < 0)
+ signedstart = -signedstart;
+ ti.reg.startpos = (uint64_t)signedstart;
+ if (ti.reg.index != 65535) {
+ _miditracks.push_back(ti);
+ }
+ }
+ }
+ }
+ }
+ count++;
+ }
+ }
+ }
+ }
+ for (std::vector<track_t>::iterator tr = _miditracks.begin();
+ tr != _miditracks.end(); /* noop */) {
+ if ((*tr).reg.index == 65535) {
+ tr = _miditracks.erase(tr);
+ } else {
+ tr++;
+ }
+ }
+ return true;
+}
diff --git a/libs/ptformat/ptformat/ptfformat.h b/libs/ptformat/ptformat/ptfformat.h
deleted file mode 100644
index 72dc64c715..0000000000
--- a/libs/ptformat/ptformat/ptfformat.h
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * libptformat - a library to read ProTools sessions
- *
- * Copyright (C) 2015 Damien Zammit
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- */
-#ifndef PTFFORMAT_H
-#define PTFFORMAT_H
-
-#include <string>
-#include <cstring>
-#include <algorithm>
-#include <vector>
-#include <stdint.h>
-#include "ptformat/visibility.h"
-
-class LIBPTFORMAT_API PTFFormat {
-public:
- PTFFormat();
- ~PTFFormat();
-
- /* Return values: 0 success
- -1 could not parse pt session
- */
- int load(std::string path, int64_t targetsr);
-
- /* Return values: 0 success
- -1 could not decrypt pt session
- */
- int unxor(std::string path);
-
- struct wav_t {
- std::string filename;
- uint16_t index;
-
- int64_t posabsolute;
- int64_t length;
-
- bool operator <(const struct wav_t& other) const {
- return (strcasecmp(this->filename.c_str(),
- other.filename.c_str()) < 0);
- }
-
- bool operator ==(const struct wav_t& other) const {
- return (this->filename == other.filename ||
- this->index == other.index);
- }
-
- };
-
- struct midi_ev_t {
- uint64_t pos;
- uint64_t length;
- uint8_t note;
- uint8_t velocity;
- };
-
- typedef struct region {
- std::string name;
- uint16_t index;
- int64_t startpos;
- int64_t sampleoffset;
- int64_t length;
- wav_t wave;
- std::vector<midi_ev_t> midi;
-
- bool operator ==(const struct region& other) {
- return (this->index == other.index);
- }
-
- bool operator <(const struct region& other) const {
- return (strcasecmp(this->name.c_str(),
- other.name.c_str()) < 0);
- }
- } region_t;
-
- typedef struct compound {
- uint16_t curr_index;
- uint16_t unknown1;
- uint16_t level;
- uint16_t ontopof_index;
- uint16_t next_index;
- std::string name;
- } compound_t;
-
- typedef struct track {
- std::string name;
- uint16_t index;
- uint8_t playlist;
- region_t reg;
-
- bool operator ==(const struct track& other) {
- return (this->name == other.name);
- }
- } track_t;
-
- std::vector<wav_t> audiofiles;
- std::vector<region_t> regions;
- std::vector<region_t> midiregions;
- std::vector<compound_t> compounds;
- std::vector<track_t> tracks;
- std::vector<track_t> miditracks;
-
- static bool regionexistsin(std::vector<region_t> reg, uint16_t index) {
- std::vector<region_t>::iterator begin = reg.begin();
- std::vector<region_t>::iterator finish = reg.end();
- std::vector<region_t>::iterator found;
-
- wav_t w = { std::string(""), 0, 0, 0 };
- std::vector<midi_ev_t> m;
- region_t r = { std::string(""), index, 0, 0, 0, w, m};
-
- if ((found = std::find(begin, finish, r)) != finish) {
- return true;
- }
- return false;
- }
-
- static bool wavexistsin(std::vector<wav_t> wv, uint16_t index) {
- std::vector<wav_t>::iterator begin = wv.begin();
- std::vector<wav_t>::iterator finish = wv.end();
- std::vector<wav_t>::iterator found;
-
- wav_t w = { std::string(""), index, 0, 0 };
-
- if ((found = std::find(begin, finish, w)) != finish) {
- return true;
- }
- return false;
- }
-
- int64_t sessionrate;
- int64_t targetrate;
- uint8_t version;
- uint8_t *product;
- std::string path;
-
- unsigned char c0;
- unsigned char c1;
- unsigned char *ptfunxored;
- uint64_t len;
- bool is_bigendian;
-
-private:
- bool jumpback(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen);
- bool jumpto(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen);
- bool foundin(std::string haystack, std::string needle);
- int64_t foundat(unsigned char *haystack, uint64_t n, const char *needle);
- uint16_t u_endian_read2(unsigned char *buf, bool);
- uint32_t u_endian_read3(unsigned char *buf, bool);
- uint32_t u_endian_read4(unsigned char *buf, bool);
- uint64_t u_endian_read5(unsigned char *buf, bool);
-
- int parse(void);
- bool parse_version();
- uint8_t gen_xor_delta(uint8_t xor_value, uint8_t mul, bool negative);
- void setrates(void);
- void cleanup(void);
- void parse5header(void);
- void parse7header(void);
- void parse8header(void);
- void parse9header(void);
- void parse10header(void);
- void parserest5(void);
- void parserest89(void);
- void parserest12(void);
- void parseaudio5(void);
- void parseaudio(void);
- void parsemidi(void);
- void parsemidi12(void);
- void resort(std::vector<wav_t>& ws);
- void resort(std::vector<region_t>& rs);
- void filter(std::vector<region_t>& rs);
- std::vector<wav_t> actualwavs;
- float ratefactor;
- std::string extension;
- uint32_t upto;
-};
-
-
-#endif
diff --git a/libs/ptformat/ptformat/ptformat.h b/libs/ptformat/ptformat/ptformat.h
new file mode 100644
index 0000000000..43b4dc1fbe
--- /dev/null
+++ b/libs/ptformat/ptformat/ptformat.h
@@ -0,0 +1,282 @@
+/*
+ * libptformat - a library to read ProTools sessions
+ *
+ * Copyright (C) 2015-2019 Damien Zammit
+ * Copyright (C) 2015-2019 Robin Gareus
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#ifndef PTFFORMAT_H
+#define PTFFORMAT_H
+
+#include <string>
+#include <cstring>
+#include <algorithm>
+#include <vector>
+#include <stdint.h>
+#include "ptformat/visibility.h"
+
+class LIBPTFORMAT_API PTFFormat {
+public:
+ PTFFormat();
+ ~PTFFormat();
+
+ /* Return values: 0 success
+ -1 error decrypting pt session
+ -2 error detecting pt session
+ -3 incompatible pt version
+ -4 error parsing pt session
+ */
+ int load(std::string const& path, int64_t targetsr);
+
+ /* Return values: 0 success
+ -1 error decrypting pt session
+ */
+ int unxor(std::string const& path);
+
+ struct wav_t {
+ std::string filename;
+ uint16_t index;
+
+ int64_t posabsolute;
+ int64_t length;
+
+ bool operator <(const struct wav_t& other) const {
+ return (strcasecmp(this->filename.c_str(),
+ other.filename.c_str()) < 0);
+ }
+
+ bool operator ==(const struct wav_t& other) const {
+ return (this->filename == other.filename ||
+ this->index == other.index);
+ }
+
+ wav_t (uint16_t idx = 0) : index (idx), posabsolute (0), length (0) {}
+ };
+
+ struct midi_ev_t {
+ uint64_t pos;
+ uint64_t length;
+ uint8_t note;
+ uint8_t velocity;
+ midi_ev_t () : pos (0), length (0), note (0), velocity (0) {}
+ };
+
+ struct region_t {
+ std::string name;
+ uint16_t index;
+ int64_t startpos;
+ int64_t sampleoffset;
+ int64_t length;
+ wav_t wave;
+ std::vector<midi_ev_t> midi;
+
+ bool operator ==(const region_t& other) const {
+ return (this->index == other.index);
+ }
+
+ bool operator <(const region_t& other) const {
+ return (strcasecmp(this->name.c_str(),
+ other.name.c_str()) < 0);
+ }
+ region_t (uint16_t idx = 0) : index (idx), startpos (0), sampleoffset (0), length (0) {}
+ };
+
+ struct track_t {
+ std::string name;
+ uint16_t index;
+ uint8_t playlist;
+ region_t reg;
+
+ bool operator <(const track_t& other) const {
+ return (this->index < other.index);
+ }
+
+ bool operator ==(const track_t& other) const {
+ return (this->index == other.index);
+ }
+ track_t (uint16_t idx = 0) : index (idx), playlist (0) {}
+ };
+
+ bool find_track(uint16_t index, track_t& tt) const {
+ std::vector<track_t>::const_iterator begin = _tracks.begin();
+ std::vector<track_t>::const_iterator finish = _tracks.end();
+ std::vector<track_t>::const_iterator found;
+
+ track_t t (index);
+
+ if ((found = std::find(begin, finish, t)) != finish) {
+ tt = *found;
+ return true;
+ }
+ return false;
+ }
+
+ bool find_region(uint16_t index, region_t& rr) const {
+ std::vector<region_t>::const_iterator begin = _regions.begin();
+ std::vector<region_t>::const_iterator finish = _regions.end();
+ std::vector<region_t>::const_iterator found;
+
+ region_t r;
+ r.index = index;
+
+ if ((found = std::find(begin, finish, r)) != finish) {
+ rr = *found;
+ return true;
+ }
+ return false;
+ }
+
+ bool find_miditrack(uint16_t index, track_t& tt) const {
+ std::vector<track_t>::const_iterator begin = _miditracks.begin();
+ std::vector<track_t>::const_iterator finish = _miditracks.end();
+ std::vector<track_t>::const_iterator found;
+
+ track_t t (index);
+
+ if ((found = std::find(begin, finish, t)) != finish) {
+ tt = *found;
+ return true;
+ }
+ return false;
+ }
+
+ bool find_midiregion(uint16_t index, region_t& rr) const {
+ std::vector<region_t>::const_iterator begin = _midiregions.begin();
+ std::vector<region_t>::const_iterator finish = _midiregions.end();
+ std::vector<region_t>::const_iterator found;
+
+ region_t r (index);
+
+ if ((found = std::find(begin, finish, r)) != finish) {
+ rr = *found;
+ return true;
+ }
+ return false;
+ }
+
+ bool find_wav(uint16_t index, wav_t& ww) const {
+ std::vector<wav_t>::const_iterator begin = _audiofiles.begin();
+ std::vector<wav_t>::const_iterator finish = _audiofiles.end();
+ std::vector<wav_t>::const_iterator found;
+
+ wav_t w (index);
+
+ if ((found = std::find(begin, finish, w)) != finish) {
+ ww = *found;
+ return true;
+ }
+ return false;
+ }
+
+ static bool regionexistsin(std::vector<region_t> const& reg, uint16_t index) {
+ std::vector<region_t>::const_iterator begin = reg.begin();
+ std::vector<region_t>::const_iterator finish = reg.end();
+
+ region_t r (index);
+
+ if (std::find(begin, finish, r) != finish) {
+ return true;
+ }
+ return false;
+ }
+
+ static bool wavexistsin (std::vector<wav_t> const& wv, uint16_t index) {
+ std::vector<wav_t>::const_iterator begin = wv.begin();
+ std::vector<wav_t>::const_iterator finish = wv.end();
+
+ wav_t w (index);
+
+ if (std::find(begin, finish, w) != finish) {
+ return true;
+ }
+ return false;
+ }
+
+ uint8_t version () const { return _version; }
+ int64_t sessionrate () const { return _sessionrate ; }
+ const std::string& path () { return _path; }
+
+ const std::vector<wav_t>& audiofiles () const { return _audiofiles ; }
+ const std::vector<region_t>& regions () const { return _regions ; }
+ const std::vector<region_t>& midiregions () const { return _midiregions ; }
+ const std::vector<track_t>& tracks () const { return _tracks ; }
+ const std::vector<track_t>& miditracks () const { return _miditracks ; }
+
+ const unsigned char* unxored_data () const { return _ptfunxored; }
+ uint64_t unxored_size () const { return _len; }
+
+private:
+
+ std::vector<wav_t> _audiofiles;
+ std::vector<region_t> _regions;
+ std::vector<region_t> _midiregions;
+ std::vector<track_t> _tracks;
+ std::vector<track_t> _miditracks;
+
+ std::string _path;
+
+ unsigned char* _ptfunxored;
+ uint64_t _len;
+ int64_t _sessionrate;
+ uint8_t _version;
+ uint8_t* _product;
+ int64_t _targetrate;
+ float _ratefactor;
+ bool is_bigendian;
+
+ struct block_t {
+ uint8_t zmark; // 'Z'
+ uint16_t block_type; // type of block
+ uint32_t block_size; // size of block
+ uint16_t content_type; // type of content
+ uint32_t offset; // offset in file
+ std::vector<block_t> child; // vector of child blocks
+ };
+ std::vector<block_t> blocks;
+
+ bool jumpback(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen);
+ bool jumpto(uint32_t *currpos, unsigned char *buf, const uint32_t maxoffset, const unsigned char *needle, const uint32_t needlelen);
+ bool foundin(std::string const& haystack, std::string const& needle);
+ int64_t foundat(unsigned char *haystack, uint64_t n, const char *needle);
+ uint16_t u_endian_read2(unsigned char *buf, bool);
+ uint32_t u_endian_read3(unsigned char *buf, bool);
+ uint32_t u_endian_read4(unsigned char *buf, bool);
+ uint64_t u_endian_read5(unsigned char *buf, bool);
+ uint64_t u_endian_read8(unsigned char *buf, bool);
+
+ char *parsestring(uint32_t pos);
+ const std::string get_content_description(uint16_t ctype);
+ int parse(void);
+ void parseblocks(void);
+ bool parseheader(void);
+ bool parserest(void);
+ bool parseaudio(void);
+ bool parsemidi(void);
+ void dump(void);
+ bool parse_block_at(uint32_t pos, struct block_t *b, struct block_t *parent, int level);
+ void dump_block(struct block_t& b, int level);
+ bool parse_version();
+ void parse_region_info(uint32_t j, block_t& blk, region_t& r);
+ void parse_three_point(uint32_t j, uint64_t& start, uint64_t& offset, uint64_t& length);
+ uint8_t gen_xor_delta(uint8_t xor_value, uint8_t mul, bool negative);
+ void setrates(void);
+ void cleanup(void);
+ void free_block(struct block_t& b);
+ void free_all_blocks(void);
+};
+
+#endif
diff --git a/libs/ptformat/wscript b/libs/ptformat/wscript
index b638e92558..0b26ade2fb 100644
--- a/libs/ptformat/wscript
+++ b/libs/ptformat/wscript
@@ -30,10 +30,10 @@ def configure(conf):
def build(bld):
# Library
if bld.is_defined ('INTERNAL_SHARED_LIBS'):
- obj = bld.shlib (features = 'cxx cxxshlib', source = [ 'ptfformat.cc' ])
+ obj = bld.shlib (features = 'cxx cxxshlib', source = [ 'ptformat.cc' ])
obj.defines = [ 'LIBPTFORMAT_DLL_EXPORTS=1' ]
else:
- obj = bld.stdlib (source = [ 'ptfformat.cc' ])
+ obj = bld.stdlib (source = [ 'ptformat.cc' ])
obj.cxxflags = [ bld.env['compiler_flags_dict']['pic'] ]
obj.cflags = [ bld.env['compiler_flags_dict']['pic'] ]