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.
This commit is contained in:
Thomas Goyne 2012-02-01 23:59:12 +00:00
parent 01b92aa4e3
commit aaf7285a6e
15 changed files with 356 additions and 356 deletions

View file

@ -1700,11 +1700,11 @@
> >
</File> </File>
<File <File
RelativePath="..\..\src\audio_marker_provider_keyframes.cpp" RelativePath="..\..\src\audio_marker.cpp"
> >
</File> </File>
<File <File
RelativePath="..\..\src\audio_marker_provider_keyframes.h" RelativePath="..\..\src\audio_marker.h"
> >
</File> </File>
<File <File
@ -1743,6 +1743,10 @@
RelativePath="..\..\src\audio_timing_karaoke.cpp" RelativePath="..\..\src\audio_timing_karaoke.cpp"
> >
</File> </File>
<File
RelativePath="..\..\src\time_range.h"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="Video UI" Name="Video UI"

View file

@ -139,7 +139,7 @@ SRC += \
audio_colorscheme.cpp \ audio_colorscheme.cpp \
audio_display.cpp \ audio_display.cpp \
audio_karaoke.cpp \ audio_karaoke.cpp \
audio_marker_provider_keyframes.cpp \ audio_marker.cpp \
audio_player.cpp \ audio_player.cpp \
audio_provider.cpp \ audio_provider.cpp \
audio_provider_convert.cpp \ audio_provider_convert.cpp \

View file

@ -58,79 +58,6 @@
#include "standard_paths.h" #include "standard_paths.h"
#include "video_context.h" #include "video_context.h"
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; }
};
class VideoPositionMarkerProvider : public AudioMarkerProvider {
VideoContext *vc;
VideoPositionMarker marker;
agi::signal::Connection video_seek_slot;
agi::signal::Connection enable_opt_changed_slot;
void Update(int frame_number)
{
if (frame_number == -1)
{
marker.SetPosition(-1);
}
else
{
marker.SetPosition(vc->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) AudioController::AudioController(agi::Context *context)
: context(context) : context(context)
, subtitle_save_slot(context->ass->AddFileSaveListener(&AudioController::OnSubtitlesSave, this)) , 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)); 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 try
{ {
// Tell listeners about this. // Tell listeners about this.
@ -371,10 +292,7 @@ void AudioController::SetTimingController(AudioTimingController *new_controller)
timing_controller.reset(new_controller); timing_controller.reset(new_controller);
if (timing_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->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()); player->SetEndPosition(timing_controller->GetPrimaryPlaybackRange().end());
} }
AnnounceSelectionChanged();
} }
void AudioController::OnSubtitlesSave() 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<AudioLabel> &labels) const
{
if (timing_controller) timing_controller->GetLabels(range, labels);
}
double AudioController::GetVolume() const double AudioController::GetVolume() const
{ {
if (!IsAudioOpen()) return 1.0; if (!IsAudioOpen()) return 1.0;
return player->GetVolume(); return player->GetVolume();
} }
void AudioController::SetVolume(double volume) void AudioController::SetVolume(double volume)
{ {
if (!IsAudioOpen()) return; if (!IsAudioOpen()) return;

View file

@ -54,115 +54,12 @@
class AudioPlayer; class AudioPlayer;
class AudioProvider; class AudioProvider;
namespace agi { struct Context; }
// Declared below
class AudioControllerAudioEventListener;
class AudioControllerTimingEventListener;
class AudioTimingController; class AudioTimingController;
class AudioMarker; namespace agi { struct Context; }
class AudioMarkerProvider; class TimeRange;
typedef std::vector<const AudioMarker*> 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<AudioLabel> &out) const = 0;
DEFINE_SIGNAL_ADDERS(AnnounceLabelChanged, AddLabelChangedListener)
};
/// @class AudioController /// @class AudioController
/// @brief Manage an open audio stream and UI state for it /// @brief Manage an open audio stream
///
/// 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.
/// ///
/// Creates and destroys audio providers and players. This behaviour should at /// Creates and destroys audio providers and players. This behaviour should at
/// some point be moved to a separate class, as it adds too many /// 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 /// providers or players owned by a controller. If some operation that isn't
/// possible in the existing design is needed, the controller should be /// possible in the existing design is needed, the controller should be
/// extended in some way to allow it. /// 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 /// Project context this controller belongs to
agi::Context *context; agi::Context *context;
@ -195,12 +92,6 @@ class AudioController : public wxEvtHandler, public AudioMarkerProvider, public
/// The timing controller was replaced /// The timing controller was replaced
agi::signal::Signal<> AnnounceTimingControllerChanged; 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 /// The audio output object
AudioPlayer *player; AudioPlayer *player;
@ -210,9 +101,6 @@ class AudioController : public wxEvtHandler, public AudioMarkerProvider, public
/// The current timing mode, if any; owned by the audio controller /// The current timing mode, if any; owned by the audio controller
agi::scoped_ptr<AudioTimingController> timing_controller; agi::scoped_ptr<AudioTimingController> timing_controller;
/// Provider current video position data for audio display
agi::scoped_ptr<AudioMarkerProvider> video_position_marker_provider;
/// The URL of the currently open audio, if any /// The URL of the currently open audio, if any
wxString audio_url; wxString audio_url;
@ -356,17 +244,6 @@ public:
/// @return An immutable TimeRange object /// @return An immutable TimeRange object
TimeRange GetPrimaryPlaybackRange() const; 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<AudioLabel> &labels) const;
/// @brief Get the playback audio volume /// @brief Get the playback audio volume
/// @return The amplification factor for the audio /// @return The amplification factor for the audio
double GetVolume() const; double GetVolume() const;
@ -396,43 +273,6 @@ public:
DEFINE_SIGNAL_ADDERS(AnnouncePlaybackPosition, AddPlaybackPositionListener) DEFINE_SIGNAL_ADDERS(AnnouncePlaybackPosition, AddPlaybackPositionListener)
DEFINE_SIGNAL_ADDERS(AnnouncePlaybackStop, AddPlaybackStopListener) DEFINE_SIGNAL_ADDERS(AnnouncePlaybackStop, AddPlaybackStopListener)
DEFINE_SIGNAL_ADDERS(AnnounceTimingControllerChanged, AddTimingControllerListener) 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 { namespace agi {

View file

@ -37,6 +37,8 @@
#include "config.h" #include "config.h"
#include "audio_display.h"
#ifndef AGI_PRE #ifndef AGI_PRE
#include <algorithm> #include <algorithm>
@ -48,7 +50,6 @@
#include "ass_time.h" #include "ass_time.h"
#include "audio_colorscheme.h" #include "audio_colorscheme.h"
#include "audio_controller.h" #include "audio_controller.h"
#include "audio_display.h"
#include "audio_renderer.h" #include "audio_renderer.h"
#include "audio_renderer_spectrum.h" #include "audio_renderer_spectrum.h"
#include "audio_renderer_waveform.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) void AudioDisplay::PaintMarkers(wxDC &dc, TimeRange updtime)
{ {
AudioMarkerVector markers; AudioMarkerVector markers;
controller->GetMarkers(updtime, markers); controller->GetTimingController()->GetMarkers(updtime, markers);
if (markers.empty()) return; if (markers.empty()) return;
wxDCPenChanger pen_retainer(dc, wxPen()); 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) void AudioDisplay::PaintLabels(wxDC &dc, TimeRange updtime)
{ {
std::vector<AudioLabelProvider::AudioLabel> labels; std::vector<AudioLabelProvider::AudioLabel> labels;
controller->GetLabels(updtime, labels); controller->GetTimingController()->GetLabels(updtime, labels);
if (labels.empty()) return; if (labels.empty()) return;
wxDCFontChanger fc(dc); 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->AddAudioCloseListener(&AudioDisplay::OnAudioOpen, this, (AudioProvider*)0));
connections.push_back(controller->AddPlaybackPositionListener(&AudioDisplay::OnPlaybackPosition, this)); connections.push_back(controller->AddPlaybackPositionListener(&AudioDisplay::OnPlaybackPosition, this));
connections.push_back(controller->AddPlaybackStopListener(&AudioDisplay::RemoveTrackCursor, this)); connections.push_back(controller->AddPlaybackStopListener(&AudioDisplay::RemoveTrackCursor, this));
connections.push_back(controller->AddTimingControllerListener(&AudioDisplay::OnStyleRangesChanged, this)); connections.push_back(controller->AddTimingControllerListener(&AudioDisplay::OnTimingController, 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(OPT_SUB("Audio/Spectrum", &AudioDisplay::ReloadRenderingSettings, 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("Audio/Display/Waveform Style", &AudioDisplay::ReloadRenderingSettings, this));
connections.push_back(OPT_SUB("Colour/Audio Display/Spectrum", &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) void AudioDisplay::OnPlaybackPosition(int ms)
{ {
int pixel_position = AbsoluteXFromTime(ms); int pixel_position = AbsoluteXFromTime(ms);

View file

@ -49,10 +49,12 @@
namespace agi { struct Context; } namespace agi { struct Context; }
class AudioController;
class AudioRenderer; class AudioRenderer;
class AudioRendererBitmapProvider; class AudioRendererBitmapProvider;
class AudioKaraoke; class AudioKaraoke;
class AudioProvider; class AudioProvider;
class TimeRange;
// Helper classes used in implementation of the audio display // Helper classes used in implementation of the audio display
class AudioDisplayScrollbar; class AudioDisplayScrollbar;
@ -113,7 +115,6 @@ class AudioDisplay: public wxWindow {
/// The controller managing us /// The controller managing us
AudioController *controller; AudioController *controller;
/// Scrollbar helper object /// Scrollbar helper object
agi::scoped_ptr<AudioDisplayScrollbar> scrollbar; agi::scoped_ptr<AudioDisplayScrollbar> scrollbar;
@ -223,6 +224,7 @@ class AudioDisplay: public wxWindow {
void OnPlaybackPosition(int ms_position); void OnPlaybackPosition(int ms_position);
void OnSelectionChanged(); void OnSelectionChanged();
void OnStyleRangesChanged(); void OnStyleRangesChanged();
void OnTimingController();
void OnMarkerMoved(); void OnMarkerMoved();
public: public:

View file

@ -47,6 +47,7 @@
#include "ass_karaoke.h" #include "ass_karaoke.h"
#include "ass_override.h" #include "ass_override.h"
#include "audio_box.h" #include "audio_box.h"
#include "audio_controller.h"
#include "audio_timing.h" #include "audio_timing.h"
#include "libresrc/libresrc.h" #include "libresrc/libresrc.h"
#include "main.h" #include "main.h"

View file

@ -1,4 +1,4 @@
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org> // Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
// //
// Permission to use, copy, modify, and distribute this software for any // Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above // purpose with or without fee is hereby granted, provided that the above
@ -16,14 +16,14 @@
// //
// $Id$ // $Id$
/// @file audio_marker_provider_keyframes.cpp /// @file audio_marker.cpp
/// @see audio_marker_provider_keyframes.h /// @see audio_marker.h
/// @ingroup audio_ui /// @ingroup audio_ui
/// ///
#include "config.h" #include "config.h"
#include "audio_marker_provider_keyframes.h" #include "audio_marker.h"
#include "include/aegisub/context.h" #include "include/aegisub/context.h"
#include "main.h" #include "main.h"
@ -49,7 +49,6 @@ public:
AudioMarkerProviderKeyframes::AudioMarkerProviderKeyframes(agi::Context *c, const char *opt_name) AudioMarkerProviderKeyframes::AudioMarkerProviderKeyframes(agi::Context *c, const char *opt_name)
: vc(c->videoController) : vc(c->videoController)
, keyframe_slot(vc->AddKeyframesListener(&AudioMarkerProviderKeyframes::Update, this)) , keyframe_slot(vc->AddKeyframesListener(&AudioMarkerProviderKeyframes::Update, this))
, audio_open_slot(c->audioController->AddAudioOpenListener(&AudioMarkerProviderKeyframes::Update, this))
, timecode_slot(vc->AddTimecodesListener(&AudioMarkerProviderKeyframes::Update, this)) , timecode_slot(vc->AddTimecodesListener(&AudioMarkerProviderKeyframes::Update, this))
, enabled_slot(OPT_SUB(opt_name, &AudioMarkerProviderKeyframes::Update, this)) , enabled_slot(OPT_SUB(opt_name, &AudioMarkerProviderKeyframes::Update, this))
, enabled_opt(OPT_GET(opt_name)) , enabled_opt(OPT_GET(opt_name))
@ -90,3 +89,55 @@ void AudioMarkerProviderKeyframes::GetMarkers(TimeRange const& range, AudioMarke
for (; a != b; ++a) for (; a != b; ++a)
out.push_back(&*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());
}

175
aegisub/src/audio_marker.h Normal file
View file

@ -0,0 +1,175 @@
// Copyright (c) 2012, Thomas Goyne <plorkyeran@aegisub.org>
//
// 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 <libaegisub/scoped_ptr.h>
#include <libaegisub/signal.h>
#ifndef AGI_PRE
#include <vector>
#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<const AudioMarker*> 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<AudioLabel> &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<AudioMarkerKeyframe> markers;
/// Pen used for all keyframe markers, stored here for performance reasons
agi::scoped_ptr<Pen> 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<VideoPositionMarker> 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;
};

View file

@ -1,73 +0,0 @@
// Copyright (c) 2011, Thomas Goyne <plorkyeran@aegisub.org>
//
// 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 <libaegisub/scoped_ptr.h>
#include <libaegisub/signal.h>
#ifndef AGI_PRE
#include <vector>
#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<AudioMarkerKeyframe> markers;
/// Pen used for all keyframe markers, stored here for performance reasons
agi::scoped_ptr<Pen> 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;
};

View file

@ -39,11 +39,9 @@ class AssKaraoke;
class AudioRenderingStyleRanges; class AudioRenderingStyleRanges;
namespace agi { struct Context; } namespace agi { struct Context; }
#include "audio_controller.h" #include "audio_marker.h"
#include "selection_controller.h" #include "selection_controller.h"
#include <libaegisub/signal.h>
/// @class AudioTimingController /// @class AudioTimingController
/// @brief Base class for objects controlling audio timing /// @brief Base class for objects controlling audio timing
/// ///

View file

@ -42,7 +42,6 @@
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "ass_file.h" #include "ass_file.h"
#include "ass_time.h" #include "ass_time.h"
#include "audio_marker_provider_keyframes.h"
#include "audio_renderer.h" #include "audio_renderer.h"
#include "audio_timing.h" #include "audio_timing.h"
#include "include/aegisub/context.h" #include "include/aegisub/context.h"
@ -158,6 +157,9 @@ class AudioTimingControllerDialogue : public AudioTimingController, private Sele
/// Marker provider for video keyframes /// Marker provider for video keyframes
AudioMarkerProviderKeyframes keyframes_provider; AudioMarkerProviderKeyframes keyframes_provider;
/// Marker provider for video playback position
VideoPositionMarkerProvider video_position_provider;
/// Has the timing been modified by the user? /// Has the timing been modified by the user?
/// If auto commit is enabled this will only be true very briefly following /// If auto commit is enabled this will only be true very briefly following
/// changes /// changes
@ -294,6 +296,7 @@ void AudioMarkerDialogueTiming::InitPair(AudioMarkerDialogueTiming *marker1, Aud
AudioTimingControllerDialogue::AudioTimingControllerDialogue(agi::Context *c) AudioTimingControllerDialogue::AudioTimingControllerDialogue(agi::Context *c)
: keyframes_provider(c, "Audio/Display/Draw/Keyframes in Dialogue Mode") : keyframes_provider(c, "Audio/Display/Draw/Keyframes in Dialogue Mode")
, video_position_provider(c)
, timing_modified(false) , timing_modified(false)
, commit_id(-1) , commit_id(-1)
, context(c) , context(c)
@ -308,6 +311,7 @@ AudioTimingControllerDialogue::AudioTimingControllerDialogue(agi::Context *c)
c->selectionController->AddSelectionListener(this); c->selectionController->AddSelectionListener(this);
keyframes_provider.AddMarkerMovedListener(std::tr1::bind(std::tr1::ref(AnnounceMarkerMoved))); keyframes_provider.AddMarkerMovedListener(std::tr1::bind(std::tr1::ref(AnnounceMarkerMoved)));
video_position_provider.AddMarkerMovedListener(std::tr1::bind(std::tr1::ref(AnnounceMarkerMoved)));
Revert(); Revert();
} }
@ -357,6 +361,7 @@ void AudioTimingControllerDialogue::GetMarkers(const TimeRange &range, AudioMark
out_markers.push_back(&active_markers[1]); out_markers.push_back(&active_markers[1]);
keyframes_provider.GetMarkers(range, out_markers); keyframes_provider.GetMarkers(range, out_markers);
video_position_provider.GetMarkers(range, out_markers);
} }
void AudioTimingControllerDialogue::OnActiveLineChanged(AssDialogue *new_line) void AudioTimingControllerDialogue::OnActiveLineChanged(AssDialogue *new_line)

View file

@ -28,7 +28,7 @@
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "ass_file.h" #include "ass_file.h"
#include "ass_karaoke.h" #include "ass_karaoke.h"
#include "audio_marker_provider_keyframes.h" #include "audio_controller.h"
#include "audio_renderer.h" #include "audio_renderer.h"
#include "audio_timing.h" #include "audio_timing.h"
#include "include/aegisub/context.h" #include "include/aegisub/context.h"
@ -101,6 +101,9 @@ class AudioTimingControllerKaraoke : public AudioTimingController {
/// Marker provider for video keyframes /// Marker provider for video keyframes
AudioMarkerProviderKeyframes keyframes_provider; AudioMarkerProviderKeyframes keyframes_provider;
/// Marker provider for video playback position
VideoPositionMarkerProvider video_position_provider;
/// Labels containing the stripped text of each syllable /// Labels containing the stripped text of each syllable
std::vector<AudioLabel> labels; std::vector<AudioLabel> labels;
@ -150,6 +153,7 @@ AudioTimingControllerKaraoke::AudioTimingControllerKaraoke(agi::Context *c, AssK
, start_marker(active_line->Start, &start_pen, AudioMarker::Feet_Right) , start_marker(active_line->Start, &start_pen, AudioMarker::Feet_Right)
, end_marker(active_line->End, &end_pen, AudioMarker::Feet_Left) , end_marker(active_line->End, &end_pen, AudioMarker::Feet_Left)
, keyframes_provider(c, "Audio/Display/Draw/Keyframes in Karaoke Mode") , keyframes_provider(c, "Audio/Display/Draw/Keyframes in Karaoke Mode")
, video_position_provider(c)
, auto_commit(OPT_GET("Audio/Auto/Commit")->GetBool()) , auto_commit(OPT_GET("Audio/Auto/Commit")->GetBool())
, auto_next(OPT_GET("Audio/Next Line on Commit")->GetBool()) , auto_next(OPT_GET("Audio/Next Line on Commit")->GetBool())
, commit_id(-1) , 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)); slots.push_back(OPT_SUB("Audio/Next Line on Commit", &AudioTimingControllerKaraoke::OnAutoNextChange, this));
keyframes_provider.AddMarkerMovedListener(std::tr1::bind(std::tr1::ref(AnnounceMarkerMoved))); keyframes_provider.AddMarkerMovedListener(std::tr1::bind(std::tr1::ref(AnnounceMarkerMoved)));
video_position_provider.AddMarkerMovedListener(std::tr1::bind(std::tr1::ref(AnnounceMarkerMoved)));
Revert(); Revert();
@ -231,6 +236,7 @@ void AudioTimingControllerKaraoke::GetMarkers(TimeRange const& range, AudioMarke
if (range.contains(end_marker)) out.push_back(&end_marker); if (range.contains(end_marker)) out.push_back(&end_marker);
keyframes_provider.GetMarkers(range, out); keyframes_provider.GetMarkers(range, out);
video_position_provider.GetMarkers(range, out);
} }
void AudioTimingControllerKaraoke::DoCommit() { void AudioTimingControllerKaraoke::DoCommit() {

76
aegisub/src/time_range.h Normal file
View file

@ -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);
}
};

View file

@ -61,6 +61,7 @@
#include "mkv_wrap.h" #include "mkv_wrap.h"
#include "selection_controller.h" #include "selection_controller.h"
#include "standard_paths.h" #include "standard_paths.h"
#include "time_range.h"
#include "threaded_frame_source.h" #include "threaded_frame_source.h"
#include "utils.h" #include "utils.h"
#include "video_context.h" #include "video_context.h"