allow zero-input (i.e. tone generator) processors to be added
[ardour2.git] / tools / omf / omftool.cc
blob55386a1e488c09b8032804cd690a1d8c475eacae
1 /* Rewritten for Ardour by Paul Davis <paul@linuxaudiosystems.com>, Feb 2010
2 but based on ...
3 */
5 /* REAPER OMF plug-in
6 Copyright (C) 2009 Hannes Breul
8 Provides OMF import.
10 Based on the m3u example included in the Reaper SDK,
11 Copyright (C) 2005-2008 Cockos Incorporated
13 Original source available at:
14 http://www.reaper.fm/sdk/plugin/plugin.php#ext_dl
16 This software is provided 'as-is', without any express or implied
17 warranty. In no event will the authors be held liable for any damages
18 arising from the use of this software.
20 Permission is granted to anyone to use this software for any purpose,
21 including commercial applications, and to alter it and redistribute it
22 freely, subject to the following restrictions:
24 1. The origin of this software must not be misrepresented; you must not
25 claim that you wrote the original software. If you use this software
26 in a product, an acknowledgment in the product documentation would be
27 appreciated but is not required.
28 2. Altered source versions must be plainly marked as such, and must not be
29 misrepresented as being the original software.
30 3. This notice may not be removed or altered from any source distribution.
33 #ifndef __STDC_FORMAT_MACROS
34 #define __STDC_FORMAT_MACROS /* PRI<foo>; C++ requires explicit requesting of these */
35 #endif
37 #include <iostream>
39 #include <getopt.h>
40 #include <stdio.h>
41 #include <math.h>
42 #include <stdlib.h>
43 #include <stdarg.h>
44 #include <string.h>
45 #include <time.h>
46 #include <inttypes.h>
47 #include <sys/errno.h>
48 #include <sndfile.h>
49 #include <glibmm.h>
51 #include "pbd/xml++.h"
52 #include "pbd/basename.h"
53 #include "omftool.h"
55 //#define DEBUG(fmt,...) fprintf (stderr, fmt, ## __VA_ARGS__)
56 #define DEBUG(fmt,...)
57 #define INFO(fmt,...) fprintf (stdout, fmt, ## __VA_ARGS__)
59 using namespace std;
60 using namespace PBD;
62 OMF::OMF ()
64 char sbuf[256];
66 bigEndian = false;
67 id_counter = 0;
68 session_name = "omfsession";
69 base_dir = ".";
70 sample_rate = 0;
71 frame_rate = 0;
72 version = 3000;
73 db = 0;
74 file = 0;
76 session = new XMLNode ("Session");
77 sources = new XMLNode ("Sources");
78 routes = new XMLNode ("Routes");
79 regions = new XMLNode ("Regions");
80 playlists = new XMLNode ("Playlists");
81 diskstreams = new XMLNode ("DiskStreams");
82 locations = new XMLNode ("Locations");
83 options = new XMLNode ("Options");
84 options = new XMLNode ("RouteGroups");
86 /* add master, default 2in/2out */
88 XMLNode* master = new_route_node ();
89 master->add_property ("name", "master");
90 set_route_node_channels (master, 2, 2, false);
92 XMLNode* tempo_map = new XMLNode ("TempoMap");
93 XMLNode* tempo = new XMLNode ("Tempo");
94 tempo->add_property ("start", "1|1|0");
95 tempo->add_property ("beats-per-minute", "120.0");
96 tempo->add_property ("note-type", "4.0");
97 tempo->add_property ("movable", "no");
98 tempo_map->add_child_nocopy (*tempo);
99 XMLNode* meter = new XMLNode ("Meter");
100 meter->add_property ("start", "1|1|0");
101 meter->add_property ("beats-per-bar", "4.0");
102 meter->add_property ("note-type", "4.0");
103 meter->add_property ("movable", "no");
104 tempo_map->add_child_nocopy (*meter);
106 XMLNode* click = new XMLNode ("Click");
107 XMLNode* io = new XMLNode ("IO");
108 click->add_child_nocopy (*io);
109 io->add_property ("name", "click");
110 add_id (io);
111 io->add_property ("direction", "Output");
112 io->add_property ("default-type", "audio");
113 XMLNode* port = new XMLNode ("Port");
114 io->add_child_nocopy (*port);
115 port->add_property ("type", "audio");
116 port->add_property ("name", "click/audio_out 1");
117 XMLNode* connection = new XMLNode ("Connection");
118 connection->add_property ("other", "system:playback_1");
119 port->add_child_nocopy (*connection);
121 port = new XMLNode ("Port");
122 io->add_child_nocopy (*port);
123 port->add_property ("type", "audio");
124 port->add_property ("name", "click/audio_out 2");
125 connection = new XMLNode ("Connection");
126 connection->add_property ("other", "system:playback_2");
127 port->add_child_nocopy (*connection);
129 session->add_child_nocopy (*options);
130 session->add_child_nocopy (*sources);
131 session->add_child_nocopy (*regions);
132 session->add_child_nocopy (*playlists);
133 session->add_child_nocopy (*diskstreams);
134 session->add_child_nocopy (*routes);
135 session->add_child_nocopy (*locations);
136 session->add_child_nocopy (*tempo_map);
137 session->add_child_nocopy (*click);
140 OMF::~OMF ()
142 /* clean up */
143 sqlite3_close (db);
144 fclose (file);
147 void
148 OMF::set_sample_rate (int sr)
150 sample_rate = sr;
153 void
154 OMF::set_session_name (const std::string& str)
156 base_dir = Glib::path_get_dirname (str); // returns "." if no dirs were given
157 session_name = Glib::path_get_basename (str);
160 void
161 OMF::set_version (int v)
163 version = v;
167 OMF::init ()
169 /* create directory tree */
171 string dir;
173 audiofile_path_vector.push_back (base_dir);
174 audiofile_path_vector.push_back (session_name);
175 audiofile_path_vector.push_back ("interchange");
176 audiofile_path_vector.push_back (session_name);
177 audiofile_path_vector.push_back ("audiofiles");
179 dir = Glib::build_filename (audiofile_path_vector);
180 g_mkdir_with_parents (dir.c_str(), 0775);
182 /* and the rest */
185 vector<string> v;
186 v.push_back (base_dir);
187 v.push_back (session_name);
189 vector<string> d;
190 d.push_back ("analysis");
191 d.push_back ("dead_sounds");
192 d.push_back ("export");
193 d.push_back ("peaks");
195 for (vector<string>::iterator i = d.begin(); i != d.end(); ++i) {
196 v.push_back (*i);
197 dir = Glib::build_filename (v);
198 g_mkdir_with_parents (dir.c_str(), 0775);
199 v.pop_back ();
202 return 0;
205 bool
206 OMF::get_audio_info (const std::string& path)
208 SNDFILE *sf;
209 SF_INFO sf_info;
211 sf_info.format = 0; // libsndfile says to clear this before sf_open().
213 if ((sf = sf_open ((char*) path.c_str(), SFM_READ, &sf_info)) == 0) {
214 char errbuf[256];
215 cerr << "Cannot open source file " << path << sf_error_str (0, errbuf, sizeof (errbuf) - 1) << endl;
216 return false;
219 if (known_sources.find (Glib::path_get_basename (path)) != known_sources.end()) {
220 /* already exists */
221 return true;
224 XMLNode* source = new_source_node();
226 known_sources.insert (pair<string,SourceInfo*>
227 (Glib::path_get_basename (path),
228 new SourceInfo (sf_info.channels,
229 sf_info.samplerate,
230 sf_info.frames,
231 source)));
233 source->add_property ("name", basename_nosuffix (path));
234 cerr << "Source file " << basename_nosuffix (path) << " = " << sf_info.channels << '/' << sf_info.samplerate << '/' << sf_info.frames << endl;
235 sf_close (sf);
236 return true;
239 void
240 OMF::add_id (XMLNode* node)
242 char sbuf[64];
243 id_counter++;
244 snprintf (sbuf, sizeof (sbuf), "%" PRId64, id_counter);
245 node->add_property ("id", sbuf);
248 XMLNode*
249 OMF::new_playlist_node ()
251 XMLNode* playlist = new XMLNode ("Playlist");
252 playlists->add_child_nocopy (*playlist);
253 add_id (playlist);
254 playlist->add_property ("type", "audio");
255 playlist->add_property ("frozen", "no");
257 return playlist;
260 XMLNode*
261 OMF::new_diskstream_node ()
263 XMLNode* diskstream = new XMLNode ("AudioDiskstream");
264 diskstreams->add_child_nocopy (*diskstream);
265 add_id (diskstream);
266 diskstream->add_property ("flags", "Recordable");
267 diskstream->add_property ("speed", "1");
268 diskstream->add_property ("channels", "1");
270 return diskstream;
272 void
273 OMF::set_region_sources (XMLNode* region, SourceInfo* sinfo)
275 char buf[256];
277 region->add_property ("name", sinfo->node->property ("name")->value());
279 for (int i = 0; i < sinfo->channels; ++i) {
280 snprintf (buf, sizeof (buf), "source-%d", i);
281 region->add_property (buf, sinfo->node->property ("id")->value());
285 void
286 OMF::legalize_name (string& name)
288 string::size_type pos;
289 string illegal_chars = ":";
290 pos = 0;
292 while ((pos = name.find_first_of (illegal_chars, pos)) != string::npos) {
293 name.replace (pos, 1, "_");
294 pos += 1;
298 void
299 OMF::set_route_node_channels (XMLNode* route, int in, int out, bool send_to_master)
301 XMLNode* input_io;
302 XMLNode* output_io;
303 char sbuf[256];
304 string name = route->property ("name")->value();
306 legalize_name (name);
308 output_io = new XMLNode ("IO");
309 route->add_child_nocopy (*output_io);
310 output_io->add_property ("name", name);
311 add_id (output_io);
312 output_io->add_property ("direction", "Output");
313 output_io->add_property ("default-type", "audio");
315 input_io = new XMLNode ("IO");
316 route->add_child_nocopy (*input_io);
317 input_io->add_property ("name", name);
318 add_id (input_io);
319 input_io->add_property ("direction", "Input");
320 input_io->add_property ("default-type", "audio");
322 for (int i = 0; i < out; ++i) {
323 XMLNode* port = new XMLNode ("Port");
324 output_io->add_child_nocopy (*port);
325 port->add_property ("type", "audio");
327 snprintf (sbuf, sizeof (sbuf), "%s/audio_out %d", name.c_str(), i+1);
329 port->add_property ("name", sbuf);
330 XMLNode* connection = new XMLNode ("Connection");
332 if (send_to_master) {
333 if (i % 2) {
334 snprintf (sbuf, sizeof (sbuf), "master/audio_in 2");
335 } else {
336 snprintf (sbuf, sizeof (sbuf), "master/audio_in 1");
338 } else {
339 if (i % 2) {
340 snprintf (sbuf, sizeof (sbuf), "system:playback_2");
341 } else {
342 snprintf (sbuf, sizeof (sbuf), "system:playback_1");
346 connection->add_property ("other", sbuf);
347 port->add_child_nocopy (*connection);
350 for (int i = 0; i < in; ++i) {
351 XMLNode* port = new XMLNode ("Port");
352 input_io->add_child_nocopy (*port);
353 port->add_property ("type", "audio");
355 snprintf (sbuf, sizeof (sbuf), "%s/audio_out %d", name.c_str(), i+1);
357 port->add_property ("name", sbuf);
358 XMLNode* connection = new XMLNode ("Connection");
360 if (i % 2) {
361 snprintf (sbuf, sizeof (sbuf), "system:capture_2");
362 } else {
363 snprintf (sbuf, sizeof (sbuf), "system:capture_1");
366 connection->add_property ("other", sbuf);
367 port->add_child_nocopy (*connection);
370 /* add main out processor */
372 XMLNode* outs = new XMLNode ("Processor");
373 route->add_child_nocopy (*outs);
374 add_id (outs);
375 outs->add_property ("name", name);
376 outs->add_property ("active", "yes");
377 outs->add_property ("own-input", "yes");
378 outs->add_property ("own-output", send_to_master ? "no" : "yes");
379 outs->add_property ("output", name);
380 outs->add_property ("type", "main-outs");
381 outs->add_property ("role", "Main");
383 /* Panner setup */
385 XMLNode* panner = new XMLNode ("Panner");
386 outs->add_child_nocopy (*panner);
388 panner->add_property ("linked", "no");
389 panner->add_property ("link-direction", "SameDirection");
390 panner->add_property ("bypassed", "no");
392 for (int i = 0; i < out; ++i) {
393 XMLNode* panout = new XMLNode ("Output");
394 panner->add_child_nocopy (*panout);
395 panout->add_property ("x", "0");
396 panout->add_property ("y", "0");
399 for (int i = 0; i < in; ++i) {
400 XMLNode* spanner = new XMLNode ("StreamPanner");
401 panner->add_child_nocopy (*spanner);
402 spanner->add_property ("x", "0");
403 spanner->add_property ("type", "Equal Power Stereo");
404 spanner->add_property ("muted", "no");
405 spanner->add_property ("mono", "no");
407 XMLNode* spc = new XMLNode ("Controllable");
408 spanner->add_child_nocopy (*spc);
409 add_id (spc);
410 spc->add_property ("name", "panner");
411 spc->add_property ("flags", "");
415 XMLNode*
416 OMF::new_route_node ()
418 char sbuf[256];
419 XMLNode* route = new XMLNode ("Route");
421 routes->add_child_nocopy (*route);
422 add_id (route);
423 route->add_property ("default-type","audio");
424 route->add_property ("active","yes");
425 route->add_property ("phase-invert","no");
426 route->add_property ("denormal-protection","no");
427 route->add_property ("meter-point","MeterPostFader");
428 snprintf (sbuf, sizeof (sbuf), "editor=%" PRId64 ":signal=%" PRId64, id_counter, id_counter);
429 route->add_property ("order-keys", sbuf);
430 route->add_property ("self-solo","no");
431 route->add_property ("soloed-by-others","0");
432 route->add_property ("mode","Normal");
434 /* other boilerplate */
436 XMLNode* controllable = new XMLNode ("Controllable");
437 route->add_child_nocopy (*controllable);
438 controllable->add_property ("name", "solo");
439 add_id (controllable);
440 controllable->add_property ("flags", "Toggle");
442 XMLNode* mutemaster = new XMLNode ("MuteMaster");
443 route->add_child_nocopy (*mutemaster);
444 mutemaster->add_property ("mute-point", "");
446 XMLNode* remotecontrol = new XMLNode ("RemoteControl");
447 route->add_child_nocopy (*remotecontrol);
448 remotecontrol->add_property ("id", route->property ("id")->value());
450 XMLNode* amp = new XMLNode ("Processor");
451 route->add_child_nocopy (*amp);
452 add_id (amp);
453 amp->add_property ("name", "Amp");
454 amp->add_property ("active", "yes");
455 amp->add_property ("type", "amp");
456 amp->add_property ("gain", "1.0");
458 XMLNode* meter = new XMLNode ("Processor");
459 route->add_child_nocopy (*meter);
460 add_id (meter);
461 meter->add_property ("name", "Meter");
462 meter->add_property ("active", "yes");
463 meter->add_property ("type", "meter");
465 XMLNode* extra = new XMLNode ("Extra");
466 route->add_child_nocopy (*extra);
467 XMLNode* gui = new XMLNode ("GUI");
468 extra->add_child_nocopy (*gui);
469 snprintf (sbuf, sizeof (sbuf), "%d:%d:%d",
470 random() % 65536,
471 random() % 65536,
472 random() % 65536);
473 gui->add_property ("color", sbuf);
474 gui->add_property ("shown-mixer", "yes");
475 gui->add_property ("height", "62");
476 gui->add_property ("shown-editor", "yes");
478 return route;
481 XMLNode*
482 OMF::new_region_node ()
484 XMLNode* region = new XMLNode ("Region");
485 XMLNode* region_extra = new XMLNode ("Extra");
486 XMLNode* gui_extra = new XMLNode ("GUI");
487 char sbuf[256];
489 region_extra->add_child_nocopy (*gui_extra);
490 region->add_child_nocopy (*region_extra);
492 /* boilerplate */
494 region->add_property ("ancestral-start", "0");
495 region->add_property ("ancestral-start", "0");
496 region->add_property ("ancestral-length", "0");
497 region->add_property ("stretch", "1");
498 region->add_property ("shift", "1");
499 region->add_property ("first-edit", "nothing");
500 region->add_property ("layer", "0");
501 region->add_property ("sync-position", "0");
502 region->add_property ("flags", "Opaque,DefaultFadeIn,DefaultFadeOut,FadeIn,FadeOut,External");
503 region->add_property ("scale-gain", "1");
504 region->add_property ("channels", "1");
505 gui_extra->add_property ("waveform-visible","yes");
506 gui_extra->add_property ("envelope-visible", "no");
507 gui_extra->add_property ("waveform-rectified", "no");
508 gui_extra->add_property ("waveform-logscaled","no");
510 add_id (region);
511 return region;
514 XMLNode*
515 OMF::new_source_node ()
517 XMLNode* source;
519 source = new XMLNode ("Source");
520 add_id (source);
521 source->add_property ("type", "audio");
522 source->add_property ("flags", "CanRename");
524 sources->add_child_nocopy (*source);
526 return source;
529 OMF::SourceInfo*
530 OMF::get_known_source (const char* name)
532 string s (name);
533 KnownSources::iterator i = known_sources.find (s);
534 if (i != known_sources.end()) {
535 return i->second;
537 return 0;
540 char *
541 OMF::read_name (size_t offset, size_t len)
543 char* buf = (char*) malloc (len+1);
544 fseek (file, offset, SEEK_SET);
545 fread (buf, len, 1, file);
546 buf[len] = '\0';
547 return buf;
550 bool
551 OMF::get_offset_and_length (const char* offstr, const char* lenstr, uint32_t& offset, uint32_t& len)
553 if (sscanf (offstr, "%d", &offset) == 0) {
554 cerr << "bad offset\n";
555 return false;
558 if (sscanf (lenstr, "%d", &len) == 0) {
559 cerr << "bad length\n";
560 return false;
563 if (((int32_t) offset) <= 0) {
564 cerr << "illegal offset\n";
565 return false;
568 if (((int32_t) len) <= 0) {
569 cerr << "illegal length\n";
570 return false;
573 return true;
577 OMF::create_xml ()
579 XMLNode* region;
580 XMLNode* playlist;
581 XMLNode* diskstream;
582 SourceInfo* sinfo;
583 char sbuf[256];
584 int route_max_channels;
585 int major;
586 int minor;
587 int micro;
589 major = version / 1000;
590 minor = version - (major * 1000);
591 micro = version - (major * 1000) - (minor * 100);
593 snprintf (sbuf, sizeof (sbuf), "%d.%d.%d", major, minor, micro);
595 session->add_property ("version", sbuf);
596 session->add_property ("name", session_name);
598 char **tracks;
599 int numtracks;
600 sqlite3_get_table(db, "SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT object FROM data WHERE property = 'OMFI:OOBJ:ObjClass' AND value = 'CMOB' LIMIT 1) AND property = 'OMFI:MOBJ:Slots')", &tracks, &numtracks, 0, 0);
602 for (int i = 1; i <= numtracks; i++) {
604 int descCount;
605 char **desc;
607 sqlite3_get_table(db, sqlite3_mprintf("SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object = %s AND property = 'OMFI:MSLT:Segment' LIMIT 1) AND value = 'SEQU' LIMIT 1", tracks[i]), &desc, &descCount, 0, 0);
608 sqlite3_free_table(desc);
610 sinfo = 0;
611 route_max_channels = 0;
613 INFO ("Processing track %d / %d...\n", i, numtracks);
615 if (descCount <= 0) {
616 continue;
619 /* create a new route, which will mean that we need a new diskstream and playlist too
622 XMLNode* route = new_route_node ();
623 XMLNode* playlist = new_playlist_node ();
624 XMLNode* diskstream = new_diskstream_node ();
626 /* route and playlist both need diskstream ID */
628 route->add_property ("diskstream-id", diskstream->property ("id")->value());
629 playlist->add_property ("orig-diskstream-id", diskstream->property ("id")->value());
631 char **name;
632 int nameCount;
633 //sqlite3_get_table(db, sqlite3_mprintf("SELECT d2.offset, d2.length FROM data d1, data d2 WHERE d1.object LIKE '%s' AND d1.property LIKE 'OMFI:MSLT:TrackDesc' AND d2.object LIKE d1.value AND d2.property LIKE 'OMFI:TRKD:TrackName' LIMIT 1", tracks[i]), &name, &nameCount, 0, 0);
634 sqlite3_get_table(db, sqlite3_mprintf("SELECT offset, length FROM data WHERE object IN (SELECT value FROM data WHERE object = %s AND property = 'OMFI:MSLT:TrackDesc' LIMIT 1) AND property = 'OMFI:TRKD:TrackName' LIMIT 1", tracks[i]), &name, &nameCount, 0, 0);
635 if (nameCount > 0) {
636 uint32_t nOffs;
637 uint32_t nLen;
638 if (get_offset_and_length (name[2], name[3], nOffs, nLen)) {
639 char* nBuf = read_name (nOffs, nLen);
640 route->add_property ("name", nBuf);
641 playlist->add_property ("name", nBuf);
642 diskstream->add_property ("name", nBuf);
643 diskstream->add_property ("playlist", nBuf);
644 free (nBuf);
645 } else {
646 INFO ("Track %d has unreadable name\n", i);
647 snprintf (sbuf, sizeof (sbuf), "Track %d", i);
648 route->add_property ("name", sbuf);
649 playlist->add_property ("name", sbuf);
650 diskstream->add_property ("name", sbuf);
651 diskstream->add_property ("playlist", sbuf);
653 } else {
654 INFO ("Track %d has no name\n", i);
655 snprintf (sbuf, sizeof (sbuf), "Track %d", i);
656 route->add_property ("name", sbuf);
657 playlist->add_property ("name", sbuf);
658 diskstream->add_property ("name", sbuf);
659 diskstream->add_property ("playlist", sbuf);
661 sqlite3_free_table(name);
663 char **rate;
664 int rateCount;
665 int num = 1, denom = 1;
667 sqlite3_get_table(db, sqlite3_mprintf("SELECT offset FROM data WHERE object = %s AND property = 'OMFI:MSLT:EditRate' LIMIT 1", tracks[i]), &rate, &rateCount, 0, 0);
669 if (rateCount > 0) {
670 uint32_t rOffs = atoi(rate[1]);
671 //sscanf(rate[1], "%d", &rOffs);
672 fseek(file, rOffs, SEEK_SET);
673 fread(&denom, 4, 1, file);
674 denom = e32(denom);
675 fread(&num, 4, 1, file);
676 num = e32(num);
677 INFO ("Rate = %d / %d\n", num, denom);
678 if (frame_rate == 0) {
679 frame_rate = (double) num / (double) denom;
681 if (sample_rate == 0) {
682 sample_rate = denom;
684 } else {
685 INFO ("OMF file is missing frame rate information for track %d\n", i);
686 frame_rate = 0.04; // 25FPS
687 if (sample_rate == 0) {
688 sample_rate = 44100;
692 sqlite3_free_table(rate);
694 char **items;
695 int itemCount;
696 //sqlite3_get_table(db, sqlite3_mprintf("SELECT d3.value FROM data d1, data d2, data d3 WHERE d1.object LIKE '%s' AND d1.property LIKE 'OMFI:MSLT:Segment' AND d2.object LIKE d1.value AND d2.property LIKE 'OMFI:SEQU:Components' AND d3.object LIKE d2.value", tracks[i]), &items, &itemCount, 0, 0);
697 sqlite3_get_table(db, sqlite3_mprintf("SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object = %s AND property = 'OMFI:MSLT:Segment' LIMIT 1) AND property = 'OMFI:SEQU:Components' LIMIT 1)", tracks[i]), &items, &itemCount, 0, 0);
698 double position = 0.0;
699 int j;
700 double fadeTime = 0.0;
702 for (j = 1; j <= itemCount; j++) {
704 printf(" item %d / %d\n", j, itemCount);
706 char **len;
707 int lenCount;
708 double length = 0.0;
709 int lenFrames = 0;
711 region = 0;
713 sqlite3_get_table(db, sqlite3_mprintf("SELECT value FROM data WHERE object = %s AND property = 'OMFI:CPNT:Length' LIMIT 1", items[j]), &len, &lenCount, 0, 0);
715 if (lenCount <= 0) {
716 sqlite3_free_table(len);
717 continue;
720 char **type;
721 int typeCount;
723 sqlite3_get_table(db, sqlite3_mprintf("SELECT value FROM data WHERE object = %s AND property = 'OMFI:OOBJ:ObjClass' LIMIT 1", items[j]), &type, &typeCount, 0, 0);
725 if (typeCount <= 0) {
726 sqlite3_free_table(type);
727 sqlite3_free_table(len);
728 continue;
731 lenFrames = atoi(len[1]);
732 length = lenFrames * frame_rate;
734 if (!strcmp(type[1], "TRAN")) {
736 position -= length;
737 char **effID;
738 int effIDCount;
739 sqlite3_get_table(db, sqlite3_mprintf("SELECT offset, length FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object = %s AND property = 'OMFI:TRAN:Effect' LIMIT 1) AND property = 'OMFI:EFFE:EffectKind' LIMIT 1) AND property = 'OMFI:EDEF:EffectID' LIMIT 1", items[j]), &effID, &effIDCount, 0, 0);
740 if (effIDCount > 0) {
741 uint32_t eOffs;
742 uint32_t eLen;
743 if (get_offset_and_length (effID[2], effID[3], eOffs, eLen)) {
744 char* eBuf = read_name (eOffs, eLen);
745 if (!strcmp(eBuf, "omfi:effect:StereoAudioDissolve") | !strcmp(eBuf, "omfi:effect:SimpleMonoAudioDissolve")) {
746 fadeTime = length;
750 sqlite3_free_table(effID);
752 } else if (!strcmp(type[1], "FILL")) {
754 position += length;
756 } else if (!strcmp(type[1], "NEST")) {
758 char **itemName;
759 int itemNameCount;
760 int64_t start = 0;
762 sqlite3_get_table(db, sqlite3_mprintf("SELECT offset, length FROM data WHERE object IN (SELECT object FROM data WHERE value IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object = %s AND property = 'OMFI:NEST:Slots' LIMIT 1)) AND property = 'OMFI:SCLP:SourceID' LIMIT 1) AND property = 'OMFI:MOBJ:MobID' LIMIT 1) AND property = 'OMFI:MOBJ:Name' LIMIT 1", items[j]), &itemName, &itemNameCount, 0, 0);
764 char **startTime;
765 int startTimeCount;
766 //sqlite3_get_table(db, sqlite3_mprintf("SELECT d3.value FROM data d1, data d2, data d3 WHERE d1.object LIKE '%s' AND d1.property LIKE 'OMFI:NEST:SLOTS' AND d2.object LIKE d1.value AND d3.object LIKE d2.value AND d3.property LIKE 'OMFI:SCLP:StartTime' LIMIT 1", items[j]), &startTime, &startTimeCount, 0, 0);
767 sqlite3_get_table(db, sqlite3_mprintf("SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object = %s AND property = 'OMFI:NEST:Slots' LIMIT 1)) AND property = 'OMFI:SCLP:StartTime' LIMIT 1", items[j]), &startTime, &startTimeCount, 0, 0);
768 if (startTimeCount > 0) {
769 start = atoi(startTime[1]);
772 sqlite3_free_table(startTime);
774 char **itemEffect;
775 int itemEffectCount;
776 //sqlite3_get_table(db, sqlite3_mprintf("select d7.offset from data d1, data d2, data d3, data d4, data d5, data d6, data d7 where d1.object like '%s' and d1.property like 'OMFI:NEST:Slots' and d2.object like d1.value and d3.object like d2.value and d3.property like 'OMFI:EFFE:EffectSlots' and d4.object like d3.value and d5.object like d4.value and d5.property like 'OMFI:ESLT:ArgValue' and d6.object like d4.value and d6.property like 'OMFI:ESLT:ArgID' and d6.value like '1' and d7.object like d5.value and d7.property like 'OMFI:CVAL:Value' LIMIT 2", items[j]), &itemEffect, &itemEffectCount, 0, 0);
777 sqlite3_get_table(db, sqlite3_mprintf("SELECT offset FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object = %s AND property = 'OMFI:NEST:Slots' LIMIT 1)) AND property = 'OMFI:EFFE:EffectSlots' LIMIT 1) LIMIT 2) AND property = 'OMFI:ESLT:ArgValue' LIMIT 2) AND property like 'OMFI:CVAL:Value' LIMIT 1", items[j]), &itemEffect, &itemEffectCount, 0, 0);
778 if (itemEffectCount > 0) {
779 int effNum = 1;
780 int effDenom = 1;
781 uint32_t effOffs = atoi(itemEffect[1]);
782 //sscanf(itemEffect[1], "%d", &effOffs);
783 fseek(file, effOffs, SEEK_SET);
784 fread(&effDenom, 4, 1, file);
785 fread(&effNum, 4, 1, file);
786 double vol = (double) effNum / (double) effDenom;
787 //ctx->AddLine("VOLPAN %.8f 0.000000 1.000000 -1.000000", vol);
788 DEBUG("VOLPAN %.8f 0.000000 1.000000 -1.000000\n", vol);
790 sqlite3_free_table(itemEffect);
792 char **sourceFile;
793 int sourceFileCount;
794 //sqlite3_get_table(db, sqlite3_mprintf("SELECT d10.offset, d10.length FROM data d1, data d2, data d3, data d4, data d5, data d6, data d7, data d8, data d9, data d10 WHERE d1.object LIKE '%s' AND d1.property LIKE 'OMFI:NEST:Slots' AND d2.object LIKE d1.value AND d3.object LIKE d2.value AND d3.property LIKE 'OMFI:SCLP:SourceID' AND d4.value LIKE d3.value AND d4.property LIKE 'OMFI:MOBJ:MobID' AND d5.object LIKE d4.object AND d5.property LIKE 'OMFI:MOBJ:Slots' AND d6.object LIKE d5.value AND d7.object LIKE d6.value AND d7.property LIKE 'OMFI:MSLT:Segment' AND d8.object LIKE d7.value AND d8.property LIKE 'OMFI:SCLP:SourceID' AND d9.value LIKE d8.value AND d9.property LIKE 'OMFI:MOBJ:MobID' AND d10.object LIKE d9.object AND d10.property LIKE 'OMFI:MOBJ:Name' LIMIT 1", items[j]), &sourceFile, &sourceFileCount, 0, 0);
795 sqlite3_get_table(db, sqlite3_mprintf("SELECT offset, length FROM data WHERE object IN (SELECT object FROM data WHERE value IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT object FROM data WHERE value IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object = %s AND property = 'OMFI:NEST:Slots' LIMIT 1) LIMIT 3) AND property = 'OMFI:SCLP:SourceID' LIMIT 1) AND property = 'OMFI:MOBJ:MobID' LIMIT 1) AND property = 'OMFI:MOBJ:Slots' LIMIT 1) LIMIT 1) AND property = 'OMFI:MSLT:Segment' LIMIT 1) AND property = 'OMFI:SCLP:SourceID' LIMIT 1) AND property = 'OMFI:MOBJ:MobID' LIMIT 1) AND property LIKE 'OMFI:MOBJ:Name' LIMIT 1", items[j]), &sourceFile, &sourceFileCount, 0, 0);
796 if (sourceFileCount > 0) {
797 uint32_t sfOffs;
798 uint32_t sfLen;
800 if (get_offset_and_length (sourceFile[2], sourceFile[3], sfOffs, sfLen)) {
801 char *sfBuf = read_name (sfOffs, sfLen);
803 if ((sinfo = get_known_source (sfBuf)) == 0) {
804 cerr << "Reference to unknown source [" << sfBuf << "]1" << endl;
805 return -1;
808 free (sfBuf);
809 } else {
810 cerr << "offs/len illegal\n";
812 } else {
813 char **fallbackFile;
814 int fallbackFileCount;
815 //sqlite3_get_table(db, sqlite3_mprintf("SELECT d9.object FROM data d1, data d2, data d3, data d4, data d5, data d6, data d7, data d8, data d9 WHERE d1.object LIKE '%s' AND d1.property LIKE 'OMFI:NEST:Slots' AND d2.object LIKE d1.value AND d3.object LIKE d2.value AND d3.property LIKE 'OMFI:SCLP:SourceID' AND d4.value LIKE d3.value AND d4.property LIKE 'OMFI:MOBJ:MobID' AND d5.object LIKE d4.object AND d5.property LIKE 'OMFI:MOBJ:Slots' AND d6.object LIKE d5.value AND d7.object LIKE d6.value AND d7.property LIKE 'OMFI:MSLT:Segment' AND d8.object LIKE d7.value AND d8.property LIKE 'OMFI:SCLP:SourceID' AND d9.value LIKE d8.value AND d9.property LIKE 'OMFI:MDAT:MobID' LIMIT 1", items[j]), &fallbackFile, &fallbackFileCount, 0, 0);
816 sqlite3_get_table(db, sqlite3_mprintf("SELECT object FROM data WHERE value IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT object FROM data WHERE value IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object = %s AND property = 'OMFI:NEST:Slots' LIMIT 1) LIMIT 3) AND property = 'OMFI:SCLP:SourceID' LIMIT 1) AND property = 'OMFI:MOBJ:MobID' LIMIT 1) AND property = 'OMFI:MOBJ:Slots' LIMIT 1) LIMIT 1) AND property = 'OMFI:MSLT:Segment' LIMIT 1) AND property = 'OMFI:SCLP:SourceID' LIMIT 1) AND property = 'OMFI:MDAT:MobID' LIMIT 1", items[j]), &fallbackFile, &fallbackFileCount, 0, 0);
817 if (fallbackFileCount > 0) {
818 if ((sinfo = get_known_source (fallbackFile[1])) == 0) {
819 cerr << "Reference to unknown source [" << fallbackFile[1] << "]2" << endl;
820 return -1;
823 } else {
824 cerr << "no fallback file\n";
827 sqlite3_free_table(fallbackFile);
831 if (sinfo) {
833 region = new_region_node ();
834 playlist->add_child_nocopy (*region);
836 snprintf (sbuf, sizeof (sbuf), "%" PRId64, llrintf (position * sample_rate));
837 region->add_property ("position", sbuf);
838 snprintf (sbuf, sizeof (sbuf), "%" PRId64, llrintf (length * sample_rate));
839 region->add_property ("length", sbuf);
840 snprintf (sbuf, sizeof (sbuf), "%" PRId64, llrintf (start * frame_rate * sample_rate));
841 region->add_property ("start", sbuf);
842 set_region_sources (region, sinfo);
844 route_max_channels = max (route_max_channels, sinfo->channels);
847 sqlite3_free_table(sourceFile);
848 sqlite3_free_table(itemName);
849 position += length;
851 } else if (!strcmp(type[1], "SCLP")) {
853 char **itemName;
854 int itemNameCount;
855 int64_t start = 0;
856 //sqlite3_get_table(db, sqlite3_mprintf("SELECT d5.offset, d5.length FROM data d3, data d4, data d5 WHERE d3.object LIKE '%s' AND d3.property LIKE 'OMFI:SCLP:SourceID' AND d4.value LIKE d3.value AND d5.object LIKE d4.object AND d5.property LIKE 'OMFI:MOBJ:Name' LIMIT 1", items[j]), &itemName, &itemNameCount, 0, 0);
857 sqlite3_get_table(db, sqlite3_mprintf("SELECT offset, length FROM data WHERE object IN (SELECT object FROM data WHERE value IN (SELECT value FROM data WHERE object = %s AND property = 'OMFI:SCLP:SourceID' LIMIT 1) AND property = 'OMFI:MOBJ:MobID' LIMIT 1) AND property = 'OMFI:MOBJ:Name' LIMIT 1", items[j]), &itemName, &itemNameCount, 0, 0);
859 fadeTime = 0.0;
861 char **startTime;
862 int startTimeCount;
863 //sqlite3_get_table(db, sqlite3_mprintf("SELECT d3.value FROM data d3 WHERE d3.object LIKE '%s' AND d3.property LIKE 'OMFI:SCLP:StartTime'", items[j]), &startTime, &startTimeCount, 0, 0);
864 sqlite3_get_table(db, sqlite3_mprintf("SELECT value FROM data WHERE object = %s AND property = 'OMFI:SCLP:StartTime' LIMIT 1", items[j]), &startTime, &startTimeCount, 0, 0);
865 if (startTimeCount > 0) {
866 start = atoi(startTime[1]);
868 sqlite3_free_table(startTime);
870 char **sourceFile;
871 int sourceFileCount;
872 //sqlite3_get_table(db, sqlite3_mprintf("SELECT d10.offset, d10.length FROM data d3, data d4, data d5, data d6, data d7, data d8, data d9, data d10 WHERE d3.object LIKE '%s' AND d3.property LIKE 'OMFI:SCLP:SourceID' AND d4.value LIKE d3.value AND d4.property LIKE 'OMFI:MOBJ:MobID' AND d5.object LIKE d4.object AND d5.property LIKE 'OMFI:MOBJ:Slots' AND d6.object LIKE d5.value AND d7.object LIKE d6.value AND d7.property LIKE 'OMFI:MSLT:Segment' AND d8.object LIKE d7.value AND d8.property LIKE 'OMFI:SCLP:SourceID' AND d9.value LIKE d8.value AND d9.property LIKE 'OMFI:MOBJ:MobID' AND d10.object LIKE d9.object AND d10.property LIKE 'OMFI:MOBJ:Name' LIMIT 1", items[j]), &sourceFile, &sourceFileCount, 0, 0);
873 sqlite3_get_table(db, sqlite3_mprintf("SELECT offset, length FROM data WHERE object IN (SELECT object FROM data WHERE value IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT object FROM data WHERE value IN (SELECT value FROM data WHERE object = %s AND property = 'OMFI:SCLP:SourceID' LIMIT 1) AND property = 'OMFI:MOBJ:MobID' LIMIT 1) AND property = 'OMFI:MOBJ:Slots' LIMIT 1) LIMIT 1) AND property = 'OMFI:MSLT:Segment' LIMIT 1) AND property = 'OMFI:SCLP:SourceID' LIMIT 1) AND property = 'OMFI:MOBJ:MobID' LIMIT 1) AND property LIKE 'OMFI:MOBJ:Name' LIMIT 1", items[j]), &sourceFile, &sourceFileCount, 0, 0);
875 if (sourceFileCount > 0) {
876 uint32_t sfOffs;
877 uint32_t sfLen;
879 if (get_offset_and_length (sourceFile[2], sourceFile[3], sfOffs, sfLen)) {
880 cerr << "get source file from " << sfOffs << " + " << sfLen << endl;
881 char *sfBuf = read_name (sfOffs, sfLen);
883 if ((sinfo = get_known_source (sfBuf)) == 0) {
884 cerr << "Reference to unknown source [" << sfBuf << ']' << endl;
885 return -1;
888 free (sfBuf);
889 } else {
890 cerr << "can't get off+len\n";
892 } else {
893 char **fallbackFile;
894 int fallbackFileCount;
895 //sqlite3_get_table(db, sqlite3_mprintf("SELECT d9.object FROM data d3, data d4, data d5, data d6, data d7, data d8, data d9 WHERE d3.object LIKE '%s' AND d3.property LIKE 'OMFI:SCLP:SourceID' AND d4.value LIKE d3.value AND d4.property LIKE 'OMFI:MOBJ:MobID' AND d5.object LIKE d4.object AND d5.property LIKE 'OMFI:MOBJ:Slots' AND d6.object LIKE d5.value AND d7.object LIKE d6.value AND d7.property LIKE 'OMFI:MSLT:Segment' AND d8.object LIKE d7.value AND d8.property LIKE 'OMFI:SCLP:SourceID' AND d9.value LIKE d8.value AND d9.property LIKE 'OMFI:MDAT:MobID' LIMIT 1", items[j]), &fallbackFile, &fallbackFileCount, 0, 0);
896 sqlite3_get_table(db, sqlite3_mprintf("SELECT object FROM data WHERE value IN (SELECT value FROM data WHERE object IN (SELECT object FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT value FROM data WHERE object IN (SELECT object FROM data WHERE value IN (SELECT value FROM data WHERE object = %s AND property = 'OMFI:SCLP:SourceID' LIMIT 1) AND property = 'OMFI:MOBJ:MobID' LIMIT 1) AND property = 'OMFI:MOBJ:Slots' LIMIT 1) LIMIT 1) AND property = 'OMFI:MSLT:Segment' LIMIT 1) AND property = 'OMFI:SCLP:SourceID' LIMIT 1)AND property = 'OMFI:SCLP:SourceID' LIMIT 1) AND property LIKE 'OMFI:MDAT:MobID' LIMIT 1", items[j]), &fallbackFile, &fallbackFileCount, 0, 0);
897 if (fallbackFileCount > 0) {
898 if ((sinfo = get_known_source (fallbackFile[1])) == 0) {
899 cerr << "Reference to unknown source [" << fallbackFile[1] << ']' << endl;
900 return -1;
904 sqlite3_free_table(fallbackFile);
907 if (sinfo) {
909 region = new_region_node ();
910 playlist->add_child_nocopy (*region);
912 snprintf (sbuf, sizeof (sbuf), "%" PRId64, llrintf (position * sample_rate));
913 region->add_property ("position", sbuf);
914 snprintf (sbuf, sizeof (sbuf), "%" PRId64, llrintf (length * sample_rate));
915 region->add_property ("length", sbuf);
916 snprintf (sbuf, sizeof (sbuf), "%" PRId64, llrintf (start * frame_rate * sample_rate));
917 region->add_property ("start", sbuf);
918 set_region_sources (region, sinfo);
920 route_max_channels = max (route_max_channels, sinfo->channels);
923 sqlite3_free_table(sourceFile);
924 sqlite3_free_table(itemName);
925 position += length;
928 sqlite3_free_table(type);
929 sqlite3_free_table(len);
932 /* finalize route information */
934 cerr << "Set up track with " << route_max_channels << " channels" << endl;
935 set_route_node_channels (route, route_max_channels, route_max_channels, true);
936 sqlite3_free_table(items);
939 sqlite3_free_table(tracks);
941 id_counter++;
942 snprintf (sbuf, sizeof (sbuf), "%" PRId64, id_counter);
943 session->add_property ("id-counter", sbuf);
944 snprintf (sbuf, sizeof (sbuf), "%" PRId32, sample_rate);
945 session->add_property ("sample-rate", sbuf);
947 XMLTree xml;
949 xml.set_root (session);
951 vector<string> v;
953 v.push_back (base_dir);
954 v.push_back (session_name);
955 v.push_back (session_name + ".ardour");
957 xml.write (Glib::build_filename(v).c_str());
958 return 0;
962 static void
963 print_help (const char* execname)
965 cout << execname
966 << " [ -r sample-rate ]"
967 << " [ -n session-name ]"
968 << " [ -v ardour-session-version ]"
969 << " OMF2_session_file"
970 << endl;
971 exit (1);
975 main (int argc, char* argv[])
977 const char *execname = strrchr (argv[0], '/');
978 const char* optstring = "r:n:v:h";
979 const char* session_name = 0;
980 int sample_rate = 0;
981 int version = 0;
983 const struct option longopts[] = {
984 { "rate", 1, 0, 'r' },
985 { "name", 1, 0, 'n' },
986 { "version", 1, 0, 'v' },
987 { "help", 0, 0, 'h' },
988 { 0, 0, 0, 0 }
992 int option_index = 0;
993 int c = 0;
995 while (1) {
996 c = getopt_long (argc, argv, optstring, longopts, &option_index);
998 if (c == -1) {
999 break;
1002 switch (c) {
1003 case 'r':
1004 sample_rate = atoi (optarg);
1005 break;
1007 case 'n':
1008 session_name = optarg;
1009 break;
1011 case 'v':
1012 version = atoi (optarg);
1013 break;
1015 case 'h':
1016 default:
1017 print_help (execname);
1018 break;
1022 if (optind > argc) {
1023 print_help (execname);
1024 /*NOTREACHED*/
1027 OMF omf;
1029 if (version) {
1030 omf.set_version (version);
1033 if (sample_rate) {
1034 omf.set_sample_rate (sample_rate);
1037 if (session_name) {
1038 omf.set_session_name (session_name);
1039 } else {
1040 omf.set_session_name (basename_nosuffix (argv[optind]));
1043 if (omf.init () == 0) {
1045 if (omf.load (argv[optind++]) == 0) {
1046 omf.create_xml ();
1050 return 0;