diff --git a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj index 09215ad58..c718375b2 100644 --- a/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj +++ b/aegisub/build/aegisub_vs2008/aegisub_vs2008.vcproj @@ -1731,6 +1731,14 @@ RelativePath="..\..\src\audio_karaoke.h" > + + + + diff --git a/aegisub/build/msbuild/Aegisub/Aegisub.vcxproj b/aegisub/build/msbuild/Aegisub/Aegisub.vcxproj index 3605cbff0..0d71961da 100644 --- a/aegisub/build/msbuild/Aegisub/Aegisub.vcxproj +++ b/aegisub/build/msbuild/Aegisub/Aegisub.vcxproj @@ -67,6 +67,7 @@ + @@ -240,6 +241,7 @@ + diff --git a/aegisub/build/msbuild/Aegisub/Aegisub.vcxproj.filters b/aegisub/build/msbuild/Aegisub/Aegisub.vcxproj.filters index 316a3b72c..f0022c21b 100644 --- a/aegisub/build/msbuild/Aegisub/Aegisub.vcxproj.filters +++ b/aegisub/build/msbuild/Aegisub/Aegisub.vcxproj.filters @@ -207,6 +207,9 @@ Audio\UI + + Audio\UI + Audio\UI @@ -713,6 +716,9 @@ Audio\UI + + Audio\UI + Audio\UI diff --git a/aegisub/src/Makefile b/aegisub/src/Makefile index e1e1b92f9..414640ce0 100644 --- a/aegisub/src/Makefile +++ b/aegisub/src/Makefile @@ -132,6 +132,7 @@ SRC += \ audio_colorscheme.cpp \ audio_display.cpp \ audio_karaoke.cpp \ + audio_marker_provider_keyframes.cpp \ audio_player.cpp \ audio_provider.cpp \ audio_provider_convert.cpp \ diff --git a/aegisub/src/audio_controller.cpp b/aegisub/src/audio_controller.cpp index a2fd020c2..aee4e3bca 100644 --- a/aegisub/src/audio_controller.cpp +++ b/aegisub/src/audio_controller.cpp @@ -47,6 +47,7 @@ #include "ass_file.h" #include "audio_controller.h" +#include "audio_marker_provider_keyframes.h" #include "audio_provider_dummy.h" #include "audio_timing.h" #include "compat.h" @@ -59,83 +60,6 @@ #include "standard_paths.h" #include "video_context.h" -class AudioMarkerKeyframe : public AudioMarker { - Pen *style; - int64_t position; -public: - AudioMarkerKeyframe(Pen *style, int64_t position) : style(style), position(position) { } - int64_t GetPosition() const { return position; } - FeetStyle GetFeet() const { return Feet_None; } - bool CanSnap() const { return true; } - wxPen GetStyle() const { return *style; } - operator int64_t() const { return position; } -}; - -class AudioMarkerProviderKeyframes : public AudioMarkerProvider { - VideoContext *vc; - - agi::signal::Connection keyframe_slot; - agi::signal::Connection audio_open_slot; - agi::signal::Connection timecode_slot; - agi::signal::Connection enabled_slot; - - std::vector keyframe_samples; - AudioController *controller; - - Pen style; - - void Update() - { - std::vector const& keyframes = vc->GetKeyFrames(); - agi::vfr::Framerate const& timecodes = vc->FPS(); - - if (keyframes.empty() || !timecodes.IsLoaded() || !OPT_GET("Audio/Display/Draw/Keyframes")->GetBool()) - { - if (!keyframe_samples.empty()) - { - keyframe_samples.clear(); - AnnounceMarkerMoved(); - } - return; - } - - keyframe_samples.clear(); - keyframe_samples.reserve(keyframes.size()); - for (size_t i = 0; i < keyframes.size(); ++i) - { - keyframe_samples.push_back(AudioMarkerKeyframe(&style, - controller->SamplesFromMilliseconds(timecodes.TimeAtFrame(keyframes[i])))); - } - AnnounceMarkerMoved(); - } - -public: - AudioMarkerProviderKeyframes(AudioController *controller, agi::Context *c) - : vc(c->videoController) - , keyframe_slot(vc->AddKeyframesListener(&AudioMarkerProviderKeyframes::Update, this)) - , audio_open_slot(controller->AddAudioOpenListener(&AudioMarkerProviderKeyframes::Update, this)) - , timecode_slot(vc->AddTimecodesListener(&AudioMarkerProviderKeyframes::Update, this)) - , enabled_slot(OPT_SUB("Audio/Display/Draw/Keyframes", &AudioMarkerProviderKeyframes::Update, this)) - , controller(controller) - , style("Colour/Audio Display/Keyframe") - { - Update(); - } - - void GetMarkers(const SampleRange &range, AudioMarkerVector &out) const - { - // Find first and last keyframes inside the range - std::vector::const_iterator a = std::lower_bound( - keyframe_samples.begin(), keyframe_samples.end(), range.begin()); - std::vector::const_iterator b = std::upper_bound( - keyframe_samples.begin(), keyframe_samples.end(), range.end()); - - // Place pointers to the markers in the output vector - for (; a != b; ++a) - out.push_back(&*a); - } -}; - class VideoPositionMarker : public AudioMarker { Pen style; int64_t position; @@ -374,7 +298,7 @@ void AudioController::OpenAudio(const wxString &url) { // This is lazy-loaded as the video controller may not exist yet when // the audio controller is created - keyframes_marker_provider.reset(new AudioMarkerProviderKeyframes(this, context)); + keyframes_marker_provider.reset(new AudioMarkerProviderKeyframes(context)); keyframes_marker_provider->AddMarkerMovedListener(std::tr1::bind(std::tr1::ref(AnnounceMarkerMoved))); } diff --git a/aegisub/src/audio_marker_provider_keyframes.cpp b/aegisub/src/audio_marker_provider_keyframes.cpp new file mode 100644 index 000000000..3fa84eff7 --- /dev/null +++ b/aegisub/src/audio_marker_provider_keyframes.cpp @@ -0,0 +1,94 @@ +// Copyright (c) 2011, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ +// +// $Id$ + +/// @file audio_marker_provider_keyframes.cpp +/// @see audio_marker_provider_keyframes.h +/// @ingroup audio_ui +/// + +#include "config.h" + +#include "audio_marker_provider_keyframes.h" + +#include "include/aegisub/context.h" +#include "main.h" +#include "pen.h" +#include "video_context.h" + +#ifndef AGI_PRE +#include +#endif + +class AudioMarkerKeyframe : public AudioMarker { + Pen *style; + int64_t position; +public: + AudioMarkerKeyframe(Pen *style, int64_t position) : style(style), position(position) { } + int64_t GetPosition() const { return position; } + FeetStyle GetFeet() const { return Feet_None; } + bool CanSnap() const { return true; } + wxPen GetStyle() const { return *style; } + operator int64_t() const { return position; } +}; + +AudioMarkerProviderKeyframes::AudioMarkerProviderKeyframes(agi::Context *c) +: controller(c->audioController) +, vc(c->videoController) +, keyframe_slot(vc->AddKeyframesListener(&AudioMarkerProviderKeyframes::Update, this)) +, audio_open_slot(controller->AddAudioOpenListener(&AudioMarkerProviderKeyframes::Update, this)) +, timecode_slot(vc->AddTimecodesListener(&AudioMarkerProviderKeyframes::Update, this)) +, enabled_slot(OPT_SUB("Audio/Display/Draw/Keyframes", &AudioMarkerProviderKeyframes::Update, this)) +, enabled_opt(OPT_GET("Audio/Display/Draw/Keyframes")) +, style(new Pen("Colour/Audio Display/Keyframe")) +{ + Update(); +} + +AudioMarkerProviderKeyframes::~AudioMarkerProviderKeyframes() { } + +void AudioMarkerProviderKeyframes::Update() { + std::vector const& keyframes = vc->GetKeyFrames(); + agi::vfr::Framerate const& timecodes = vc->FPS(); + + if (keyframes.empty() || !timecodes.IsLoaded() || !enabled_opt->GetBool()) { + if (!markers.empty()) { + markers.clear(); + AnnounceMarkerMoved(); + } + return; + } + + markers.clear(); + markers.reserve(keyframes.size()); + for (size_t i = 0; i < keyframes.size(); ++i) { + markers.push_back(AudioMarkerKeyframe(style.get(), + controller->SamplesFromMilliseconds(timecodes.TimeAtFrame(keyframes[i])))); + } + AnnounceMarkerMoved(); +} + +void AudioMarkerProviderKeyframes::GetMarkers(SampleRange const& range, AudioMarkerVector &out) const { + // Find first and last keyframes inside the range + std::vector::const_iterator + a = lower_bound(markers.begin(), markers.end(), range.begin()), + b = upper_bound(markers.begin(), markers.end(), range.end()); + + // Place pointers to the markers in the output vector + for (; a != b; ++a) + out.push_back(&*a); +} diff --git a/aegisub/src/audio_marker_provider_keyframes.h b/aegisub/src/audio_marker_provider_keyframes.h new file mode 100644 index 000000000..6c164accd --- /dev/null +++ b/aegisub/src/audio_marker_provider_keyframes.h @@ -0,0 +1,74 @@ +// Copyright (c) 2011, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ +// +// $Id$ + +/// @file audio_marker_provider_keyframes.h +/// @see audio_marker_provider_keyframes.cpp +/// @ingroup audio_ui +/// + +#include "audio_controller.h" + +#include +#include + +#ifndef AGI_PRE +#include +#endif + +class AudioMarkerKeyframe; +class Pen; +class VideoContext; +namespace agi { + class OptionValue; + struct Context; +} + +/// Marker provider for video keyframes +class AudioMarkerProviderKeyframes : public AudioMarkerProvider { + /// Audio controller for time -> sample conversions + AudioController *controller; + /// Video controller to get keyframes from + VideoContext *vc; + + agi::signal::Connection keyframe_slot; + agi::signal::Connection audio_open_slot; + agi::signal::Connection timecode_slot; + agi::signal::Connection enabled_slot; + const agi::OptionValue *enabled_opt; + + /// Current set of markers for the keyframes + std::vector markers; + + /// Pen used for all keyframe markers, stored here for performance reasons + agi::scoped_ptr style; + + /// Regenerate the list of markers + void Update(); + +public: + /// Constructor + /// @param c Project context; must have audio and video controllers initialized + AudioMarkerProviderKeyframes(agi::Context *c); + /// 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(SampleRange const& range, AudioMarkerVector &out) const; +};