+2015-03-24 Carl Hetherington <cth@carlh.net>
+
+ * Hand-apply 7ba9dcdbfe8f0d94ad9887843995c152c45dfe9e from master;
+ allow "deletion" of the audio part of a FFmpeg file from the
+ timeline; delete unmaps the audio (#316).
+
2015-02-25 Carl Hetherington <cth@carlh.net>
* Version 2.0.41 released.
-7ba9dcdbfe8f0d94ad9887843995c152c45dfe9e
e30fd8d
31eafa8a121b8d341d198e4fe426ee843cc70167
3e3d3e46a74af7b3e6431033c7c80bd058c02cf6
/*
- Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
using std::pair;
using std::string;
using std::min;
+using std::vector;
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
using dcp::raw_convert;
return digester.get ();
}
+
+list<dcp::Channel>
+AudioMapping::mapped_dcp_channels () const
+{
+ static float const minus_96_db = 0.000015849;
+
+ list<dcp::Channel> mapped;
+
+ for (vector<vector<float> >::const_iterator i = _gain.begin(); i != _gain.end(); ++i) {
+ for (size_t j = 0; j < i->size(); ++j) {
+ if (abs ((*i)[j]) > minus_96_db) {
+ mapped.push_back ((dcp::Channel) j);
+ }
+ }
+ }
+
+ mapped.sort ();
+ mapped.unique ();
+
+ return mapped;
+}
+
+void
+AudioMapping::unmap_all ()
+{
+ for (vector<vector<float> >::iterator i = _gain.begin(); i != _gain.end(); ++i) {
+ for (vector<float>::iterator j = i->begin(); j != i->end(); ++j) {
+ *j = 0;
+ }
+ }
+}
+
/*
- Copyright (C) 2013-2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
}
std::string digest () const;
+
+ std::list<dcp::Channel> mapped_dcp_channels () const;
+ void unmap_all ();
private:
void setup (int);
#include "content_menu.h"
#include "repeat_dialog.h"
#include "wx_util.h"
+#include "timeline_video_content_view.h"
+#include "timeline_audio_content_view.h"
using std::cout;
using std::vector;
}
void
-ContentMenu::popup (weak_ptr<Film> f, ContentList c, wxPoint p)
+ContentMenu::popup (weak_ptr<Film> f, ContentList c, TimelineContentViewList v, wxPoint p)
{
_film = f;
_content = c;
+ _views = v;
_repeat->Enable (!_content.empty ());
int n = 0;
d->Destroy ();
_content.clear ();
+ _views.clear ();
}
void
return;
}
- film->playlist()->remove (_content);
+ /* We are removing from the timeline if _views is not empty */
+ bool handled = false;
+ if (!_views.empty ()) {
+ /* Special case: we only remove FFmpegContent if its video view is selected;
+ if not, and its audio view is selected, we unmap the audio.
+ */
+ for (ContentList::iterator i = _content.begin(); i != _content.end(); ++i) {
+ shared_ptr<FFmpegContent> fc = dynamic_pointer_cast<FFmpegContent> (*i);
+ if (!fc) {
+ continue;
+ }
+
+ shared_ptr<TimelineVideoContentView> video;
+ shared_ptr<TimelineAudioContentView> audio;
+
+ for (TimelineContentViewList::iterator i = _views.begin(); i != _views.end(); ++i) {
+ shared_ptr<TimelineVideoContentView> v = dynamic_pointer_cast<TimelineVideoContentView> (*i);
+ shared_ptr<TimelineAudioContentView> a = dynamic_pointer_cast<TimelineAudioContentView> (*i);
+ if (v && v->content() == fc) {
+ video = v;
+ } else if (a && a->content() == fc) {
+ audio = a;
+ }
+ }
+
+ if (!video && audio) {
+ AudioMapping m = fc->audio_mapping ();
+ m.unmap_all ();
+ fc->set_audio_mapping (m);
+ handled = true;
+ }
+ }
+ }
+
+ if (!handled) {
+ film->playlist()->remove (_content);
+ }
_content.clear ();
+ _views.clear ();
}
void
#include <wx/wx.h>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
+#include "timeline_content_view.h"
#include "lib/types.h"
class Film;
ContentMenu (wxWindow* p);
~ContentMenu ();
- void popup (boost::weak_ptr<Film>, ContentList, wxPoint);
+ void popup (boost::weak_ptr<Film>, ContentList, TimelineContentViewList, wxPoint);
private:
void repeat ();
boost::weak_ptr<Film> _film;
wxWindow* _parent;
ContentList _content;
+ TimelineContentViewList _views;
wxMenuItem* _repeat;
wxMenuItem* _join;
wxMenuItem* _find_missing;
/*
- Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+ Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
void
ContentPanel::right_click (wxListEvent& ev)
{
- _menu->popup (_film, selected (), ev.GetPoint ());
+ _menu->popup (_film, selected (), TimelineContentViewList (), ev.GetPoint ());
}
/** Set up broad sensitivity based on the type of content that is selected */
Timeline::playlist_changed ()
{
ensure_ui_thread ();
-
+ recreate_views ();
+}
+
+void
+Timeline::recreate_views ()
+{
shared_ptr<const Film> fl = _film.lock ();
if (!fl) {
return;
if (dynamic_pointer_cast<VideoContent> (*i)) {
_views.push_back (shared_ptr<TimelineView> (new TimelineVideoContentView (*this, *i)));
}
- if (dynamic_pointer_cast<AudioContent> (*i)) {
+
+ shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (*i);
+ if (ac && !ac->audio_mapping().mapped_dcp_channels().empty ()) {
_views.push_back (shared_ptr<TimelineView> (new TimelineAudioContentView (*this, *i)));
}
assign_tracks ();
setup_pixels_per_second ();
Refresh ();
+ } else if (property == AudioContentProperty::AUDIO_MAPPING) {
+ recreate_views ();
}
}
cv->set_selected (true);
}
- _menu.popup (_film, selected_content (), ev.GetPosition ());
+ _menu.popup (_film, selected_content (), selected_views (), ev.GetPosition ());
}
void
void assign_tracks ();
void set_position_from_event (wxMouseEvent &);
void clear_selection ();
+ void recreate_views ();
boost::shared_ptr<TimelineView> event_to_view (wxMouseEvent &);
TimelineContentViewList selected_views () const;