1 /* Rewritten for Ardour by Paul Davis <paul@linuxaudiosystems.com>, Feb 2010
6 Copyright (C) 2009 Hannes Breul
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 */
47 #include <sys/errno.h>
51 #include "pbd/xml++.h"
52 #include "pbd/basename.h"
55 //#define DEBUG(fmt,...) fprintf (stderr, fmt, ## __VA_ARGS__)
56 #define DEBUG(fmt,...)
57 #define INFO(fmt,...) fprintf (stdout, fmt, ## __VA_ARGS__)
68 session_name
= "omfsession";
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");
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
);
148 OMF::set_sample_rate (int sr
)
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
);
161 OMF::set_version (int v
)
169 /* create directory tree */
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);
186 v
.push_back (base_dir
);
187 v
.push_back (session_name
);
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
) {
197 dir
= Glib::build_filename (v
);
198 g_mkdir_with_parents (dir
.c_str(), 0775);
206 OMF::get_audio_info (const std::string
& path
)
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) {
215 cerr
<< "Cannot open source file " << path
<< sf_error_str (0, errbuf
, sizeof (errbuf
) - 1) << endl
;
219 if (known_sources
.find (Glib::path_get_basename (path
)) != known_sources
.end()) {
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
,
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
;
240 OMF::add_id (XMLNode
* node
)
244 snprintf (sbuf
, sizeof (sbuf
), "%" PRId64
, id_counter
);
245 node
->add_property ("id", sbuf
);
249 OMF::new_playlist_node ()
251 XMLNode
* playlist
= new XMLNode ("Playlist");
252 playlists
->add_child_nocopy (*playlist
);
254 playlist
->add_property ("type", "audio");
255 playlist
->add_property ("frozen", "no");
261 OMF::new_diskstream_node ()
263 XMLNode
* diskstream
= new XMLNode ("AudioDiskstream");
264 diskstreams
->add_child_nocopy (*diskstream
);
266 diskstream
->add_property ("flags", "Recordable");
267 diskstream
->add_property ("speed", "1");
268 diskstream
->add_property ("channels", "1");
273 OMF::set_region_sources (XMLNode
* region
, SourceInfo
* sinfo
)
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());
286 OMF::legalize_name (string
& name
)
288 string::size_type pos
;
289 string illegal_chars
= ":";
292 while ((pos
= name
.find_first_of (illegal_chars
, pos
)) != string::npos
) {
293 name
.replace (pos
, 1, "_");
299 OMF::set_route_node_channels (XMLNode
* route
, int in
, int out
, bool send_to_master
)
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
);
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
);
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
) {
334 snprintf (sbuf
, sizeof (sbuf
), "master/audio_in 2");
336 snprintf (sbuf
, sizeof (sbuf
), "master/audio_in 1");
340 snprintf (sbuf
, sizeof (sbuf
), "system:playback_2");
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");
361 snprintf (sbuf
, sizeof (sbuf
), "system:capture_2");
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
);
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");
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
);
410 spc
->add_property ("name", "panner");
411 spc
->add_property ("flags", "");
416 OMF::new_route_node ()
419 XMLNode
* route
= new XMLNode ("Route");
421 routes
->add_child_nocopy (*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
);
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
);
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",
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");
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");
489 region_extra
->add_child_nocopy (*gui_extra
);
490 region
->add_child_nocopy (*region_extra
);
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");
515 OMF::new_source_node ()
519 source
= new XMLNode ("Source");
521 source
->add_property ("type", "audio");
522 source
->add_property ("flags", "CanRename");
524 sources
->add_child_nocopy (*source
);
530 OMF::get_known_source (const char* name
)
533 KnownSources::iterator i
= known_sources
.find (s
);
534 if (i
!= known_sources
.end()) {
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
);
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";
558 if (sscanf (lenstr
, "%d", &len
) == 0) {
559 cerr
<< "bad length\n";
563 if (((int32_t) offset
) <= 0) {
564 cerr
<< "illegal offset\n";
568 if (((int32_t) len
) <= 0) {
569 cerr
<< "illegal length\n";
584 int route_max_channels
;
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
);
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
++) {
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
);
611 route_max_channels
= 0;
613 INFO ("Processing track %d / %d...\n", i
, numtracks
);
615 if (descCount
<= 0) {
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());
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);
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
);
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
);
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
);
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);
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
);
675 fread(&num
, 4, 1, file
);
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) {
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) {
692 sqlite3_free_table(rate
);
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;
700 double fadeTime
= 0.0;
702 for (j
= 1; j
<= itemCount
; j
++) {
704 printf(" item %d / %d\n", j
, itemCount
);
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);
716 sqlite3_free_table(len
);
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
);
731 lenFrames
= atoi(len
[1]);
732 length
= lenFrames
* frame_rate
;
734 if (!strcmp(type
[1], "TRAN")) {
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) {
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")) {
750 sqlite3_free_table(effID
);
752 } else if (!strcmp(type
[1], "FILL")) {
756 } else if (!strcmp(type
[1], "NEST")) {
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);
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
);
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) {
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
);
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) {
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
;
810 cerr
<< "offs/len illegal\n";
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
;
824 cerr
<< "no fallback file\n";
827 sqlite3_free_table(fallbackFile
);
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
);
851 } else if (!strcmp(type
[1], "SCLP")) {
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);
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
);
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) {
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
;
890 cerr
<< "can't get off+len\n";
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
;
904 sqlite3_free_table(fallbackFile
);
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
);
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
);
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
);
949 xml
.set_root (session
);
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());
963 print_help (const char* execname
)
966 << " [ -r sample-rate ]"
967 << " [ -n session-name ]"
968 << " [ -v ardour-session-version ]"
969 << " OMF2_session_file"
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;
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' },
992 int option_index
= 0;
996 c
= getopt_long (argc
, argv
, optstring
, longopts
, &option_index
);
1004 sample_rate
= atoi (optarg
);
1008 session_name
= optarg
;
1012 version
= atoi (optarg
);
1017 print_help (execname
);
1022 if (optind
> argc
) {
1023 print_help (execname
);
1030 omf
.set_version (version
);
1034 omf
.set_sample_rate (sample_rate
);
1038 omf
.set_session_name (session_name
);
1040 omf
.set_session_name (basename_nosuffix (argv
[optind
]));
1043 if (omf
.init () == 0) {
1045 if (omf
.load (argv
[optind
++]) == 0) {