23 #include <glib/gstdio.h>
25 #include <glibmm/convert.h>
30 #include "ardour/debug.h"
53 ExportElementFactory::ExportElementFactory (
Session & session) :
112 , export_status (session.get_export_status ())
113 , normalizing (false)
130 FileSpec spec (channel_config, format, filename, broadcast_info);
131 config_map.insert (make_pair (timespan, spec));
142 std::set<ExportTimespanPtr> timespan_set;
144 bool new_timespan = timespan_set.insert (it->first).second;
186 spec.
filename->set_timespan (it->first);
201 typedef std::map<std::string, int> ExtCountMap;
205 counts[it->second.format->extension()]++;
208 bool duplicates_found =
false;
209 for (ExtCountMap::iterator it = counts.begin(); it != counts.end(); ++it) {
210 if (it->second > 1) { duplicates_found =
true; }
215 it->second.filename->include_format_name = duplicates_found;
245 frames_to_read = frames;
250 export_status->processed_frames_current_timespan += frames_to_read;
253 int ret =
graph_builder->process (frames_to_read, last_cycle);
288 std::cerr <<
"command: " << size <<
", " << output << std::endl;
298 std::string filename =
config_map.begin()->second.filename->get_path(fmt);
300 if (fmt->with_cue()) {
304 if (fmt->with_toc()) {
308 if (fmt->with_mp4chaps()) {
316 if (!fmt->command().empty()) {
318 #if 0 // would be nicer with C++11 initialiser...
319 std::map<char, std::string> subs {
321 {
'd', Glib::path_get_dirname(filename) + G_DIR_SEPARATOR },
328 std::map<char, std::string> subs;
329 subs.insert (std::pair<char, std::string> (
'f', filename));
330 subs.insert (std::pair<char, std::string> (
'd', Glib::path_get_dirname (filename) + G_DIR_SEPARATOR));
332 subs.insert (std::pair<char, std::string> (
's',
session.
path ()));
333 subs.insert (std::pair<char, std::string> (
'n',
session.
name ()));
337 if (se->
start (2) == 0) {
344 error <<
"post-export hook failed! " << fmt->command() <<
endmsg;
349 if (fmt->soundcloud_upload()) {
353 "uploading %1 - username=%2, password=%3, token=%4",
355 std::string path = soundcloud_uploader->
Upload (
363 if (path.length() != 0) {
370 error <<
_(
"upload to Soundcloud failed. Perhaps your email or password are incorrect?\n") <<
endmsg;
372 delete soundcloud_uploader;
419 CDMarkerStatus status (filepath, timespan, file_format, filename);
426 (this->*header_func) (status);
431 Locations::LocationList::const_iterator i;
434 for (i = locations.begin(); i != locations.end(); ++i) {
435 if ((*i)->start() >= timespan->get_start() && (*i)->end() <= timespan->get_end() && (*i)->is_cd_marker() && !(*i)->is_session_range()) {
447 Locations::LocationList::const_iterator nexti;
451 framepos_t last_end_time = timespan->get_start();
454 for (i = temp.begin(); i != temp.end(); ++i) {
458 if ((*i)->start() < last_end_time) {
459 if ((*i)->is_mark()) {
463 (this->*index_func) (status);
475 if ((*i)->is_mark()) {
480 if (nexti != temp.end()) {
483 last_end_time = (*nexti)->start();
488 last_end_time = timespan->get_end();
494 last_end_time = (*i)->end();
497 (this->*track_func) (status);
500 }
catch (std::exception& e) {
502 ::g_unlink (filepath.c_str());
503 }
catch (Glib::Exception& e) {
505 ::g_unlink (filepath.c_str());
519 return filename +
".toc";
521 return filename +
".cue";
524 unsigned lastdot = filename.find_last_of(
'.');
525 return filename.substr(0,lastdot) +
".chapters.txt";
528 return filename +
".marker";
542 status.
out <<
"REM Cue file generated by " << PROGRAM_NAME << endl;
545 status.
out <<
"CATALOG " << barcode << endl;
547 if (album_artist !=
"")
550 if (album_title !=
"")
564 status.
out <<
"FILE \"" << Glib::path_get_basename(status.
filename) <<
"\" ";
565 if (!status.
format->format_name().compare (
"WAV") || !status.
format->format_name().compare (
"BWF")) {
566 status.
out <<
"WAVE";
572 status.
out <<
"BINARY";
574 status.
out <<
"MOTOROLA";
578 status.
out << status.
format->format_name();
594 status.
out <<
"CATALOG " << barcode << endl;
596 if (album_title !=
"")
599 status.
out <<
"CD_DA" << endl;
600 status.
out <<
"CD_TEXT {" << endl <<
" LANGUAGE_MAP {" << endl <<
" 0 : EN" << endl <<
" }" << endl;
603 status.
out <<
" }" << endl <<
"}" << endl;
609 status.
out <<
"00:00:00.000 Intro" << endl;
617 snprintf (buf,
sizeof(buf),
" TRACK %02d AUDIO", status.
track_number);
618 status.
out << buf << endl;
620 status.
out <<
" FLAGS" ;
622 status.
out <<
" SCMS ";
624 status.
out <<
" DCP ";
628 status.
out <<
" PRE";
650 status.
out <<
" INDEX 00" << buf << endl;
654 status.
out <<
" INDEX 01" << buf << endl;
665 status.
out << endl <<
"TRACK AUDIO" << endl;
670 status.
out <<
"COPY" << endl;
673 status.
out <<
"PRE_EMPHASIS" << endl;
675 status.
out <<
"NO PRE_EMPHASIS" << endl;
682 status.
out <<
"CD_TEXT {" << endl <<
" LANGUAGE 0 {" << endl;
685 status.
out <<
" PERFORMER ";
689 status.
out <<
"\"\"" << endl;
697 status.
out <<
" ISRC \"";
704 status.
out <<
" }" << endl <<
"}" << endl;
710 status.
out << buf << endl;
713 status.
out <<
"START" << buf << endl;
729 snprintf (buf,
sizeof(buf),
" INDEX %02d",
cue_indexnum);
732 status.
out << buf << endl;
743 status.
out <<
"INDEX" << buf << endl;
756 int mins, secs, frames;
758 mins = when / (60 * fr);
759 remainder = when - (mins * 60 * fr);
760 secs = remainder / fr;
761 remainder -= secs * fr;
762 frames = remainder / (fr / 75);
763 sprintf (buf,
" %02d:%02d:%02d", mins, secs, frames);
771 int hours, mins, secs, msecs;
773 hours = when / (3600 * fr);
774 remainder = when - (hours * 3600 * fr);
775 mins = remainder / (60 * fr);
776 remainder -= mins * 60 * fr;
777 secs = remainder / fr;
778 remainder -= secs * fr;
779 msecs = (remainder * 1000) / fr;
780 sprintf (buf,
"%02d:%02d:%02d.%03d", hours, mins, secs, msecs);
786 Glib::ustring check (txt);
788 std::string latin1_txt;
792 latin1_txt = Glib::convert (txt,
"ISO-8859-1",
"UTF-8");
793 }
catch (Glib::ConvertError& err) {
794 throw Glib::ConvertError (err.code(),
string_compose (
_(
"Cannot convert %1 to Latin-1 text"), txt));
799 for (std::string::const_iterator c = latin1_txt.begin(); c != latin1_txt.end(); ++c) {
803 }
else if ((*c) ==
'\\') {
805 }
else if (isprint (*c)) {
808 snprintf (buf,
sizeof (buf),
"\\%03o", (
int) (
unsigned char) *c);
827 for (std::string::const_iterator c = txt.begin(); c != txt.end(); ++c) {
831 }
else if (*c ==
'\\') {
846 std::string latin1_txt;
850 latin1_txt = Glib::convert (txt,
"ISO-8859-1",
"UTF-8");
851 }
catch (Glib::ConvertError& err) {
852 throw Glib::ConvertError (err.code(),
string_compose (
_(
"Cannot convert %1 to Latin-1 text"), txt));
857 out =
'"' + latin1_txt +
'"';
void write_toc_header(CDMarkerStatus &status)
bool add_export_config(ExportTimespanPtr timespan, ExportChannelConfigPtr channel_config, ExportFormatSpecPtr format, ExportFilenamePtr filename, BroadcastInfoPtr broadcast_info)
framecnt_t nominal_frame_rate() const
ExportTimespanPtr current_timespan
ExportFormatSpecPtr add_format_copy(ExportFormatSpecPtr other)
ExportChannelConfigPtr add_channel_config()
ExportTimespanPtr add_timespan()
int start_audio_export(framepos_t position)
int process(framecnt_t frames)
std::list< Location * > LocationList
std::string toc_escape_filename(const std::string &)
std::string soundcloud_username
ComparableSharedPtr< ExportTimespan > ExportTimespanPtr
void write_index_info_toc(CDMarkerStatus &status)
PBD::ScopedConnection process_connection
void handle_duplicate_format_extensions()
LIBPBD_API Transmitter error
framepos_t index_position
bool operator()(Location *a, Location *b)
std::ostream & endmsg(std::ostream &ostr)
void write_index_info_mp4ch(CDMarkerStatus &status)
framecnt_t frame_rate() const
boost::shared_ptr< ExportStatus > get_export_status()
framepos_t process_position
void write_track_info_cue(CDMarkerStatus &status)
void command_output(std::string output, size_t size)
ExportStatusPtr export_status
void write_cue_header(CDMarkerStatus &status)
std::map< std::string, std::string > cd_info
void write_track_info_toc(CDMarkerStatus &status)
void write_track_info_mp4ch(CDMarkerStatus &status)
const LocationList & list()
static bool tag_file(std::string const &filename, SessionMetadata const &metadata)
void write_mp4ch_header(CDMarkerStatus &status)
bool soundcloud_open_page
std::string cue_escape_cdtext(const std::string &txt)
framepos_t track_start_frame
void export_cd_marker_file(ExportTimespanPtr timespan, ExportFormatSpecPtr file_format, std::string filename, CDMarkerFormat format)
void frames_to_cd_frames_string(char *buf, framepos_t when)
#define DEBUG_TRACE(bits, str)
ExportTimespanPtr timespan
boost::shared_ptr< ExportFilename > ExportFilenamePtr
LIBPBD_API Transmitter info
LIBPBD_API bool open_uri(const char *)
std::string soundcloud_password
PBD::Signal1< int, framecnt_t > ProcessExport
framepos_t track_position
std::string Get_Auth_Token(std::string username, std::string password)
framepos_t track_duration
boost::shared_ptr< ExportChannelConfiguration > ExportChannelConfigPtr
LIBPBD_API Glib::ustring basename_nosuffix(Glib::ustring)
ExportFilenamePtr add_filename_copy(ExportFilenamePtr other)
int start(int stderr_mode=1)
ExportFilenamePtr filename
const std::string & name() const
void frames_to_chapter_marks_string(char *buf, framepos_t when)
int process_timespan(framecnt_t frames)
ExportFilenamePtr add_filename()
PBD::Signal2< void, std::string, size_t > ReadStdout
bool soundcloud_make_public
boost::shared_ptr< ExportGraphBuilder > graph_builder
std::string Upload(std::string file_path, std::string title, std::string token, bool ispublic, bool downloadable, ARDOUR::ExportHandler *caller)
ExportFormatSpecPtr format
std::string get_cd_marker_filename(std::string filename, CDMarkerFormat format)
void write_index_info_cue(CDMarkerStatus &status)
std::string toc_escape_cdtext(const std::string &)
LIBARDOUR_API uint64_t Soundcloud
bool soundcloud_downloadable
ExportHandler(Session &session)
TimespanBounds timespan_bounds
boost::shared_ptr< ExportFormatSpecification > ExportFormatSpecPtr
std::string string_compose(const std::string &fmt, const T1 &o1)
ExportFormatSpecPtr add_format()