From aaf7285a6ef987905a6429d0eebe5f1ca6c3e985 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Wed, 1 Feb 2012 23:59:12 +0000 Subject: [PATCH] Remove UI-related responsibilities from AudioController Keeping track of audio markers and labels to be shown in the audio display is not particularly related to AudioController's primary responsiblity of controlling the playback of audio. Originally committed to SVN as r6427. --- .../aegisub_vs2008/aegisub_vs2008.vcproj | 8 +- aegisub/src/Makefile | 2 +- aegisub/src/audio_controller.cpp | 98 ---------- aegisub/src/audio_controller.h | 168 +---------------- aegisub/src/audio_display.cpp | 26 ++- aegisub/src/audio_display.h | 4 +- aegisub/src/audio_karaoke.cpp | 1 + ...rovider_keyframes.cpp => audio_marker.cpp} | 61 +++++- aegisub/src/audio_marker.h | 175 ++++++++++++++++++ aegisub/src/audio_marker_provider_keyframes.h | 73 -------- aegisub/src/audio_timing.h | 4 +- aegisub/src/audio_timing_dialogue.cpp | 7 +- aegisub/src/audio_timing_karaoke.cpp | 8 +- aegisub/src/time_range.h | 76 ++++++++ aegisub/src/video_context.cpp | 1 + 15 files changed, 356 insertions(+), 356 deletions(-) rename aegisub/src/{audio_marker_provider_keyframes.cpp => audio_marker.cpp} (64%) create mode 100644 aegisub/src/audio_marker.h delete mode 100644 aegisub/src/audio_marker_provider_keyframes.h create mode 100644 aegisub/src/time_range.h 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"