forked from mia/Aegisub
Use signals in AudioController and AudioTimingController
Originally committed to SVN as r4907.
This commit is contained in:
parent
3bb1f590d7
commit
3345797ff6
31 changed files with 222 additions and 448 deletions
|
@ -39,7 +39,6 @@
|
||||||
#include "ass_export_filter.h"
|
#include "ass_export_filter.h"
|
||||||
#include "ass_exporter.h"
|
#include "ass_exporter.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
|
|
|
@ -425,8 +425,8 @@ void AudioBox::OnPrev(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnPlay500Before(wxCommandEvent &event) {
|
void AudioBox::OnPlay500Before(wxCommandEvent &event) {
|
||||||
AudioController::SampleRange times(controller->GetPrimaryPlaybackRange());
|
SampleRange times(controller->GetPrimaryPlaybackRange());
|
||||||
controller->PlayRange(AudioController::SampleRange(
|
controller->PlayRange(SampleRange(
|
||||||
times.begin() - controller->SamplesFromMilliseconds(500),
|
times.begin() - controller->SamplesFromMilliseconds(500),
|
||||||
times.begin()));
|
times.begin()));
|
||||||
}
|
}
|
||||||
|
@ -437,8 +437,8 @@ void AudioBox::OnPlay500Before(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnPlay500After(wxCommandEvent &event) {
|
void AudioBox::OnPlay500After(wxCommandEvent &event) {
|
||||||
AudioController::SampleRange times(controller->GetPrimaryPlaybackRange());
|
SampleRange times(controller->GetPrimaryPlaybackRange());
|
||||||
controller->PlayRange(AudioController::SampleRange(
|
controller->PlayRange(SampleRange(
|
||||||
times.end(),
|
times.end(),
|
||||||
times.end() + controller->SamplesFromMilliseconds(500)));
|
times.end() + controller->SamplesFromMilliseconds(500)));
|
||||||
}
|
}
|
||||||
|
@ -449,8 +449,8 @@ void AudioBox::OnPlay500After(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnPlay500First(wxCommandEvent &event) {
|
void AudioBox::OnPlay500First(wxCommandEvent &event) {
|
||||||
AudioController::SampleRange times(controller->GetPrimaryPlaybackRange());
|
SampleRange times(controller->GetPrimaryPlaybackRange());
|
||||||
controller->PlayRange(AudioController::SampleRange(
|
controller->PlayRange(SampleRange(
|
||||||
times.begin(),
|
times.begin(),
|
||||||
times.begin() + std::min(
|
times.begin() + std::min(
|
||||||
controller->SamplesFromMilliseconds(500),
|
controller->SamplesFromMilliseconds(500),
|
||||||
|
@ -463,8 +463,8 @@ void AudioBox::OnPlay500First(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void AudioBox::OnPlay500Last(wxCommandEvent &event) {
|
void AudioBox::OnPlay500Last(wxCommandEvent &event) {
|
||||||
AudioController::SampleRange times(controller->GetPrimaryPlaybackRange());
|
SampleRange times(controller->GetPrimaryPlaybackRange());
|
||||||
controller->PlayRange(AudioController::SampleRange(
|
controller->PlayRange(SampleRange(
|
||||||
times.end() - std::min(
|
times.end() - std::min(
|
||||||
controller->SamplesFromMilliseconds(500),
|
controller->SamplesFromMilliseconds(500),
|
||||||
times.length()),
|
times.length()),
|
||||||
|
|
|
@ -54,14 +54,11 @@
|
||||||
#include <wx/tglbtn.h>
|
#include <wx/tglbtn.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef AGI_AUDIO_CONTROLLER_INCLUDED
|
|
||||||
#error You must include "audio_controller.h" before "audio_box.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
//////////////
|
//////////////
|
||||||
// Prototypes
|
// Prototypes
|
||||||
|
class AudioController;
|
||||||
class AssDialogue;
|
class AssDialogue;
|
||||||
|
class AudioTimingController;
|
||||||
class AudioDisplay;
|
class AudioDisplay;
|
||||||
class AudioKaraoke;
|
class AudioKaraoke;
|
||||||
class FrameMain;
|
class FrameMain;
|
||||||
|
@ -80,7 +77,7 @@ class AudioBox : public wxPanel {
|
||||||
/// Selection controller used for timing controllers
|
/// Selection controller used for timing controllers
|
||||||
SelectionController<AssDialogue> *selection_controller;
|
SelectionController<AssDialogue> *selection_controller;
|
||||||
|
|
||||||
/// The regular dalogue timing controller
|
/// The regular dialogue timing controller
|
||||||
AudioTimingController *timing_controller_dialogue;
|
AudioTimingController *timing_controller_dialogue;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
|
|
|
@ -74,71 +74,51 @@ bool operator < (int64_t a, const AudioMarkerKeyframe &b) { return a < b.GetPosi
|
||||||
bool operator < (const AudioMarkerKeyframe &a, int64_t b) { return a.GetPosition() < b; }
|
bool operator < (const AudioMarkerKeyframe &a, int64_t b) { return a.GetPosition() < b; }
|
||||||
wxPen AudioMarkerKeyframe::style;
|
wxPen AudioMarkerKeyframe::style;
|
||||||
|
|
||||||
class AudioMarkerProviderKeyframes : public AudioMarkerProvider, private AudioControllerAudioEventListener {
|
class AudioMarkerProviderKeyframes : public AudioMarkerProvider {
|
||||||
// GetMarkers needs to be const but still needs to modify this state, which is really
|
VideoContext *vc;
|
||||||
// just a cache... use the mutable "hack".
|
|
||||||
mutable int last_keyframes_revision;
|
|
||||||
mutable std::vector<AudioMarkerKeyframe> keyframe_samples;
|
|
||||||
AudioController *controller;
|
|
||||||
int64_t samplerate;
|
|
||||||
|
|
||||||
void ReloadKeyframes() const
|
agi::signal::Connection keyframe_slot;
|
||||||
|
agi::signal::Connection audio_open_slot;
|
||||||
|
|
||||||
|
std::vector<AudioMarkerKeyframe> keyframe_samples;
|
||||||
|
AudioController *controller;
|
||||||
|
|
||||||
|
void OnKeyframesOpen(std::vector<int> const& raw_keyframes)
|
||||||
{
|
{
|
||||||
keyframe_samples.clear();
|
keyframe_samples.clear();
|
||||||
|
|
||||||
VideoContext *vc = VideoContext::Get();
|
|
||||||
if (!vc) return;
|
|
||||||
|
|
||||||
last_keyframes_revision = vc->GetKeyframesRevision();
|
|
||||||
const std::vector<int> &raw_keyframes = vc->GetKeyFrames();
|
|
||||||
keyframe_samples.reserve(raw_keyframes.size());
|
keyframe_samples.reserve(raw_keyframes.size());
|
||||||
for (size_t i = 0; i < raw_keyframes.size(); ++i)
|
for (size_t i = 0; i < raw_keyframes.size(); ++i)
|
||||||
{
|
{
|
||||||
keyframe_samples.push_back(AudioMarkerKeyframe(
|
keyframe_samples.push_back(AudioMarkerKeyframe(
|
||||||
vc->TimeAtFrame(raw_keyframes[i]) * samplerate / 1000));
|
controller->SamplesFromMilliseconds(vc->TimeAtFrame(raw_keyframes[i]))));
|
||||||
}
|
}
|
||||||
std::sort(keyframe_samples.begin(), keyframe_samples.end());
|
std::sort(keyframe_samples.begin(), keyframe_samples.end());
|
||||||
|
AnnounceMarkerMoved();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// AudioControllerAudioEventListener implementation
|
// AudioControllerAudioEventListener implementation
|
||||||
virtual void OnAudioOpen(AudioProvider *provider)
|
void OnAudioOpen(AudioProvider *)
|
||||||
{
|
{
|
||||||
samplerate = provider->GetSampleRate();
|
OnKeyframesOpen(vc->GetKeyFrames());
|
||||||
ReloadKeyframes();
|
|
||||||
}
|
}
|
||||||
virtual void OnAudioClose() { }
|
|
||||||
virtual void OnPlaybackPosition(int64_t sample_position) { }
|
|
||||||
virtual void OnPlaybackStop() { }
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AudioMarkerProviderKeyframes(AudioController *controller)
|
AudioMarkerProviderKeyframes(AudioController *controller)
|
||||||
: controller(controller)
|
: vc(VideoContext::Get())
|
||||||
|
, keyframe_slot(vc->AddKeyframesOpenListener(&AudioMarkerProviderKeyframes::OnKeyframesOpen, this))
|
||||||
|
, audio_open_slot(controller->AddAudioOpenListener(&AudioMarkerProviderKeyframes::OnAudioOpen, this))
|
||||||
|
, controller(controller)
|
||||||
{
|
{
|
||||||
// Assume that a video context with keyframes revision 0 never has keyframes loaded
|
OnKeyframesOpen(vc->GetKeyFrames());
|
||||||
last_keyframes_revision = 0;
|
|
||||||
samplerate = 44100;
|
|
||||||
controller->AddAudioListener(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~AudioMarkerProviderKeyframes()
|
void GetMarkers(const SampleRange &range, AudioMarkerVector &out) const
|
||||||
{
|
{
|
||||||
controller->RemoveAudioListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetMarkers(const AudioController::SampleRange &range, AudioMarkerVector &out) const
|
|
||||||
{
|
|
||||||
VideoContext *vc = VideoContext::Get();
|
|
||||||
if (!vc) return;
|
|
||||||
|
|
||||||
// Re-read keyframe data if the revision number changed, the keyframe data probably did too
|
|
||||||
if (vc->GetKeyframesRevision() != last_keyframes_revision)
|
|
||||||
ReloadKeyframes();
|
|
||||||
|
|
||||||
// Find first and last keyframes inside the range
|
// Find first and last keyframes inside the range
|
||||||
std::vector<AudioMarkerKeyframe>::iterator a = std::lower_bound(
|
std::vector<AudioMarkerKeyframe>::const_iterator a = std::lower_bound(
|
||||||
keyframe_samples.begin(), keyframe_samples.end(), range.begin());
|
keyframe_samples.begin(), keyframe_samples.end(), range.begin());
|
||||||
std::vector<AudioMarkerKeyframe>::iterator b = std::upper_bound(
|
std::vector<AudioMarkerKeyframe>::const_iterator b = std::upper_bound(
|
||||||
keyframe_samples.begin(), keyframe_samples.end(), range.end());
|
keyframe_samples.begin(), keyframe_samples.end(), range.end());
|
||||||
|
|
||||||
// Place pointers to the markers in the output vector
|
// Place pointers to the markers in the output vector
|
||||||
|
@ -147,22 +127,9 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Type of the audio event listener container in AudioController
|
|
||||||
typedef std::set<AudioControllerAudioEventListener *> AudioEventListenerSet;
|
|
||||||
/// Type of the timing event listener container in AudioController
|
|
||||||
typedef std::set<AudioControllerTimingEventListener *> TimingEventListenerSet;
|
|
||||||
|
|
||||||
/// Macro to iterate audio event listeners in AudioController implementation
|
|
||||||
#define AUDIO_LISTENERS(listener) for (AudioEventListenerSet::iterator listener = audio_event_listeners.begin(); listener != audio_event_listeners.end(); ++listener)
|
|
||||||
/// Macro to iterate audio event listeners in AudioController implementation
|
|
||||||
#define TIMING_LISTENERS(listener) for (TimingEventListenerSet::iterator listener = timing_event_listeners.begin(); listener != timing_event_listeners.end(); ++listener)
|
|
||||||
|
|
||||||
|
|
||||||
AudioController::AudioController()
|
AudioController::AudioController()
|
||||||
: player(0)
|
: player(0)
|
||||||
, provider(0)
|
, provider(0)
|
||||||
, timing_controller(0)
|
|
||||||
, keyframes_marker_provider(new AudioMarkerProviderKeyframes(this))
|
, keyframes_marker_provider(new AudioMarkerProviderKeyframes(this))
|
||||||
, playback_mode(PM_NotPlaying)
|
, playback_mode(PM_NotPlaying)
|
||||||
, playback_timer(this)
|
, playback_timer(this)
|
||||||
|
@ -195,10 +162,7 @@ void AudioController::OnPlaybackTimer(wxTimerEvent &event)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AUDIO_LISTENERS(l)
|
AnnouncePlaybackPosition(pos);
|
||||||
{
|
|
||||||
(*l)->OnPlaybackPosition(pos);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,10 +276,7 @@ void AudioController::OpenAudio(const wxString &url)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell listeners about this.
|
// Tell listeners about this.
|
||||||
AUDIO_LISTENERS(l)
|
AnnounceAudioOpen(provider);
|
||||||
{
|
|
||||||
(*l)->OnAudioOpen(provider);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -328,10 +289,7 @@ void AudioController::CloseAudio()
|
||||||
player = 0;
|
player = 0;
|
||||||
provider = 0;
|
provider = 0;
|
||||||
|
|
||||||
AUDIO_LISTENERS(l)
|
AnnounceAudioClose();
|
||||||
{
|
|
||||||
(*l)->OnAudioClose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -347,90 +305,37 @@ wxString AudioController::GetAudioURL() const
|
||||||
return _T("");
|
return _T("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AudioController::AddAudioListener(AudioControllerAudioEventListener *listener)
|
|
||||||
{
|
|
||||||
audio_event_listeners.insert(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AudioController::RemoveAudioListener(AudioControllerAudioEventListener *listener)
|
|
||||||
{
|
|
||||||
audio_event_listeners.erase(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AudioController::AddTimingListener(AudioControllerTimingEventListener *listener)
|
|
||||||
{
|
|
||||||
timing_event_listeners.insert(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AudioController::RemoveTimingListener(AudioControllerTimingEventListener *listener)
|
|
||||||
{
|
|
||||||
timing_event_listeners.erase(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AudioController::SetTimingController(AudioTimingController *new_controller)
|
void AudioController::SetTimingController(AudioTimingController *new_controller)
|
||||||
{
|
{
|
||||||
delete timing_controller;
|
if (timing_controller.get() != new_controller) {
|
||||||
timing_controller = new_controller;
|
timing_controller.reset(new_controller);
|
||||||
|
timing_controller->AddMarkerMovedListener(std::tr1::bind(std::tr1::ref(AnnounceMarkerMoved)));
|
||||||
TIMING_LISTENERS(l)
|
timing_controller->AddUpdatedPrimaryRangeListener(&AudioController::OnTimingControllerUpdatedPrimaryRange, this);
|
||||||
{
|
timing_controller->AddUpdatedStyleRangesListener(&AudioController::OnTimingControllerUpdatedStyleRanges, this);
|
||||||
(*l)->OnTimingControllerChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AnnounceTimingControllerChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AudioController::OnTimingControllerUpdatedPrimaryRange(AudioTimingController *sending_controller)
|
void AudioController::OnTimingControllerUpdatedPrimaryRange()
|
||||||
{
|
{
|
||||||
assert(sending_controller != 0);
|
|
||||||
if (sending_controller != timing_controller)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (playback_mode == PM_PrimaryRange)
|
if (playback_mode == PM_PrimaryRange)
|
||||||
{
|
{
|
||||||
player->SetEndPosition(timing_controller->GetPrimaryPlaybackRange().end());
|
player->SetEndPosition(timing_controller->GetPrimaryPlaybackRange().end());
|
||||||
}
|
}
|
||||||
|
|
||||||
TIMING_LISTENERS(l)
|
AnnounceSelectionChanged();
|
||||||
{
|
|
||||||
(*l)->OnSelectionChanged();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioController::OnTimingControllerUpdatedStyleRanges(AudioTimingController *sending_controller)
|
void AudioController::OnTimingControllerUpdatedStyleRanges()
|
||||||
{
|
{
|
||||||
assert(sending_controller != 0);
|
|
||||||
if (sending_controller != timing_controller)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/// @todo redraw and stuff, probably
|
/// @todo redraw and stuff, probably
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioController::PlayRange(const SampleRange &range)
|
||||||
void AudioController::OnTimingControllerMarkerMoved(AudioTimingController *sending_controller, AudioMarker *marker)
|
|
||||||
{
|
|
||||||
assert(sending_controller != 0);
|
|
||||||
if (sending_controller != timing_controller)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/// @todo shouldn't this be more detailed?
|
|
||||||
TIMING_LISTENERS(l)
|
|
||||||
{
|
|
||||||
(*l)->OnMarkersMoved();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AudioController::PlayRange(const AudioController::SampleRange &range)
|
|
||||||
{
|
{
|
||||||
if (!IsAudioOpen()) return;
|
if (!IsAudioOpen()) return;
|
||||||
|
|
||||||
|
@ -438,10 +343,7 @@ void AudioController::PlayRange(const AudioController::SampleRange &range)
|
||||||
playback_mode = PM_Range;
|
playback_mode = PM_Range;
|
||||||
playback_timer.Start(20);
|
playback_timer.Start(20);
|
||||||
|
|
||||||
AUDIO_LISTENERS(l)
|
AnnouncePlaybackPosition(range.begin());
|
||||||
{
|
|
||||||
(*l)->OnPlaybackPosition(range.begin());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -461,10 +363,7 @@ void AudioController::PlayToEnd(int64_t start_sample)
|
||||||
playback_mode = PM_ToEnd;
|
playback_mode = PM_ToEnd;
|
||||||
playback_timer.Start(20);
|
playback_timer.Start(20);
|
||||||
|
|
||||||
AUDIO_LISTENERS(l)
|
AnnouncePlaybackPosition(start_sample);
|
||||||
{
|
|
||||||
(*l)->OnPlaybackPosition(start_sample);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -476,10 +375,7 @@ void AudioController::Stop()
|
||||||
playback_mode = PM_NotPlaying;
|
playback_mode = PM_NotPlaying;
|
||||||
playback_timer.Stop();
|
playback_timer.Stop();
|
||||||
|
|
||||||
AUDIO_LISTENERS(l)
|
AnnouncePlaybackStop();
|
||||||
{
|
|
||||||
(*l)->OnPlaybackStop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -505,9 +401,9 @@ void AudioController::ResyncPlaybackPosition(int64_t new_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AudioController::SampleRange AudioController::GetPrimaryPlaybackRange() const
|
SampleRange AudioController::GetPrimaryPlaybackRange() const
|
||||||
{
|
{
|
||||||
if (timing_controller != 0)
|
if (timing_controller.get())
|
||||||
{
|
{
|
||||||
return timing_controller->GetPrimaryPlaybackRange();
|
return timing_controller->GetPrimaryPlaybackRange();
|
||||||
}
|
}
|
||||||
|
@ -522,6 +418,7 @@ void AudioController::GetMarkers(const SampleRange &range, AudioMarkerVector &ma
|
||||||
{
|
{
|
||||||
/// @todo Find all sources of markers
|
/// @todo Find all sources of markers
|
||||||
keyframes_marker_provider->GetMarkers(range, markers);
|
keyframes_marker_provider->GetMarkers(range, markers);
|
||||||
|
if (timing_controller.get()) timing_controller->GetMarkers(range, markers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -565,4 +462,3 @@ int64_t AudioController::MillisecondsFromSamples(int64_t samples) const
|
||||||
|
|
||||||
return millisamples / sr;
|
return millisamples / sr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,9 +48,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <libaegisub/exception.h>
|
#include <libaegisub/exception.h>
|
||||||
|
#include <libaegisub/scoped_ptr.h>
|
||||||
#define AGI_AUDIO_CONTROLLER_INCLUDED 1
|
#include <libaegisub/signals.h>
|
||||||
|
|
||||||
|
|
||||||
class AudioPlayer;
|
class AudioPlayer;
|
||||||
class AudioProvider;
|
class AudioProvider;
|
||||||
|
@ -62,39 +61,16 @@ class AudioTimingController;
|
||||||
class AudioMarker;
|
class AudioMarker;
|
||||||
class AudioMarkerProvider;
|
class AudioMarkerProvider;
|
||||||
|
|
||||||
|
|
||||||
typedef std::vector<const AudioMarker*> AudioMarkerVector;
|
typedef std::vector<const AudioMarker*> AudioMarkerVector;
|
||||||
|
|
||||||
|
|
||||||
/// @class AudioController
|
/// @class SampleRange
|
||||||
/// @brief Manage an open audio stream and UI state for it
|
/// @brief Represents an immutable range of audio samples
|
||||||
///
|
class SampleRange {
|
||||||
/// Keeps track of the UI interaction state of the open audio for a project, ie. what the current
|
|
||||||
/// selection is, what moveable markers are on the audio, and any secondary non-moveable 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 some point be moved
|
|
||||||
/// to a separate class, as it adds too many responsibilities to this class, but at the time of
|
|
||||||
/// writing, it would extend the scope of reworking components too much.
|
|
||||||
///
|
|
||||||
/// There is not supposed to be a way to get direct access to the audio 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:
|
|
||||||
|
|
||||||
/// @class SampleRange
|
|
||||||
/// @brief Represents an immutable range of audio samples
|
|
||||||
class SampleRange {
|
|
||||||
int64_t _begin;
|
int64_t _begin;
|
||||||
int64_t _end;
|
int64_t _end;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
/// @param begin Index of the first sample to include in the range
|
/// @param begin Index of the first sample to include in the range
|
||||||
/// @param end Index of one past the last sample to include in the range
|
/// @param end Index of one past the last sample to include in the range
|
||||||
|
@ -134,16 +110,62 @@ public:
|
||||||
|| contains(other._begin)
|
|| contains(other._begin)
|
||||||
|| contains(other._end);
|
|| contains(other._end);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// @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 sample range
|
||||||
|
virtual void GetMarkers(const SampleRange &range, AudioMarkerVector &out) const = 0;
|
||||||
|
|
||||||
|
DEFINE_SIGNAL_ADDERS(AnnounceMarkerMoved, AddMarkerMovedListener)
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @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, ie. 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 some point be moved
|
||||||
|
/// to a separate class, as it adds too many responsibilities to this class, but at the time of
|
||||||
|
/// writing, it would extend the scope of reworking components too much.
|
||||||
|
///
|
||||||
|
/// There is not supposed to be a way to get direct access to the audio 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 {
|
||||||
private:
|
private:
|
||||||
|
/// A new audio stream was opened (and any previously open was closed)
|
||||||
|
agi::signal::Signal<AudioProvider*> AnnounceAudioOpen;
|
||||||
|
|
||||||
/// Listeners for audio-related events
|
/// The current audio stream was closed
|
||||||
std::set<AudioControllerAudioEventListener *> audio_event_listeners;
|
agi::signal::Signal<> AnnounceAudioClose;
|
||||||
|
|
||||||
/// Listeners for timing-related events
|
/// Playback is in progress and the current position was updated
|
||||||
std::set<AudioControllerTimingEventListener *> timing_event_listeners;
|
agi::signal::Signal<int64_t> AnnouncePlaybackPosition;
|
||||||
|
|
||||||
|
/// Playback has stopped
|
||||||
|
agi::signal::Signal<> AnnouncePlaybackStop;
|
||||||
|
|
||||||
|
/// The timing controller was replaced
|
||||||
|
agi::signal::Signal<> AnnounceTimingControllerChanged;
|
||||||
|
|
||||||
|
/// The selected time range changed
|
||||||
|
agi::signal::Signal<> AnnounceSelectionChanged;
|
||||||
|
|
||||||
/// The audio output object
|
/// The audio output object
|
||||||
AudioPlayer *player;
|
AudioPlayer *player;
|
||||||
|
@ -152,10 +174,10 @@ private:
|
||||||
AudioProvider *provider;
|
AudioProvider *provider;
|
||||||
|
|
||||||
/// The current timing mode, if any; owned by the audio controller
|
/// The current timing mode, if any; owned by the audio controller
|
||||||
AudioTimingController *timing_controller;
|
agi::scoped_ptr<AudioTimingController> timing_controller;
|
||||||
|
|
||||||
/// Provide keyframe data for audio displays
|
/// Provide keyframe data for audio displays
|
||||||
std::auto_ptr<AudioMarkerProvider> keyframes_marker_provider;
|
agi::scoped_ptr<AudioMarkerProvider> keyframes_marker_provider;
|
||||||
|
|
||||||
|
|
||||||
enum PlaybackMode {
|
enum PlaybackMode {
|
||||||
|
@ -174,6 +196,11 @@ private:
|
||||||
/// Event handler for the playback timer
|
/// Event handler for the playback timer
|
||||||
void OnPlaybackTimer(wxTimerEvent &event);
|
void OnPlaybackTimer(wxTimerEvent &event);
|
||||||
|
|
||||||
|
/// @brief Timing controller signals primary playback range changed
|
||||||
|
void OnTimingControllerUpdatedPrimaryRange();
|
||||||
|
|
||||||
|
/// @brief Timing controller signals that the rendering style ranges have changed
|
||||||
|
void OnTimingControllerUpdatedStyleRanges();
|
||||||
|
|
||||||
#ifdef wxHAS_POWER_EVENTS
|
#ifdef wxHAS_POWER_EVENTS
|
||||||
/// Handle computer going into suspend mode by stopping audio and closing device
|
/// Handle computer going into suspend mode by stopping audio and closing device
|
||||||
|
@ -182,7 +209,6 @@ private:
|
||||||
void OnComputerResuming(wxPowerEvent &event);
|
void OnComputerResuming(wxPowerEvent &event);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
|
@ -213,23 +239,6 @@ public:
|
||||||
wxString GetAudioURL() const;
|
wxString GetAudioURL() const;
|
||||||
|
|
||||||
|
|
||||||
/// @brief Add an audio event listener
|
|
||||||
/// @param listener The listener to add
|
|
||||||
void AddAudioListener(AudioControllerAudioEventListener *listener);
|
|
||||||
|
|
||||||
/// @brief Remove an audio event listener
|
|
||||||
/// @param listener The listener to remove
|
|
||||||
void RemoveAudioListener(AudioControllerAudioEventListener *listener);
|
|
||||||
|
|
||||||
/// @brief Add a timing event listener
|
|
||||||
/// @param listener The listener to add
|
|
||||||
void AddTimingListener(AudioControllerTimingEventListener *listener);
|
|
||||||
|
|
||||||
/// @brief Remove a timing event listener
|
|
||||||
/// @param listener The listener to remove
|
|
||||||
void RemoveTimingListener(AudioControllerTimingEventListener *listener);
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Start or restart audio playback, playing a range
|
/// @brief Start or restart audio playback, playing a range
|
||||||
/// @param range The range of audio to play back
|
/// @param range The range of audio to play back
|
||||||
///
|
///
|
||||||
|
@ -279,12 +288,9 @@ public:
|
||||||
/// @return An immutable SampleRange object
|
/// @return An immutable SampleRange object
|
||||||
SampleRange GetPrimaryPlaybackRange() const;
|
SampleRange GetPrimaryPlaybackRange() const;
|
||||||
|
|
||||||
/// @brief Get all static markers inside a range
|
/// @brief Get all markers inside a range
|
||||||
/// @param range The sample range to retrieve markers for
|
/// @param range The sample range to retrieve markers for
|
||||||
/// @param markers Vector to fill found markers into
|
/// @param markers Vector to fill found markers into
|
||||||
///
|
|
||||||
/// The markers retrieved are static markers the user can't interact with.
|
|
||||||
/// Markers for user interaction are obtained through the timing controller.
|
|
||||||
void GetMarkers(const SampleRange &range, AudioMarkerVector &markers) const;
|
void GetMarkers(const SampleRange &range, AudioMarkerVector &markers) const;
|
||||||
|
|
||||||
|
|
||||||
|
@ -304,7 +310,7 @@ public:
|
||||||
|
|
||||||
/// @brief Return the current timing controller
|
/// @brief Return the current timing controller
|
||||||
/// @return The current timing controller or 0
|
/// @return The current timing controller or 0
|
||||||
AudioTimingController * GetTimingController() const { return timing_controller; }
|
AudioTimingController * GetTimingController() const { return timing_controller.get(); }
|
||||||
|
|
||||||
/// @brief Change the current timing controller
|
/// @brief Change the current timing controller
|
||||||
/// @param new_mode The new timing controller or 0. This may be the same object as
|
/// @param new_mode The new timing controller or 0. This may be the same object as
|
||||||
|
@ -312,31 +318,6 @@ public:
|
||||||
/// the object being timed, eg. changed to a new dialogue line.
|
/// the object being timed, eg. changed to a new dialogue line.
|
||||||
void SetTimingController(AudioTimingController *new_controller);
|
void SetTimingController(AudioTimingController *new_controller);
|
||||||
|
|
||||||
|
|
||||||
/// @brief Timing controller signals primary playback range changed
|
|
||||||
/// @param timing_controller The timing controller sending this notification
|
|
||||||
///
|
|
||||||
/// Only timing controllers should call this function. This function must be called
|
|
||||||
/// when the primary playback range is changed in the timing controller, usually
|
|
||||||
/// as a result of user interaction.
|
|
||||||
void OnTimingControllerUpdatedPrimaryRange(AudioTimingController *timing_controller);
|
|
||||||
|
|
||||||
/// @brief Timing controller signals that the rendering style ranges have changed
|
|
||||||
/// @param timing_controller The timing controller sending this notification
|
|
||||||
///
|
|
||||||
/// Only timing controllers should call this function. This function must be called
|
|
||||||
/// when one or more rendering style ranges have changed in the timing controller.
|
|
||||||
void OnTimingControllerUpdatedStyleRanges(AudioTimingController *timing_controller);
|
|
||||||
|
|
||||||
/// @brief Timing controller signals that an audio marker has moved
|
|
||||||
/// @param timing_controller The timing controller sending this notification
|
|
||||||
/// @param marker The marker that was moved
|
|
||||||
///
|
|
||||||
/// Only timing controllers should call this function. This function must be called
|
|
||||||
/// when a marker owned by the timing controller has been updated in some way.
|
|
||||||
void OnTimingControllerMarkerMoved(AudioTimingController *timing_controller, AudioMarker *marker);
|
|
||||||
|
|
||||||
|
|
||||||
/// @brief Convert a count of audio samples to a time in milliseconds
|
/// @brief Convert a count of audio samples to a time in milliseconds
|
||||||
/// @param samples Sample count to convert
|
/// @param samples Sample count to convert
|
||||||
/// @return The number of milliseconds equivalent to the sample-count, rounded down
|
/// @return The number of milliseconds equivalent to the sample-count, rounded down
|
||||||
|
@ -346,57 +327,15 @@ public:
|
||||||
/// @param ms Time in milliseconds to convert
|
/// @param ms Time in milliseconds to convert
|
||||||
/// @return The index of the first sample that is wholly inside the millisecond
|
/// @return The index of the first sample that is wholly inside the millisecond
|
||||||
int64_t SamplesFromMilliseconds(int64_t ms) const;
|
int64_t SamplesFromMilliseconds(int64_t ms) const;
|
||||||
|
|
||||||
|
DEFINE_SIGNAL_ADDERS(AnnounceAudioOpen, AddAudioOpenListener)
|
||||||
|
DEFINE_SIGNAL_ADDERS(AnnounceAudioClose, AddAudioCloseListener)
|
||||||
|
DEFINE_SIGNAL_ADDERS(AnnouncePlaybackPosition, AddPlaybackPositionListener)
|
||||||
|
DEFINE_SIGNAL_ADDERS(AnnouncePlaybackStop, AddPlaybackStopListener)
|
||||||
|
DEFINE_SIGNAL_ADDERS(AnnounceTimingControllerChanged, AddTimingControllerListener)
|
||||||
|
DEFINE_SIGNAL_ADDERS(AnnounceSelectionChanged, AddSelectionChangedListener)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @class AudioControllerAudioEventListener
|
|
||||||
/// @brief Abstract interface for objects that want audio events
|
|
||||||
class AudioControllerAudioEventListener {
|
|
||||||
public:
|
|
||||||
/// A new audio stream was opened (and any previously open was closed)
|
|
||||||
virtual void OnAudioOpen(AudioProvider *) = 0;
|
|
||||||
|
|
||||||
/// The current audio stream was closed
|
|
||||||
virtual void OnAudioClose() = 0;
|
|
||||||
|
|
||||||
/// Playback is in progress and ths current position was updated
|
|
||||||
virtual void OnPlaybackPosition(int64_t sample_position) = 0;
|
|
||||||
|
|
||||||
/// Playback has stopped
|
|
||||||
virtual void OnPlaybackStop() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/// @class AudioControllerTimingEventListener
|
|
||||||
/// @brief Abstract interface for objects that want audio timing events
|
|
||||||
class AudioControllerTimingEventListener {
|
|
||||||
public:
|
|
||||||
/// One or more moveable markers were moved
|
|
||||||
virtual void OnMarkersMoved() = 0;
|
|
||||||
|
|
||||||
/// The selection was changed
|
|
||||||
virtual void OnSelectionChanged() = 0;
|
|
||||||
|
|
||||||
/// The timing controller was replaced
|
|
||||||
virtual void OnTimingControllerChanged() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @class AudioMarkerProvider
|
|
||||||
/// @brief Abstract interface for audio marker providers
|
|
||||||
class AudioMarkerProvider {
|
|
||||||
public:
|
|
||||||
/// Virtual destructor, does nothing
|
|
||||||
virtual ~AudioMarkerProvider() { }
|
|
||||||
|
|
||||||
/// @brief Return markers in a sample range
|
|
||||||
virtual void GetMarkers(const AudioController::SampleRange &range, AudioMarkerVector &out) const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @class AudioMarker
|
/// @class AudioMarker
|
||||||
/// @brief A marker on the audio display
|
/// @brief A marker on the audio display
|
||||||
class AudioMarker {
|
class AudioMarker {
|
||||||
|
@ -431,8 +370,6 @@ public:
|
||||||
virtual bool CanSnap() const = 0;
|
virtual bool CanSnap() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace agi {
|
namespace agi {
|
||||||
DEFINE_BASE_EXCEPTION(AudioControllerError, Exception);
|
DEFINE_BASE_EXCEPTION(AudioControllerError, Exception);
|
||||||
DEFINE_SIMPLE_EXCEPTION(AudioOpenError, AudioControllerError, "audio_controller/open_failed");
|
DEFINE_SIMPLE_EXCEPTION(AudioOpenError, AudioControllerError, "audio_controller/open_failed");
|
||||||
|
|
|
@ -496,7 +496,7 @@ public:
|
||||||
|
|
||||||
if (marker->CanSnap() && (default_snap != event.ShiftDown()))
|
if (marker->CanSnap() && (default_snap != event.ShiftDown()))
|
||||||
{
|
{
|
||||||
AudioController::SampleRange snap_sample_range(
|
SampleRange snap_sample_range(
|
||||||
display->SamplesFromRelativeX(event.GetPosition().x - snap_range),
|
display->SamplesFromRelativeX(event.GetPosition().x - snap_range),
|
||||||
display->SamplesFromRelativeX(event.GetPosition().x + snap_range));
|
display->SamplesFromRelativeX(event.GetPosition().x + snap_range));
|
||||||
const AudioMarker *snap_marker = 0;
|
const AudioMarker *snap_marker = 0;
|
||||||
|
@ -546,8 +546,13 @@ AudioDisplay::AudioDisplay(wxWindow *parent, AudioController *controller)
|
||||||
|
|
||||||
track_cursor_pos = -1;
|
track_cursor_pos = -1;
|
||||||
|
|
||||||
controller->AddAudioListener(this);
|
slots.push_back(controller->AddAudioOpenListener(&AudioDisplay::OnAudioOpen, this));
|
||||||
controller->AddTimingListener(this);
|
slots.push_back(controller->AddAudioCloseListener(&AudioDisplay::OnAudioOpen, this, (AudioProvider*)0));
|
||||||
|
slots.push_back(controller->AddPlaybackPositionListener(&AudioDisplay::OnPlaybackPosition, this));
|
||||||
|
slots.push_back(controller->AddPlaybackStopListener(&AudioDisplay::RemoveTrackCursor, this));
|
||||||
|
slots.push_back(controller->AddTimingControllerListener(&AudioDisplay::Refresh, this, true, (const wxRect*)0));
|
||||||
|
slots.push_back(controller->AddMarkerMovedListener(&AudioDisplay::Refresh, this, true, (const wxRect*)0));
|
||||||
|
slots.push_back(controller->AddSelectionChangedListener(&AudioDisplay::OnSelectionChanged, this));
|
||||||
|
|
||||||
OPT_SUB("Audio/Spectrum", &AudioDisplay::ReloadRenderingSettings, this);
|
OPT_SUB("Audio/Spectrum", &AudioDisplay::ReloadRenderingSettings, this);
|
||||||
|
|
||||||
|
@ -564,8 +569,6 @@ AudioDisplay::AudioDisplay(wxWindow *parent, AudioController *controller)
|
||||||
|
|
||||||
AudioDisplay::~AudioDisplay()
|
AudioDisplay::~AudioDisplay()
|
||||||
{
|
{
|
||||||
controller->RemoveAudioListener(this);
|
|
||||||
controller->RemoveTimingListener(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -614,7 +617,7 @@ void AudioDisplay::ScrollSampleToCenter(int64_t sample_position)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioDisplay::ScrollSampleRangeInView(const AudioController::SampleRange &range)
|
void AudioDisplay::ScrollSampleRangeInView(const SampleRange &range)
|
||||||
{
|
{
|
||||||
int client_width = GetClientRect().GetWidth();
|
int client_width = GetClientRect().GetWidth();
|
||||||
int range_begin = AbsoluteXFromSamples(range.begin());
|
int range_begin = AbsoluteXFromSamples(range.begin());
|
||||||
|
@ -810,7 +813,7 @@ void AudioDisplay::OnPaint(wxPaintEvent& event)
|
||||||
bool redraw_timeline = false;
|
bool redraw_timeline = false;
|
||||||
|
|
||||||
/// @todo Get rendering style ranges from timing controller instead
|
/// @todo Get rendering style ranges from timing controller instead
|
||||||
AudioController::SampleRange sel_samples(controller->GetPrimaryPlaybackRange());
|
SampleRange sel_samples(controller->GetPrimaryPlaybackRange());
|
||||||
int selection_start = AbsoluteXFromSamples(sel_samples.begin());
|
int selection_start = AbsoluteXFromSamples(sel_samples.begin());
|
||||||
int selection_end = AbsoluteXFromSamples(sel_samples.end());
|
int selection_end = AbsoluteXFromSamples(sel_samples.end());
|
||||||
|
|
||||||
|
@ -856,12 +859,10 @@ void AudioDisplay::OnPaint(wxPaintEvent& event)
|
||||||
// Draw markers on top of it all
|
// Draw markers on top of it all
|
||||||
AudioMarkerVector markers;
|
AudioMarkerVector markers;
|
||||||
const int foot_size = 6;
|
const int foot_size = 6;
|
||||||
AudioController::SampleRange updrectsamples(
|
SampleRange updrectsamples(
|
||||||
SamplesFromRelativeX(updrect.x - foot_size),
|
SamplesFromRelativeX(updrect.x - foot_size),
|
||||||
SamplesFromRelativeX(updrect.x + updrect.width + foot_size));
|
SamplesFromRelativeX(updrect.x + updrect.width + foot_size));
|
||||||
controller->GetMarkers(updrectsamples, markers);
|
controller->GetMarkers(updrectsamples, markers);
|
||||||
if (controller->GetTimingController())
|
|
||||||
controller->GetTimingController()->GetMarkers(updrectsamples, markers);
|
|
||||||
wxDCPenChanger pen_retainer(dc, wxPen());
|
wxDCPenChanger pen_retainer(dc, wxPen());
|
||||||
wxDCBrushChanger brush_retainer(dc, wxBrush());
|
wxDCBrushChanger brush_retainer(dc, wxBrush());
|
||||||
for (AudioMarkerVector::iterator marker_i = markers.begin(); marker_i != markers.end(); ++marker_i)
|
for (AudioMarkerVector::iterator marker_i = markers.begin(); marker_i != markers.end(); ++marker_i)
|
||||||
|
@ -1184,35 +1185,15 @@ void AudioDisplay::OnAudioOpen(AudioProvider *_provider)
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioDisplay::OnAudioClose()
|
|
||||||
{
|
|
||||||
OnAudioOpen(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AudioDisplay::OnPlaybackPosition(int64_t sample_position)
|
void AudioDisplay::OnPlaybackPosition(int64_t sample_position)
|
||||||
{
|
{
|
||||||
SetTrackCursor(AbsoluteXFromSamples(sample_position), false);
|
SetTrackCursor(AbsoluteXFromSamples(sample_position), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioDisplay::OnPlaybackStop()
|
|
||||||
{
|
|
||||||
RemoveTrackCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AudioDisplay::OnMarkersMoved()
|
|
||||||
{
|
|
||||||
Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AudioDisplay::OnSelectionChanged()
|
void AudioDisplay::OnSelectionChanged()
|
||||||
{
|
{
|
||||||
/// @todo Handle rendering style ranges from timing controller instead
|
/// @todo Handle rendering style ranges from timing controller instead
|
||||||
AudioController::SampleRange sel(controller->GetPrimaryPlaybackRange());
|
SampleRange sel(controller->GetPrimaryPlaybackRange());
|
||||||
scrollbar->SetSelection(AbsoluteXFromSamples(sel.begin()), AbsoluteXFromSamples(sel.length()));
|
scrollbar->SetSelection(AbsoluteXFromSamples(sel.begin()), AbsoluteXFromSamples(sel.length()));
|
||||||
|
|
||||||
if (sel.overlaps(old_selection))
|
if (sel.overlaps(old_selection))
|
||||||
|
@ -1242,11 +1223,3 @@ void AudioDisplay::OnSelectionChanged()
|
||||||
|
|
||||||
old_selection = sel;
|
old_selection = sel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioDisplay::OnTimingControllerChanged()
|
|
||||||
{
|
|
||||||
Refresh();
|
|
||||||
/// @todo Do something more about the new timing controller?
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef AGI_PRE
|
#ifndef AGI_PRE
|
||||||
|
#include <list>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <wx/bitmap.h>
|
#include <wx/bitmap.h>
|
||||||
|
@ -47,6 +48,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <libaegisub/scoped_ptr.h>
|
#include <libaegisub/scoped_ptr.h>
|
||||||
|
#include <libaegisub/signals.h>
|
||||||
|
|
||||||
|
|
||||||
class AudioRenderer;
|
class AudioRenderer;
|
||||||
|
@ -108,8 +110,9 @@ public:
|
||||||
/// The audio display is the common view that allows the user to interact with the active
|
/// The audio display is the common view that allows the user to interact with the active
|
||||||
/// timing controller. The audio display also renders audio according to the audio controller
|
/// timing controller. The audio display also renders audio according to the audio controller
|
||||||
/// and the timing controller, using an audio renderer instance.
|
/// and the timing controller, using an audio renderer instance.
|
||||||
class AudioDisplay: public wxWindow, private AudioControllerAudioEventListener, private AudioControllerTimingEventListener {
|
class AudioDisplay: public wxWindow {
|
||||||
private:
|
private:
|
||||||
|
std::list<agi::signal::Connection> slots;
|
||||||
|
|
||||||
/// The audio renderer manager
|
/// The audio renderer manager
|
||||||
agi::scoped_ptr<AudioRenderer> audio_renderer;
|
agi::scoped_ptr<AudioRenderer> audio_renderer;
|
||||||
|
@ -178,9 +181,8 @@ private:
|
||||||
/// @brief Remove the tracking cursor from the display
|
/// @brief Remove the tracking cursor from the display
|
||||||
void RemoveTrackCursor();
|
void RemoveTrackCursor();
|
||||||
|
|
||||||
|
/// Previous audio selection for optimizing redraw when selection changes
|
||||||
/// Previous audio selection for optimising redraw when selection changes
|
SampleRange old_selection;
|
||||||
AudioController::SampleRange old_selection;
|
|
||||||
|
|
||||||
/// @brief Reload all rendering settings from Options and reset caches
|
/// @brief Reload all rendering settings from Options and reset caches
|
||||||
///
|
///
|
||||||
|
@ -197,19 +199,10 @@ private:
|
||||||
/// wxWidgets input focus changed event
|
/// wxWidgets input focus changed event
|
||||||
void OnFocus(wxFocusEvent &event);
|
void OnFocus(wxFocusEvent &event);
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
// AudioControllerAudioEventListener implementation
|
// AudioControllerAudioEventListener implementation
|
||||||
virtual void OnAudioOpen(AudioProvider *provider);
|
virtual void OnAudioOpen(AudioProvider *provider);
|
||||||
virtual void OnAudioClose();
|
|
||||||
virtual void OnPlaybackPosition(int64_t sample_position);
|
virtual void OnPlaybackPosition(int64_t sample_position);
|
||||||
virtual void OnPlaybackStop();
|
|
||||||
|
|
||||||
// AudioControllerTimingEventListener implementation
|
|
||||||
virtual void OnMarkersMoved();
|
|
||||||
virtual void OnSelectionChanged();
|
virtual void OnSelectionChanged();
|
||||||
virtual void OnTimingControllerChanged();
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -261,7 +254,7 @@ public:
|
||||||
/// closer to the edge of the display than the margin. The edge that is not ensured to
|
/// closer to the edge of the display than the margin. The edge that is not ensured to
|
||||||
/// be in view might be outside of view or might be closer to the display edge than the
|
/// be in view might be outside of view or might be closer to the display edge than the
|
||||||
/// margin.
|
/// margin.
|
||||||
void ScrollSampleRangeInView(const AudioController::SampleRange &range);
|
void ScrollSampleRangeInView(const SampleRange &range);
|
||||||
|
|
||||||
|
|
||||||
/// @brief Change the zoom level
|
/// @brief Change the zoom level
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "audio_player_alsa.h"
|
#include "audio_player_alsa.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "audio_player_dsound.h"
|
#include "audio_player_dsound.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "audio_player_openal.h"
|
#include "audio_player_openal.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
|
@ -38,7 +38,6 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "audio_player_oss.h"
|
#include "audio_player_oss.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
#include <wx/filename.h>
|
#include <wx/filename.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "audio_provider_hd.h"
|
#include "audio_provider_hd.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "dialog_progress.h"
|
#include "dialog_progress.h"
|
||||||
|
|
|
@ -36,7 +36,6 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "audio_provider_ram.h"
|
#include "audio_provider_ram.h"
|
||||||
#include "dialog_progress.h"
|
#include "dialog_progress.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
|
|
@ -38,17 +38,27 @@
|
||||||
class AssDialogue;
|
class AssDialogue;
|
||||||
class AudioController;
|
class AudioController;
|
||||||
|
|
||||||
|
#include <libaegisub/signals.h>
|
||||||
|
|
||||||
/// @class AudioTimingController
|
/// @class AudioTimingController
|
||||||
/// @brief Base class for objects controlling audio timing
|
/// @brief Base class for objects controlling audio timing
|
||||||
///
|
///
|
||||||
/// There is just one active audio timing controller at a time per audio controller.
|
/// There is just one active audio timing controller at a time per audio controller.
|
||||||
/// The timing controller manages the timing mode and supplies markers that can be
|
/// The timing controller manages the timing mode and supplies markers that can be
|
||||||
/// manupulated to the audio display, as well as the current selection.
|
/// manipulated to the audio display, as well as the current selection.
|
||||||
///
|
///
|
||||||
/// The timing controller must then be sent the marker drag events as well as clicks
|
/// The timing controller must then be sent the marker drag events as well as clicks
|
||||||
/// in empty areas of the audio display.
|
/// in empty areas of the audio display.
|
||||||
class AudioTimingController : public AudioMarkerProvider {
|
class AudioTimingController : public AudioMarkerProvider {
|
||||||
|
protected:
|
||||||
|
/// The primary playback range has changed, usually as a result of user interaction.
|
||||||
|
agi::signal::Signal<> AnnounceUpdatedPrimaryRange;
|
||||||
|
|
||||||
|
/// One or more rendering style ranges have changed in the timing controller.
|
||||||
|
agi::signal::Signal<> AnnounceUpdatedStyleRanges;
|
||||||
|
|
||||||
|
/// A marker has been updated in some way.
|
||||||
|
agi::signal::Signal<AudioMarker*> AnnounceMarkerMoved;
|
||||||
public:
|
public:
|
||||||
/// @brief Get any warning message to show in the audio display
|
/// @brief Get any warning message to show in the audio display
|
||||||
/// @return The warning message to show, may be empty if there is none
|
/// @return The warning message to show, may be empty if there is none
|
||||||
|
@ -58,13 +68,13 @@ public:
|
||||||
/// @return A sample range
|
/// @return A sample range
|
||||||
///
|
///
|
||||||
/// This is used for "bring working area into view" operations.
|
/// This is used for "bring working area into view" operations.
|
||||||
virtual AudioController::SampleRange GetIdealVisibleSampleRange() const = 0;
|
virtual SampleRange GetIdealVisibleSampleRange() const = 0;
|
||||||
|
|
||||||
/// @brief Get the primary playback range
|
/// @brief Get the primary playback range
|
||||||
/// @return A sample range
|
/// @return A sample range
|
||||||
///
|
///
|
||||||
/// Get the sample range the user is most likely to want to play back currently.
|
/// Get the sample range the user is most likely to want to play back currently.
|
||||||
virtual AudioController::SampleRange GetPrimaryPlaybackRange() const = 0;
|
virtual SampleRange GetPrimaryPlaybackRange() const = 0;
|
||||||
|
|
||||||
/// @brief Does this timing mode have labels on the audio display?
|
/// @brief Does this timing mode have labels on the audio display?
|
||||||
/// @return True if this timing mode needs labels on the audio display.
|
/// @return True if this timing mode needs labels on the audio display.
|
||||||
|
@ -122,9 +132,11 @@ public:
|
||||||
virtual void OnMarkerDrag(AudioMarker *marker, int64_t new_position) = 0;
|
virtual void OnMarkerDrag(AudioMarker *marker, int64_t new_position) = 0;
|
||||||
|
|
||||||
/// @brief Destructor
|
/// @brief Destructor
|
||||||
///
|
|
||||||
/// Does nothing in the base class, only present for virtual destruction.
|
|
||||||
virtual ~AudioTimingController() { }
|
virtual ~AudioTimingController() { }
|
||||||
|
|
||||||
|
DEFINE_SIGNAL_ADDERS(AnnounceUpdatedPrimaryRange, AddUpdatedPrimaryRangeListener)
|
||||||
|
DEFINE_SIGNAL_ADDERS(AnnounceUpdatedStyleRanges, AddUpdatedStyleRangesListener)
|
||||||
|
DEFINE_SIGNAL_ADDERS(AnnounceMarkerMoved, AddMarkerMovedListener)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -143,12 +143,12 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// AudioMarkerProvider interface
|
// AudioMarkerProvider interface
|
||||||
virtual void GetMarkers(const AudioController::SampleRange &range, AudioMarkerVector &out_markers) const;
|
virtual void GetMarkers(const SampleRange &range, AudioMarkerVector &out_markers) const;
|
||||||
|
|
||||||
// AudioTimingController interface
|
// AudioTimingController interface
|
||||||
virtual wxString GetWarningMessage() const;
|
virtual wxString GetWarningMessage() const;
|
||||||
virtual AudioController::SampleRange GetIdealVisibleSampleRange() const;
|
virtual SampleRange GetIdealVisibleSampleRange() const;
|
||||||
virtual AudioController::SampleRange GetPrimaryPlaybackRange() const;
|
virtual SampleRange GetPrimaryPlaybackRange() const;
|
||||||
virtual bool HasLabels() const;
|
virtual bool HasLabels() const;
|
||||||
virtual void Next();
|
virtual void Next();
|
||||||
virtual void Prev();
|
virtual void Prev();
|
||||||
|
@ -270,7 +270,7 @@ const AudioMarkerDialogueTiming *AudioTimingControllerDialogue::GetRightMarker()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AudioTimingControllerDialogue::GetMarkers(const AudioController::SampleRange &range, AudioMarkerVector &out_markers) const
|
void AudioTimingControllerDialogue::GetMarkers(const SampleRange &range, AudioMarkerVector &out_markers) const
|
||||||
{
|
{
|
||||||
if (range.contains(markers[0].GetPosition()))
|
if (range.contains(markers[0].GetPosition()))
|
||||||
out_markers.push_back(&markers[0]);
|
out_markers.push_back(&markers[0]);
|
||||||
|
@ -303,16 +303,16 @@ wxString AudioTimingControllerDialogue::GetWarningMessage() const
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AudioController::SampleRange AudioTimingControllerDialogue::GetIdealVisibleSampleRange() const
|
SampleRange AudioTimingControllerDialogue::GetIdealVisibleSampleRange() const
|
||||||
{
|
{
|
||||||
return GetPrimaryPlaybackRange();
|
return GetPrimaryPlaybackRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AudioController::SampleRange AudioTimingControllerDialogue::GetPrimaryPlaybackRange() const
|
SampleRange AudioTimingControllerDialogue::GetPrimaryPlaybackRange() const
|
||||||
{
|
{
|
||||||
return AudioController::SampleRange(
|
return SampleRange(
|
||||||
GetLeftMarker()->GetPosition(),
|
GetLeftMarker()->GetPosition(),
|
||||||
GetRightMarker()->GetPosition());
|
GetRightMarker()->GetPosition());
|
||||||
}
|
}
|
||||||
|
@ -396,7 +396,7 @@ void AudioTimingControllerDialogue::Revert()
|
||||||
|
|
||||||
bool AudioTimingControllerDialogue::IsNearbyMarker(int64_t sample, int sensitivity) const
|
bool AudioTimingControllerDialogue::IsNearbyMarker(int64_t sample, int sensitivity) const
|
||||||
{
|
{
|
||||||
AudioController::SampleRange range(sample-sensitivity, sample+sensitivity);
|
SampleRange range(sample-sensitivity, sample+sensitivity);
|
||||||
|
|
||||||
return range.contains(markers[0].GetPosition()) || range.contains(markers[1].GetPosition());
|
return range.contains(markers[0].GetPosition()) || range.contains(markers[1].GetPosition());
|
||||||
}
|
}
|
||||||
|
@ -419,7 +419,7 @@ AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sen
|
||||||
// Clicked near the left marker:
|
// Clicked near the left marker:
|
||||||
// Insta-move it and start dragging it
|
// Insta-move it and start dragging it
|
||||||
left->SetPosition(sample);
|
left->SetPosition(sample);
|
||||||
audio_controller->OnTimingControllerMarkerMoved(this, left);
|
AnnounceMarkerMoved(left);
|
||||||
timing_modified = true;
|
timing_modified = true;
|
||||||
UpdateSelection();
|
UpdateSelection();
|
||||||
return left;
|
return left;
|
||||||
|
@ -436,7 +436,7 @@ AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sen
|
||||||
// Insta-set the left marker to the clicked position and return the right as the dragged one,
|
// Insta-set the left marker to the clicked position and return the right as the dragged one,
|
||||||
// such that if the user does start dragging, he will create a new selection from scratch
|
// such that if the user does start dragging, he will create a new selection from scratch
|
||||||
left->SetPosition(sample);
|
left->SetPosition(sample);
|
||||||
audio_controller->OnTimingControllerMarkerMoved(this, left);
|
AnnounceMarkerMoved(left);
|
||||||
timing_modified = true;
|
timing_modified = true;
|
||||||
UpdateSelection();
|
UpdateSelection();
|
||||||
return right;
|
return right;
|
||||||
|
@ -449,7 +449,7 @@ AudioMarker * AudioTimingControllerDialogue::OnRightClick(int64_t sample, int se
|
||||||
AudioMarkerDialogueTiming *right = GetRightMarker();
|
AudioMarkerDialogueTiming *right = GetRightMarker();
|
||||||
|
|
||||||
right->SetPosition(sample);
|
right->SetPosition(sample);
|
||||||
audio_controller->OnTimingControllerMarkerMoved(this, right);
|
AnnounceMarkerMoved(right);
|
||||||
timing_modified = true;
|
timing_modified = true;
|
||||||
UpdateSelection();
|
UpdateSelection();
|
||||||
return right;
|
return right;
|
||||||
|
@ -462,7 +462,7 @@ void AudioTimingControllerDialogue::OnMarkerDrag(AudioMarker *marker, int64_t ne
|
||||||
assert(marker == &markers[0] || marker == &markers[1]);
|
assert(marker == &markers[0] || marker == &markers[1]);
|
||||||
|
|
||||||
static_cast<AudioMarkerDialogueTiming*>(marker)->SetPosition(new_position);
|
static_cast<AudioMarkerDialogueTiming*>(marker)->SetPosition(new_position);
|
||||||
audio_controller->OnTimingControllerMarkerMoved(this, marker);
|
AnnounceMarkerMoved(marker);
|
||||||
timing_modified = true;
|
timing_modified = true;
|
||||||
|
|
||||||
UpdateSelection();
|
UpdateSelection();
|
||||||
|
@ -472,7 +472,7 @@ void AudioTimingControllerDialogue::OnMarkerDrag(AudioMarker *marker, int64_t ne
|
||||||
|
|
||||||
void AudioTimingControllerDialogue::UpdateSelection()
|
void AudioTimingControllerDialogue::UpdateSelection()
|
||||||
{
|
{
|
||||||
audio_controller->OnTimingControllerUpdatedPrimaryRange(this);
|
AnnounceUpdatedPrimaryRange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,6 @@
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "ass_style.h"
|
#include "ass_style.h"
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "selection_controller.h"
|
#include "selection_controller.h"
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
|
|
@ -42,7 +42,6 @@
|
||||||
#include <wx/display.h> /// Must be included last.
|
#include <wx/display.h> /// Must be included last.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "dialog_detached_video.h"
|
#include "dialog_detached_video.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
|
@ -51,7 +51,6 @@
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "ass_override.h"
|
#include "ass_override.h"
|
||||||
#include "ass_style.h"
|
#include "ass_style.h"
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "dialog_fonts_collector.h"
|
#include "dialog_fonts_collector.h"
|
||||||
#include "font_file_lister.h"
|
#include "font_file_lister.h"
|
||||||
|
|
|
@ -47,7 +47,6 @@
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "dialog_search_replace.h"
|
#include "dialog_search_replace.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
|
@ -44,7 +44,6 @@
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "dialog_spellchecker.h"
|
#include "dialog_spellchecker.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
|
|
@ -379,7 +379,7 @@ void DialogStyling::OnPlayVideoButton(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void DialogStyling::OnPlayAudioButton(wxCommandEvent &event) {
|
void DialogStyling::OnPlayAudioButton(wxCommandEvent &event) {
|
||||||
audio->PlayRange(AudioController::SampleRange(
|
audio->PlayRange(SampleRange(
|
||||||
audio->SamplesFromMilliseconds(line->Start.GetMS()),
|
audio->SamplesFromMilliseconds(line->Start.GetMS()),
|
||||||
audio->SamplesFromMilliseconds(line->End.GetMS())));
|
audio->SamplesFromMilliseconds(line->End.GetMS())));
|
||||||
TypeBox->SetFocus();
|
TypeBox->SetFocus();
|
||||||
|
|
|
@ -444,7 +444,7 @@ void DialogTranslation::OnPlayVideoButton(wxCommandEvent &event) {
|
||||||
/// @param event
|
/// @param event
|
||||||
///
|
///
|
||||||
void DialogTranslation::OnPlayAudioButton(wxCommandEvent &event) {
|
void DialogTranslation::OnPlayAudioButton(wxCommandEvent &event) {
|
||||||
audio->PlayRange(AudioController::SampleRange(
|
audio->PlayRange(SampleRange(
|
||||||
audio->SamplesFromMilliseconds(current->Start.GetMS()),
|
audio->SamplesFromMilliseconds(current->Start.GetMS()),
|
||||||
audio->SamplesFromMilliseconds(current->End.GetMS())));
|
audio->SamplesFromMilliseconds(current->End.GetMS())));
|
||||||
TransText->SetFocus();
|
TransText->SetFocus();
|
||||||
|
|
|
@ -43,7 +43,6 @@
|
||||||
#include <wx/filename.h>
|
#include <wx/filename.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "drop.h"
|
#include "drop.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,6 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "ffmpegsource_common.h"
|
#include "ffmpegsource_common.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
|
|
@ -132,7 +132,8 @@ FrameMain::FrameMain (wxArrayString args)
|
||||||
|
|
||||||
// Contexts and controllers
|
// Contexts and controllers
|
||||||
audioController = new AudioController;
|
audioController = new AudioController;
|
||||||
audioController->AddAudioListener(this);
|
audioController->AddAudioOpenListener(&FrameMain::OnAudioOpen, this);
|
||||||
|
audioController->AddAudioCloseListener(&FrameMain::OnAudioClose, this);
|
||||||
|
|
||||||
// Create menu and tool bars
|
// Create menu and tool bars
|
||||||
StartupLog(_T("Apply saved Maximized state"));
|
StartupLog(_T("Apply saved Maximized state"));
|
||||||
|
|
|
@ -47,10 +47,6 @@
|
||||||
#include <wx/timer.h>
|
#include <wx/timer.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef AGI_AUDIO_CONTROLLER_INCLUDED
|
|
||||||
#error You must include "audio_controller.h" before "frame_main.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class AssFile;
|
class AssFile;
|
||||||
class VideoDisplay;
|
class VideoDisplay;
|
||||||
class VideoSlider;
|
class VideoSlider;
|
||||||
|
@ -63,6 +59,7 @@ class DialogDetachedVideo;
|
||||||
class DialogStyling;
|
class DialogStyling;
|
||||||
class AegisubFileDropTarget;
|
class AegisubFileDropTarget;
|
||||||
class AudioController;
|
class AudioController;
|
||||||
|
class AudioProvider;
|
||||||
|
|
||||||
namespace Automation4 { class FeatureMacro; class ScriptManager; }
|
namespace Automation4 { class FeatureMacro; class ScriptManager; }
|
||||||
|
|
||||||
|
@ -73,7 +70,7 @@ namespace Automation4 { class FeatureMacro; class ScriptManager; }
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
///
|
///
|
||||||
/// DOCME
|
/// DOCME
|
||||||
class FrameMain: public wxFrame, private AudioControllerAudioEventListener {
|
class FrameMain: public wxFrame {
|
||||||
friend class AegisubFileDropTarget;
|
friend class AegisubFileDropTarget;
|
||||||
friend class AegisubApp;
|
friend class AegisubApp;
|
||||||
friend class SubtitlesGrid;
|
friend class SubtitlesGrid;
|
||||||
|
@ -327,13 +324,9 @@ private:
|
||||||
void RebuildRecentList(wxString listName,wxMenu *menu,int startID);
|
void RebuildRecentList(wxString listName,wxMenu *menu,int startID);
|
||||||
void SynchronizeProject(bool FromSubs=false);
|
void SynchronizeProject(bool FromSubs=false);
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
// AudioControllerAudioEventListener implementation
|
// AudioControllerAudioEventListener implementation
|
||||||
virtual void OnAudioOpen(AudioProvider *provider);
|
void OnAudioOpen(AudioProvider *provider);
|
||||||
virtual void OnAudioClose();
|
void OnAudioClose();
|
||||||
virtual void OnPlaybackPosition(int64_t sample_position);
|
|
||||||
virtual void OnPlaybackStop();
|
|
||||||
|
|
||||||
|
|
||||||
void OnSubtitlesFileChanged();
|
void OnSubtitlesFileChanged();
|
||||||
|
|
|
@ -1517,8 +1517,8 @@ void FrameMain::OnMedusaStop(wxCommandEvent &) {
|
||||||
|
|
||||||
// Otherwise, play the last 500 ms
|
// Otherwise, play the last 500 ms
|
||||||
else {
|
else {
|
||||||
AudioController::SampleRange sel(audioController->GetPrimaryPlaybackRange());
|
SampleRange sel(audioController->GetPrimaryPlaybackRange());
|
||||||
audioController->PlayRange(AudioController::SampleRange(
|
audioController->PlayRange(SampleRange(
|
||||||
sel.end() - audioController->SamplesFromMilliseconds(500),
|
sel.end() - audioController->SamplesFromMilliseconds(500),
|
||||||
sel.end()));;
|
sel.end()));;
|
||||||
}
|
}
|
||||||
|
@ -1526,7 +1526,7 @@ void FrameMain::OnMedusaStop(wxCommandEvent &) {
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaShiftStartForward(wxCommandEvent &) {
|
void FrameMain::OnMedusaShiftStartForward(wxCommandEvent &) {
|
||||||
AudioController::SampleRange newsel(
|
SampleRange newsel(
|
||||||
audioController->GetPrimaryPlaybackRange(),
|
audioController->GetPrimaryPlaybackRange(),
|
||||||
audioController->SamplesFromMilliseconds(10),
|
audioController->SamplesFromMilliseconds(10),
|
||||||
0);
|
0);
|
||||||
|
@ -1536,7 +1536,7 @@ void FrameMain::OnMedusaShiftStartForward(wxCommandEvent &) {
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaShiftStartBack(wxCommandEvent &) {
|
void FrameMain::OnMedusaShiftStartBack(wxCommandEvent &) {
|
||||||
AudioController::SampleRange newsel(
|
SampleRange newsel(
|
||||||
audioController->GetPrimaryPlaybackRange(),
|
audioController->GetPrimaryPlaybackRange(),
|
||||||
-audioController->SamplesFromMilliseconds(10),
|
-audioController->SamplesFromMilliseconds(10),
|
||||||
0);
|
0);
|
||||||
|
@ -1546,7 +1546,7 @@ void FrameMain::OnMedusaShiftStartBack(wxCommandEvent &) {
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaShiftEndForward(wxCommandEvent &) {
|
void FrameMain::OnMedusaShiftEndForward(wxCommandEvent &) {
|
||||||
AudioController::SampleRange newsel(
|
SampleRange newsel(
|
||||||
audioController->GetPrimaryPlaybackRange(),
|
audioController->GetPrimaryPlaybackRange(),
|
||||||
0,
|
0,
|
||||||
audioController->SamplesFromMilliseconds(10));
|
audioController->SamplesFromMilliseconds(10));
|
||||||
|
@ -1556,7 +1556,7 @@ void FrameMain::OnMedusaShiftEndForward(wxCommandEvent &) {
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaShiftEndBack(wxCommandEvent &) {
|
void FrameMain::OnMedusaShiftEndBack(wxCommandEvent &) {
|
||||||
AudioController::SampleRange newsel(
|
SampleRange newsel(
|
||||||
audioController->GetPrimaryPlaybackRange(),
|
audioController->GetPrimaryPlaybackRange(),
|
||||||
0,
|
0,
|
||||||
-audioController->SamplesFromMilliseconds(10));
|
-audioController->SamplesFromMilliseconds(10));
|
||||||
|
@ -1566,16 +1566,16 @@ void FrameMain::OnMedusaShiftEndBack(wxCommandEvent &) {
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaPlayBefore(wxCommandEvent &) {
|
void FrameMain::OnMedusaPlayBefore(wxCommandEvent &) {
|
||||||
AudioController::SampleRange sel(audioController->GetPrimaryPlaybackRange());
|
SampleRange sel(audioController->GetPrimaryPlaybackRange());
|
||||||
audioController->PlayRange(AudioController::SampleRange(
|
audioController->PlayRange(SampleRange(
|
||||||
sel.begin() - audioController->SamplesFromMilliseconds(500),
|
sel.begin() - audioController->SamplesFromMilliseconds(500),
|
||||||
sel.begin()));;
|
sel.begin()));;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
void FrameMain::OnMedusaPlayAfter(wxCommandEvent &) {
|
void FrameMain::OnMedusaPlayAfter(wxCommandEvent &) {
|
||||||
AudioController::SampleRange sel(audioController->GetPrimaryPlaybackRange());
|
SampleRange sel(audioController->GetPrimaryPlaybackRange());
|
||||||
audioController->PlayRange(AudioController::SampleRange(
|
audioController->PlayRange(SampleRange(
|
||||||
sel.end(),
|
sel.end(),
|
||||||
sel.end() + audioController->SamplesFromMilliseconds(500)));;
|
sel.end() + audioController->SamplesFromMilliseconds(500)));;
|
||||||
}
|
}
|
||||||
|
@ -1623,16 +1623,6 @@ void FrameMain::OnAudioClose()
|
||||||
SetDisplayMode(-1, 0);
|
SetDisplayMode(-1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FrameMain::OnPlaybackPosition(int64_t sample_position)
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameMain::OnPlaybackStop()
|
|
||||||
{
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
void FrameMain::OnSubtitlesFileChanged() {
|
void FrameMain::OnSubtitlesFileChanged() {
|
||||||
if (OPT_GET("App/Auto/Save on Every Change")->GetBool()) {
|
if (OPT_GET("App/Auto/Save on Every Change")->GetBool()) {
|
||||||
if (ass->IsModified() && !ass->filename.empty()) SaveSubtitles(false);
|
if (ass->IsModified() && !ass->filename.empty()) SaveSubtitles(false);
|
||||||
|
@ -1640,4 +1630,3 @@ void FrameMain::OnSubtitlesFileChanged() {
|
||||||
|
|
||||||
UpdateTitle();
|
UpdateTitle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,6 @@
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "ass_time.h"
|
#include "ass_time.h"
|
||||||
#include "selection_controller.h"
|
#include "selection_controller.h"
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "audio_box.h"
|
#include "audio_box.h"
|
||||||
#ifdef WITH_AUTOMATION
|
#ifdef WITH_AUTOMATION
|
||||||
#include "auto4_base.h"
|
#include "auto4_base.h"
|
||||||
|
|
|
@ -50,7 +50,6 @@
|
||||||
|
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "dialog_progress.h"
|
#include "dialog_progress.h"
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
|
|
||||||
#include "ass_dialogue.h"
|
#include "ass_dialogue.h"
|
||||||
#include "ass_file.h"
|
#include "ass_file.h"
|
||||||
#include "audio_controller.h"
|
|
||||||
#include "frame_main.h"
|
#include "frame_main.h"
|
||||||
#include "help_button.h"
|
#include "help_button.h"
|
||||||
#include "libresrc/libresrc.h"
|
#include "libresrc/libresrc.h"
|
||||||
|
|
|
@ -308,7 +308,7 @@ void VideoContext::PlayNextFrame() {
|
||||||
JumpToFrame(frame_n + 1);
|
JumpToFrame(frame_n + 1);
|
||||||
// Start playing audio
|
// Start playing audio
|
||||||
if (playAudioOnStep->GetBool()) {
|
if (playAudioOnStep->GetBool()) {
|
||||||
audio->PlayRange(AudioController::SampleRange(
|
audio->PlayRange(SampleRange(
|
||||||
audio->SamplesFromMilliseconds(TimeAtFrame(thisFrame)),
|
audio->SamplesFromMilliseconds(TimeAtFrame(thisFrame)),
|
||||||
audio->SamplesFromMilliseconds(TimeAtFrame(thisFrame + 1))));
|
audio->SamplesFromMilliseconds(TimeAtFrame(thisFrame + 1))));
|
||||||
}
|
}
|
||||||
|
@ -322,7 +322,7 @@ void VideoContext::PlayPrevFrame() {
|
||||||
JumpToFrame(frame_n -1);
|
JumpToFrame(frame_n -1);
|
||||||
// Start playing audio
|
// Start playing audio
|
||||||
if (playAudioOnStep->GetBool()) {
|
if (playAudioOnStep->GetBool()) {
|
||||||
audio->PlayRange(AudioController::SampleRange(
|
audio->PlayRange(SampleRange(
|
||||||
audio->SamplesFromMilliseconds(TimeAtFrame(thisFrame - 1)),
|
audio->SamplesFromMilliseconds(TimeAtFrame(thisFrame - 1)),
|
||||||
audio->SamplesFromMilliseconds(TimeAtFrame(thisFrame))));
|
audio->SamplesFromMilliseconds(TimeAtFrame(thisFrame))));
|
||||||
}
|
}
|
||||||
|
@ -355,7 +355,7 @@ void VideoContext::PlayLine() {
|
||||||
if (!curline) return;
|
if (!curline) return;
|
||||||
|
|
||||||
// Start playing audio
|
// Start playing audio
|
||||||
audio->PlayRange(AudioController::SampleRange(
|
audio->PlayRange(SampleRange(
|
||||||
audio->SamplesFromMilliseconds(curline->Start.GetMS()),
|
audio->SamplesFromMilliseconds(curline->Start.GetMS()),
|
||||||
audio->SamplesFromMilliseconds(curline->End.GetMS())));
|
audio->SamplesFromMilliseconds(curline->End.GetMS())));
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue