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:
parent
01b92aa4e3
commit
aaf7285a6e
15 changed files with 356 additions and 356 deletions
|
@ -1700,11 +1700,11 @@
|
|||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\audio_marker_provider_keyframes.cpp"
|
||||
RelativePath="..\..\src\audio_marker.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\audio_marker_provider_keyframes.h"
|
||||
RelativePath="..\..\src\audio_marker.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
@ -1743,6 +1743,10 @@
|
|||
RelativePath="..\..\src\audio_timing_karaoke.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\time_range.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Video UI"
|
||||
|
|
|
@ -139,7 +139,7 @@ SRC += \
|
|||
audio_colorscheme.cpp \
|
||||
audio_display.cpp \
|
||||
audio_karaoke.cpp \
|
||||
audio_marker_provider_keyframes.cpp \
|
||||
audio_marker.cpp \
|
||||
audio_player.cpp \
|
||||
audio_provider.cpp \
|
||||
audio_provider_convert.cpp \
|
||||
|
|
|
@ -58,79 +58,6 @@
|
|||
#include "standard_paths.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)
|
||||
: 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<AudioLabel> &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;
|
||||
|
|
|
@ -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<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)
|
||||
};
|
||||
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<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
|
||||
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<AudioLabel> &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 {
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "audio_display.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -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<AudioLabelProvider::AudioLabel> 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);
|
||||
|
|
|
@ -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<AudioDisplayScrollbar> scrollbar;
|
||||
|
||||
|
@ -223,6 +224,7 @@ class AudioDisplay: public wxWindow {
|
|||
void OnPlaybackPosition(int ms_position);
|
||||
void OnSelectionChanged();
|
||||
void OnStyleRangesChanged();
|
||||
void OnTimingController();
|
||||
void OnMarkerMoved();
|
||||
|
||||
public:
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
// 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());
|
||||
}
|
175
aegisub/src/audio_marker.h
Normal file
175
aegisub/src/audio_marker.h
Normal 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;
|
||||
};
|
|
@ -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;
|
||||
};
|
|
@ -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 <libaegisub/signal.h>
|
||||
|
||||
/// @class AudioTimingController
|
||||
/// @brief Base class for objects controlling audio timing
|
||||
///
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<AudioLabel> 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() {
|
||||
|
|
76
aegisub/src/time_range.h
Normal file
76
aegisub/src/time_range.h
Normal 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);
|
||||
}
|
||||
};
|
|
@ -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"
|
||||
|
|
Loading…
Reference in a new issue