+
+/** Change the gains of the supplied AudioMapping to make it a default
+ * for this film. The defaults are guessed based on what processor (if any)
+ * is in use, the number of input channels and any filename supplied.
+ */
+void
+Film::make_audio_mapping_default (AudioMapping& mapping, optional<boost::filesystem::path> filename) const
+{
+ static string const regex[] = {
+ ".*[\\._-]L[\\._-].*",
+ ".*[\\._-]R[\\._-].*",
+ ".*[\\._-]C[\\._-].*",
+ ".*[\\._-]Lfe[\\._-].*",
+ ".*[\\._-]Ls[\\._-].*",
+ ".*[\\._-]Rs[\\._-].*"
+ };
+
+ static int const regexes = sizeof(regex) / sizeof(*regex);
+
+ if (audio_processor ()) {
+ audio_processor()->make_audio_mapping_default (mapping);
+ } else {
+ mapping.make_zero ();
+ if (mapping.input_channels() == 1) {
+ bool guessed = false;
+
+ /* See if we can guess where this stream should go */
+ if (filename) {
+ for (int i = 0; i < regexes; ++i) {
+ boost::regex e (regex[i], boost::regex::icase);
+ if (boost::regex_match (filename->string(), e) && i < mapping.output_channels()) {
+ mapping.set (0, i, 1);
+ guessed = true;
+ }
+ }
+ }
+
+ if (!guessed) {
+ /* If we have no idea, just put it on centre */
+ mapping.set (0, static_cast<int> (dcp::CENTRE), 1);
+ }
+ } else {
+ /* 1:1 mapping */
+ for (int i = 0; i < min (mapping.input_channels(), mapping.output_channels()); ++i) {
+ mapping.set (i, i, 1);
+ }
+ }
+ }
+}
+
+/** @return The names of the channels that audio contents' outputs are passed into;
+ * this is either the DCP or a AudioProcessor.
+ */
+vector<string>
+Film::audio_output_names () const
+{
+ if (audio_processor ()) {
+ return audio_processor()->input_names ();
+ }
+
+ DCPOMATIC_ASSERT (MAX_DCP_AUDIO_CHANNELS == 16);
+
+ vector<string> n;
+
+ for (int i = 0; i < audio_channels(); ++i) {
+ n.push_back (short_audio_channel_name (i));
+ }
+
+ return n;
+}
+
+void
+Film::repeat_content (ContentList c, int n)
+{
+ _playlist->repeat (c, n);
+}
+
+void
+Film::remove_content (ContentList c)
+{
+ _playlist->remove (c);
+}
+
+void
+Film::audio_analysis_finished ()
+{
+ /* XXX */
+}
+
+list<DCPTimePeriod>
+Film::reels () const
+{
+ list<DCPTimePeriod> p;
+ DCPTime const len = length();
+
+ switch (reel_type ()) {
+ case REELTYPE_SINGLE:
+ p.push_back (DCPTimePeriod (DCPTime (), len));
+ break;
+ case REELTYPE_BY_VIDEO_CONTENT:
+ {
+ optional<DCPTime> last_split;
+ shared_ptr<Content> last_video;
+ BOOST_FOREACH (shared_ptr<Content> c, content ()) {
+ if (c->video) {
+ BOOST_FOREACH (DCPTime t, c->reel_split_points()) {
+ if (last_split) {
+ p.push_back (DCPTimePeriod (last_split.get(), t));
+ }
+ last_split = t;
+ }
+ last_video = c;
+ }
+ }
+
+ DCPTime video_end = last_video ? last_video->end() : DCPTime(0);
+ if (last_split) {
+ /* Definitely go from the last split to the end of the video content */
+ p.push_back (DCPTimePeriod (last_split.get(), video_end));
+ }
+
+ if (video_end < len) {
+ /* And maybe go after that as well if there is any non-video hanging over the end */
+ p.push_back (DCPTimePeriod (video_end, len));
+ }
+ break;
+ }
+ case REELTYPE_BY_LENGTH:
+ {
+ DCPTime current;
+ /* Integer-divide reel length by the size of one frame to give the number of frames per reel */
+ Frame const reel_in_frames = _reel_length / ((j2k_bandwidth() / video_frame_rate()) / 8);
+ while (current < len) {
+ DCPTime end = min (len, current + DCPTime::from_frames (reel_in_frames, video_frame_rate ()));
+ p.push_back (DCPTimePeriod (current, end));
+ current = end;
+ }
+ break;
+ }
+ }
+
+ return p;
+}
+
+/** @param period A period within the DCP
+ * @return Name of the content which most contributes to the given period.
+ */
+string
+Film::content_summary (DCPTimePeriod period) const
+{
+ return _playlist->content_summary (period);
+}
+
+list<string>
+Film::fix_conflicting_settings ()
+{
+ list<string> notes;
+
+ list<boost::filesystem::path> was_referencing;
+ BOOST_FOREACH (shared_ptr<Content> i, content()) {
+ shared_ptr<DCPContent> d = dynamic_pointer_cast<DCPContent> (i);
+ if (d) {
+ list<string> reasons;
+ bool was = false;
+ if (!d->can_reference_video(reasons) && d->reference_video()) {
+ d->set_reference_video (false);
+ was = true;
+ }
+ if (!d->can_reference_audio(reasons) && d->reference_audio()) {
+ d->set_reference_audio (false);
+ was = true;
+ }
+ if (!d->can_reference_subtitle(reasons) && d->reference_subtitle()) {
+ d->set_reference_subtitle (false);
+ was = true;
+ }
+ if (was) {
+ was_referencing.push_back (d->path(0).parent_path().filename());
+ }
+ }
+ }
+
+ BOOST_FOREACH (boost::filesystem::path d, was_referencing) {
+ notes.push_back (String::compose (_("The DCP %1 was being referred to by this film. This not now possible because the reel sizes in the film no longer agree with those in the imported DCP.\n\nSetting the 'Reel type' to 'split by video content' will probably help.\n\nAfter doing that you would need to re-tick the appropriate 'refer to existing DCP' checkboxes."), d.string()));
+ }
+
+ return notes;
+}
+
+void
+Film::use_template (string name)
+{
+ _template_film.reset (new Film (optional<boost::filesystem::path>()));
+ _template_film->read_metadata (Config::instance()->template_path (name));
+ _use_isdcf_name = _template_film->_use_isdcf_name;
+ _dcp_content_type = _template_film->_dcp_content_type;
+ _container = _template_film->_container;
+ _resolution = _template_film->_resolution;
+ _j2k_bandwidth = _template_film->_j2k_bandwidth;
+ _video_frame_rate = _template_film->_video_frame_rate;
+ _signed = _template_film->_signed;
+ _encrypted = _template_film->_encrypted;
+ _audio_channels = _template_film->_audio_channels;
+ _sequence = _template_film->_sequence;
+ _three_d = _template_film->_three_d;
+ _interop = _template_film->_interop;
+ _audio_processor = _template_film->_audio_processor;
+ _reel_type = _template_film->_reel_type;
+ _reel_length = _template_film->_reel_length;
+ _upload_after_make_dcp = _template_film->_upload_after_make_dcp;
+}
+
+pair<double, double>
+Film::speed_up_range (int dcp_frame_rate) const
+{
+ return _playlist->speed_up_range (dcp_frame_rate);
+}
+
+void
+Film::copy_from (shared_ptr<const Film> film)
+{
+ read_metadata (film->file (metadata_file));
+}