with_cue (_("Create CUE file for disk-at-once CD/DVD creation")),
with_toc (_("Create TOC file for disk-at-once CD/DVD creation")),
+ with_mp4chaps (_("Create chapter mark file for MP4 chapter marks")),
tag_checkbox (_("Tag file with session's metadata"))
{
with_cue.signal_toggled().connect (sigc::mem_fun (*this, &ExportFormatDialog::update_with_cue));
with_toc.signal_toggled().connect (sigc::mem_fun (*this, &ExportFormatDialog::update_with_toc));
+ with_mp4chaps.signal_toggled().connect (sigc::mem_fun (*this, &ExportFormatDialog::update_with_mp4chaps));
command_entry.signal_changed().connect (sigc::mem_fun (*this, &ExportFormatDialog::update_command));
cue_toc_vbox.pack_start (with_cue, false, false);
cue_toc_vbox.pack_start (with_toc, false, false);
+ cue_toc_vbox.pack_start (with_mp4chaps, false, false);
/* Load state before hooking up the rest of the signals */
with_cue.set_active (spec->with_cue());
with_toc.set_active (spec->with_toc());
+ with_mp4chaps.set_active (spec->with_mp4chaps());
for (Gtk::ListStore::Children::iterator it = src_quality_list->children().begin(); it != src_quality_list->children().end(); ++it) {
if (it->get_value (src_quality_cols.id) == spec->src_quality()) {
manager.select_with_toc (with_toc.get_active());
}
+void
+ExportFormatDialog::update_with_mp4chaps ()
+{
+ manager.select_with_mp4chaps (with_mp4chaps.get_active());
+}
void
ExportFormatDialog::update_command ()
Gtk::CheckButton with_cue;
Gtk::CheckButton with_toc;
+ Gtk::CheckButton with_mp4chaps;
Gtk::VBox cue_toc_vbox;
void update_with_toc ();
void update_with_cue ();
+ void update_with_mp4chaps();
void update_command ();
Gtk::TreeView sample_format_view;
void select_with_cue (bool);
void select_with_toc (bool);
+ void select_with_mp4chaps (bool);
void select_upload (bool);
void set_command (std::string);
void select_src_quality (ExportFormatBase::SRCQuality value);
void set_tag (bool tag_it) { _tag = tag_it; }
void set_with_cue (bool yn) { _with_cue = yn; }
void set_with_toc (bool yn) { _with_toc = yn; }
+ void set_with_mp4chaps (bool yn) { _with_mp4chaps = yn; }
void set_soundcloud_upload (bool yn) { _soundcloud_upload = yn; }
void set_command (std::string command) { _command = command; }
float normalize_target () const { return _normalize_target; }
bool with_toc() const { return _with_toc; }
bool with_cue() const { return _with_cue; }
+ bool with_mp4chaps() const { return _with_mp4chaps; }
+
bool soundcloud_upload() const { return _soundcloud_upload; }
std::string command() const { return _command; }
float _normalize_target;
bool _with_toc;
bool _with_cue;
+ bool _with_mp4chaps;
bool _soundcloud_upload;
std::string _command;
void write_cue_header (CDMarkerStatus & status);
void write_toc_header (CDMarkerStatus & status);
+ void write_mp4ch_header (CDMarkerStatus & status);
void write_track_info_cue (CDMarkerStatus & status);
void write_track_info_toc (CDMarkerStatus & status);
+ void write_track_info_mp4ch (CDMarkerStatus & status);
void write_index_info_cue (CDMarkerStatus & status);
void write_index_info_toc (CDMarkerStatus & status);
+ void write_index_info_mp4ch (CDMarkerStatus & status);
void frames_to_cd_frames_string (char* buf, framepos_t when);
+ void frames_to_chapter_marks_string (char* buf, framepos_t when);
+
std::string toc_escape_cdtext (const std::string&);
std::string toc_escape_filename (const std::string&);
std::string cue_escape_cdtext (const std::string& txt);
enum CDMarkerFormat {
CDMarkerNone,
CDMarkerCUE,
- CDMarkerTOC
+ CDMarkerTOC,
+ MP4Chaps
};
enum HeaderFormat {
check_for_description_change ();
}
+void
+ExportFormatManager::select_with_mp4chaps (bool value)
+{
+ current_selection->set_with_mp4chaps (value);
+ check_for_description_change ();
+}
void
ExportFormatManager::set_command (std::string command)
, _normalize_target (1.0)
, _with_toc (false)
, _with_cue (false)
+ , _with_mp4chaps (false)
, _soundcloud_upload (false)
, _command ("")
{
root->add_property ("id", _id.to_s());
root->add_property ("with-cue", _with_cue ? "true" : "false");
root->add_property ("with-toc", _with_toc ? "true" : "false");
+ root->add_property ("with-mp4chaps", _with_mp4chaps ? "true" : "false");
root->add_property ("command", _command);
node = root->add_child ("Encoding");
} else {
_with_cue = false;
}
-
+
if ((prop = root.property ("with-toc"))) {
_with_toc = string_is_affirmative (prop->value());
} else {
_with_toc = false;
}
-
-
+
+ if ((prop = root.property ("with-mp4chaps"))) {
+ _with_mp4chaps = string_is_affirmative (prop->value());
+ } else {
+ _with_mp4chaps = false;
+ }
+
if ((prop = root.property ("command"))) {
_command = prop->value();
} else {
components.push_back ("CUE");
}
+ if (_with_mp4chaps) {
+ components.push_back ("MP4ch");
+ }
+
if (!_command.empty()) {
components.push_back ("+");
}
export_cd_marker_file (current_timespan, fmt, filename, CDMarkerTOC);
}
+ if (fmt->with_mp4chaps()) {
+ export_cd_marker_file (current_timespan, fmt, filename, MP4Chaps);
+ }
+
if (fmt->tag()) {
AudiofileTagger::tag_file(filename, *SessionMetadata::Metadata());
}
track_func = &ExportHandler::write_track_info_cue;
index_func = &ExportHandler::write_index_info_cue;
break;
+ case MP4Chaps:
+ header_func = &ExportHandler::write_mp4ch_header;
+ track_func = &ExportHandler::write_track_info_mp4ch;
+ index_func = &ExportHandler::write_index_info_mp4ch;
+ break;
default:
return;
}
string
ExportHandler::get_cd_marker_filename(std::string filename, CDMarkerFormat format)
{
- /* do not strip file suffix because there may be more than one format,
+ /* do not strip file suffix because there may be more than one format,
and we do not want the CD marker file from one format to overwrite
another (e.g. foo.wav.cue > foo.aiff.cue)
*/
switch (format) {
- case CDMarkerTOC:
+ case CDMarkerTOC:
return filename + ".toc";
- case CDMarkerCUE:
+ case CDMarkerCUE:
return filename + ".cue";
- default:
+ case MP4Chaps:
+ return filename + ".chapters.txt";
+ default:
return filename + ".marker"; // Should not be reached when actually creating a file
}
}
status.out << " }" << endl << "}" << endl;
}
+void
+ExportHandler::write_mp4ch_header (CDMarkerStatus & status)
+{
+}
+
void
ExportHandler::write_track_info_cue (CDMarkerStatus & status)
{
status.out << "START" << buf << endl;
}
+void ExportHandler::write_track_info_mp4ch (CDMarkerStatus & status)
+{
+ gchar buf[18];
+
+ frames_to_chapter_marks_string(buf, status.track_start_frame);
+ status.out << buf << " " << status.marker->name() << endl;
+}
+
void
ExportHandler::write_index_info_cue (CDMarkerStatus & status)
{
status.out << "INDEX" << buf << endl;
}
+void
+ExportHandler::write_index_info_mp4ch (CDMarkerStatus & status)
+{
+}
+
void
ExportHandler::frames_to_cd_frames_string (char* buf, framepos_t when)
{
sprintf (buf, " %02d:%02d:%02d", mins, secs, frames);
}
+void
+ExportHandler::frames_to_chapter_marks_string (char* buf, framepos_t when)
+{
+ framecnt_t remainder;
+ framecnt_t fr = session.nominal_frame_rate();
+ int hours, mins, secs, msecs;
+
+ hours = when / (3600 * fr);
+ remainder = when - (hours * 3600 * fr);
+ mins = remainder / (60 * fr);
+ remainder -= mins * 60 * fr;
+ secs = remainder / fr;
+ remainder -= secs * fr;
+ msecs = (remainder * 1000) / fr;
+ sprintf (buf, "%02d:%02d:%02d.%03d", hours, mins, secs, msecs);
+}
+
std::string
ExportHandler::toc_escape_cdtext (const std::string& txt)
{