diff --git a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj index f8bfacfa2..9dd938748 100644 --- a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj +++ b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj @@ -1700,11 +1700,11 @@ > + + TimeAtFrame(frame_number)); - } - AnnounceMarkerMoved(); - } - - void OptChanged(agi::OptionValue const& opt) - { - if (opt.GetBool()) - { - video_seek_slot.Unblock(); - Update(vc->GetFrameN()); - } - else - { - video_seek_slot.Block(); - Update(-1); - } - } - -public: - VideoPositionMarkerProvider(agi::Context *c) - : vc(c->videoController) - , video_seek_slot(vc->AddSeekListener(&VideoPositionMarkerProvider::Update, this)) - , enable_opt_changed_slot(OPT_SUB("Audio/Display/Draw/Video Position", &VideoPositionMarkerProvider::OptChanged, this)) - { - OptChanged(*OPT_GET("Audio/Display/Draw/Video Position")); - } - - void GetMarkers(const TimeRange &range, AudioMarkerVector &out) const - { - if (range.contains(marker)) - { - out.push_back(&marker); - } - } -}; - AudioController::AudioController(agi::Context *context) : context(context) , subtitle_save_slot(context->ass->AddFileSaveListener(&AudioController::OnSubtitlesSave, this)) @@ -318,12 +245,6 @@ void AudioController::OpenAudio(const wxString &url) config::mru->Add("Audio", STD_STR(url)); - if (!video_position_marker_provider.get()) - { - video_position_marker_provider.reset(new VideoPositionMarkerProvider(context)); - video_position_marker_provider->AddMarkerMovedListener(std::tr1::bind(std::tr1::ref(AnnounceMarkerMoved))); - } - try { // Tell listeners about this. @@ -371,10 +292,7 @@ void AudioController::SetTimingController(AudioTimingController *new_controller) timing_controller.reset(new_controller); if (timing_controller) { - timing_controller->AddMarkerMovedListener(bind(std::tr1::ref(AnnounceMarkerMoved))); - timing_controller->AddLabelChangedListener(bind(std::tr1::ref(AnnounceLabelChanged))); timing_controller->AddUpdatedPrimaryRangeListener(&AudioController::OnTimingControllerUpdatedPrimaryRange, this); - timing_controller->AddUpdatedStyleRangesListener(bind(std::tr1::ref(AnnounceStyleRangesChanged))); } } @@ -387,8 +305,6 @@ void AudioController::OnTimingControllerUpdatedPrimaryRange() { player->SetEndPosition(timing_controller->GetPrimaryPlaybackRange().end()); } - - AnnounceSelectionChanged(); } void AudioController::OnSubtitlesSave() @@ -497,26 +413,12 @@ TimeRange AudioController::GetPrimaryPlaybackRange() const } } - -void AudioController::GetMarkers(const TimeRange &range, AudioMarkerVector &markers) const -{ - /// @todo Find all sources of markers - if (timing_controller) timing_controller->GetMarkers(range, markers); - if (video_position_marker_provider.get()) video_position_marker_provider->GetMarkers(range, markers); -} - -void AudioController::GetLabels(const TimeRange &range, std::vector &labels) const -{ - if (timing_controller) timing_controller->GetLabels(range, labels); -} - double AudioController::GetVolume() const { if (!IsAudioOpen()) return 1.0; return player->GetVolume(); } - void AudioController::SetVolume(double volume) { if (!IsAudioOpen()) return; diff --git a/aegisub/src/audio_controller.h b/aegisub/src/audio_controller.h index 1a90af7fb..6f6d02789 100644 --- a/aegisub/src/audio_controller.h +++ b/aegisub/src/audio_controller.h @@ -54,115 +54,12 @@ class AudioPlayer; class AudioProvider; -namespace agi { struct Context; } - -// Declared below -class AudioControllerAudioEventListener; -class AudioControllerTimingEventListener; class AudioTimingController; -class AudioMarker; -class AudioMarkerProvider; - -typedef std::vector AudioMarkerVector; - -/// @class TimeRange -/// @brief Represents an immutable range of time -class TimeRange { - int _begin; - int _end; - -public: - /// @brief Constructor - /// @param begin Index of the first millisecond to include in the range - /// @param end Index of one past the last millisecond to include in the range - TimeRange(int begin, int end) : _begin(begin), _end(end) - { - assert(end >= begin); - } - - /// @brief Copy constructor, optionally adjusting the range - /// @param src The range to duplicate - /// @param begin_adjust Number of milliseconds to add to the start of the range - /// @param end_adjust Number of milliseconds to add to the end of the range - TimeRange(const TimeRange &src, int begin_adjust = 0, int end_adjust = 0) - { - _begin = src._begin + begin_adjust; - _end = src._end + end_adjust; - assert(_end >= _begin); - } - - /// Get the length of the range in milliseconds - int length() const { return _end - _begin; } - /// Get the start time of the range in milliseconds - int begin() const { return _begin; } - /// Get the exclusive end time of the range in milliseconds - int end() const { return _end; } - - /// Determine whether the range contains a given time in milliseconds - bool contains(int ms) const { return ms >= begin() && ms < end(); } - - /// Determine whether there is an overlap between two ranges - bool overlaps(const TimeRange &other) const - { - return other.contains(_begin) || contains(other._begin); - } -}; - -/// @class AudioMarkerProvider -/// @brief Abstract interface for audio marker providers -class AudioMarkerProvider { -protected: - /// One or more of the markers provided by this object have changed - agi::signal::Signal<> AnnounceMarkerMoved; -public: - /// Virtual destructor, does nothing - virtual ~AudioMarkerProvider() { } - - /// @brief Return markers in a time range - virtual void GetMarkers(const TimeRange &range, AudioMarkerVector &out) const = 0; - - DEFINE_SIGNAL_ADDERS(AnnounceMarkerMoved, AddMarkerMovedListener) -}; - -/// @class AudioLabelProvider -/// @brief Abstract interface for audio label providers -class AudioLabelProvider { -protected: - /// One or more of the labels provided by this object have changed - agi::signal::Signal<> AnnounceLabelChanged; -public: - /// A label for a range of time on the audio display - struct AudioLabel { - /// Text of the label - wxString text; - /// Range which this label applies to - TimeRange range; - AudioLabel(wxString const& text, TimeRange const& range) : text(text), range(range) { } - }; - - /// Virtual destructor, does nothing - virtual ~AudioLabelProvider() { } - - /// @brief Get labels in a time range - /// @param range Range of times to get labels for - /// @param[out] out Vector which should be filled with the labels - virtual void GetLabels(TimeRange const& range, std::vector &out) const = 0; - - DEFINE_SIGNAL_ADDERS(AnnounceLabelChanged, AddLabelChangedListener) -}; +namespace agi { struct Context; } +class TimeRange; /// @class AudioController -/// @brief Manage an open audio stream and UI state for it -/// -/// Keeps track of the UI interaction state of the open audio for a project, -/// i.e. what the current selection is, what movable markers are on the audio, -/// and any secondary non-movable markers that are present. -/// -/// Changes in interaction are broadcast to all managed audio displays so they -/// can redraw, and the audio displays report all interactions back to the -/// controller. There is a one to many relationship between controller and -/// audio displays. There is at most one audio controller for an open -/// subtitling project. +/// @brief Manage an open audio stream /// /// Creates and destroys audio providers and players. This behaviour should at /// some point be moved to a separate class, as it adds too many @@ -173,7 +70,7 @@ public: /// providers or players owned by a controller. If some operation that isn't /// possible in the existing design is needed, the controller should be /// extended in some way to allow it. -class AudioController : public wxEvtHandler, public AudioMarkerProvider, public AudioLabelProvider { +class AudioController : public wxEvtHandler { /// Project context this controller belongs to agi::Context *context; @@ -195,12 +92,6 @@ class AudioController : public wxEvtHandler, public AudioMarkerProvider, public /// The timing controller was replaced agi::signal::Signal<> AnnounceTimingControllerChanged; - /// The selected time range changed - agi::signal::Signal<> AnnounceSelectionChanged; - - /// The styling ranges have been updated by the timing controller - agi::signal::Signal<> AnnounceStyleRangesChanged; - /// The audio output object AudioPlayer *player; @@ -210,9 +101,6 @@ class AudioController : public wxEvtHandler, public AudioMarkerProvider, public /// The current timing mode, if any; owned by the audio controller agi::scoped_ptr timing_controller; - /// Provider current video position data for audio display - agi::scoped_ptr video_position_marker_provider; - /// The URL of the currently open audio, if any wxString audio_url; @@ -356,17 +244,6 @@ public: /// @return An immutable TimeRange object TimeRange GetPrimaryPlaybackRange() const; - /// @brief Get all markers inside a range - /// @param range The time range to retrieve markers for - /// @param markers Vector to fill found markers into - void GetMarkers(const TimeRange &range, AudioMarkerVector &markers) const; - - /// @brief Get all labels inside a range - /// @param range The time range to retrieve labels for - /// @param labels Vector to fill found labels into - void GetLabels(const TimeRange &range, std::vector &labels) const; - - /// @brief Get the playback audio volume /// @return The amplification factor for the audio double GetVolume() const; @@ -396,43 +273,6 @@ public: DEFINE_SIGNAL_ADDERS(AnnouncePlaybackPosition, AddPlaybackPositionListener) DEFINE_SIGNAL_ADDERS(AnnouncePlaybackStop, AddPlaybackStopListener) DEFINE_SIGNAL_ADDERS(AnnounceTimingControllerChanged, AddTimingControllerListener) - DEFINE_SIGNAL_ADDERS(AnnounceSelectionChanged, AddSelectionChangedListener) - DEFINE_SIGNAL_ADDERS(AnnounceStyleRangesChanged, AddStyleRangesChangedListener) -}; - -/// @class AudioMarker -/// @brief A marker on the audio display -class AudioMarker { -public: - - /// Describe which directions a marker has feet in - enum FeetStyle { - Feet_None = 0, - Feet_Left, - Feet_Right, - Feet_Both // Conveniently Feet_Left|Feet_Right - }; - - /// @brief Get the marker's position - /// @return The marker's position in milliseconds - virtual int GetPosition() const = 0; - - /// @brief Get the marker's drawing style - /// @return A pen object describing the marker's drawing style - virtual wxPen GetStyle() const = 0; - - /// @brief Get the marker's feet style - /// @return The marker's feet style - virtual FeetStyle GetFeet() const = 0; - - /// @brief Retrieve whether this marker participates in snapping - /// @return True if this marker may snap to other snappable markers - /// - /// If a marker being dragged returns true from this method, and another - /// marker which also returns true from this method is within range, the - /// marker being dragged will be positioned at the position of the other - /// marker if it is released while it is inside snapping range. - virtual bool CanSnap() const = 0; }; namespace agi { diff --git a/aegisub/src/audio_display.cpp b/aegisub/src/audio_display.cpp index 334923464..126277a5e 100644 --- a/aegisub/src/audio_display.cpp +++ b/aegisub/src/audio_display.cpp @@ -37,6 +37,8 @@ #include "config.h" +#include "audio_display.h" + #ifndef AGI_PRE #include @@ -48,7 +50,6 @@ #include "ass_time.h" #include "audio_colorscheme.h" #include "audio_controller.h" -#include "audio_display.h" #include "audio_renderer.h" #include "audio_renderer_spectrum.h" #include "audio_renderer_waveform.h" @@ -848,7 +849,7 @@ void AudioDisplay::PaintAudio(wxDC &dc, TimeRange updtime, wxRect updrect) void AudioDisplay::PaintMarkers(wxDC &dc, TimeRange updtime) { AudioMarkerVector markers; - controller->GetMarkers(updtime, markers); + controller->GetTimingController()->GetMarkers(updtime, markers); if (markers.empty()) return; wxDCPenChanger pen_retainer(dc, wxPen()); @@ -884,7 +885,7 @@ void AudioDisplay::PaintFoot(wxDC &dc, int marker_x, int dir) void AudioDisplay::PaintLabels(wxDC &dc, TimeRange updtime) { std::vector labels; - controller->GetLabels(updtime, labels); + controller->GetTimingController()->GetLabels(updtime, labels); if (labels.empty()) return; wxDCFontChanger fc(dc); @@ -1166,10 +1167,7 @@ void AudioDisplay::OnAudioOpen(AudioProvider *provider) connections.push_back(controller->AddAudioCloseListener(&AudioDisplay::OnAudioOpen, this, (AudioProvider*)0)); connections.push_back(controller->AddPlaybackPositionListener(&AudioDisplay::OnPlaybackPosition, this)); connections.push_back(controller->AddPlaybackStopListener(&AudioDisplay::RemoveTrackCursor, this)); - connections.push_back(controller->AddTimingControllerListener(&AudioDisplay::OnStyleRangesChanged, this)); - connections.push_back(controller->AddMarkerMovedListener(&AudioDisplay::OnMarkerMoved, this)); - connections.push_back(controller->AddSelectionChangedListener(&AudioDisplay::OnSelectionChanged, this)); - connections.push_back(controller->AddStyleRangesChangedListener(&AudioDisplay::OnStyleRangesChanged, this)); + connections.push_back(controller->AddTimingControllerListener(&AudioDisplay::OnTimingController, this)); connections.push_back(OPT_SUB("Audio/Spectrum", &AudioDisplay::ReloadRenderingSettings, this)); connections.push_back(OPT_SUB("Audio/Display/Waveform Style", &AudioDisplay::ReloadRenderingSettings, this)); connections.push_back(OPT_SUB("Colour/Audio Display/Spectrum", &AudioDisplay::ReloadRenderingSettings, this)); @@ -1183,6 +1181,20 @@ void AudioDisplay::OnAudioOpen(AudioProvider *provider) } } +void AudioDisplay::OnTimingController() +{ + AudioTimingController *timing_controller = controller->GetTimingController(); + if (timing_controller) + { + timing_controller->AddMarkerMovedListener(&AudioDisplay::OnMarkerMoved, this); + timing_controller->AddUpdatedPrimaryRangeListener(&AudioDisplay::OnSelectionChanged, this); + timing_controller->AddUpdatedStyleRangesListener(&AudioDisplay::OnStyleRangesChanged, this); + + OnStyleRangesChanged(); + OnMarkerMoved(); + } +} + void AudioDisplay::OnPlaybackPosition(int ms) { int pixel_position = AbsoluteXFromTime(ms); diff --git a/aegisub/src/audio_display.h b/aegisub/src/audio_display.h index 07e47e5a4..d9ec7c069 100644 --- a/aegisub/src/audio_display.h +++ b/aegisub/src/audio_display.h @@ -49,10 +49,12 @@ namespace agi { struct Context; } +class AudioController; class AudioRenderer; class AudioRendererBitmapProvider; class AudioKaraoke; class AudioProvider; +class TimeRange; // Helper classes used in implementation of the audio display class AudioDisplayScrollbar; @@ -113,7 +115,6 @@ class AudioDisplay: public wxWindow { /// The controller managing us AudioController *controller; - /// Scrollbar helper object agi::scoped_ptr scrollbar; @@ -223,6 +224,7 @@ class AudioDisplay: public wxWindow { void OnPlaybackPosition(int ms_position); void OnSelectionChanged(); void OnStyleRangesChanged(); + void OnTimingController(); void OnMarkerMoved(); public: diff --git a/aegisub/src/audio_karaoke.cpp b/aegisub/src/audio_karaoke.cpp index 51bd762e4..2d84a350e 100644 --- a/aegisub/src/audio_karaoke.cpp +++ b/aegisub/src/audio_karaoke.cpp @@ -47,6 +47,7 @@ #include "ass_karaoke.h" #include "ass_override.h" #include "audio_box.h" +#include "audio_controller.h" #include "audio_timing.h" #include "libresrc/libresrc.h" #include "main.h" diff --git a/aegisub/src/audio_marker_provider_keyframes.cpp b/aegisub/src/audio_marker.cpp similarity index 64% rename from aegisub/src/audio_marker_provider_keyframes.cpp rename to aegisub/src/audio_marker.cpp index d2eb6ba1b..46e709d89 100644 --- a/aegisub/src/audio_marker_provider_keyframes.cpp +++ b/aegisub/src/audio_marker.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2011, Thomas Goyne +// Copyright (c) 2012, Thomas Goyne // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -16,14 +16,14 @@ // // $Id$ -/// @file audio_marker_provider_keyframes.cpp -/// @see audio_marker_provider_keyframes.h +/// @file audio_marker.cpp +/// @see audio_marker.h /// @ingroup audio_ui /// #include "config.h" -#include "audio_marker_provider_keyframes.h" +#include "audio_marker.h" #include "include/aegisub/context.h" #include "main.h" @@ -49,7 +49,6 @@ public: AudioMarkerProviderKeyframes::AudioMarkerProviderKeyframes(agi::Context *c, const char *opt_name) : vc(c->videoController) , keyframe_slot(vc->AddKeyframesListener(&AudioMarkerProviderKeyframes::Update, this)) -, audio_open_slot(c->audioController->AddAudioOpenListener(&AudioMarkerProviderKeyframes::Update, this)) , timecode_slot(vc->AddTimecodesListener(&AudioMarkerProviderKeyframes::Update, this)) , enabled_slot(OPT_SUB(opt_name, &AudioMarkerProviderKeyframes::Update, this)) , enabled_opt(OPT_GET(opt_name)) @@ -90,3 +89,55 @@ void AudioMarkerProviderKeyframes::GetMarkers(TimeRange const& range, AudioMarke for (; a != b; ++a) out.push_back(&*a); } + +class VideoPositionMarker : public AudioMarker { + Pen style; + int position; + +public: + VideoPositionMarker() + : style("Colour/Audio Display/Play Cursor") + , position(-1) + { + } + + void SetPosition(int new_pos) { position = new_pos; } + + int GetPosition() const { return position; } + FeetStyle GetFeet() const { return Feet_None; } + bool CanSnap() const { return true; } + wxPen GetStyle() const { return style; } + operator int() const { return position; } +}; + +VideoPositionMarkerProvider::VideoPositionMarkerProvider(agi::Context *c) +: vc(c->videoController) +, video_seek_slot(vc->AddSeekListener(&VideoPositionMarkerProvider::Update, this)) +, enable_opt_changed_slot(OPT_SUB("Audio/Display/Draw/Video Position", &VideoPositionMarkerProvider::OptChanged, this)) +{ + OptChanged(*OPT_GET("Audio/Display/Draw/Video Position")); +} + +VideoPositionMarkerProvider::~VideoPositionMarkerProvider() { } + +void VideoPositionMarkerProvider::Update(int frame_number) { + marker->SetPosition(vc->TimeAtFrame(frame_number)); + AnnounceMarkerMoved(); +} + +void VideoPositionMarkerProvider::OptChanged(agi::OptionValue const& opt) { + if (opt.GetBool()) { + video_seek_slot.Unblock(); + marker.reset(new VideoPositionMarker); + marker->SetPosition(vc->GetFrameN()); + } + else { + video_seek_slot.Block(); + marker.reset(); + } +} + +void VideoPositionMarkerProvider::GetMarkers(const TimeRange &range, AudioMarkerVector &out) const { + if (marker && range.contains(*marker)) + out.push_back(marker.get()); +} diff --git a/aegisub/src/audio_marker.h b/aegisub/src/audio_marker.h new file mode 100644 index 000000000..792476098 --- /dev/null +++ b/aegisub/src/audio_marker.h @@ -0,0 +1,175 @@ +// Copyright (c) 2012, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ +// +// $Id$ + +/// @file audio_marker.h +/// @see audio_marker.cpp +/// @ingroup audio_ui +/// + +#pragma once + +#include +#include + +#ifndef AGI_PRE +#include +#endif + +class AudioMarkerKeyframe; +class Pen; +class VideoContext; +class TimeRange; +class VideoPositionMarker; + +#include "time_range.h" + +namespace agi { + class OptionValue; + struct Context; +} + +/// @class AudioMarker +/// @brief A marker on the audio display +class AudioMarker { +public: + /// Describe which directions a marker has feet in + enum FeetStyle { + Feet_None = 0, + Feet_Left, + Feet_Right, + Feet_Both // Conveniently Feet_Left|Feet_Right + }; + + /// @brief Get the marker's position + /// @return The marker's position in milliseconds + virtual int GetPosition() const = 0; + + /// @brief Get the marker's drawing style + /// @return A pen object describing the marker's drawing style + virtual wxPen GetStyle() const = 0; + + /// @brief Get the marker's feet style + /// @return The marker's feet style + virtual FeetStyle GetFeet() const = 0; + + /// @brief Retrieve whether this marker participates in snapping + /// @return True if this marker may snap to other snappable markers + /// + /// If a marker being dragged returns true from this method, and another + /// marker which also returns true from this method is within range, the + /// marker being dragged will be positioned at the position of the other + /// marker if it is released while it is inside snapping range. + virtual bool CanSnap() const = 0; +}; + +typedef std::vector AudioMarkerVector; + +/// Abstract interface for audio marker providers +class AudioMarkerProvider { +protected: + /// One or more of the markers provided by this object have changed + agi::signal::Signal<> AnnounceMarkerMoved; +public: + /// Virtual destructor, does nothing + virtual ~AudioMarkerProvider() { } + + /// @brief Return markers in a time range + virtual void GetMarkers(const TimeRange &range, AudioMarkerVector &out) const = 0; + + DEFINE_SIGNAL_ADDERS(AnnounceMarkerMoved, AddMarkerMovedListener) +}; + +/// @class AudioLabelProvider +/// @brief Abstract interface for audio label providers +class AudioLabelProvider { +protected: + /// One or more of the labels provided by this object have changed + agi::signal::Signal<> AnnounceLabelChanged; +public: + /// A label for a range of time on the audio display + struct AudioLabel { + /// Text of the label + wxString text; + /// Range which this label applies to + TimeRange range; + AudioLabel(wxString const& text, TimeRange const& range) : text(text), range(range) { } + }; + + /// Virtual destructor, does nothing + virtual ~AudioLabelProvider() { } + + /// @brief Get labels in a time range + /// @param range Range of times to get labels for + /// @param[out] out Vector which should be filled with the labels + virtual void GetLabels(TimeRange const& range, std::vector &out) const = 0; + + DEFINE_SIGNAL_ADDERS(AnnounceLabelChanged, AddLabelChangedListener) +}; + + +/// Marker provider for video keyframes +class AudioMarkerProviderKeyframes : public AudioMarkerProvider { + /// Video controller to get keyframes from + VideoContext *vc; + + agi::signal::Connection keyframe_slot; + agi::signal::Connection timecode_slot; + agi::signal::Connection enabled_slot; + const agi::OptionValue *enabled_opt; + + /// Current set of markers for the keyframes + std::vector markers; + + /// Pen used for all keyframe markers, stored here for performance reasons + agi::scoped_ptr style; + + /// Regenerate the list of markers + void Update(); + +public: + /// Constructor + /// @param c Project context; must have audio and video controllers initialized + /// @param opt_name Name of the option to use to decide whether or not this provider is enabled + AudioMarkerProviderKeyframes(agi::Context *c, const char *opt_name); + /// Explicit destructor needed due to members with incomplete types + ~AudioMarkerProviderKeyframes(); + + /// Get all keyframe markers within a range + /// @param range Time range to get markers for + /// @param[out] out Vector to fill with markers in the range + void GetMarkers(TimeRange const& range, AudioMarkerVector &out) const; +}; + +/// Marker provider for the current video playback position +class VideoPositionMarkerProvider : public AudioMarkerProvider { + VideoContext *vc; + + agi::scoped_ptr marker; + + agi::signal::Connection video_seek_slot; + agi::signal::Connection enable_opt_changed_slot; + + void Update(int frame_number); + void OptChanged(agi::OptionValue const& opt); + +public: + VideoPositionMarkerProvider(agi::Context *c); + ~VideoPositionMarkerProvider(); + + void GetMarkers(const TimeRange &range, AudioMarkerVector &out) const; +}; diff --git a/aegisub/src/audio_marker_provider_keyframes.h b/aegisub/src/audio_marker_provider_keyframes.h deleted file mode 100644 index bc2fd5a12..000000000 --- a/aegisub/src/audio_marker_provider_keyframes.h +++ /dev/null @@ -1,73 +0,0 @@ -// Copyright (c) 2011, Thomas Goyne -// -// Permission to use, copy, modify, and distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -// -// Aegisub Project http://www.aegisub.org/ -// -// $Id$ - -/// @file audio_marker_provider_keyframes.h -/// @see audio_marker_provider_keyframes.cpp -/// @ingroup audio_ui -/// - -#include "audio_controller.h" - -#include -#include - -#ifndef AGI_PRE -#include -#endif - -class AudioMarkerKeyframe; -class Pen; -class VideoContext; -namespace agi { - class OptionValue; - struct Context; -} - -/// Marker provider for video keyframes -class AudioMarkerProviderKeyframes : public AudioMarkerProvider { - /// Video controller to get keyframes from - VideoContext *vc; - - agi::signal::Connection keyframe_slot; - agi::signal::Connection audio_open_slot; - agi::signal::Connection timecode_slot; - agi::signal::Connection enabled_slot; - const agi::OptionValue *enabled_opt; - - /// Current set of markers for the keyframes - std::vector markers; - - /// Pen used for all keyframe markers, stored here for performance reasons - agi::scoped_ptr style; - - /// Regenerate the list of markers - void Update(); - -public: - /// Constructor - /// @param c Project context; must have audio and video controllers initialized - /// @param opt_name Name of the option to use to decide whether or not this provider is enabled - AudioMarkerProviderKeyframes(agi::Context *c, const char *opt_name); - /// Explicit destructor needed due to members with incomplete types - ~AudioMarkerProviderKeyframes(); - - /// Get all keyframe markers within a range - /// @param range Range of samples to get markers for - /// @param[out] out Vector to fill with markers in the range - void GetMarkers(TimeRange const& range, AudioMarkerVector &out) const; -}; diff --git a/aegisub/src/audio_timing.h b/aegisub/src/audio_timing.h index c3ce1d237..730300f40 100644 --- a/aegisub/src/audio_timing.h +++ b/aegisub/src/audio_timing.h @@ -39,11 +39,9 @@ class AssKaraoke; class AudioRenderingStyleRanges; namespace agi { struct Context; } -#include "audio_controller.h" +#include "audio_marker.h" #include "selection_controller.h" -#include - /// @class AudioTimingController /// @brief Base class for objects controlling audio timing /// diff --git a/aegisub/src/audio_timing_dialogue.cpp b/aegisub/src/audio_timing_dialogue.cpp index c1d36de08..86ea88c16 100644 --- a/aegisub/src/audio_timing_dialogue.cpp +++ b/aegisub/src/audio_timing_dialogue.cpp @@ -42,7 +42,6 @@ #include "ass_dialogue.h" #include "ass_file.h" #include "ass_time.h" -#include "audio_marker_provider_keyframes.h" #include "audio_renderer.h" #include "audio_timing.h" #include "include/aegisub/context.h" @@ -158,6 +157,9 @@ class AudioTimingControllerDialogue : public AudioTimingController, private Sele /// Marker provider for video keyframes AudioMarkerProviderKeyframes keyframes_provider; + /// Marker provider for video playback position + VideoPositionMarkerProvider video_position_provider; + /// Has the timing been modified by the user? /// If auto commit is enabled this will only be true very briefly following /// changes @@ -294,6 +296,7 @@ void AudioMarkerDialogueTiming::InitPair(AudioMarkerDialogueTiming *marker1, Aud AudioTimingControllerDialogue::AudioTimingControllerDialogue(agi::Context *c) : keyframes_provider(c, "Audio/Display/Draw/Keyframes in Dialogue Mode") +, video_position_provider(c) , timing_modified(false) , commit_id(-1) , context(c) @@ -308,6 +311,7 @@ AudioTimingControllerDialogue::AudioTimingControllerDialogue(agi::Context *c) c->selectionController->AddSelectionListener(this); keyframes_provider.AddMarkerMovedListener(std::tr1::bind(std::tr1::ref(AnnounceMarkerMoved))); + video_position_provider.AddMarkerMovedListener(std::tr1::bind(std::tr1::ref(AnnounceMarkerMoved))); Revert(); } @@ -357,6 +361,7 @@ void AudioTimingControllerDialogue::GetMarkers(const TimeRange &range, AudioMark out_markers.push_back(&active_markers[1]); keyframes_provider.GetMarkers(range, out_markers); + video_position_provider.GetMarkers(range, out_markers); } void AudioTimingControllerDialogue::OnActiveLineChanged(AssDialogue *new_line) diff --git a/aegisub/src/audio_timing_karaoke.cpp b/aegisub/src/audio_timing_karaoke.cpp index 9020adb5e..9d46245da 100644 --- a/aegisub/src/audio_timing_karaoke.cpp +++ b/aegisub/src/audio_timing_karaoke.cpp @@ -28,7 +28,7 @@ #include "ass_dialogue.h" #include "ass_file.h" #include "ass_karaoke.h" -#include "audio_marker_provider_keyframes.h" +#include "audio_controller.h" #include "audio_renderer.h" #include "audio_timing.h" #include "include/aegisub/context.h" @@ -101,6 +101,9 @@ class AudioTimingControllerKaraoke : public AudioTimingController { /// Marker provider for video keyframes AudioMarkerProviderKeyframes keyframes_provider; + /// Marker provider for video playback position + VideoPositionMarkerProvider video_position_provider; + /// Labels containing the stripped text of each syllable std::vector labels; @@ -150,6 +153,7 @@ AudioTimingControllerKaraoke::AudioTimingControllerKaraoke(agi::Context *c, AssK , start_marker(active_line->Start, &start_pen, AudioMarker::Feet_Right) , end_marker(active_line->End, &end_pen, AudioMarker::Feet_Left) , keyframes_provider(c, "Audio/Display/Draw/Keyframes in Karaoke Mode") +, video_position_provider(c) , auto_commit(OPT_GET("Audio/Auto/Commit")->GetBool()) , auto_next(OPT_GET("Audio/Next Line on Commit")->GetBool()) , commit_id(-1) @@ -159,6 +163,7 @@ AudioTimingControllerKaraoke::AudioTimingControllerKaraoke(agi::Context *c, AssK slots.push_back(OPT_SUB("Audio/Next Line on Commit", &AudioTimingControllerKaraoke::OnAutoNextChange, this)); keyframes_provider.AddMarkerMovedListener(std::tr1::bind(std::tr1::ref(AnnounceMarkerMoved))); + video_position_provider.AddMarkerMovedListener(std::tr1::bind(std::tr1::ref(AnnounceMarkerMoved))); Revert(); @@ -231,6 +236,7 @@ void AudioTimingControllerKaraoke::GetMarkers(TimeRange const& range, AudioMarke if (range.contains(end_marker)) out.push_back(&end_marker); keyframes_provider.GetMarkers(range, out); + video_position_provider.GetMarkers(range, out); } void AudioTimingControllerKaraoke::DoCommit() { diff --git a/aegisub/src/time_range.h b/aegisub/src/time_range.h new file mode 100644 index 000000000..a77705311 --- /dev/null +++ b/aegisub/src/time_range.h @@ -0,0 +1,76 @@ +// Copyright (c) 2010, Niels Martin Hansen +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Aegisub Group nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Aegisub Project http://www.aegisub.org/ +// +// $Id$ + +/// @file time_range.h +/// @ingroup audio_ui + +/// @class TimeRange +/// @brief Represents an immutable range of time +class TimeRange { + int _begin; + int _end; + +public: + /// @brief Constructor + /// @param begin Index of the first millisecond to include in the range + /// @param end Index of one past the last millisecond to include in the range + TimeRange(int begin, int end) : _begin(begin), _end(end) + { + assert(end >= begin); + } + + /// @brief Copy constructor, optionally adjusting the range + /// @param src The range to duplicate + /// @param begin_adjust Number of milliseconds to add to the start of the range + /// @param end_adjust Number of milliseconds to add to the end of the range + TimeRange(const TimeRange &src, int begin_adjust = 0, int end_adjust = 0) + { + _begin = src._begin + begin_adjust; + _end = src._end + end_adjust; + assert(_end >= _begin); + } + + /// Get the length of the range in milliseconds + int length() const { return _end - _begin; } + /// Get the start time of the range in milliseconds + int begin() const { return _begin; } + /// Get the exclusive end time of the range in milliseconds + int end() const { return _end; } + + /// Determine whether the range contains a given time in milliseconds + bool contains(int ms) const { return ms >= begin() && ms < end(); } + + /// Determine whether there is an overlap between two ranges + bool overlaps(const TimeRange &other) const + { + return other.contains(_begin) || contains(other._begin); + } +}; diff --git a/aegisub/src/video_context.cpp b/aegisub/src/video_context.cpp index bcc1d6ede..51d3cfd5e 100644 --- a/aegisub/src/video_context.cpp +++ b/aegisub/src/video_context.cpp @@ -61,6 +61,7 @@ #include "mkv_wrap.h" #include "selection_controller.h" #include "standard_paths.h" +#include "time_range.h" #include "threaded_frame_source.h" #include "utils.h" #include "video_context.h"