Change AudioController's public API from samples to milliseconds

The sample rate of the currently open audio is not something that things
which do not interact with the raw audio data should have to care about,
or even know about.

Originally committed to SVN as r6426.
This commit is contained in:
Thomas Goyne 2012-02-01 23:58:58 +00:00
parent bba825ed0d
commit 01b92aa4e3
18 changed files with 413 additions and 514 deletions

View file

@ -245,5 +245,5 @@ void AudioBox::ScrollAudioBy(int pixel_amount) {
void AudioBox::ScrollToActiveLine() {
if (controller->GetTimingController())
audioDisplay->ScrollSampleRangeInView(controller->GetTimingController()->GetIdealVisibleSampleRange());
audioDisplay->ScrollTimeRangeInView(controller->GetTimingController()->GetIdealVisibleTimeRange());
}

View file

@ -34,7 +34,6 @@
/// @ingroup audio_ui
///
#include "config.h"
#ifndef AGI_PRE
@ -61,7 +60,7 @@
class VideoPositionMarker : public AudioMarker {
Pen style;
int64_t position;
int position;
public:
VideoPositionMarker()
@ -70,20 +69,16 @@ public:
{
}
void SetPosition(int64_t new_pos)
{
position = new_pos;
}
void SetPosition(int new_pos) { position = new_pos; }
int64_t GetPosition() const { return position; }
int 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; }
operator int() const { return position; }
};
class VideoPositionMarkerProvider : public AudioMarkerProvider {
AudioController *ac;
VideoContext *vc;
VideoPositionMarker marker;
@ -99,7 +94,7 @@ class VideoPositionMarkerProvider : public AudioMarkerProvider {
}
else
{
marker.SetPosition(ac->SamplesFromMilliseconds(vc->TimeAtFrame(frame_number)));
marker.SetPosition(vc->TimeAtFrame(frame_number));
}
AnnounceMarkerMoved();
}
@ -120,15 +115,14 @@ class VideoPositionMarkerProvider : public AudioMarkerProvider {
public:
VideoPositionMarkerProvider(agi::Context *c)
: ac(c->audioController)
, vc(c->videoController)
: 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 SampleRange &range, AudioMarkerVector &out) const
void GetMarkers(const TimeRange &range, AudioMarkerVector &out) const
{
if (range.contains(marker))
{
@ -177,7 +171,7 @@ void AudioController::OnPlaybackTimer(wxTimerEvent &)
}
else
{
AnnouncePlaybackPosition(pos);
AnnouncePlaybackPosition(MillisecondsFromSamples(pos));
}
}
@ -409,11 +403,11 @@ void AudioController::OnSubtitlesSave()
}
}
void AudioController::PlayRange(const SampleRange &range)
void AudioController::PlayRange(const TimeRange &range)
{
if (!IsAudioOpen()) return;
player->Play(range.begin(), range.length());
player->Play(SamplesFromMilliseconds(range.begin()), SamplesFromMilliseconds(range.length()));
playback_mode = PM_Range;
playback_timer.Start(20);
@ -428,26 +422,25 @@ void AudioController::PlayPrimaryRange()
playback_mode = PM_PrimaryRange;
}
void AudioController::PlayToEndOfPrimary(int64_t start_sample)
void AudioController::PlayToEndOfPrimary(int start_ms)
{
if (!IsAudioOpen()) return;
player->Play(start_sample, GetPrimaryPlaybackRange().end() - start_sample);
playback_mode = PM_PrimaryRange;
playback_timer.Start(20);
AnnouncePlaybackPosition(start_sample);
PlayRange(TimeRange(start_ms, GetPrimaryPlaybackRange().end()));
if (playback_mode == PM_Range)
playback_mode = PM_PrimaryRange;
}
void AudioController::PlayToEnd(int64_t start_sample)
void AudioController::PlayToEnd(int start_ms)
{
if (!IsAudioOpen()) return;
int64_t start_sample = SamplesFromMilliseconds(start_ms);
player->Play(start_sample, provider->GetNumSamples()-start_sample);
playback_mode = PM_ToEnd;
playback_timer.Start(20);
AnnouncePlaybackPosition(start_sample);
AnnouncePlaybackPosition(start_ms);
}
@ -469,23 +462,30 @@ bool AudioController::IsPlaying()
}
int64_t AudioController::GetPlaybackPosition()
int AudioController::GetPlaybackPosition()
{
if (!IsPlaying()) return 0;
return player->GetCurrentPosition();
return MillisecondsFromSamples(player->GetCurrentPosition());
}
int AudioController::GetDuration() const
{
if (!provider) return 0;
return (provider->GetNumSamples() * 1000 + provider->GetSampleRate() - 1) / provider->GetSampleRate();
}
void AudioController::ResyncPlaybackPosition(int64_t new_position)
void AudioController::ResyncPlaybackPosition(int new_position)
{
if (!IsPlaying()) return;
player->SetCurrentPosition(new_position);
player->SetCurrentPosition(SamplesFromMilliseconds(new_position));
}
SampleRange AudioController::GetPrimaryPlaybackRange() const
TimeRange AudioController::GetPrimaryPlaybackRange() const
{
if (timing_controller)
{
@ -493,19 +493,19 @@ SampleRange AudioController::GetPrimaryPlaybackRange() const
}
else
{
return SampleRange(0, 0);
return TimeRange(0, 0);
}
}
void AudioController::GetMarkers(const SampleRange &range, AudioMarkerVector &markers) 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 SampleRange &range, std::vector<AudioLabel> &labels) const
void AudioController::GetLabels(const TimeRange &range, std::vector<AudioLabel> &labels) const
{
if (timing_controller) timing_controller->GetLabels(range, labels);
}
@ -551,15 +551,17 @@ int64_t AudioController::MillisecondsFromSamples(int64_t samples) const
return millisamples / sr;
}
void AudioController::SaveClip(wxString const& filename, SampleRange const& range) const
void AudioController::SaveClip(wxString const& filename, TimeRange const& range) const
{
if (filename.empty() || range.begin() > provider->GetNumSamples() || range.length() == 0) return;
int64_t start_sample = SamplesFromMilliseconds(range.begin());
int64_t end_sample = SamplesFromMilliseconds(range.end());
if (filename.empty() || start_sample > provider->GetNumSamples() || range.length() == 0) return;
agi::io::Save outfile(STD_STR(filename), true);
std::ofstream& out(outfile.Get());
size_t bytes_per_sample = provider->GetBytesPerSample() * provider->GetChannels();
size_t bufsize = range.length() * bytes_per_sample;
size_t bufsize = (end_sample - start_sample) * bytes_per_sample;
int intval;
short shortval;
@ -580,8 +582,8 @@ void AudioController::SaveClip(wxString const& filename, SampleRange const& rang
//samples per read
size_t spr = 65536 / bytes_per_sample;
std::vector<char> buf(bufsize);
for(int64_t i = range.begin(); i < range.end(); i += spr) {
size_t len = std::min<size_t>(spr, range.end() - i);
for(int64_t i = start_sample; i < end_sample; i += spr) {
size_t len = std::min<size_t>(spr, end_sample - i);
provider->GetAudio(&buf[0], i, len);
out.write(&buf[0], len * bytes_per_sample);
}

View file

@ -65,47 +65,44 @@ class AudioMarkerProvider;
typedef std::vector<const AudioMarker*> AudioMarkerVector;
/// @class SampleRange
/// @brief Represents an immutable range of audio samples
class SampleRange {
int64_t _begin;
int64_t _end;
/// @class TimeRange
/// @brief Represents an immutable range of time
class TimeRange {
int _begin;
int _end;
public:
/// @brief Constructor
/// @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
SampleRange(int64_t begin, int64_t end)
: _begin(begin)
, _end(end)
/// @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 samples to add to the start of the range
/// @param end_adjust Number of samples to add to the end of the range
SampleRange(const SampleRange &src, int64_t begin_adjust = 0, int64_t end_adjust = 0)
/// @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 number of samples in the range
int64_t length() const { return _end - _begin; }
/// Get the index of the first sample in the range
int64_t begin() const { return _begin; }
/// Get the index of one past the last sample in the range
int64_t end() const { return _end; }
/// 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 sample index
bool contains(int64_t sample) const { return sample >= begin() && sample < 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 SampleRange &other) const
bool overlaps(const TimeRange &other) const
{
return other.contains(_begin) || contains(other._begin);
}
@ -121,8 +118,8 @@ public:
/// Virtual destructor, does nothing
virtual ~AudioMarkerProvider() { }
/// @brief Return markers in a sample range
virtual void GetMarkers(const SampleRange &range, AudioMarkerVector &out) const = 0;
/// @brief Return markers in a time range
virtual void GetMarkers(const TimeRange &range, AudioMarkerVector &out) const = 0;
DEFINE_SIGNAL_ADDERS(AnnounceMarkerMoved, AddMarkerMovedListener)
};
@ -134,22 +131,22 @@ protected:
/// One or more of the labels provided by this object have changed
agi::signal::Signal<> AnnounceLabelChanged;
public:
/// A label for a range of samples on the audio display
/// 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
SampleRange range;
AudioLabel(wxString const& text, SampleRange const& range) : text(text), range(range) { }
TimeRange range;
AudioLabel(wxString const& text, TimeRange const& range) : text(text), range(range) { }
};
/// Virtual destructor, does nothing
virtual ~AudioLabelProvider() { }
/// @brief Get labels in a sample range
/// @param range Range of samples to get labels for
/// @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(SampleRange const& range, std::vector<AudioLabel> &out) const = 0;
virtual void GetLabels(TimeRange const& range, std::vector<AudioLabel> &out) const = 0;
DEFINE_SIGNAL_ADDERS(AnnounceLabelChanged, AddLabelChangedListener)
};
@ -190,7 +187,7 @@ class AudioController : public wxEvtHandler, public AudioMarkerProvider, public
agi::signal::Signal<> AnnounceAudioClose;
/// Playback is in progress and the current position was updated
agi::signal::Signal<int64_t> AnnouncePlaybackPosition;
agi::signal::Signal<int> AnnouncePlaybackPosition;
/// Playback has stopped
agi::signal::Signal<> AnnouncePlaybackStop;
@ -258,8 +255,17 @@ class AudioController : public wxEvtHandler, public AudioMarkerProvider, public
void OnComputerResuming(wxPowerEvent &event);
#endif
public:
/// @brief Convert a count of audio samples to a time in milliseconds
/// @param samples Sample count to convert
/// @return The number of milliseconds equivalent to the sample-count, rounded down
int64_t MillisecondsFromSamples(int64_t samples) const;
/// @brief Convert a time in milliseconds to a count of audio samples
/// @param ms Time in milliseconds to convert
/// @return The index of the first sample that is wholly inside the millisecond
int64_t SamplesFromMilliseconds(int64_t ms) const;
public:
/// @brief Constructor
AudioController(agi::Context *context);
@ -294,7 +300,7 @@ public:
///
/// The end of the played back range may be requested changed, but is not
/// changed automatically from any other operations.
void PlayRange(const SampleRange &range);
void PlayRange(const TimeRange &range);
/// @brief Start or restart audio playback, playing the primary playback range
///
@ -304,19 +310,19 @@ public:
void PlayPrimaryRange();
/// @brief Start or restart audio playback, playing from a point to the end of of the primary playback range
/// @param start_sample Index of the sample to start playback at
/// @param start_ms Time in milliseconds to start playback at
///
/// This behaves like PlayPrimaryRange, but the start point can differ from
/// the beginning of the primary range.
void PlayToEndOfPrimary(int64_t start_sample);
void PlayToEndOfPrimary(int start_ms);
/// @brief Start or restart audio playback, playing from a point to the end of stream
/// @param start_sample Index of the sample to start playback at
/// @param start_ms Time in milliseconds to start playback at
///
/// Playback to end cannot be converted to a range playback like range
/// playback can, it will continue until the end is reached, it is stopped,
/// or restarted.
void PlayToEnd(int64_t start_sample);
void PlayToEnd(int start_ms);
/// @brief Stop all audio playback
void Stop();
@ -326,35 +332,39 @@ public:
bool IsPlaying();
/// @brief Get the current playback position
/// @return Approximate current sample index being heard by the user
/// @return Approximate current time in milliseconds being heard by the user
///
/// Returns 0 if playback is stopped. The return value is only approximate.
int64_t GetPlaybackPosition();
int GetPlaybackPosition();
/// Get the duration of the currently open audio in milliseconds, or 0 if none
/// @return Duration in milliseconds
int GetDuration() const;
/// @brief If playing, restart playback from the specified position
/// @param new_position Sample index to restart playback from
/// @param new_position Time to restart playback from
///
/// This function can be used to re-synchronise audio playback to another
/// source that might not be able to keep up with the full speed, such as
/// video playback in high resolution or with complex subtitles.
///
/// This function only does something if audio is already playing.
void ResyncPlaybackPosition(int64_t new_position);
void ResyncPlaybackPosition(int new_position);
/// @brief Get the primary playback range
/// @return An immutable SampleRange object
SampleRange GetPrimaryPlaybackRange() const;
/// @return An immutable TimeRange object
TimeRange GetPrimaryPlaybackRange() const;
/// @brief Get all markers inside a range
/// @param range The sample range to retrieve markers for
/// @param range The time range to retrieve markers for
/// @param markers Vector to fill found markers into
void GetMarkers(const SampleRange &range, AudioMarkerVector &markers) const;
void GetMarkers(const TimeRange &range, AudioMarkerVector &markers) const;
/// @brief Get all labels inside a range
/// @param range The sample range to retrieve labels for
/// @param range The time range to retrieve labels for
/// @param labels Vector to fill found labels into
void GetLabels(const SampleRange &range, std::vector<AudioLabel> &labels) const;
void GetLabels(const TimeRange &range, std::vector<AudioLabel> &labels) const;
/// @brief Get the playback audio volume
@ -376,20 +386,10 @@ public:
/// dialogue line.
void SetTimingController(AudioTimingController *new_controller);
/// @brief Convert a count of audio samples to a time in milliseconds
/// @param samples Sample count to convert
/// @return The number of milliseconds equivalent to the sample-count, rounded down
int64_t MillisecondsFromSamples(int64_t samples) const;
/// @brief Convert a time in milliseconds to a count of audio samples
/// @param ms Time in milliseconds to convert
/// @return The index of the first sample that is wholly inside the millisecond
int64_t SamplesFromMilliseconds(int64_t ms) const;
/// @brief Save a portion of the decoded loaded audio to a wav file
/// @param filename File to save to
/// @param range Range of samples to save
void SaveClip(wxString const& filename, SampleRange const& range) const;
/// @param range Time range to save
void SaveClip(wxString const& filename, TimeRange const& range) const;
DEFINE_SIGNAL_ADDERS(AnnounceAudioOpen, AddAudioOpenListener)
DEFINE_SIGNAL_ADDERS(AnnounceAudioClose, AddAudioCloseListener)
@ -414,8 +414,8 @@ public:
};
/// @brief Get the marker's position
/// @return The marker's position in samples
virtual int64_t GetPosition() const = 0;
/// @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

View file

@ -55,7 +55,6 @@
#include "audio_timing.h"
#include "block_cache.h"
#include "compat.h"
#include "include/aegisub/audio_provider.h"
#include "include/aegisub/context.h"
#include "include/aegisub/hotkey.h"
#include "main.h"
@ -250,10 +249,9 @@ const int AudioDisplayScrollbar::min_width;
class AudioDisplayTimeline : public AudioDisplayInteractionObject {
int64_t num_samples;
int samplerate;
int samples_per_pixel;
int pixel_left;
int duration; ///< Total duration in ms
double ms_per_pixel; ///< Milliseconds per pixel
int pixel_left; ///< Leftmost visible pixel (i.e. scroll position)
wxRect bounds;
@ -276,27 +274,21 @@ class AudioDisplayTimeline : public AudioDisplayInteractionObject {
int scale_major_modulo; ///< If minor_scale_mark_index % scale_major_modulo == 0 the mark is a major mark
double scale_minor_divisor; ///< Absolute scale-mark index multiplied by this number gives sample index for scale mark
AudioDisplay *display;
AudioDisplay *display; ///< Containing audio display
UIColours colours; ///< Colour provider
public:
AudioDisplayTimeline(AudioDisplay *display)
: num_samples(0)
, samplerate(44100)
, samples_per_pixel(1)
: duration(0)
, ms_per_pixel(1.0)
, pixel_left(0)
, dragging(false)
, display(display)
{
}
int GetHeight() const
{
int width, height;
display->GetTextExtent("0123456789:.", &width, &height);
return height + 4;
bounds.height = height + 4;
}
void SetColourScheme(std::string const& name)
@ -308,57 +300,55 @@ public:
{
// The size is without anything that goes below the timeline (like scrollbar)
bounds.width = display_size.x;
bounds.height = GetHeight();
bounds.x = 0;
bounds.y = 0;
}
int GetHeight() const { return bounds.height; }
const wxRect & GetBounds() const { return bounds; }
void ChangeAudio(int64_t new_length, int new_samplerate)
void ChangeAudio(int new_duration)
{
num_samples = new_length;
samplerate = new_samplerate;
duration = new_duration;
}
void ChangeZoom(int new_pixel_samples)
void ChangeZoom(double new_ms_per_pixel)
{
samples_per_pixel = new_pixel_samples;
ms_per_pixel = new_ms_per_pixel;
// Pixels per second
double px_sec = (double)samplerate / (double)samples_per_pixel;
double px_sec = 1000.0 / ms_per_pixel;
if (px_sec > 3000) {
scale_minor = Sc_Millisecond;
scale_minor_divisor = (double)samplerate / 1000;
scale_minor_divisor = 1.0;
scale_major_modulo = 10;
} else if (px_sec > 300) {
scale_minor = Sc_Centisecond;
scale_minor_divisor = (double)samplerate / 100;
scale_minor_divisor = 10.0;
scale_major_modulo = 10;
} else if (px_sec > 30) {
scale_minor = Sc_Decisecond;
scale_minor_divisor = (double)samplerate / 10;
scale_minor_divisor = 100.0;
scale_major_modulo = 10;
} else if (px_sec > 3) {
scale_minor = Sc_Second;
scale_minor_divisor = (double)samplerate;
scale_minor_divisor = 1000.0;
scale_major_modulo = 10;
} else if (px_sec > 1.0/3.0) {
scale_minor = Sc_Decasecond;
scale_minor_divisor = (double)samplerate * 10;
scale_minor_divisor = 10000.0;
scale_major_modulo = 6;
} else if (px_sec > 1.0/9.0) {
scale_minor = Sc_Minute;
scale_minor_divisor = (double)samplerate * 60;
scale_minor_divisor = 60000.0;
scale_major_modulo = 10;
} else if (px_sec > 1.0/90.0) {
scale_minor = Sc_Decaminute;
scale_minor_divisor = (double)samplerate * 600;
scale_minor_divisor = 600000.0;
scale_major_modulo = 6;
} else {
scale_minor = Sc_Hour;
scale_minor_divisor = (double)samplerate * 3600;
scale_minor_divisor = 3600000.0;
scale_major_modulo = 10;
}
}
@ -408,19 +398,19 @@ public:
dc.SetTextForeground(colours.Light());
// Figure out the first scale mark to show
int64_t sample_left = pixel_left * samples_per_pixel;
int next_scale_mark = (int)(sample_left / scale_minor_divisor);
if (next_scale_mark * scale_minor_divisor < sample_left)
int ms_left = int(pixel_left * ms_per_pixel);
int next_scale_mark = int(ms_left / scale_minor_divisor);
if (next_scale_mark * scale_minor_divisor < ms_left)
next_scale_mark += 1;
assert(next_scale_mark * scale_minor_divisor >= sample_left);
assert(next_scale_mark * scale_minor_divisor >= ms_left);
// Draw scale marks
int next_scale_mark_pos;
int last_text_right = -1;
int last_hour = -1, last_minute = -1;
if (num_samples / samplerate < 3600) last_hour = 0; // Trick to only show hours if audio is longer than 1 hour
if (duration < 3600) last_hour = 0; // Trick to only show hours if audio is longer than 1 hour
do {
next_scale_mark_pos = (int)(next_scale_mark * scale_minor_divisor / samples_per_pixel) - pixel_left;
next_scale_mark_pos = int(next_scale_mark * scale_minor_divisor / ms_per_pixel) - pixel_left;
bool mark_is_major = next_scale_mark % scale_major_modulo == 0;
if (mark_is_major)
@ -431,7 +421,7 @@ public:
// Print time labels on major scale marks
if (mark_is_major && next_scale_mark_pos > last_text_right)
{
double mark_time = next_scale_mark * scale_minor_divisor / samplerate;
double mark_time = next_scale_mark * scale_minor_divisor / 1000.0;
int mark_hour = (int)(mark_time / 3600);
int mark_minute = (int)(mark_time / 60) % 60;
double mark_second = mark_time - mark_hour*3600 - mark_minute*60;
@ -504,8 +494,8 @@ public:
{
timing_controller->OnMarkerDrag(
marker,
display->SamplesFromRelativeX(event.GetPosition().x),
default_snap != event.ShiftDown() ? display->SamplesFromAbsoluteX(snap_range) : 0);
display->TimeFromRelativeX(event.GetPosition().x),
default_snap != event.ShiftDown() ? display->TimeFromAbsoluteX(snap_range) : 0);
}
// We lose the marker drag if the button used to initiate it goes up
@ -514,14 +504,14 @@ public:
};
class AudioStyleRangeMerger : public AudioRenderingStyleRanges {
typedef std::map<int64_t, AudioRenderingStyle> style_map;
typedef std::map<int, AudioRenderingStyle> style_map;
public:
typedef style_map::iterator iterator;
private:
style_map points;
void Split(int64_t point)
void Split(int point)
{
iterator it = points.lower_bound(point);
if (it == points.end() || it->first != point)
@ -531,7 +521,7 @@ private:
}
}
void Restyle(int64_t start, int64_t end, AudioRenderingStyle style)
void Restyle(int start, int end, AudioRenderingStyle style)
{
assert(points.lower_bound(end) != points.end());
for (iterator pt = points.lower_bound(start); pt->first < end; ++pt)
@ -547,7 +537,7 @@ public:
points[0] = AudioStyle_Normal;
}
void AddRange(int64_t start, int64_t end, AudioRenderingStyle style)
void AddRange(int start, int end, AudioRenderingStyle style)
{
if (start < 0) start = 0;
@ -567,7 +557,6 @@ AudioDisplay::AudioDisplay(wxWindow *parent, AudioController *controller, agi::C
, audio_open_connection(controller->AddAudioOpenListener(&AudioDisplay::OnAudioOpen, this))
, context(context)
, audio_renderer(new AudioRenderer)
, provider(0)
, controller(controller)
, scrollbar(new AudioDisplayScrollbar(this))
, timeline(new AudioDisplayTimeline(this))
@ -627,29 +616,11 @@ void AudioDisplay::ScrollPixelToLeft(int pixel_position)
}
void AudioDisplay::ScrollPixelToCenter(int pixel_position)
{
ScrollPixelToLeft(pixel_position - GetClientRect().GetWidth()/2);
}
void AudioDisplay::ScrollSampleToLeft(int64_t sample_position)
{
ScrollPixelToLeft(AbsoluteXFromSamples(sample_position));
}
void AudioDisplay::ScrollSampleToCenter(int64_t sample_position)
{
ScrollPixelToCenter(AbsoluteXFromSamples(sample_position));
}
void AudioDisplay::ScrollSampleRangeInView(const SampleRange &range)
void AudioDisplay::ScrollTimeRangeInView(const TimeRange &range)
{
int client_width = GetClientRect().GetWidth();
int range_begin = AbsoluteXFromSamples(range.begin());
int range_end = AbsoluteXFromSamples(range.end());
int range_begin = AbsoluteXFromTime(range.begin());
int range_end = AbsoluteXFromTime(range.end());
int range_len = range_end - range_begin;
// Is everything already in view?
@ -690,35 +661,24 @@ void AudioDisplay::SetZoomLevel(int new_zoom_level)
{
zoom_level = new_zoom_level;
if (!provider)
{
pixel_samples = 1;
return;
}
const int samples_per_second = provider ? provider->GetSampleRate() : 48000;
const int base_pixels_per_second = 50; /// @todo Make this customisable
const int base_samples_per_pixel = samples_per_second / base_pixels_per_second;
const int factor = GetZoomLevelFactor(zoom_level);
const int base_pixels_per_second = 50; /// @todo Make this customisable
const double base_ms_per_pixel = 1000.0 / base_pixels_per_second;
const double new_ms_per_pixel = 100.0 * base_ms_per_pixel / factor;
const int new_samples_per_pixel = std::max(1, 100 * base_samples_per_pixel / factor);
if (pixel_samples != new_samples_per_pixel)
if (ms_per_pixel != new_ms_per_pixel)
{
int client_width = GetClientSize().GetWidth();
int64_t center_sample = int64_t(scroll_left + client_width / 2) * pixel_samples;
double center_time = (scroll_left + client_width / 2) * ms_per_pixel;
pixel_samples = new_samples_per_pixel;
audio_renderer->SetSamplesPerPixel(pixel_samples);
pixel_audio_width = provider->GetNumSamples() / pixel_samples + 1;
ms_per_pixel = new_ms_per_pixel;
pixel_audio_width = std::max(1, int(controller->GetDuration() / ms_per_pixel));
audio_renderer->SetMillisecondsPerPixel(ms_per_pixel);
scrollbar->ChangeLengths(pixel_audio_width, client_width);
timeline->ChangeZoom(pixel_samples);
ScrollSampleToCenter(center_sample);
timeline->ChangeZoom(ms_per_pixel);
ScrollTimeToCenter(center_time);
Refresh();
}
}
@ -770,13 +730,6 @@ void AudioDisplay::SetAmplitudeScale(float scale)
Refresh();
}
float AudioDisplay::GetAmplitudeScale() const
{
return audio_renderer->GetAmplitudeScale();
}
void AudioDisplay::ReloadRenderingSettings()
{
std::string colour_scheme_name;
@ -831,13 +784,6 @@ void AudioDisplay::OnPaint(wxPaintEvent&)
{
wxAutoBufferedPaintDC dc(this);
if (!provider)
{
dc.SetBackground(*wxBLACK_BRUSH);
dc.Clear();
return;
}
wxRect audio_bounds(0, audio_top, GetClientSize().GetWidth(), audio_height);
bool redraw_scrollbar = false;
bool redraw_timeline = false;
@ -857,13 +803,13 @@ void AudioDisplay::OnPaint(wxPaintEvent&)
if (audio_bounds.Intersects(updrect))
{
SampleRange updsamples(
SamplesFromRelativeX(updrect.x - foot_size),
SamplesFromRelativeX(updrect.x + updrect.width + foot_size));
TimeRange updtime(
std::max(0, TimeFromRelativeX(updrect.x - foot_size)),
std::max(0, TimeFromRelativeX(updrect.x + updrect.width + foot_size)));
PaintAudio(dc, updsamples, updrect);
PaintMarkers(dc, updsamples);
PaintLabels(dc, updsamples);
PaintAudio(dc, updtime, updrect);
PaintMarkers(dc, updtime);
PaintLabels(dc, updtime);
}
}
@ -878,10 +824,10 @@ void AudioDisplay::OnPaint(wxPaintEvent&)
timeline->Paint(dc);
}
void AudioDisplay::PaintAudio(wxDC &dc, SampleRange updsamples, wxRect updrect)
void AudioDisplay::PaintAudio(wxDC &dc, TimeRange updtime, wxRect updrect)
{
std::map<int64_t, int>::iterator pt = style_ranges.upper_bound(updsamples.begin());
std::map<int64_t, int>::iterator pe = style_ranges.upper_bound(updsamples.end());
std::map<int, int>::iterator pt = style_ranges.upper_bound(updtime.begin());
std::map<int, int>::iterator pe = style_ranges.upper_bound(updtime.end());
if (pt != style_ranges.begin())
--pt;
@ -889,8 +835,8 @@ void AudioDisplay::PaintAudio(wxDC &dc, SampleRange updsamples, wxRect updrect)
while (pt != pe)
{
AudioRenderingStyle range_style = static_cast<AudioRenderingStyle>(pt->second);
int range_x1 = std::max(updrect.x, RelativeXFromSamples(pt->first));
int range_x2 = (++pt == pe) ? updrect.x + updrect.width : RelativeXFromSamples(pt->first);
int range_x1 = std::max(updrect.x, RelativeXFromTime(pt->first));
int range_x2 = (++pt == pe) ? updrect.x + updrect.width : RelativeXFromTime(pt->first);
if (range_x2 > range_x1)
{
@ -899,10 +845,10 @@ void AudioDisplay::PaintAudio(wxDC &dc, SampleRange updsamples, wxRect updrect)
}
}
void AudioDisplay::PaintMarkers(wxDC &dc, SampleRange updsamples)
void AudioDisplay::PaintMarkers(wxDC &dc, TimeRange updtime)
{
AudioMarkerVector markers;
controller->GetMarkers(updsamples, markers);
controller->GetMarkers(updtime, markers);
if (markers.empty()) return;
wxDCPenChanger pen_retainer(dc, wxPen());
@ -910,7 +856,7 @@ void AudioDisplay::PaintMarkers(wxDC &dc, SampleRange updsamples)
for (AudioMarkerVector::iterator marker_i = markers.begin(); marker_i != markers.end(); ++marker_i)
{
const AudioMarker *marker = *marker_i;
int marker_x = RelativeXFromSamples(marker->GetPosition());
int marker_x = RelativeXFromTime(marker->GetPosition());
dc.SetPen(marker->GetStyle());
dc.DrawLine(marker_x, audio_top, marker_x, audio_top+audio_height);
@ -935,10 +881,10 @@ void AudioDisplay::PaintFoot(wxDC &dc, int marker_x, int dir)
dc.DrawPolygon(3, foot_bot, marker_x, audio_top+audio_height);
}
void AudioDisplay::PaintLabels(wxDC &dc, SampleRange updsamples)
void AudioDisplay::PaintLabels(wxDC &dc, TimeRange updtime)
{
std::vector<AudioLabelProvider::AudioLabel> labels;
controller->GetLabels(updsamples, labels);
controller->GetLabels(updtime, labels);
if (labels.empty()) return;
wxDCFontChanger fc(dc);
@ -949,8 +895,8 @@ void AudioDisplay::PaintLabels(wxDC &dc, SampleRange updsamples)
for (size_t i = 0; i < labels.size(); ++i)
{
wxSize extent = dc.GetTextExtent(labels[i].text);
int left = RelativeXFromSamples(labels[i].range.begin());
int width = AbsoluteXFromSamples(labels[i].range.length());
int left = RelativeXFromTime(labels[i].range.begin());
int width = AbsoluteXFromTime(labels[i].range.length());
// If it doesn't fit, truncate
if (width < extent.GetWidth())
@ -1034,7 +980,7 @@ void AudioDisplay::SetTrackCursor(int new_pos, bool show_time)
if (show_time)
{
AssTime new_label_time = controller->MillisecondsFromSamples(SamplesFromAbsoluteX(track_cursor_pos));
AssTime new_label_time = TimeFromAbsoluteX(track_cursor_pos);
track_cursor_label = new_label_time.GetASSFormated();
track_cursor_label_rect.x += new_pos - old_pos;
RefreshRect(track_cursor_label_rect, false);
@ -1118,9 +1064,7 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event)
if (event.MiddleIsDown())
{
context->videoController->JumpToTime(
controller->MillisecondsFromSamples(SamplesFromRelativeX(mousepos.x)),
agi::vfr::EXACT);
context->videoController->JumpToTime(TimeFromRelativeX(mousepos.x), agi::vfr::EXACT);
return;
}
@ -1131,15 +1075,15 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event)
AudioTimingController *timing = controller->GetTimingController();
if (!timing) return;
int drag_sensitivity = pixel_samples * OPT_GET("Audio/Start Drag Sensitivity")->GetInt();
int snap_sensitivity = OPT_GET("Audio/Snap/Enable")->GetBool() != event.ShiftDown() ? pixel_samples * OPT_GET("Audio/Snap/Distance")->GetInt() : 0;
int drag_sensitivity = int(OPT_GET("Audio/Start Drag Sensitivity")->GetInt() * ms_per_pixel);
int snap_sensitivity = OPT_GET("Audio/Snap/Enable")->GetBool() != event.ShiftDown() ? int(OPT_GET("Audio/Snap/Distance")->GetInt() * ms_per_pixel) : 0;
// Not scrollbar, not timeline, no button action
if (event.Moving())
{
int64_t samplepos = SamplesFromRelativeX(mousepos.x);
int timepos = TimeFromRelativeX(mousepos.x);
if (timing->IsNearbyMarker(samplepos, drag_sensitivity))
if (timing->IsNearbyMarker(timepos, drag_sensitivity))
SetCursor(wxCursor(wxCURSOR_SIZEWE));
else
SetCursor(wxNullCursor);
@ -1147,10 +1091,10 @@ void AudioDisplay::OnMouseEvent(wxMouseEvent& event)
if (event.LeftDown() || event.RightDown())
{
int64_t samplepos = SamplesFromRelativeX(mousepos.x);
int timepos = TimeFromRelativeX(mousepos.x);
AudioMarker *marker = event.LeftDown() ?
timing->OnLeftClick(samplepos, drag_sensitivity, snap_sensitivity) :
timing->OnRightClick(samplepos, drag_sensitivity, snap_sensitivity);
timing->OnLeftClick(timepos, drag_sensitivity, snap_sensitivity) :
timing->OnRightClick(timepos, drag_sensitivity, snap_sensitivity);
if (marker)
{
@ -1176,8 +1120,11 @@ void AudioDisplay::OnSize(wxSizeEvent &)
timeline->SetDisplaySize(wxSize(size.x, scrollbar->GetBounds().y));
scrollbar->SetDisplaySize(size);
SampleRange sel(controller->GetPrimaryPlaybackRange());
scrollbar->SetSelection(AbsoluteXFromSamples(sel.begin()), AbsoluteXFromSamples(sel.length()));
if (controller->GetTimingController())
{
TimeRange sel(controller->GetTimingController()->GetPrimaryPlaybackRange());
scrollbar->SetSelection(AbsoluteXFromTime(sel.begin()), AbsoluteXFromTime(sel.length()));
}
audio_height = size.GetHeight();
audio_height -= scrollbar->GetBounds().GetHeight();
@ -1199,17 +1146,15 @@ void AudioDisplay::OnFocus(wxFocusEvent &)
void AudioDisplay::OnAudioOpen(AudioProvider *provider)
{
this->provider = provider;
if (!audio_renderer_provider)
ReloadRenderingSettings();
audio_renderer->SetAudioProvider(provider);
audio_renderer->SetCacheMaxSize(OPT_GET("Audio/Renderer/Spectrum/Memory Max")->GetInt() * 1024 * 1024);
if (provider)
timeline->ChangeAudio(provider->GetNumSamples(), provider->GetSampleRate());
timeline->ChangeAudio(controller->GetDuration());
ms_per_pixel = 0;
SetZoomLevel(zoom_level);
Refresh();
@ -1238,9 +1183,9 @@ void AudioDisplay::OnAudioOpen(AudioProvider *provider)
}
}
void AudioDisplay::OnPlaybackPosition(int64_t sample_position)
void AudioDisplay::OnPlaybackPosition(int ms)
{
int pixel_position = AbsoluteXFromSamples(sample_position);
int pixel_position = AbsoluteXFromTime(ms);
SetTrackCursor(pixel_position, false);
if (OPT_GET("Audio/Lock Scroll on Cursor")->GetBool())
@ -1260,12 +1205,12 @@ void AudioDisplay::OnPlaybackPosition(int64_t sample_position)
void AudioDisplay::OnSelectionChanged()
{
SampleRange sel(controller->GetPrimaryPlaybackRange());
scrollbar->SetSelection(AbsoluteXFromSamples(sel.begin()), AbsoluteXFromSamples(sel.length()));
TimeRange sel(controller->GetPrimaryPlaybackRange());
scrollbar->SetSelection(AbsoluteXFromTime(sel.begin()), AbsoluteXFromTime(sel.length()));
if (OPT_GET("Audio/Auto/Scroll")->GetBool())
{
ScrollSampleRangeInView(sel);
ScrollTimeRangeInView(sel);
}
RefreshRect(scrollbar->GetBounds(), false);
@ -1278,16 +1223,16 @@ void AudioDisplay::OnStyleRangesChanged()
AudioStyleRangeMerger asrm;
controller->GetTimingController()->GetRenderingStyles(asrm);
std::map<int64_t, int> old_style_ranges;
std::map<int, int> old_style_ranges;
swap(old_style_ranges, style_ranges);
style_ranges.insert(asrm.begin(), asrm.end());
std::map<int64_t, int>::iterator old_style_it = old_style_ranges.begin();
std::map<int64_t, int>::iterator new_style_it = style_ranges.begin();
std::map<int, int>::iterator old_style_it = old_style_ranges.begin();
std::map<int, int>::iterator new_style_it = style_ranges.begin();
int old_style = old_style_it->second;
int new_style = new_style_it->second;
int64_t range_start = 0;
int range_start = 0;
// Repaint each range which has changed
while (old_style_it != old_style_ranges.end() || new_style_it != style_ranges.end())
@ -1313,20 +1258,20 @@ void AudioDisplay::OnStyleRangesChanged()
// Fill in the last style range
if (old_style != new_style)
{
Redraw(range_start, SamplesFromRelativeX(GetClientSize().GetWidth()));
Redraw(range_start, TimeFromRelativeX(GetClientSize().GetWidth()));
}
}
void AudioDisplay::Redraw(int64_t sample_start, int64_t sample_end)
void AudioDisplay::Redraw(int time_start, int time_end)
{
if (sample_start == sample_end) return;
if (time_start == time_end) return;
sample_start = RelativeXFromSamples(sample_start) - foot_size;
sample_end = RelativeXFromSamples(sample_end) + foot_size;
time_start = RelativeXFromTime(time_start) - foot_size;
time_end = RelativeXFromTime(time_end) + foot_size;
if (sample_end >= 0 && sample_start <= GetClientSize().GetWidth())
if (time_end >= 0 && time_start <= GetClientSize().GetWidth())
{
RefreshRect(wxRect(sample_start, audio_top, sample_end - sample_start, audio_height), false);
RefreshRect(wxRect(time_start, audio_top, time_end - time_start, audio_height), false);
}
}

View file

@ -110,9 +110,6 @@ class AudioDisplay: public wxWindow {
/// The current audio renderer
agi::scoped_ptr<AudioRendererBitmapProvider> audio_renderer_provider;
/// Our current audio provider
AudioProvider *provider;
/// The controller managing us
AudioController *controller;
@ -139,8 +136,8 @@ class AudioDisplay: public wxWindow {
/// Total width of the audio in pixels
int pixel_audio_width;
/// Horizontal zoom measured in audio samples per pixel
int pixel_samples;
/// Horizontal zoom measured in millisecond per pixels
double ms_per_pixel;
/// Amplitude scaling ("vertical zoom") as a factor, 1.0 is neutral
float scale_amplitude;
@ -171,7 +168,7 @@ class AudioDisplay: public wxWindow {
void RemoveTrackCursor();
/// Previous style ranges for optimizing redraw when ranges change
std::map<int64_t, int> style_ranges;
std::map<int, int> style_ranges;
/// @brief Reload all rendering settings from Options and reset caches
///
@ -179,21 +176,21 @@ class AudioDisplay: public wxWindow {
/// in Options and need to be reloaded to take effect.
void ReloadRenderingSettings();
/// @brief Repaint a range of samples
/// @param sample_start First sample to repaint
/// @param sample_end Last sample to repaint
void Redraw(int64_t sample_start, int64_t sample_end);
/// @brief Repaint a time range
/// @param ms_start Beginning of range to repaint
/// @param ms_end End of range to repaint
void Redraw(int ms_start, int ms_end);
/// Paint the audio data for a range of samples
/// Paint the audio data for a time range
/// @param dc DC to paint to
/// @param updsamples Sample range to repaint
/// @param updtime Time range to repaint
/// @param updrect Pixel range to repaint
void PaintAudio(wxDC &dc, SampleRange updsamples, wxRect updrect);
void PaintAudio(wxDC &dc, TimeRange updtime, wxRect updrect);
/// Paint the markers in a range of samples
/// Paint the markers in a time range
/// @param dc DC to paint to
/// @param updsamples Sample range to repaint
void PaintMarkers(wxDC &dc, SampleRange updsamples);
/// @param updtime Time range to repaint
void PaintMarkers(wxDC &dc, TimeRange updtime);
/// Draw a single foot for a marker
/// @param dc DC to paint to
@ -201,10 +198,10 @@ class AudioDisplay: public wxWindow {
/// @param dir -1 for left, 1 for right
void PaintFoot(wxDC &dc, int marker_x, int dir);
/// Paint the labels in a range of samples
/// Paint the labels in a time range
/// @param dc DC to paint to
/// @param updsamples Sample range to repaint
void PaintLabels(wxDC &dc, SampleRange updsamples);
/// @param updtime Time range to repaint
void PaintLabels(wxDC &dc, TimeRange updtime);
/// Paint the track cursor
/// @param dc DC to paint to
@ -223,7 +220,7 @@ class AudioDisplay: public wxWindow {
// AudioControllerAudioEventListener implementation
void OnAudioOpen(AudioProvider *provider);
void OnPlaybackPosition(int64_t sample_position);
void OnPlaybackPosition(int ms_position);
void OnSelectionChanged();
void OnStyleRangesChanged();
void OnMarkerMoved();
@ -248,46 +245,49 @@ public:
/// @brief Scroll the audio display
/// @param pixel_position Absolute pixel to put in center of the audio display
void ScrollPixelToCenter(int pixel_position);
void ScrollPixelToCenter(int pixel_position) { ScrollPixelToLeft(pixel_position - GetClientRect().GetWidth()/2); }
/// @brief Scroll the audio display
/// @param sample_position Audio sample to put at left edge of the audio display
void ScrollSampleToLeft(int64_t sample_position);
/// @param ms Time in milliseconds to put at left edge of the audio display
void ScrollTimeToLeft(int ms) { ScrollPixelToLeft(AbsoluteXFromTime(ms)); }
/// @brief Scroll the audio display
/// @param sample_position Audio sample to put in center of the audio display
void ScrollSampleToCenter(int64_t sample_position);
/// @param ms Time in milliseconds to put in center of the audio display
void ScrollTimeToCenter(int ms) { ScrollPixelToCenter(AbsoluteXFromTime(ms)); }
/// @brief Scroll the audio display
/// @param range Range of audio samples to ensure is in view
/// @param range Time range to ensure is in view
///
/// If the entire range is already visible inside the display, nothing is scrolled. If
/// just one of the two endpoints is visible, the display is scrolled such that the
/// visible endpoint stays in view but more of the rest of the range becomes visible.
/// If the entire range is already visible inside the display, nothing is
/// scrolled. If just one of the two endpoints is visible, the display is
/// scrolled such that the visible endpoint stays in view but more of the
/// rest of the range becomes visible.
///
/// If the entire range fits inside the display, the display is centered over the range.
/// For this calculation, the display is considered smaller by some margins, see below.
/// If the entire range fits inside the display, the display is centered
/// over the range. For this calculation, the display is considered
/// smaller by some margins, see below.
///
/// If the range does not fit within the display with margins subtracted, the start of
/// the range is ensured visible and as much of the rest of the range is brought into
/// view.
/// If the range does not fit within the display with margins subtracted,
/// the start of the range is ensured visible and as much of the rest of
/// the range is brought into view.
///
/// For the purpose of this function, a 5 percent margin is assumed at each end of the
/// audio display such that a range endpoint that is ensured to be in view never gets
/// 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
/// For the purpose of this function, a 5 percent margin is assumed at each
/// end of the audio display such that a range endpoint that is ensured to
/// be in view never gets 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
/// margin.
void ScrollSampleRangeInView(const SampleRange &range);
void ScrollTimeRangeInView(const TimeRange &range);
/// @brief Change the zoom level
/// @param new_zoom_level The new zoom level to use
///
/// A zoom level of 0 is the default zoom level, all other levels are based on this.
/// Negative zoom levels zoom out, positive zoom in.
/// A zoom level of 0 is the default zoom level, all other levels are based
/// on this. Negative zoom levels zoom out, positive zoom in.
///
/// The zoom levels generally go from +30 to -30. It is possible to zoom in more than
/// +30
/// The zoom levels generally go from +30 to -30. It is possible to zoom in
/// more than +30.
void SetZoomLevel(int new_zoom_level);
/// @brief Get the zoom level
@ -320,21 +320,15 @@ public:
/// @param scale New amplitude scale factor, 1.0 is no scaling
void SetAmplitudeScale(float scale);
/// @brief Get amplitude scale factor
/// @return The amplitude scaling factor
float GetAmplitudeScale() const;
/// @brief Get a sample index from an X coordinate relative to current scroll
int64_t SamplesFromRelativeX(int x) const { return (scroll_left + x) * pixel_samples; }
/// @brief Get a sample index from an absolute X coordinate
int64_t SamplesFromAbsoluteX(int x) const { return x * pixel_samples; }
/// @brief Get an X coordinate relative to the current scroll from a sample index
int RelativeXFromSamples(int64_t samples) const { return samples/pixel_samples - scroll_left; }
/// @brief Get an absolute X coordinate from a sample index
int AbsoluteXFromSamples(int64_t samples) const { return samples/pixel_samples; }
/// Get a time in milliseconds from an X coordinate relative to current scroll
int TimeFromRelativeX(int x) const { return int((scroll_left + x) * ms_per_pixel); }
/// Get a time in milliseconds from an absolute X coordinate
int TimeFromAbsoluteX(int x) const { return int(x * ms_per_pixel); }
/// Get an X coordinate relative to the current scroll from a time in milliseconds
int RelativeXFromTime(int ms) const { return int(ms / ms_per_pixel) - scroll_left; }
/// Get an absolute X coordinate from a time in milliseconds
int AbsoluteXFromTime(int ms) const { return int(ms / ms_per_pixel); }
DECLARE_EVENT_TABLE()
};

View file

@ -36,21 +36,20 @@
class AudioMarkerKeyframe : public AudioMarker {
Pen *style;
int64_t position;
int position;
public:
AudioMarkerKeyframe(Pen *style, int64_t position) : style(style), position(position) { }
int64_t GetPosition() const { return position; }
AudioMarkerKeyframe(Pen *style, int position) : style(style), position(position) { }
int 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; }
operator int() const { return position; }
};
AudioMarkerProviderKeyframes::AudioMarkerProviderKeyframes(agi::Context *c, const char *opt_name)
: controller(c->audioController)
, vc(c->videoController)
: vc(c->videoController)
, keyframe_slot(vc->AddKeyframesListener(&AudioMarkerProviderKeyframes::Update, this))
, audio_open_slot(controller->AddAudioOpenListener(&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))
@ -76,13 +75,12 @@ void AudioMarkerProviderKeyframes::Update() {
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]))));
markers.push_back(AudioMarkerKeyframe(style.get(), timecodes.TimeAtFrame(keyframes[i])));
}
AnnounceMarkerMoved();
}
void AudioMarkerProviderKeyframes::GetMarkers(SampleRange const& range, AudioMarkerVector &out) const {
void AudioMarkerProviderKeyframes::GetMarkers(TimeRange const& range, AudioMarkerVector &out) const {
// Find first and last keyframes inside the range
std::vector<AudioMarkerKeyframe>::const_iterator
a = lower_bound(markers.begin(), markers.end(), range.begin()),

View file

@ -40,8 +40,6 @@ namespace agi {