diff --git a/aegisub/src/audio_box.cpp b/aegisub/src/audio_box.cpp index 14daa5e46..8628e7536 100644 --- a/aegisub/src/audio_box.cpp +++ b/aegisub/src/audio_box.cpp @@ -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()); } diff --git a/aegisub/src/audio_controller.cpp b/aegisub/src/audio_controller.cpp index 02465ba57..7805671c0 100644 --- a/aegisub/src/audio_controller.cpp +++ b/aegisub/src/audio_controller.cpp @@ -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 &labels) const +void AudioController::GetLabels(const TimeRange &range, std::vector &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 buf(bufsize); - for(int64_t i = range.begin(); i < range.end(); i += spr) { - size_t len = std::min(spr, range.end() - i); + for(int64_t i = start_sample; i < end_sample; i += spr) { + size_t len = std::min(spr, end_sample - i); provider->GetAudio(&buf[0], i, len); out.write(&buf[0], len * bytes_per_sample); } diff --git a/aegisub/src/audio_controller.h b/aegisub/src/audio_controller.h index 71c0a54df..1a90af7fb 100644 --- a/aegisub/src/audio_controller.h +++ b/aegisub/src/audio_controller.h @@ -65,47 +65,44 @@ class AudioMarkerProvider; typedef std::vector 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 &out) const = 0; + virtual void GetLabels(TimeRange const& range, std::vector &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 AnnouncePlaybackPosition; + agi::signal::Signal 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 &labels) const; + void GetLabels(const TimeRange &range, std::vector &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 diff --git a/aegisub/src/audio_display.cpp b/aegisub/src/audio_display.cpp index 8c379db18..334923464 100644 --- a/aegisub/src/audio_display.cpp +++ b/aegisub/src/audio_display.cpp @@ -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 style_map; + typedef std::map 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::iterator pt = style_ranges.upper_bound(updsamples.begin()); - std::map::iterator pe = style_ranges.upper_bound(updsamples.end()); + std::map::iterator pt = style_ranges.upper_bound(updtime.begin()); + std::map::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(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 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 old_style_ranges; + std::map old_style_ranges; swap(old_style_ranges, style_ranges); style_ranges.insert(asrm.begin(), asrm.end()); - std::map::iterator old_style_it = old_style_ranges.begin(); - std::map::iterator new_style_it = style_ranges.begin(); + std::map::iterator old_style_it = old_style_ranges.begin(); + std::map::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); } } diff --git a/aegisub/src/audio_display.h b/aegisub/src/audio_display.h index bd3ad96d9..07e47e5a4 100644 --- a/aegisub/src/audio_display.h +++ b/aegisub/src/audio_display.h @@ -110,9 +110,6 @@ class AudioDisplay: public wxWindow { /// The current audio renderer agi::scoped_ptr 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 style_ranges; + std::map 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() }; - diff --git a/aegisub/src/audio_marker_provider_keyframes.cpp b/aegisub/src/audio_marker_provider_keyframes.cpp index 392f2c55a..d2eb6ba1b 100644 --- a/aegisub/src/audio_marker_provider_keyframes.cpp +++ b/aegisub/src/audio_marker_provider_keyframes.cpp @@ -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::const_iterator a = lower_bound(markers.begin(), markers.end(), range.begin()), diff --git a/aegisub/src/audio_marker_provider_keyframes.h b/aegisub/src/audio_marker_provider_keyframes.h index fb72b0cb4..bc2fd5a12 100644 --- a/aegisub/src/audio_marker_provider_keyframes.h +++ b/aegisub/src/audio_marker_provider_keyframes.h @@ -40,8 +40,6 @@ namespace agi { /// 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; @@ -71,5 +69,5 @@ public: /// 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; + void GetMarkers(TimeRange const& range, AudioMarkerVector &out) const; }; diff --git a/aegisub/src/audio_renderer.cpp b/aegisub/src/audio_renderer.cpp index dc038c1b6..585523de3 100644 --- a/aegisub/src/audio_renderer.cpp +++ b/aegisub/src/audio_renderer.cpp @@ -79,7 +79,7 @@ size_t AudioRendererBitmapCacheBitmapFactory::GetBlockSize() const AudioRenderer::AudioRenderer() -: pixel_samples(0) +: pixel_ms(0) , pixel_height(0) , amplitude_scale(0) , cache_bitmap_width(32) // arbitrary value for now @@ -91,7 +91,7 @@ AudioRenderer::AudioRenderer() bitmaps.resize(AudioStyle_MAX, AudioRendererBitmapCache(256, AudioRendererBitmapCacheBitmapFactory(this))); // Make sure there's *some* values for those fields, and in the caches - SetSamplesPerPixel(1); + SetMillisecondsPerPixel(1); SetHeight(1); } @@ -99,14 +99,14 @@ AudioRenderer::~AudioRenderer() { } -void AudioRenderer::SetSamplesPerPixel(int _pixel_samples) +void AudioRenderer::SetMillisecondsPerPixel(double new_pixel_ms) { - if (pixel_samples == _pixel_samples) return; + if (pixel_ms == new_pixel_ms) return; - pixel_samples = _pixel_samples; + pixel_ms = new_pixel_ms; if (renderer) - renderer->SetSamplesPerPixel(pixel_samples); + renderer->SetMillisecondsPerPixel(pixel_ms); ResetBlockCount(); } @@ -147,7 +147,7 @@ void AudioRenderer::SetRenderer(AudioRendererBitmapProvider *_renderer) { renderer->SetProvider(provider); renderer->SetAmplitudeScale(amplitude_scale); - renderer->SetSamplesPerPixel(pixel_samples); + renderer->SetMillisecondsPerPixel(pixel_ms); } } @@ -181,7 +181,8 @@ void AudioRenderer::ResetBlockCount() { if (provider) { - size_t rendered_width = (size_t)((provider->GetNumSamples() + pixel_samples - 1) / pixel_samples); + double duration = provider->GetNumSamples() * 1000.0 / provider->GetSampleRate(); + size_t rendered_width = (size_t)ceil(duration / pixel_ms); cache_numblocks = rendered_width / cache_bitmap_width; for_each(bitmaps, bind(&AudioRendererBitmapCache::SetBlockCount, _1, cache_numblocks)); } @@ -263,13 +264,13 @@ void AudioRendererBitmapProvider::SetProvider(AudioProvider *_provider) } -void AudioRendererBitmapProvider::SetSamplesPerPixel(int _pixel_samples) +void AudioRendererBitmapProvider::SetMillisecondsPerPixel(double new_pixel_ms) { - if (pixel_samples == _pixel_samples) return; + if (pixel_ms == new_pixel_ms) return; - pixel_samples = _pixel_samples; + pixel_ms = new_pixel_ms; - OnSetSamplesPerPixel(); + OnSetMillisecondsPerPixel(); } diff --git a/aegisub/src/audio_renderer.h b/aegisub/src/audio_renderer.h index 2aa7e2ef2..41e52727d 100644 --- a/aegisub/src/audio_renderer.h +++ b/aegisub/src/audio_renderer.h @@ -97,8 +97,8 @@ typedef DataBlockCache Audio class AudioRenderer { friend struct AudioRendererBitmapCacheBitmapFactory; - /// Horizontal zoom level, samples per pixel - int pixel_samples; + /// Horizontal zoom level, milliseconds per pixel + double pixel_ms; /// Rendering height in pixels int pixel_height; /// Vertical zoom level/amplitude scale @@ -152,10 +152,10 @@ public: ~AudioRenderer(); /// @brief Set horizontal zoom - /// @param pixel_samples Audio samples per pixel to render at + /// @param pixel_ms Milliseconds per pixel to render audio at /// /// Changing the zoom level invalidates all cached bitmaps. - void SetSamplesPerPixel(int pixel_samples); + void SetMillisecondsPerPixel(double pixel_ms); /// @brief Set rendering height /// @param pixel_height Height in pixels to render at @@ -184,18 +184,6 @@ public: /// Changing the max cache size does not trigger cache aging. void SetCacheMaxSize(size_t max_size); - /// @brief Get horizontal zoom - /// @return Audio samples per pixel rendering at - int GetSamplesPerPixel() const { return pixel_samples; } - - /// @brief Get rendering height - /// @return Height in pixels rendering at - int GetHeight() const { return pixel_height; } - - /// @brief Get vertical zoom - /// @return The amplitude scaling factor - float GetAmplitudeScale() const { return amplitude_scale; } - /// @brief Change renderer /// @param renderer New renderer to use /// @@ -257,8 +245,8 @@ class AudioRendererBitmapProvider { protected: /// Audio provider to use for rendering AudioProvider *provider; - /// Horizontal zoom in samples per pixel - int pixel_samples; + /// Horizontal zoom in milliseconds per pixel + double pixel_ms; /// Vertical zoom/amplitude scale factor float amplitude_scale; @@ -270,7 +258,7 @@ protected: /// @brief Called when horizontal zoom changes /// /// Implementations can override this method to do something when the horizontal zoom is changed - virtual void OnSetSamplesPerPixel() { } + virtual void OnSetMillisecondsPerPixel() { } /// @brief Called when vertical zoom changes /// @@ -279,7 +267,7 @@ protected: public: /// @brief Constructor - AudioRendererBitmapProvider() : provider(0), pixel_samples(0), amplitude_scale(0) { }; + AudioRendererBitmapProvider() : provider(0), pixel_ms(0), amplitude_scale(0) { }; /// @brief Destructor virtual ~AudioRendererBitmapProvider() { } @@ -307,8 +295,8 @@ public: void SetProvider(AudioProvider *provider); /// @brief Change horizontal zoom - /// @param pixel_samples Samples per pixel to zoom to - void SetSamplesPerPixel(int pixel_samples); + /// @param pixel_ms Milliseconds per pixel to zoom to + void SetMillisecondsPerPixel(double new_pixel_ms); /// @brief Change vertical zoom /// @param amplitude_scale Scaling factor to zoom to diff --git a/aegisub/src/audio_renderer_spectrum.cpp b/aegisub/src/audio_renderer_spectrum.cpp index 53cf9d62d..c563cc05b 100644 --- a/aegisub/src/audio_renderer_spectrum.cpp +++ b/aegisub/src/audio_renderer_spectrum.cpp @@ -266,7 +266,7 @@ void AudioSpectrumRenderer::Render(wxBitmap &bmp, int start, AudioRenderingStyle for (int ax = start; ax < end; ++ax) { // Derived audio data - size_t block_index = (size_t)(ax * pixel_samples) >> derivation_dist; + size_t block_index = (size_t)(ax * pixel_ms * provider->GetSampleRate() / 1000) >> derivation_dist; float *power = cache->Get(block_index); // Prepare bitmap writing diff --git a/aegisub/src/audio_renderer_waveform.cpp b/aegisub/src/audio_renderer_waveform.cpp index 7cb11ea8a..f39fee0a4 100644 --- a/aegisub/src/audio_renderer_waveform.cpp +++ b/aegisub/src/audio_renderer_waveform.cpp @@ -82,6 +82,8 @@ void AudioWaveformRenderer::Render(wxBitmap &bmp, int start, AudioRenderingStyle const AudioColorScheme *pal = GetColorScheme(style); + int pixel_samples = (pixel_ms * provider->GetSampleRate() + 500) / 1000; + // Fill the background dc.SetBrush(wxBrush(pal->get(0.0f))); dc.SetPen(*wxTRANSPARENT_PEN); @@ -174,7 +176,7 @@ void AudioWaveformRenderer::OnSetProvider() audio_buffer = 0; } -void AudioWaveformRenderer::OnSetSamplesPerPixel() +void AudioWaveformRenderer::OnSetMillisecondsPerPixel() { delete[] audio_buffer; audio_buffer = 0; diff --git a/aegisub/src/audio_renderer_waveform.h b/aegisub/src/audio_renderer_waveform.h index 1862b53b5..38905777a 100644 --- a/aegisub/src/audio_renderer_waveform.h +++ b/aegisub/src/audio_renderer_waveform.h @@ -65,7 +65,7 @@ class AudioWaveformRenderer : public AudioRendererBitmapProvider { const AudioColorScheme *GetColorScheme(AudioRenderingStyle style) const; void OnSetProvider(); - void OnSetSamplesPerPixel(); + void OnSetMillisecondsPerPixel(); public: /// @brief Constructor diff --git a/aegisub/src/audio_rendering_style.h b/aegisub/src/audio_rendering_style.h index 86f6cca80..f1b0403fe 100644 --- a/aegisub/src/audio_rendering_style.h +++ b/aegisub/src/audio_rendering_style.h @@ -58,8 +58,8 @@ protected: ~AudioRenderingStyleRanges() { } public: /// @brief Add a range to the line - /// @param start First sample index in range - /// @param end One past last sample index in range + /// @param start First milisecond in range + /// @param end One past last milisecond in range /// @param style Style of the range added - virtual void AddRange(int64_t start, int64_t end, AudioRenderingStyle style) = 0; + virtual void AddRange(int start, int end, AudioRenderingStyle style) = 0; }; diff --git a/aegisub/src/audio_timing.h b/aegisub/src/audio_timing.h index 5d9124699..c3ce1d237 100644 --- a/aegisub/src/audio_timing.h +++ b/aegisub/src/audio_timing.h @@ -67,18 +67,18 @@ public: /// @return The warning message to show, may be empty if there is none virtual wxString GetWarningMessage() const = 0; - /// @brief Get the sample range the user is most likely to want to see for the current state - /// @return A sample range + /// @brief Get the time range the user is most likely to want to see for the current state + /// @return A time range /// /// This is used for "bring working area into view" operations. - virtual SampleRange GetIdealVisibleSampleRange() const = 0; + virtual TimeRange GetIdealVisibleTimeRange() const = 0; /// @brief Get the primary playback range - /// @return A sample range + /// @return A time range /// - /// Get the sample range the user is most likely to want to play back + /// Get the time range the user is most likely to want to play back /// currently. - virtual SampleRange GetPrimaryPlaybackRange() const = 0; + virtual TimeRange GetPrimaryPlaybackRange() const = 0; /// @brief Get all rendering style ranges /// @param[out] ranges Rendering ranges will be added to this @@ -106,37 +106,37 @@ public: virtual void Revert() = 0; /// @brief Determine if a position is close to a draggable marker - /// @param sample The audio sample index to test - /// @param sensitivity Distance in samples to consider markers as nearby - /// @return True if a marker is close by the given sample, as defined by sensitivity + /// @param ms The time in milliseconds to test + /// @param sensitivity Distance in milliseconds to consider markers as nearby + /// @return True if a marker is close by the given time, as defined by sensitivity /// /// This is solely for hit-testing against draggable markers, for /// controlling the mouse cursor. - virtual bool IsNearbyMarker(int64_t sample, int sensitivity) const = 0; + virtual bool IsNearbyMarker(int ms, int sensitivity) const = 0; /// @brief The user pressed the left button down at an empty place in the audio - /// @param sample The audio sample index the user clicked - /// @param sensitivity Distance in samples to consider existing markers - /// @param snap_range Maximum snapping range in samples + /// @param ms The time in milliseconds the user clicked + /// @param sensitivity Distance in milliseconds to consider existing markers + /// @param snap_range Maximum snapping range in milliseconds /// @return An audio marker or 0. If a marker is returned and the user /// starts dragging the mouse after pressing down the button, the returned /// marker is being dragged. - virtual AudioMarker * OnLeftClick(int64_t sample, int sensitivity, int64_t snap_range) = 0; + virtual AudioMarker * OnLeftClick(int ms, int sensitivity, int snap_range) = 0; /// @brief The user pressed the right button down at an empty place in the audio - /// @param sample The audio sample index the user clicked - /// @param sensitivity Distance in samples to consider existing markers - /// @param snap_range Maximum snapping range in samples + /// @param ms The time in milliseconds the user clicked + /// @param sensitivity Distance in milliseconds to consider existing markers + /// @param snap_range Maximum snapping range in milliseconds /// @return An audio marker or 0. If a marker is returned and the user /// starts dragging the mouse after pressing down the button, the returned /// marker is being dragged. - virtual AudioMarker * OnRightClick(int64_t sample, int sensitivity, int64_t snap_range) = 0; + virtual AudioMarker * OnRightClick(int ms, int sensitivity, int snap_range) = 0; /// @brief The user dragged a timing marker /// @param marker The marker being dragged - /// @param new_position Sample position the marker was dragged to - /// @param snap_range Maximum snapping range in samples - virtual void OnMarkerDrag(AudioMarker *marker, int64_t new_position, int64_t snap_range) = 0; + /// @param new_position Time position the marker was dragged to + /// @param snap_range Maximum snapping range in milliseconds + virtual void OnMarkerDrag(AudioMarker *marker, int new_position, int snap_range) = 0; /// @brief Destructor virtual ~AudioTimingController() { } diff --git a/aegisub/src/audio_timing_dialogue.cpp b/aegisub/src/audio_timing_dialogue.cpp index 4bce7991c..c1d36de08 100644 --- a/aegisub/src/audio_timing_dialogue.cpp +++ b/aegisub/src/audio_timing_dialogue.cpp @@ -42,7 +42,6 @@ #include "ass_dialogue.h" #include "ass_file.h" #include "ass_time.h" -#include "audio_controller.h" #include "audio_marker_provider_keyframes.h" #include "audio_renderer.h" #include "audio_timing.h" @@ -61,8 +60,8 @@ class AudioMarkerDialogueTiming : public AudioMarker { /// The other marker for the dialogue line's pair AudioMarkerDialogueTiming *other; - /// Current sample position of this marker - int64_t position; + /// Current ms position of this marker + int position; /// Draw style for the marker wxPen style; @@ -77,7 +76,7 @@ class AudioMarkerDialogueTiming : public AudioMarker { public: // AudioMarker interface - int64_t GetPosition() const { return position; } + int GetPosition() const { return position; } wxPen GetStyle() const { return style; } FeetStyle GetFeet() const { return feet; } bool CanSnap() const { return false; } @@ -86,12 +85,12 @@ public: // Specific interface /// @brief Move the marker to a new position - /// @param new_position The position to move the marker to, in audio samples + /// @param new_position The position to move the marker to, in milliseconds /// /// If the marker moves to the opposite side of the other marker in the pair, /// the styles of the two markers will be changed to match the new start/end /// relationship of them. - void SetPosition(int64_t new_position); + void SetPosition(int new_position); /// @brief Constructor @@ -109,23 +108,23 @@ public: static void InitPair(AudioMarkerDialogueTiming *marker1, AudioMarkerDialogueTiming *marker2); /// Implicit decay to the position of the marker - operator int64_t() const { return position; } + operator int() const { return position; } }; /// @class InactiveLineMarker /// @brief Markers for the beginning and ends of inactive lines class InactiveLineMarker : public AudioMarker { - int64_t position; + int position; Pen style; FeetStyle feet; public: - int64_t GetPosition() const { return position; } + int GetPosition() const { return position; } wxPen GetStyle() const { return style; } FeetStyle GetFeet() const { return feet; } bool CanSnap() const { return true; } - InactiveLineMarker(int64_t position, bool start) + InactiveLineMarker(int position, bool start) : position(position) , style("Colour/Audio Display/Line Boundary Inactive Line", "Audio/Line Boundaries Thickness") , feet(start ? Feet_Right : Feet_Left) @@ -133,7 +132,7 @@ public: } /// Implicit decay to the position of the marker - operator int64_t() const { return position; } + operator int() const { return position; } }; @@ -200,13 +199,13 @@ class AudioTimingControllerDialogue : public AudioTimingController, private Sele /// @brief Set the position of a marker and announce the change to the world /// @param marker Marker to move - /// @param sample New position of the marker - void SetMarker(AudioMarkerDialogueTiming *marker, int64_t sample); + /// @param ms New position of the marker + void SetMarker(AudioMarkerDialogueTiming *marker, int ms); /// Snap a position to a nearby marker, if any /// @param position Position to snap - /// @param snap_range Maximum distance to snap in samples - int64_t SnapPosition(int64_t position, int64_t snap_range) const; + /// @param snap_range Maximum distance to snap in milliseconds + int SnapPosition(int position, int snap_range) const; // SubtitleSelectionListener interface void OnActiveLineChanged(AssDialogue *new_line); @@ -217,22 +216,22 @@ class AudioTimingControllerDialogue : public AudioTimingController, private Sele public: // AudioMarkerProvider interface - void GetMarkers(const SampleRange &range, AudioMarkerVector &out_markers) const; + void GetMarkers(const TimeRange &range, AudioMarkerVector &out_markers) const; // AudioTimingController interface wxString GetWarningMessage() const; - SampleRange GetIdealVisibleSampleRange() const; - SampleRange GetPrimaryPlaybackRange() const; + TimeRange GetIdealVisibleTimeRange() const; + TimeRange GetPrimaryPlaybackRange() const; void GetRenderingStyles(AudioRenderingStyleRanges &ranges) const; - void GetLabels(SampleRange const& range, std::vector &out) const { } + void GetLabels(TimeRange const& range, std::vector &out) const { } void Next(); void Prev(); void Commit(); void Revert(); - bool IsNearbyMarker(int64_t sample, int sensitivity) const; - AudioMarker * OnLeftClick(int64_t sample, int sensitivity, int64_t snap_range); - AudioMarker * OnRightClick(int64_t sample, int sensitivity, int64_t snap_range); - void OnMarkerDrag(AudioMarker *marker, int64_t new_position, int64_t snap_range); + bool IsNearbyMarker(int ms, int sensitivity) const; + AudioMarker * OnLeftClick(int ms, int sensitivity, int snap_range); + AudioMarker * OnRightClick(int ms, int sensitivity, int snap_range); + void OnMarkerDrag(AudioMarker *marker, int new_position, int snap_range); public: // Specific interface @@ -248,7 +247,7 @@ AudioTimingController *CreateDialogueTimingController(agi::Context *c) } // AudioMarkerDialogueTiming -void AudioMarkerDialogueTiming::SetPosition(int64_t new_position) +void AudioMarkerDialogueTiming::SetPosition(int new_position) { position = new_position; @@ -302,12 +301,9 @@ AudioTimingControllerDialogue::AudioTimingControllerDialogue(agi::Context *c) , inactive_line_mode(OPT_GET("Audio/Inactive Lines Display Mode")) , inactive_line_comments(OPT_GET("Audio/Display/Draw/Inactive Comments")) , commit_connection(c->ass->AddCommitListener(&AudioTimingControllerDialogue::OnFileChanged, this)) -, audio_open_connection(c->audioController->AddAudioOpenListener(&AudioTimingControllerDialogue::Revert, this)) , inactive_line_mode_connection(OPT_SUB("Audio/Inactive Lines Display Mode", &AudioTimingControllerDialogue::RegenerateInactiveLines, this)) , inactive_line_comment_connection(OPT_SUB("Audio/Display/Draw/Inactive Comments", &AudioTimingControllerDialogue::RegenerateInactiveLines, this)) { - assert(c->audioController != 0); - AudioMarkerDialogueTiming::InitPair(&active_markers[0], &active_markers[1]); c->selectionController->AddSelectionListener(this); @@ -342,7 +338,7 @@ const AudioMarkerDialogueTiming *AudioTimingControllerDialogue::GetRightMarker() return &std::max(active_markers[0], active_markers[1]); } -void AudioTimingControllerDialogue::GetMarkers(const SampleRange &range, AudioMarkerVector &out_markers) const +void AudioTimingControllerDialogue::GetMarkers(const TimeRange &range, AudioMarkerVector &out_markers) const { // The order matters here; later markers are painted on top of earlier // markers, so the markers that we want to end up on top need to appear last @@ -365,10 +361,7 @@ void AudioTimingControllerDialogue::GetMarkers(const SampleRange &range, AudioMa void AudioTimingControllerDialogue::OnActiveLineChanged(AssDialogue *new_line) { - if (context->audioController->IsAudioOpen()) - { - Revert(); - } + Revert(); } void AudioTimingControllerDialogue::OnSelectedSetChanged(const Selection &lines_added, const Selection &lines_removed) @@ -393,14 +386,14 @@ wxString AudioTimingControllerDialogue::GetWarningMessage() const return wxString(); } -SampleRange AudioTimingControllerDialogue::GetIdealVisibleSampleRange() const +TimeRange AudioTimingControllerDialogue::GetIdealVisibleTimeRange() const { return GetPrimaryPlaybackRange(); } -SampleRange AudioTimingControllerDialogue::GetPrimaryPlaybackRange() const +TimeRange AudioTimingControllerDialogue::GetPrimaryPlaybackRange() const { - return SampleRange(*GetLeftMarker(), *GetRightMarker()); + return TimeRange(*GetLeftMarker(), *GetRightMarker()); } void AudioTimingControllerDialogue::GetRenderingStyles(AudioRenderingStyleRanges &ranges) const @@ -424,8 +417,8 @@ void AudioTimingControllerDialogue::Prev() void AudioTimingControllerDialogue::Commit() { - int new_start_ms = context->audioController->MillisecondsFromSamples(*GetLeftMarker()); - int new_end_ms = context->audioController->MillisecondsFromSamples(*GetRightMarker()); + int new_start_ms = *GetLeftMarker(); + int new_end_ms = *GetRightMarker(); // If auto committing is enabled, timing_modified will be true iif it is an // auto commit, as there is never pending changes to commit when the button @@ -464,8 +457,8 @@ void AudioTimingControllerDialogue::Commit() Next(); if (context->selectionController->GetActiveLine()->End == 0) { const int default_duration = OPT_GET("Timing/Default Duration")->GetInt(); - active_markers[0].SetPosition(context->audioController->SamplesFromMilliseconds(new_end_ms)); - active_markers[1].SetPosition(context->audioController->SamplesFromMilliseconds(new_end_ms + default_duration)); + active_markers[0].SetPosition(new_end_ms); + active_markers[1].SetPosition(new_end_ms + default_duration); timing_modified = true; UpdateSelection(); } @@ -478,8 +471,8 @@ void AudioTimingControllerDialogue::Revert() { if (line->Start != 0 || line->End != 0) { - active_markers[0].SetPosition(context->audioController->SamplesFromMilliseconds(line->Start)); - active_markers[1].SetPosition(context->audioController->SamplesFromMilliseconds(line->End)); + active_markers[0].SetPosition(line->Start); + active_markers[1].SetPosition(line->End); timing_modified = false; AnnounceUpdatedPrimaryRange(); if (inactive_line_mode->GetInt() == 0) @@ -489,30 +482,30 @@ void AudioTimingControllerDialogue::Revert() RegenerateInactiveLines(); } -bool AudioTimingControllerDialogue::IsNearbyMarker(int64_t sample, int sensitivity) const +bool AudioTimingControllerDialogue::IsNearbyMarker(int ms, int sensitivity) const { - SampleRange range(sample-sensitivity, sample+sensitivity); + TimeRange range(ms-sensitivity, ms+sensitivity); return range.contains(active_markers[0]) || range.contains(active_markers[1]); } -AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sensitivity, int64_t snap_range) +AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int ms, int sensitivity, int snap_range) { assert(sensitivity >= 0); - int64_t dist_l, dist_r; + int dist_l, dist_r; AudioMarkerDialogueTiming *left = GetLeftMarker(); AudioMarkerDialogueTiming *right = GetRightMarker(); - dist_l = tabs(*left - sample); - dist_r = tabs(*right - sample); + dist_l = tabs(*left - ms); + dist_r = tabs(*right - ms); if (dist_l < dist_r && dist_l <= sensitivity) { // Clicked near the left marker: // Insta-move it and start dragging it - SetMarker(left, SnapPosition(sample, snap_range)); + SetMarker(left, SnapPosition(ms, snap_range)); return left; } @@ -526,18 +519,18 @@ AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sen // Clicked far from either marker: // 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 - SetMarker(left, SnapPosition(sample, snap_range)); + SetMarker(left, SnapPosition(ms, snap_range)); return right; } -AudioMarker * AudioTimingControllerDialogue::OnRightClick(int64_t sample, int sensitivity, int64_t snap_range) +AudioMarker * AudioTimingControllerDialogue::OnRightClick(int ms, int sensitivity, int snap_range) { AudioMarkerDialogueTiming *right = GetRightMarker(); - SetMarker(right, SnapPosition(sample, snap_range)); + SetMarker(right, SnapPosition(ms, snap_range)); return right; } -void AudioTimingControllerDialogue::OnMarkerDrag(AudioMarker *marker, int64_t new_position, int64_t snap_range) +void AudioTimingControllerDialogue::OnMarkerDrag(AudioMarker *marker, int new_position, int snap_range) { assert(marker == &active_markers[0] || marker == &active_markers[1]); @@ -550,9 +543,9 @@ void AudioTimingControllerDialogue::UpdateSelection() AnnounceUpdatedStyleRanges(); } -void AudioTimingControllerDialogue::SetMarker(AudioMarkerDialogueTiming *marker, int64_t sample) +void AudioTimingControllerDialogue::SetMarker(AudioMarkerDialogueTiming *marker, int ms) { - marker->SetPosition(sample); + marker->SetPosition(ms); timing_modified = true; if (auto_commit->GetBool()) Commit(); UpdateSelection(); @@ -619,15 +612,15 @@ void AudioTimingControllerDialogue::RegenerateInactiveLines() AnnounceUpdatedStyleRanges(); } -int64_t AudioTimingControllerDialogue::SnapPosition(int64_t position, int64_t snap_range) const +int AudioTimingControllerDialogue::SnapPosition(int position, int snap_range) const { if (snap_range <= 0) return position; - SampleRange snap_sample_range(position - snap_range, position + snap_range); + TimeRange snap_time_range(position - snap_range, position + snap_range); const AudioMarker *snap_marker = 0; AudioMarkerVector potential_snaps; - GetMarkers(snap_sample_range, potential_snaps); + GetMarkers(snap_time_range, potential_snaps); for (AudioMarkerVector::iterator mi = potential_snaps.begin(); mi != potential_snaps.end(); ++mi) { if ((*mi)->CanSnap()) @@ -646,8 +639,6 @@ int64_t AudioTimingControllerDialogue::SnapPosition(int64_t position, int64_t sn void AudioTimingControllerDialogue::AddInactiveMarkers(AssDialogue *line) { - inactive_markers.push_back(InactiveLineMarker( - context->audioController->SamplesFromMilliseconds(line->Start), true)); - inactive_markers.push_back(InactiveLineMarker( - context->audioController->SamplesFromMilliseconds(line->End), false)); + inactive_markers.push_back(InactiveLineMarker(line->Start, true)); + inactive_markers.push_back(InactiveLineMarker(line->End, false)); } diff --git a/aegisub/src/audio_timing_karaoke.cpp b/aegisub/src/audio_timing_karaoke.cpp index 34f4085b2..9020adb5e 100644 --- a/aegisub/src/audio_timing_karaoke.cpp +++ b/aegisub/src/audio_timing_karaoke.cpp @@ -43,27 +43,27 @@ /// @class KaraokeMarker /// @brief AudioMarker implementation for AudioTimingControllerKaraoke class KaraokeMarker : public AudioMarker { - int64_t position; + int position; Pen *pen; FeetStyle style; public: - int64_t GetPosition() const { return position; } + int GetPosition() const { return position; } wxPen GetStyle() const { return *pen; } FeetStyle GetFeet() const { return style; } bool CanSnap() const { return false; } - void Move(int64_t new_pos) { position = new_pos; } + void Move(int new_pos) { position = new_pos; } - KaraokeMarker(int64_t position, Pen *pen, FeetStyle style) + KaraokeMarker(int position, Pen *pen, FeetStyle style) : position(position) , pen(pen) , style(style) { } - KaraokeMarker(int64_t position) : position(position) { } - operator int64_t() const { return position; } + KaraokeMarker(int position) : position(position) { } + operator int() const { return position; } }; /// @class AudioTimingControllerKaraoke @@ -111,27 +111,24 @@ class AudioTimingControllerKaraoke : public AudioTimingController { void OnAutoCommitChange(agi::OptionValue const& opt); void OnAutoNextChange(agi::OptionValue const& opt); - int64_t ToMS(int64_t samples) const { return c->audioController->MillisecondsFromSamples(samples); } - int64_t ToSamples(int64_t ms) const { return c->audioController->SamplesFromMilliseconds(ms); } - void DoCommit(); public: // AudioTimingController implementation - void GetMarkers(const SampleRange &range, AudioMarkerVector &out_markers) const; + void GetMarkers(const TimeRange &range, AudioMarkerVector &out_markers) const; wxString GetWarningMessage() const { return ""; } - SampleRange GetIdealVisibleSampleRange() const; + TimeRange GetIdealVisibleTimeRange() const; void GetRenderingStyles(AudioRenderingStyleRanges &ranges) const; - SampleRange GetPrimaryPlaybackRange() const; - void GetLabels(const SampleRange &range, std::vector &out_labels) const; + TimeRange GetPrimaryPlaybackRange() const; + void GetLabels(const TimeRange &range, std::vector &out_labels) const; void Next(); void Prev(); void Commit(); void Revert(); - bool IsNearbyMarker(int64_t sample, int sensitivity) const; - AudioMarker * OnLeftClick(int64_t sample, int sensitivity, int64_t); - AudioMarker * OnRightClick(int64_t, int, int64_t) { return 0; } - void OnMarkerDrag(AudioMarker *marker, int64_t new_position, int64_t); + bool IsNearbyMarker(int ms, int sensitivity) const; + AudioMarker * OnLeftClick(int ms, int sensitivity, int); + AudioMarker * OnRightClick(int, int, int) { return 0; } + void OnMarkerDrag(AudioMarker *marker, int new_position, int); AudioTimingControllerKaraoke(agi::Context *c, AssKaraoke *kara, agi::signal::Connection& file_changed); }; @@ -150,8 +147,8 @@ AudioTimingControllerKaraoke::AudioTimingControllerKaraoke(agi::Context *c, AssK , separator_pen("Colour/Audio Display/Syllable Boundaries", "Audio/Line Boundaries Thickness", wxPENSTYLE_DOT) , start_pen("Colour/Audio Display/Line boundary Start", "Audio/Line Boundaries Thickness") , end_pen("Colour/Audio Display/Line boundary End", "Audio/Line Boundaries Thickness") -, start_marker(ToSamples(active_line->Start), &start_pen, AudioMarker::Feet_Right) -, end_marker(ToSamples(active_line->End), &end_pen, AudioMarker::Feet_Left) +, start_marker(active_line->Start, &start_pen, AudioMarker::Feet_Right) +, end_marker(active_line->End, &end_pen, AudioMarker::Feet_Left) , keyframes_provider(c, "Audio/Display/Draw/Keyframes in Karaoke Mode") , auto_commit(OPT_GET("Audio/Auto/Commit")->GetBool()) , auto_next(OPT_GET("Audio/Next Line on Commit")->GetBool()) @@ -210,21 +207,21 @@ void AudioTimingControllerKaraoke::Prev() { void AudioTimingControllerKaraoke::GetRenderingStyles(AudioRenderingStyleRanges &ranges) const { - SampleRange sr = GetPrimaryPlaybackRange(); + TimeRange sr = GetPrimaryPlaybackRange(); ranges.AddRange(sr.begin(), sr.end(), AudioStyle_Selected); } -SampleRange AudioTimingControllerKaraoke::GetPrimaryPlaybackRange() const { - return SampleRange( +TimeRange AudioTimingControllerKaraoke::GetPrimaryPlaybackRange() const { + return TimeRange( cur_syl > 0 ? markers[cur_syl - 1] : start_marker, cur_syl < markers.size() ? markers[cur_syl] : end_marker); } -SampleRange AudioTimingControllerKaraoke::GetIdealVisibleSampleRange() const { - return SampleRange(start_marker, end_marker); +TimeRange AudioTimingControllerKaraoke::GetIdealVisibleTimeRange() const { + return TimeRange(start_marker, end_marker); } -void AudioTimingControllerKaraoke::GetMarkers(SampleRange const& range, AudioMarkerVector &out) const { +void AudioTimingControllerKaraoke::GetMarkers(TimeRange const& range, AudioMarkerVector &out) const { size_t i; for (i = 0; i < markers.size() && markers[i] < range.begin(); ++i) ; for (; i < markers.size() && markers[i] < range.end(); ++i) @@ -256,8 +253,8 @@ void AudioTimingControllerKaraoke::Revert() { cur_syl = 0; commit_id = -1; - start_marker.Move(ToSamples(active_line->Start)); - end_marker.Move(ToSamples(active_line->End)); + start_marker.Move(active_line->Start); + end_marker.Move(active_line->End); markers.clear(); labels.clear(); @@ -266,10 +263,9 @@ void AudioTimingControllerKaraoke::Revert() { labels.reserve(kara->size()); for (AssKaraoke::iterator it = kara->begin(); it != kara->end(); ++it) { - int64_t sample = ToSamples(it->start_time); if (it != kara->begin()) - markers.push_back(KaraokeMarker(sample, &separator_pen, AudioMarker::Feet_None)); - labels.push_back(AudioLabel(it->text, SampleRange(sample, ToSamples(it->start_time + it->duration)))); + markers.push_back(KaraokeMarker(it->start_time, &separator_pen, AudioMarker::Feet_None)); + labels.push_back(AudioLabel(it->text, TimeRange(it->start_time, it->start_time + it->duration))); } AnnounceUpdatedPrimaryRange(); @@ -277,8 +273,8 @@ void AudioTimingControllerKaraoke::Revert() { AnnounceMarkerMoved(); } -bool AudioTimingControllerKaraoke::IsNearbyMarker(int64_t sample, int sensitivity) const { - SampleRange range(sample - sensitivity, sample + sensitivity); +bool AudioTimingControllerKaraoke::IsNearbyMarker(int ms, int sensitivity) const { + TimeRange range(ms - sensitivity, ms + sensitivity); for (size_t i = 0; i < markers.size(); ++i) if (range.contains(markers[i])) @@ -287,10 +283,10 @@ bool AudioTimingControllerKaraoke::IsNearbyMarker(int64_t sample, int sensitivit return false; } -AudioMarker *AudioTimingControllerKaraoke::OnLeftClick(int64_t sample, int sensitivity, int64_t) { - SampleRange range(sample - sensitivity, sample + sensitivity); +AudioMarker *AudioTimingControllerKaraoke::OnLeftClick(int ms, int sensitivity, int) { + TimeRange range(ms - sensitivity, ms + sensitivity); - size_t syl = distance(markers.begin(), lower_bound(markers.begin(), markers.end(), sample)); + size_t syl = distance(markers.begin(), lower_bound(markers.begin(), markers.end(), ms)); if (syl < markers.size() && range.contains(markers[syl])) return &markers[syl]; if (syl > 0 && range.contains(markers[syl - 1])) @@ -304,7 +300,7 @@ AudioMarker *AudioTimingControllerKaraoke::OnLeftClick(int64_t sample, int sensi return 0; } -void AudioTimingControllerKaraoke::OnMarkerDrag(AudioMarker *m, int64_t new_position, int64_t) { +void AudioTimingControllerKaraoke::OnMarkerDrag(AudioMarker *m, int new_position, int) { KaraokeMarker *marker = static_cast(m); // No rearranging of syllables allowed new_position = mid( @@ -315,7 +311,7 @@ void AudioTimingControllerKaraoke::OnMarkerDrag(AudioMarker *m, int64_t new_posi marker->Move(new_position); size_t syl = marker - &markers.front() + 1; - kara->SetStartTime(syl, ToMS(new_position)); + kara->SetStartTime(syl, new_position); if (syl == cur_syl || syl == cur_syl + 1) { AnnounceUpdatedPrimaryRange(); @@ -324,8 +320,8 @@ void AudioTimingControllerKaraoke::OnMarkerDrag(AudioMarker *m, int64_t new_posi AnnounceMarkerMoved(); - labels[syl - 1].range = SampleRange(labels[syl - 1].range.begin(), new_position); - labels[syl].range = SampleRange(new_position, labels[syl].range.end()); + labels[syl - 1].range = TimeRange(labels[syl - 1].range.begin(), new_position); + labels[syl].range = TimeRange(new_position, labels[syl].range.end()); AnnounceLabelChanged(); if (auto_commit) @@ -334,7 +330,7 @@ void AudioTimingControllerKaraoke::OnMarkerDrag(AudioMarker *m, int64_t new_posi commit_id = -1; } -void AudioTimingControllerKaraoke::GetLabels(SampleRange const& range, std::vector &out) const { +void AudioTimingControllerKaraoke::GetLabels(TimeRange const& range, std::vector &out) const { for (size_t i = 0; i < labels.size(); ++i) { if (range.overlaps(labels[i].range)) out.push_back(labels[i]); diff --git a/aegisub/src/command/audio.cpp b/aegisub/src/command/audio.cpp index 10443e32d..71eaaab1c 100644 --- a/aegisub/src/command/audio.cpp +++ b/aegisub/src/command/audio.cpp @@ -223,8 +223,7 @@ struct audio_save_clip : public Command { for (Selection::iterator it = sel.begin(); it != sel.end(); ++it) { c->audioController->SaveClip( wxFileSelector(_("Save audio clip"), "", "", "wav", "", wxFD_SAVE|wxFD_OVERWRITE_PROMPT, c->parent), - SampleRange(c->audioController->SamplesFromMilliseconds((*it)->Start), - c->audioController->SamplesFromMilliseconds((*it)->End))); + TimeRange((*it)->Start, (*it)->End)); } } }; @@ -268,10 +267,8 @@ struct audio_play_before : public validate_audio_open { void operator()(agi::Context *c) { c->videoController->Stop(); - SampleRange times(c->audioController->GetPrimaryPlaybackRange()); - c->audioController->PlayRange(SampleRange( - times.begin() - c->audioController->SamplesFromMilliseconds(500), - times.begin())); + int begin = c->audioController->GetPrimaryPlaybackRange().begin(); + c->audioController->PlayRange(TimeRange(begin - 500, begin)); } }; @@ -284,10 +281,8 @@ struct audio_play_after : public validate_audio_open { void operator()(agi::Context *c) { c->videoController->Stop(); - SampleRange times(c->audioController->GetPrimaryPlaybackRange()); - c->audioController->PlayRange(SampleRange( - times.end(), - times.end() + c->audioController->SamplesFromMilliseconds(500))); + int end = c->audioController->GetPrimaryPlaybackRange().end(); + c->audioController->PlayRange(TimeRange(end, end + 500)); } }; @@ -300,11 +295,8 @@ struct audio_play_end : public validate_audio_open { void operator()(agi::Context *c) { c->videoController->Stop(); - SampleRange times(c->audioController->GetPrimaryPlaybackRange()); - c->audioController->PlayToEndOfPrimary( - times.end() - std::min( - c->audioController->SamplesFromMilliseconds(500), - times.length())); + TimeRange times(c->audioController->GetPrimaryPlaybackRange()); + c->audioController->PlayToEndOfPrimary(times.end() - std::min(500, times.length())); } }; @@ -317,12 +309,10 @@ struct audio_play_begin : public validate_audio_open { void operator()(agi::Context *c) { c->videoController->Stop(); - SampleRange times(c->audioController->GetPrimaryPlaybackRange()); - c->audioController->PlayRange(SampleRange( + TimeRange times(c->audioController->GetPrimaryPlaybackRange()); + c->audioController->PlayRange(TimeRange( times.begin(), - times.begin() + std::min( - c->audioController->SamplesFromMilliseconds(500), - times.length()))); + times.begin() + std::min(500, times.length()))); } }; diff --git a/aegisub/src/video_context.cpp b/aegisub/src/video_context.cpp index 6114a8c41..bcc1d6ede 100644 --- a/aegisub/src/video_context.cpp +++ b/aegisub/src/video_context.cpp @@ -320,9 +320,7 @@ void VideoContext::NextFrame() { JumpToFrame(frame_n + 1); // Start playing audio if (playAudioOnStep->GetBool()) { - context->audioController->PlayRange(SampleRange( - context->audioController->SamplesFromMilliseconds(TimeAtFrame(frame_n - 1)), - context->audioController->SamplesFromMilliseconds(TimeAtFrame(frame_n)))); + context->audioController->PlayRange(TimeRange(TimeAtFrame(frame_n - 1), TimeAtFrame(frame_n))); } } @@ -333,9 +331,7 @@ void VideoContext::PrevFrame() { JumpToFrame(frame_n - 1); // Start playing audio if (playAudioOnStep->GetBool()) { - context->audioController->PlayRange(SampleRange( - context->audioController->SamplesFromMilliseconds(TimeAtFrame(frame_n)), - context->audioController->SamplesFromMilliseconds(TimeAtFrame(frame_n + 1)))); + context->audioController->PlayRange(TimeRange(TimeAtFrame(frame_n), TimeAtFrame(frame_n + 1))); } } @@ -352,7 +348,7 @@ void VideoContext::Play() { endFrame = GetLength() - 1; // Start playing audio - context->audioController->PlayToEnd(context->audioController->SamplesFromMilliseconds(startMS)); + context->audioController->PlayToEnd(startMS); // Start timer playTime.Start(); @@ -366,9 +362,7 @@ void VideoContext::PlayLine() { if (!curline) return; // Start playing audio - context->audioController->PlayRange(SampleRange( - context->audioController->SamplesFromMilliseconds(curline->Start), - context->audioController->SamplesFromMilliseconds(curline->End))); + context->audioController->PlayRange(TimeRange(curline->Start, curline->End)); // Round-trip conversion to convert start to exact int startFrame = FrameAtTime(context->selectionController->GetActiveLine()->Start,agi::vfr::START);