+ dcp::NameFormat::Map values;
+ values['t'] = "j2c";
+ values['r'] = raw_convert<string> (reel_index + 1);
+ values['n'] = raw_convert<string> (reel_count);
+ if (summary) {
+ values['c'] = careful_string_filter (summary.get());
+ }
+ return Config::instance()->dcp_asset_filename_format().get(values, "_" + asset->id() + ".mxf");
+}
+
+string
+audio_asset_filename (shared_ptr<dcp::SoundAsset> asset, int reel_index, int reel_count, optional<string> summary)
+{
+ dcp::NameFormat::Map values;
+ values['t'] = "pcm";
+ values['r'] = raw_convert<string> (reel_index + 1);
+ values['n'] = raw_convert<string> (reel_count);
+ if (summary) {
+ values['c'] = careful_string_filter (summary.get());
+ }
+ return Config::instance()->dcp_asset_filename_format().get(values, "_" + asset->id() + ".mxf");
+}
+
+
+string
+atmos_asset_filename (shared_ptr<dcp::AtmosAsset> asset, int reel_index, int reel_count, optional<string> summary)
+{
+ dcp::NameFormat::Map values;
+ values['t'] = "atmos";
+ values['r'] = raw_convert<string> (reel_index + 1);
+ values['n'] = raw_convert<string> (reel_count);
+ if (summary) {
+ values['c'] = careful_string_filter (summary.get());
+ }
+ return Config::instance()->dcp_asset_filename_format().get(values, "_" + asset->id() + ".mxf");
+}
+
+
+float
+relaxed_string_to_float (string s)
+{
+ try {
+ boost::algorithm::replace_all (s, ",", ".");
+ return lexical_cast<float> (s);
+ } catch (bad_lexical_cast &) {
+ boost::algorithm::replace_all (s, ".", ",");
+ return lexical_cast<float> (s);
+ }
+}
+
+string
+careful_string_filter (string s)
+{
+ /* Filter out `bad' characters which `may' cause problems with some systems (either for DCP name or filename).
+ There's no apparent list of what really is allowed, so this is a guess.
+ Safety first and all that.
+ */
+
+ /* First transliterate using libicu to try to remove accents in a "nice" way */
+ auto transliterated = icu::UnicodeString::fromUTF8(icu::StringPiece(s));
+ auto status = U_ZERO_ERROR;
+ auto transliterator = icu::Transliterator::createInstance("NFD; [:M:] Remove; NFC", UTRANS_FORWARD, status);
+ transliterator->transliterate(transliterated);
+
+ /* Some things are missed by ICU's transliterator */
+ std::map<wchar_t, wchar_t> replacements = {
+ { L'ł', L'l' },
+ { L'Ł', L'L' }
+ };
+
+ icu::UnicodeString transliterated_more;
+ for (int i = 0; i < transliterated.length(); ++i) {
+ auto replacement = replacements.find(transliterated[i]);
+ if (replacement != replacements.end()) {
+ transliterated_more += replacement->second;
+ } else {
+ transliterated_more += transliterated[i];
+ }
+ }
+
+ /* Then remove anything that's not in a very limited character set */
+ wstring out;
+ wstring const allowed = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_%.+";
+ for (int i = 0; i < transliterated_more.length(); ++i) {
+ wchar_t c = transliterated_more[i];
+ if (allowed.find(c) != string::npos) {
+ out += c;
+ }
+ }
+
+ return boost::locale::conv::utf_to_utf<char>(out);
+}
+
+/** @param mapped List of mapped audio channels from a Film.
+ * @param channels Total number of channels in the Film.
+ * @return First: number of non-LFE soundtrack channels (L/R/C/Ls/Rs/Lc/Rc/Bsl/Bsr), second: number of LFE channels.
+ */
+pair<int, int>
+audio_channel_types (list<int> mapped, int channels)
+{
+ int non_lfe = 0;
+ int lfe = 0;
+
+ for (auto i: mapped) {
+ if (i >= channels) {
+ /* This channel is mapped but is not included in the DCP */
+ continue;
+ }
+
+ switch (static_cast<dcp::Channel>(i)) {
+ case dcp::Channel::LFE:
+ ++lfe;
+ break;
+ case dcp::Channel::LEFT:
+ case dcp::Channel::RIGHT:
+ case dcp::Channel::CENTRE:
+ case dcp::Channel::LS:
+ case dcp::Channel::RS:
+ case dcp::Channel::BSL:
+ case dcp::Channel::BSR:
+ ++non_lfe;
+ break;
+ case dcp::Channel::HI:
+ case dcp::Channel::VI:
+ case dcp::Channel::MOTION_DATA:
+ case dcp::Channel::SYNC_SIGNAL:
+ case dcp::Channel::SIGN_LANGUAGE:
+ case dcp::Channel::CHANNEL_COUNT:
+ break;
+ }
+ }
+
+ return make_pair (non_lfe, lfe);
+}
+
+shared_ptr<AudioBuffers>
+remap (shared_ptr<const AudioBuffers> input, int output_channels, AudioMapping map)
+{
+ auto mapped = make_shared<AudioBuffers>(output_channels, input->frames());
+ mapped->make_silent ();
+
+ int to_do = min (map.input_channels(), input->channels());
+
+ for (int i = 0; i < to_do; ++i) {
+ for (int j = 0; j < mapped->channels(); ++j) {
+ if (map.get(i, j) > 0) {
+ mapped->accumulate_channel(
+ input.get(),
+ i,
+ j,
+ map.get(i, j)
+ );
+ }
+ }
+ }
+
+ return mapped;
+}
+
+Eyes
+increment_eyes (Eyes e)
+{
+ if (e == Eyes::LEFT) {
+ return Eyes::RIGHT;