summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2017-02-16 01:17:00 +1100
committerDamien Zammit <damien@zamaudio.com>2017-02-16 01:17:00 +1100
commit317b19b0657fd9bc3bb0157dd504e1d7d27cde89 (patch)
tree4314d650389e5fa55f6684e2bf29b0b643574220
parent6e9bf3af79bec6cf605cd52ae243c2035b40de52 (diff)
Add preliminary MIDI support (1 track only)
Signed-off-by: Damien Zammit <damien@zamaudio.com>
-rw-r--r--ptfformat.cc125
-rw-r--r--ptfformat.h12
-rw-r--r--ptftool.cc103
3 files changed, 184 insertions, 56 deletions
diff --git a/ptfformat.cc b/ptfformat.cc
index ac3a02f..9e6e505 100644
--- a/ptfformat.cc
+++ b/ptfformat.cc
@@ -248,6 +248,7 @@ PTFFormat::parse(void) {
return -1;
parseaudio5();
parserest5();
+ parsemidi();
} else if (version == 7) {
parse7header();
setrates();
@@ -255,6 +256,7 @@ PTFFormat::parse(void) {
return -1;
parseaudio();
parserest89();
+ parsemidi();
} else if (version == 8) {
parse8header();
setrates();
@@ -262,6 +264,7 @@ PTFFormat::parse(void) {
return -1;
parseaudio();
parserest89();
+ parsemidi();
} else if (version == 9) {
parse9header();
setrates();
@@ -269,6 +272,7 @@ PTFFormat::parse(void) {
return -1;
parseaudio();
parserest89();
+ parsemidi();
} else if (version == 10 || version == 11 || version == 12) {
parse10header();
setrates();
@@ -276,6 +280,7 @@ PTFFormat::parse(void) {
return -1;
parseaudio();
parserest10();
+ parsemidi();
} else {
// Should not occur
return -1;
@@ -530,6 +535,7 @@ PTFFormat::parserest5(void) {
vector<wav_t>::iterator found;
// Add file to lists
if ((found = std::find(begin, finish, f)) != finish) {
+ std::vector<midi_ev_t> m;
region_t r = {
name,
rindex,
@@ -537,6 +543,7 @@ PTFFormat::parserest5(void) {
(int64_t)(sampleoffset*ratefactor),
(int64_t)(length*ratefactor),
*found,
+ m
};
regions.push_back(r);
vector<track_t>::iterator ti;
@@ -556,6 +563,7 @@ PTFFormat::parserest5(void) {
};
tracks.push_back(t);
} else {
+ std::vector<midi_ev_t> m;
region_t r = {
name,
rindex,
@@ -563,6 +571,7 @@ PTFFormat::parserest5(void) {
(int64_t)(sampleoffset*ratefactor),
(int64_t)(length*ratefactor),
f,
+ m,
};
regions.push_back(r);
vector<track_t>::iterator ti;
@@ -689,6 +698,106 @@ PTFFormat::parseaudio5(void) {
resort(audiofiles);
}
+bool
+PTFFormat::parsemidi(void) {
+ uint64_t i, k, n_midi_events, sample_time_zero;
+ uint64_t midi_pos, midi_len, max_pos = 0, min_pos = 0xffffffffffffffff;
+ uint8_t midi_velocity, midi_note;
+ uint16_t rsize;
+ std::vector<midi_ev_t> midi;
+ midi_ev_t m;
+ bool found = false;
+
+ // Find MdNLB
+ k = 0;
+ while (k < len) {
+ if ( (ptfunxored[k ] == 'M') &&
+ (ptfunxored[k+1] == 'd') &&
+ (ptfunxored[k+2] == 'N') &&
+ (ptfunxored[k+3] == 'L') &&
+ (ptfunxored[k+4] == 'B')) {
+ found = true;
+ break;
+ }
+ k++;
+ }
+
+ if (!found) {
+ return false;
+ }
+
+ k += 11;
+ n_midi_events = ptfunxored[k] | ptfunxored[k+1] << 8 |
+ ptfunxored[k+2] << 16 | ptfunxored[k+3] << 24;
+
+ k += 4;
+ sample_time_zero = 0xe8d4a51000;
+ for (i = 0; i < n_midi_events; i++, k += 35) {
+ midi_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;
+ midi_pos -= sample_time_zero;
+ midi_pos /= 40;
+ midi_note = ptfunxored[k+8];
+ midi_len = (uint64_t)ptfunxored[k+9] |
+ (uint64_t)ptfunxored[k+10] << 8 |
+ (uint64_t)ptfunxored[k+11] << 16 |
+ (uint64_t)ptfunxored[k+12] << 24 |
+ (uint64_t)ptfunxored[k+13] << 32;
+ midi_len /= 40;
+ midi_velocity = ptfunxored[k+17];
+
+ if (midi_pos + midi_len > max_pos) {
+ max_pos = midi_pos + midi_len;
+ }
+ if (midi_pos < min_pos) {
+ min_pos = midi_pos;
+ }
+
+ m.pos = midi_pos;
+ m.length = midi_len;
+ m.note = midi_note;
+ m.velocity = midi_velocity;
+ midi.push_back(m);
+
+ //fprintf(stderr, "MIDI: Note=%d Vel=%d Start=%d(samples) Len=%d(samples)\n", midi_note, midi_velocity, midi_pos, midi_len);
+ }
+
+ rsize = (uint16_t)regions.size();
+ wav_t w = { std::string(""), 0, 0, 0 };
+ region_t r = {
+ "MIDI",
+ rsize,
+ (int64_t)(min_pos*ratefactor),
+ (int64_t)(0),
+ (int64_t)(max_pos*ratefactor),
+ w,
+ midi,
+ };
+ regions.push_back(r);
+
+ uint16_t trmax = 0;
+ for (vector<track_t>::iterator
+ a = tracks.begin();
+ a != tracks.end(); ++a) {
+ if (a->index + 1 > trmax) {
+ trmax = a->index + 1;
+ }
+ }
+
+ track_t tr = {
+ "MIDI",
+ trmax,
+ 0,
+ r
+ };
+ tracks.push_back(tr);
+
+ return true;
+}
+
void
PTFFormat::parseaudio(void) {
uint64_t i,j,k,l;
@@ -900,13 +1009,15 @@ PTFFormat::parserest89(void) {
if ((found = std::find(begin, finish, f)) != finish) {
audiofiles.push_back(f);
// 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
+ f,
+ m
};
regions.push_back(r);
// Region only
@@ -914,13 +1025,15 @@ PTFFormat::parserest89(void) {
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
+ f,
+ m
};
regions.push_back(r);
}
@@ -1174,13 +1287,15 @@ PTFFormat::parserest10(void) {
if ((found = std::find(begin, finish, f)) != finish) {
audiofiles.push_back(f);
// 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
+ f,
+ m
};
regions.push_back(r);
// Region only
@@ -1188,13 +1303,15 @@ PTFFormat::parserest10(void) {
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
+ f,
+ m
};
regions.push_back(r);
}
diff --git a/ptfformat.h b/ptfformat.h
index e6c121d..17977c8 100644
--- a/ptfformat.h
+++ b/ptfformat.h
@@ -51,6 +51,13 @@ public:
};
+ 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;
@@ -58,6 +65,7 @@ public:
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);
@@ -85,7 +93,8 @@ public:
std::vector<region_t>::iterator found;
wav_t w = { std::string(""), 0, 0, 0 };
- region_t r = { std::string(""), index, 0, 0, 0, w };
+ 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;
@@ -133,6 +142,7 @@ private:
void parserest10(void);
void parseaudio5(void);
void parseaudio(void);
+ bool parsemidi(void);
void resort(std::vector<wav_t>& ws);
std::vector<wav_t> actualwavs;
float ratefactor;
diff --git a/ptftool.cc b/ptftool.cc
index 92107c3..735e82e 100644
--- a/ptftool.cc
+++ b/ptftool.cc
@@ -38,29 +38,35 @@ int main (int argc, char **argv) {
break;
case 0:
printf("ProTools %d Session: Samplerate = %ldHz\nTarget samplerate = 48000\n\n", ptf.version, ptf.sessionrate);
- if (ptf.audiofiles.size() > 0) {
- printf("%lu wavs, %lu regions, %lu active regions\n\n",
- ptf.audiofiles.size(),
- ptf.regions.size(),
- ptf.tracks.size()
- );
- printf("Audio file (WAV#) @ offset, length:\n");
- for (vector<PTFFormat::wav_t>::iterator
- a = ptf.audiofiles.begin();
- a != ptf.audiofiles.end(); ++a) {
- //printf("%s @ %lu, %lu\n", a->filename.c_str(),
- printf("`%s` w(%d) @ %lu, %lu\n",
- a->filename.c_str(),
- a->index,
- a->posabsolute,
- a->length);
- }
-
- printf("\nRegion (Region#) (WAV#) @ into-sample, length:\n");
- for (vector<PTFFormat::region_t>::iterator
- a = ptf.regions.begin();
- a != ptf.regions.end(); ++a) {
- //printf("%s (%s) @ %lu + %lu, %lu\n", a->name.c_str(),
+ printf("%lu wavs, %lu regions, %lu active regions\n\n",
+ ptf.audiofiles.size(),
+ ptf.regions.size(),
+ ptf.tracks.size()
+ );
+ printf("Audio file (WAV#) @ offset, length:\n");
+ for (vector<PTFFormat::wav_t>::iterator
+ a = ptf.audiofiles.begin();
+ a != ptf.audiofiles.end(); ++a) {
+ printf("`%s` w(%d) @ %lu, %lu\n",
+ a->filename.c_str(),
+ a->index,
+ a->posabsolute,
+ a->length);
+ }
+
+ printf("\nRegion (Region#) (WAV#) @ into-sample, length:\n");
+ for (vector<PTFFormat::region_t>::iterator
+ a = ptf.regions.begin();
+ a != ptf.regions.end(); ++a) {
+ if (!strcmp(a->name.c_str(), "MIDI")) {
+ for (vector<PTFFormat::midi_ev_t>::iterator
+ b = a->midi.begin();
+ b != a->midi.end(); ++b) {
+ printf(" MIDI: n(%d) v(%d) @ %lu, %lu\n",
+ b->note, b->velocity,
+ b->pos, b->length);
+ }
+ } else {
printf("`%s` r(%d) w(%d) @ %lu, %lu\n",
a->name.c_str(),
a->index,
@@ -68,36 +74,31 @@ int main (int argc, char **argv) {
a->sampleoffset,
a->length);
}
+ }
- printf("\nTrack name (Track#) (Region#) @ Absolute:\n");
- for (vector<PTFFormat::track_t>::iterator
- a = ptf.tracks.begin();
- a != ptf.tracks.end(); ++a) {
- //printf("%s (%s) @ %lu + %lu, %lu\n", a->name.c_str(),
- printf("`%s` t(%d) r(%d) @ %lu\n",
- a->name.c_str(),
- a->index,
- a->reg.index,
- a->reg.startpos);
- }
-
- printf("\nTrack name (Track#) (WAV filename) @ Absolute + Into-sample, Length:\n");
- for (vector<PTFFormat::track_t>::iterator
- a = ptf.tracks.begin();
- a != ptf.tracks.end(); ++a) {
- //printf("%s (%s) @ %lu + %lu, %lu\n", a->name.c_str(),
- printf("`%s` t(%d) (%s) @ %lu + %lu, %lu\n",
- a->name.c_str(),
- a->index,
- a->reg.wave.filename.c_str(),
- a->reg.startpos,
- a->reg.sampleoffset,
- a->reg.length
- );
- }
+ printf("\nTrack name (Track#) (Region#) @ Absolute:\n");
+ for (vector<PTFFormat::track_t>::iterator
+ a = ptf.tracks.begin();
+ a != ptf.tracks.end(); ++a) {
+ printf("`%s` t(%d) r(%d) @ %lu\n",
+ a->name.c_str(),
+ a->index,
+ a->reg.index,
+ a->reg.startpos);
+ }
- } else {
- printf("No audio files in session, quit\n");
+ printf("\nTrack name (Track#) (WAV filename) @ Absolute + Into-sample, Length:\n");
+ for (vector<PTFFormat::track_t>::iterator
+ a = ptf.tracks.begin();
+ a != ptf.tracks.end(); ++a) {
+ printf("`%s` t(%d) (%s) @ %lu + %lu, %lu\n",
+ a->name.c_str(),
+ a->index,
+ a->reg.wave.filename.c_str(),
+ a->reg.startpos,
+ a->reg.sampleoffset,
+ a->reg.length
+ );
}
break;
}