Get audio styling ranges from the timing controller. Based on a patch by jfs.

Originally committed to SVN as r5878.
This commit is contained in:
Thomas Goyne 2011-11-18 22:56:45 +00:00
parent 262d5195c5
commit 8d28b44773
13 changed files with 279 additions and 198 deletions

View File

@ -336,17 +336,15 @@ void AudioController::SetTimingController(AudioTimingController *new_controller)
{
if (timing_controller.get() != new_controller) {
timing_controller.reset(new_controller);
timing_controller->AddMarkerMovedListener(std::tr1::bind(std::tr1::ref(AnnounceMarkerMoved)));
timing_controller->AddLabelChangedListener(std::tr1::bind(std::tr1::ref(AnnounceLabelChanged)));
timing_controller->AddMarkerMovedListener(bind(std::tr1::ref(AnnounceMarkerMoved)));
timing_controller->AddLabelChangedListener(bind(std::tr1::ref(AnnounceLabelChanged)));
timing_controller->AddUpdatedPrimaryRangeListener(&AudioController::OnTimingControllerUpdatedPrimaryRange, this);
timing_controller->AddUpdatedStyleRangesListener(&AudioController::OnTimingControllerUpdatedStyleRanges, this);
timing_controller->AddUpdatedStyleRangesListener(bind(std::tr1::ref(AnnounceStyleRangesChanged)));
}
AnnounceTimingControllerChanged();
}
void AudioController::OnTimingControllerUpdatedPrimaryRange()
{
if (playback_mode == PM_PrimaryRange)
@ -357,12 +355,6 @@ void AudioController::OnTimingControllerUpdatedPrimaryRange()
AnnounceSelectionChanged();
}
void AudioController::OnTimingControllerUpdatedStyleRanges()
{
/// @todo redraw and stuff, probably
}
void AudioController::OnSubtitlesSave()
{
if (IsAudioOpen())

View File

@ -201,6 +201,9 @@ class AudioController : public wxEvtHandler, public AudioMarkerProvider, public
/// The selected time range changed
agi::signal::Signal<> AnnounceSelectionChanged;
/// The styling ranges have been updated by the timing controller
agi::signal::Signal<> AnnounceStyleRangesChanged;
/// The audio output object
AudioPlayer *player;
@ -390,6 +393,7 @@ public:
DEFINE_SIGNAL_ADDERS(AnnouncePlaybackStop, AddPlaybackStopListener)
DEFINE_SIGNAL_ADDERS(AnnounceTimingControllerChanged, AddTimingControllerListener)
DEFINE_SIGNAL_ADDERS(AnnounceSelectionChanged, AddSelectionChangedListener)
DEFINE_SIGNAL_ADDERS(AnnounceStyleRangesChanged, AddStyleRangesChangedListener)
};
/// @class AudioMarker

View File

@ -494,8 +494,54 @@ public:
}
};
class AudioStyleRangeMerger : public AudioRenderingStyleRanges {
typedef std::map<int64_t, AudioRenderingStyle> style_map;
public:
typedef style_map::iterator iterator;
private:
style_map points;
void Split(int64_t point)
{
iterator it = points.lower_bound(point);
if (it == points.end() || it->first != point)
{
assert(it != points.begin());
points[point] = (--it)->second;
}
}
void Restyle(int64_t start, int64_t end, AudioRenderingStyle style)
{
assert(points.lower_bound(end) != points.end());
for (iterator pt = points.lower_bound(start); pt->first < end; ++pt)
{
if (style > pt->second)
pt->second = style;
}
}
public:
AudioStyleRangeMerger()
{
points[0] = AudioStyle_Normal;
}
void AddRange(int64_t start, int64_t end, AudioRenderingStyle style)
{
if (start < 0) start = 0;
if (end < start) return;
Split(start);
Split(end);
Restyle(start, end, style);
}
iterator begin() { return points.begin(); }
iterator end() { return points.end(); }
};
AudioDisplay::AudioDisplay(wxWindow *parent, AudioController *controller, agi::Context *context)
: wxWindow(parent, -1, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS|wxBORDER_SIMPLE)
@ -506,8 +552,9 @@ AudioDisplay::AudioDisplay(wxWindow *parent, AudioController *controller, agi::C
, scrollbar(new AudioDisplayScrollbar(this))
, timeline(new AudioDisplayTimeline(this))
, dragged_object(0)
, old_selection(0, 0)
{
style_ranges[0] = AudioStyle_Normal;
scroll_left = 0;
pixel_audio_width = 0;
scale_amplitude = 1.0;
@ -521,6 +568,7 @@ AudioDisplay::AudioDisplay(wxWindow *parent, AudioController *controller, agi::C
slots.push_back(controller->AddTimingControllerListener(&AudioDisplay::Refresh, this, true, (const wxRect*)0));
slots.push_back(controller->AddMarkerMovedListener(&AudioDisplay::OnMarkerMoved, this));
slots.push_back(controller->AddSelectionChangedListener(&AudioDisplay::OnSelectionChanged, this));
slots.push_back(controller->AddStyleRangesChangedListener(&AudioDisplay::OnStyleRangesChanged, this));
OPT_SUB("Audio/Spectrum", &AudioDisplay::ReloadRenderingSettings, this);
@ -764,15 +812,9 @@ BEGIN_EVENT_TABLE(AudioDisplay, wxWindow)
EVT_SET_FOCUS(AudioDisplay::OnFocus)
EVT_KILL_FOCUS(AudioDisplay::OnFocus)
EVT_KEY_DOWN(AudioDisplay::OnKeyDown)
END_EVENT_TABLE()
END_EVENT_TABLE();
struct RedrawSubregion {
int x1, x2;
bool selected;
RedrawSubregion(int x1, int x2, bool selected) : x1(x1), x2(x2), selected(selected) { }
};
void AudioDisplay::OnPaint(wxPaintEvent& event)
{
wxAutoBufferedPaintDC dc(this);
@ -793,11 +835,6 @@ void AudioDisplay::OnPaint(wxPaintEvent& event)
bool redraw_scrollbar = false;
bool redraw_timeline = false;
/// @todo Get rendering style ranges from timing controller instead
SampleRange sel_samples(controller->GetPrimaryPlaybackRange());
int selection_start = AbsoluteXFromSamples(sel_samples.begin());
int selection_end = AbsoluteXFromSamples(sel_samples.end());
wxPoint client_org = GetClientAreaOrigin();
for (wxRegionIterator region(GetUpdateRegion()); region; ++region)
{
@ -816,38 +853,31 @@ void AudioDisplay::OnPaint(wxPaintEvent& event)
continue;
}
// p1 -> p2 = before selection
// p2 -> p3 = in selection
// p3 -> p4 = after selection
int p1 = scroll_left + updrect.x;
int p2 = selection_start;
int p3 = selection_end;
int p4 = p1 + updrect.width;
std::vector<RedrawSubregion> subregions;
if (p1 < p2)
subregions.push_back(RedrawSubregion(p1, std::min(p2, p4), false));
if (p4 > p2 && p1 < p3)
subregions.push_back(RedrawSubregion(std::max(p1, p2), std::min(p3, p4), true));
if (p4 > p3)
subregions.push_back(RedrawSubregion(std::max(p1, p3), p4, false));
int x = updrect.x;
for (std::vector<RedrawSubregion>::iterator sr = subregions.begin(); sr != subregions.end(); ++sr)
{
audio_renderer->Render(dc, wxPoint(x, audio_top), sr->x1, sr->x2 - sr->x1, sr->selected);
x += sr->x2 - sr->x1;
}
const int foot_size = 6;
SampleRange updrectsamples(
SampleRange updsamples(
SamplesFromRelativeX(updrect.x - foot_size),
SamplesFromRelativeX(updrect.x + updrect.width + foot_size));
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());
if (pt != style_ranges.begin())
--pt;
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);
if (range_x2 > range_x1)
{
audio_renderer->Render(dc, wxPoint(range_x1, audio_top), range_x1, range_x2 - range_x1, range_style);
}
}
// Draw markers on top of it all
AudioMarkerVector markers;
controller->GetMarkers(updrectsamples, markers);
controller->GetMarkers(updsamples, markers);
wxDCPenChanger pen_retainer(dc, wxPen());
wxDCBrushChanger brush_retainer(dc, wxBrush());
for (AudioMarkerVector::iterator marker_i = markers.begin(); marker_i != markers.end(); ++marker_i)
@ -876,7 +906,7 @@ void AudioDisplay::OnPaint(wxPaintEvent& event)
// Draw labels
std::vector<AudioLabelProvider::AudioLabel> labels;
controller->GetLabels(updrectsamples, labels);
controller->GetLabels(updsamples, labels);
if (!labels.empty())
{
wxDCFontChanger fc(dc);
@ -943,7 +973,7 @@ void AudioDisplay::OnPaint(wxPaintEvent& event)
track_cursor_label_rect.SetPosition(label_pos);
track_cursor_label_rect.SetSize(label_size);
if (need_extra_redraw)
RefreshRect(track_cursor_label_rect);
RefreshRect(track_cursor_label_rect, false);
}
}
@ -976,11 +1006,11 @@ void AudioDisplay::SetTrackCursor(int new_pos, bool show_time)
int old_pos = track_cursor_pos;
track_cursor_pos = new_pos;
RefreshRect(wxRect(old_pos - scroll_left - 0, audio_top, 1, audio_height));
RefreshRect(wxRect(new_pos - scroll_left - 0, audio_top, 1, audio_height));
RefreshRect(wxRect(old_pos - scroll_left - 0, audio_top, 1, audio_height), false);
RefreshRect(wxRect(new_pos - scroll_left - 0, audio_top, 1, audio_height), false);
// Make sure the old label gets cleared away
RefreshRect(track_cursor_label_rect);
RefreshRect(track_cursor_label_rect, false);
if (show_time)
{
@ -988,7 +1018,7 @@ void AudioDisplay::SetTrackCursor(int new_pos, bool show_time)
new_label_time.SetMS(controller->MillisecondsFromSamples(SamplesFromAbsoluteX(track_cursor_pos)));
track_cursor_label = new_label_time.GetASSFormated();
track_cursor_label_rect.x += new_pos - old_pos;
RefreshRect(track_cursor_label_rect);
RefreshRect(track_cursor_label_rect, false);
}
else
{
@ -1148,7 +1178,7 @@ void AudioDisplay::OnSize(wxSizeEvent &event)
void AudioDisplay::OnFocus(wxFocusEvent &event)
{
// The scrollbar indicates focus so repaint that
RefreshRect(scrollbar->GetBounds());
RefreshRect(scrollbar->GetBounds(), false);
}
@ -1174,42 +1204,76 @@ void AudioDisplay::OnPlaybackPosition(int64_t sample_position)
void AudioDisplay::OnSelectionChanged()
{
/// @todo Handle rendering style ranges from timing controller instead
SampleRange sel(controller->GetPrimaryPlaybackRange());
scrollbar->SetSelection(AbsoluteXFromSamples(sel.begin()), AbsoluteXFromSamples(sel.length()));
if (OPT_GET("Audio/Auto/Scroll")->GetBool())
{
ScrollSampleRangeInView(sel);
int s1 = RelativeXFromSamples(sel.begin());
int e1 = RelativeXFromSamples(sel.end());
int s2 = RelativeXFromSamples(old_selection.begin());
int e2 = RelativeXFromSamples(old_selection.end());
if (sel.overlaps(old_selection))
{
// Only redraw the parts of the selection that changed, to avoid flicker
if (s1 != s2)
{
RefreshRect(wxRect(std::min(s1, s2)-10, audio_top, abs(s1-s2)+20, audio_height));
}
if (e1 != e2)
{
RefreshRect(wxRect(std::min(e1, e2)-10, audio_top, abs(e1-e2)+20, audio_height));
}
}
else
{
RefreshRect(wxRect(s1 - 10, audio_top, e1 + 20, audio_height));
RefreshRect(wxRect(s2 - 10, audio_top, e2 + 20, audio_height));
}
RefreshRect(scrollbar->GetBounds());
RefreshRect(scrollbar->GetBounds(), false);
}
old_selection = sel;
void AudioDisplay::OnStyleRangesChanged()
{
AudioStyleRangeMerger asrm;
controller->GetTimingController()->GetRenderingStyles(asrm);
std::map<int64_t, 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();
int old_style = old_style_it->second;
int new_style = new_style_it->second;
int64_t range_start = 0;
// Repaint each range which has changed
while (old_style_it != old_style_ranges.end() || new_style_it != style_ranges.end())
{
if (new_style_it == style_ranges.end() || (old_style_it != old_style_ranges.end() && old_style_it->first <= new_style_it->first))
{
if (old_style != new_style)
Redraw(range_start, old_style_it->first);
old_style = old_style_it->second;
range_start = old_style_it->first;
++old_style_it;
}
else
{
if (old_style != new_style)
Redraw(range_start, new_style_it->first);
new_style = new_style_it->second;
range_start = new_style_it->first;
++new_style_it;
}
}
// Fill in the last style range
if (old_style != new_style)
{
Redraw(range_start, SamplesFromRelativeX(GetClientSize().GetWidth()));
}
}
void AudioDisplay::Redraw(int64_t sample_start, int64_t sample_end)
{
if (sample_start == sample_end) return;
sample_start = RelativeXFromSamples(sample_start) - foot_size;
sample_end = RelativeXFromSamples(sample_end) + foot_size;
if (sample_end >= 0 && sample_start <= GetClientSize().GetWidth())
{
RefreshRect(wxRect(sample_start, audio_top, sample_end, audio_height), false);
}
}
void AudioDisplay::OnMarkerMoved()
{
/// @todo investigate if it's worth refreshing only the changed spots
RefreshRect(wxRect(0, audio_top, GetClientSize().GetWidth(), audio_height));
RefreshRect(wxRect(0, audio_top, GetClientSize().GetWidth(), audio_height), false);
}

View File

@ -98,7 +98,7 @@ public:
/// timing controller. The audio display also renders audio according to the audio controller
/// and the timing controller, using an audio renderer instance.
class AudioDisplay: public wxWindow {
private:
std::list<agi::signal::Connection> slots;
agi::Context *context;
@ -146,6 +146,8 @@ private:
/// Height of main audio area in pixels
int audio_height;
/// Width of the audio marker feet in pixels
static const int foot_size = 6;
/// Zoom level given as a number, see SetZoomLevel for details
int zoom_level;
@ -163,8 +165,8 @@ private:
/// @brief Remove the tracking cursor from the display
void RemoveTrackCursor();
/// Previous audio selection for optimizing redraw when selection changes
SampleRange old_selection;
/// Previous style ranges for optimizing redraw when ranges change
std::map<int64_t, int> style_ranges;
/// @brief Reload all rendering settings from Options and reset caches
///
@ -172,6 +174,11 @@ private:
/// 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);
/// wxWidgets paint event
void OnPaint(wxPaintEvent &event);
/// wxWidgets mouse input event
@ -187,10 +194,10 @@ private:
void OnAudioOpen(AudioProvider *provider);
void OnPlaybackPosition(int64_t sample_position);
void OnSelectionChanged();
void OnStyleRangesChanged();
void OnMarkerMoved();
public:
AudioDisplay(wxWindow *parent, AudioController *controller, agi::Context *context);
~AudioDisplay();

View File

@ -46,9 +46,12 @@
#include "audio_renderer.h"
#include "include/aegisub/audio_provider.h"
#undef min
#undef max
template<class C, class F> static void for_each(C &container, F const& func)
{
std::for_each(container.begin(), container.end(), func);
}
using std::tr1::placeholders::_1;
AudioRendererBitmapCacheBitmapFactory::AudioRendererBitmapCacheBitmapFactory(AudioRenderer *_renderer)
{
@ -80,19 +83,18 @@ size_t AudioRendererBitmapCacheBitmapFactory::GetBlockSize() const
AudioRenderer::AudioRenderer()
: cache_bitmap_width(32) // arbitrary value for now
, bitmaps_normal(256, AudioRendererBitmapCacheBitmapFactory(this))
, bitmaps_selected(256, AudioRendererBitmapCacheBitmapFactory(this))
, cache_bitmap_maxsize(0)
, cache_renderer_maxsize(0)
, renderer(0)
, provider(0)
{
bitmaps.resize(AudioStyle_MAX, AudioRendererBitmapCache(256, AudioRendererBitmapCacheBitmapFactory(this)));
// Make sure there's *some* values for those fields, and in the caches
SetSamplesPerPixel(1);
SetHeight(1);
}
AudioRenderer::~AudioRenderer()
{
// Nothing to do, everything is auto-allocated
@ -183,26 +185,22 @@ void AudioRenderer::ResetBlockCount()
{
size_t rendered_width = (size_t)((provider->GetNumSamples() + pixel_samples - 1) / pixel_samples);
cache_numblocks = rendered_width / cache_bitmap_width;
bitmaps_normal.SetBlockCount(cache_numblocks);
bitmaps_selected.SetBlockCount(cache_numblocks);
for_each(bitmaps, bind(&AudioRendererBitmapCache::SetBlockCount, _1, cache_numblocks));
}
}
wxBitmap AudioRenderer::GetCachedBitmap(int i, bool selected)
wxBitmap AudioRenderer::GetCachedBitmap(int i, AudioRenderingStyle style)
{
assert(provider);
assert(renderer);
// Pick the cache to use
AudioRendererBitmapCache *cache = selected ? &bitmaps_selected : &bitmaps_normal;
bool created = false;
wxBitmap *bmp = cache->Get(i, &created);
wxBitmap *bmp = bitmaps[style].Get(i, &created);
assert(bmp);
if (created)
{
renderer->Render(*bmp, i*cache_bitmap_width, selected);
renderer->Render(*bmp, i*cache_bitmap_width, style);
}
assert(bmp->IsOk());
@ -210,7 +208,7 @@ wxBitmap AudioRenderer::GetCachedBitmap(int i, bool selected)
}
void AudioRenderer::Render(wxDC &dc, wxPoint origin, int start, int length, bool selected)
void AudioRenderer::Render(wxDC &dc, wxPoint origin, int start, int length, AudioRenderingStyle style)
{
assert(start >= 0);
@ -257,7 +255,7 @@ void AudioRenderer::Render(wxDC &dc, wxPoint origin, int start, int length, bool
else if (firstbitmap == lastbitmap)
{
const int renderwidth = lastbitmapoffset - firstbitmapoffset;
wxBitmap bmp = GetCachedBitmap(firstbitmap, selected);
wxBitmap bmp = GetCachedBitmap(firstbitmap, style);
wxMemoryDC bmpdc(bmp);
dc.Blit(origin, wxSize(renderwidth, pixel_height), &bmpdc, wxPoint(firstbitmapoffset, 0));
origin.x += renderwidth;
@ -267,7 +265,7 @@ void AudioRenderer::Render(wxDC &dc, wxPoint origin, int start, int length, bool
wxBitmap bmp;
{
bmp = GetCachedBitmap(firstbitmap, selected);
bmp = GetCachedBitmap(firstbitmap, style);
// Can't use dc.DrawBitmap here because we need to clip the bitmap
wxMemoryDC bmpdc(bmp);
dc.Blit(origin, wxSize(cache_bitmap_width-firstbitmapoffset, pixel_height),
@ -277,13 +275,13 @@ void AudioRenderer::Render(wxDC &dc, wxPoint origin, int start, int length, bool
for (int i = firstbitmap+1; i < lastbitmap; ++i)
{
bmp = GetCachedBitmap(i, selected);
bmp = GetCachedBitmap(i, style);
dc.DrawBitmap(bmp, origin);
origin.x += cache_bitmap_width;
}
{
bmp = GetCachedBitmap(lastbitmap, selected);
bmp = GetCachedBitmap(lastbitmap, style);
// We also need clipping here
wxMemoryDC bmpdc(bmp);
dc.Blit(origin, wxSize(lastbitmapoffset+1, pixel_height), &bmpdc, wxPoint(0, 0));
@ -294,26 +292,20 @@ void AudioRenderer::Render(wxDC &dc, wxPoint origin, int start, int length, bool
// Now render blank audio from origin to end
if (origin.x < lastx)
{
renderer->RenderBlank(dc, wxRect(origin.x-1, origin.y, lastx-origin.x+1, pixel_height), selected);
renderer->RenderBlank(dc, wxRect(origin.x-1, origin.y, lastx-origin.x+1, pixel_height), style);
}
if (selected)
bitmaps_selected.Age(cache_bitmap_maxsize);
else
bitmaps_normal.Age(cache_bitmap_maxsize);
bitmaps[style].Age(cache_bitmap_maxsize);
renderer->AgeCache(cache_renderer_maxsize);
}
void AudioRenderer::Invalidate()
{
bitmaps_normal.Age(0);
bitmaps_selected.Age(0);
for_each(bitmaps, bind(&AudioRendererBitmapCache::Age, _1, 0));
}
void AudioRendererBitmapProvider::SetProvider(AudioProvider *_provider)
{
if (provider == _provider) return;
@ -342,4 +334,3 @@ void AudioRendererBitmapProvider::SetAmplitudeScale(float _amplitude_scale)
OnSetAmplitudeScale();
}

View File

@ -38,6 +38,7 @@
#ifndef AGI_PRE
#include <memory>
#include <vector>
#include <wx/dc.h>
#include <wx/gdicmn.h>
@ -52,6 +53,41 @@ class AudioProvider;
class AudioRendererBitmapProvider;
class AudioRenderer;
/// @brief Styles audio may be rendered in
///
/// The constants are ordered by priority:
/// Selected has highest priority and should overlap active, which should
/// overlap inactive, which should overlap normal regions.
enum AudioRenderingStyle {
/// Regular audio with no special properties
AudioStyle_Normal,
/// Audio belonging to objects that can not be manipulated currently
AudioStyle_Inactive,
/// Audio that may be manipulated indirectly, usually part of selected lines
AudioStyle_Active,
/// Primary selection for work, usually coinciding with the primary playback range
AudioStyle_Selected,
/// Number of audio styles
AudioStyle_MAX
};
/// @class AudioRenderingStyleRanges
/// @brief Abstract container for ranges of audio rendering styles
///
/// Interface for producers of audio rendering ranges, consumers should implement
/// this interface for objects to pass to producers.
class 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 style Style of the range added
virtual void AddRange(int64_t start, int64_t end, AudioRenderingStyle style) = 0;
};
/// @class AudioRendererBitmapCacheBitmapFactory
/// @brief Produces wxBitmap objects for DataBlockCache storage for the audio renderer
struct AudioRendererBitmapCacheBitmapFactory {
@ -104,10 +140,8 @@ class AudioRenderer {
/// Width of bitmaps to store in cache
const int cache_bitmap_width;
/// Cached bitmaps for normal audio ranges
AudioRendererBitmapCache bitmaps_normal;
/// Cached bitmaps for marked (selected) audio ranges
AudioRendererBitmapCache bitmaps_selected;
/// Cached bitmaps for audio ranges
std::vector<AudioRendererBitmapCache> bitmaps;
/// Number of blocks in the bitmap caches
size_t cache_numblocks;
/// The maximum allowed size of each bitmap cache, in bytes
@ -122,13 +156,13 @@ class AudioRenderer {
AudioProvider *provider;
/// @brief Make sure bitmap index i is in cache
/// @param i Index of bitmap to get into cache
/// @param selected Whether to get a "selected" state bitmap or not
/// @param i Index of bitmap to get into cache
/// @param style Rendering style required for bitmap
/// @return The requested bitmap
///
/// Will attempt retrieving the requested bitmap from the cache, creating it
/// if the cache doesn't have it.
wxBitmap GetCachedBitmap(int i, bool selected);
wxBitmap GetCachedBitmap(int i, AudioRenderingStyle style);
/// @brief Update the block count in the bitmap caches
///
@ -230,11 +264,11 @@ public:
/// @param origin Top left corner to render at, in the DC's coordinates
/// @param start First pixel from beginning of the audio stream to render
/// @param length Number of pixels of audio to render
/// @param selected Whether to render the audio as being selected or not
/// @param style Style to render audio in
///
/// The first audio sample rendered is start*pixel_samples, and the number
/// of audio samples rendered is length*pixel_samples.
void Render(wxDC &dc, wxPoint origin, int start, int length, bool selected);
void Render(wxDC &dc, wxPoint origin, int start, int length, AudioRenderingStyle style);
/// @brief Invalidate all cached data
///
@ -284,22 +318,22 @@ public:
virtual ~AudioRendererBitmapProvider() { }
/// @brief Rendering function
/// @param bmp Bitmap to render to
/// @param start First pixel from beginning of the audio stream to render
/// @param selected Whether to render the audio as being selected or not
/// @param bmp Bitmap to render to
/// @param start First pixel from beginning of the audio stream to render
/// @param style Style to render audio in
///
/// Deriving classes must implement this method. The bitmap in bmp holds
/// the width and height to render.
virtual void Render(wxBitmap &bmp, int start, bool selected) = 0;
virtual void Render(wxBitmap &bmp, int start, AudioRenderingStyle style) = 0;
/// @brief Blank audio rendering function
/// @param dc The device context to render to
/// @param rect The rectangle to fill with the image of blank audio
/// @param selected Whether to render as being selected or not
/// @param dc The device context to render to
/// @param rect The rectangle to fill with the image of blank audio
/// @param style Style to render audio in
///
/// Deriving classes must implement this method. The rectangle has the height
/// of the entire canvas the audio is being rendered in.
virtual void RenderBlank(wxDC &dc, const wxRect &rect, bool selected) = 0;
virtual void RenderBlank(wxDC &dc, const wxRect &rect, AudioRenderingStyle style) = 0;
/// @brief Change audio provider
/// @param provider Audio provider to change to

View File

@ -264,7 +264,7 @@ void AudioSpectrumRenderer::FillBlock(size_t block_index, float *block)
}
void AudioSpectrumRenderer::Render(wxBitmap &bmp, int start, bool selected)
void AudioSpectrumRenderer::Render(wxBitmap &bmp, int start, AudioRenderingStyle style)
{
if (!cache)
return;
@ -284,7 +284,7 @@ void AudioSpectrumRenderer::Render(wxBitmap &bmp, int start, bool selected)
ptrdiff_t stride = img.GetWidth()*3;
int imgheight = img.GetHeight();
AudioColorScheme *pal = selected ? &colors_selected : &colors_normal;
AudioColorScheme *pal = style == AudioStyle_Selected ? &colors_selected : &colors_normal;
/// @todo Make minband and maxband configurable
int minband = 0;
@ -341,10 +341,10 @@ void AudioSpectrumRenderer::Render(wxBitmap &bmp, int start, bool selected)
}
void AudioSpectrumRenderer::RenderBlank(wxDC &dc, const wxRect &rect, bool selected)
void AudioSpectrumRenderer::RenderBlank(wxDC &dc, const wxRect &rect, AudioRenderingStyle style)
{
// Get the colour of silence
AudioColorScheme *pal = selected ? &colors_selected : &colors_normal;
AudioColorScheme *pal = style == AudioStyle_Selected ? &colors_selected : &colors_normal;
unsigned char color_raw[4];
pal->map(0.0, color_raw);
wxColour col(color_raw[0], color_raw[1], color_raw[2]);

View File

@ -115,13 +115,13 @@ public:
virtual ~AudioSpectrumRenderer();
/// @brief Render a range of audio spectrum
/// @param bmp [in,out] Bitmap to render into, also carries lenght information
/// @param start First column of pixel data in display to render
/// @param selected Whether to use the alternate colour scheme
void Render(wxBitmap &bmp, int start, bool selected);
/// @param bmp [in,out] Bitmap to render into, also carries lenght information
/// @param start First column of pixel data in display to render
/// @param style Style to render audio in
void Render(wxBitmap &bmp, int start, AudioRenderingStyle style);
/// @brief Render blank area
void RenderBlank(wxDC &dc, const wxRect &rect, bool selected);
void RenderBlank(wxDC &dc, const wxRect &rect, AudioRenderingStyle style);
/// @brief Set the derivation resolution
/// @param derivation_size Binary logarithm of number of samples to use in deriving frequency-power data

View File

@ -71,13 +71,13 @@ AudioWaveformRenderer::~AudioWaveformRenderer()
}
void AudioWaveformRenderer::Render(wxBitmap &bmp, int start, bool selected)
void AudioWaveformRenderer::Render(wxBitmap &bmp, int start, AudioRenderingStyle style)
{
wxMemoryDC dc(bmp);
wxRect rect(wxPoint(0, 0), bmp.GetSize());
int midpoint = rect.height / 2;
AudioColorScheme *pal = selected ? &colors_selected : &colors_normal;
AudioColorScheme *pal = style == AudioStyle_Selected ? &colors_selected : &colors_normal;
// Fill the background
dc.SetBrush(wxBrush(pal->get(0.0f)));
@ -140,9 +140,9 @@ void AudioWaveformRenderer::Render(wxBitmap &bmp, int start, bool selected)
}
void AudioWaveformRenderer::RenderBlank(wxDC &dc, const wxRect &rect, bool selected)
void AudioWaveformRenderer::RenderBlank(wxDC &dc, const wxRect &rect, AudioRenderingStyle style)
{
AudioColorScheme *pal = selected ? &colors_selected : &colors_normal;
AudioColorScheme *pal = style == AudioStyle_Selected ? &colors_selected : &colors_normal;
wxColor line(pal->get(1.0));
wxColor bg(pal->get(0.0));

View File

@ -61,13 +61,13 @@ public:
virtual ~AudioWaveformRenderer();
/// @brief Render a range of audio waveform
/// @param bmp [in,out] Bitmap to render into, also carries lenght information
/// @param start First column of pixel data in display to render
/// @param selected Whether to use the alternate colour scheme
void Render(wxBitmap &bmp, int start, bool selected);
/// @param bmp [in,out] Bitmap to render into, also carries lenght information
/// @param start First column of pixel data in display to render
/// @param style Style to render audio in
void Render(wxBitmap &bmp, int start, AudioRenderingStyle style);
/// @brief Render blank area
void RenderBlank(wxDC &dc, const wxRect &rect, bool selected);
void RenderBlank(wxDC &dc, const wxRect &rect, AudioRenderingStyle style);
/// @brief Cleans up the cache
/// @param max_size Maximum size in bytes for the cache

View File

@ -36,6 +36,7 @@
class AssDialogue;
class AssFile;
class AssKaraoke;
class AudioRenderingStyleRanges;
namespace agi { struct Context; }
#include "audio_controller.h"
@ -79,6 +80,10 @@ public:
/// currently.
virtual SampleRange GetPrimaryPlaybackRange() const = 0;
/// @brief Get all rendering style ranges
/// @param[out] swpts Rendering ranges will be added to this
virtual void GetRenderingStyles(AudioRenderingStyleRanges &ranges) const = 0;
/// @brief Does this timing mode have labels on the audio display?
/// @return True if this timing mode needs labels on the audio display.
///

View File

@ -44,6 +44,7 @@
#include "ass_time.h"
#include "audio_controller.h"
#include "audio_marker_provider_keyframes.h"
#include "audio_renderer.h"
#include "audio_timing.h"
#include "include/aegisub/context.h"
#include "main.h"
@ -106,8 +107,10 @@ public:
/// This checks that the markers aren't already part of a pair, and then
/// sets their "other" field. Positions and styles aren't affected.
static void InitPair(AudioMarkerDialogueTiming *marker1, AudioMarkerDialogueTiming *marker2);
};
/// Implicit decay to the position of the marker
operator int64_t() const { return position; }
};
/// @class AudioTimingControllerDialogue
@ -176,6 +179,7 @@ public:
wxString GetWarningMessage() const;
SampleRange GetIdealVisibleSampleRange() const;
SampleRange GetPrimaryPlaybackRange() const;
void GetRenderingStyles(AudioRenderingStyleRanges &ranges) const;
bool HasLabels() const { return false; }
void GetLabels(SampleRange const& range, std::vector<AudioLabel> &out) const { }
void Next();
@ -195,8 +199,6 @@ public:
~AudioTimingControllerDialogue();
};
AudioTimingController *CreateDialogueTimingController(agi::Context *c)
{
return new AudioTimingControllerDialogue(c);
@ -226,7 +228,6 @@ void AudioMarkerDialogueTiming::SetPosition(int64_t new_position)
}
}
AudioMarkerDialogueTiming::AudioMarkerDialogueTiming()
: other(0)
, position(0)
@ -238,7 +239,6 @@ AudioMarkerDialogueTiming::AudioMarkerDialogueTiming()
// Nothing more to do
}
void AudioMarkerDialogueTiming::InitPair(AudioMarkerDialogueTiming *marker1, AudioMarkerDialogueTiming *marker2)
{
assert(marker1->other == 0);
@ -248,8 +248,6 @@ void AudioMarkerDialogueTiming::InitPair(AudioMarkerDialogueTiming *marker1, Aud
marker2->other = marker1;
}
// AudioTimingControllerDialogue
AudioTimingControllerDialogue::AudioTimingControllerDialogue(agi::Context *c)
@ -279,35 +277,31 @@ AudioTimingControllerDialogue::~AudioTimingControllerDialogue()
context->selectionController->RemoveSelectionListener(this);
}
AudioMarkerDialogueTiming *AudioTimingControllerDialogue::GetLeftMarker()
{
return markers[0].GetPosition() < markers[1].GetPosition() ? &markers[0] : &markers[1];
return markers[0] < markers[1] ? &markers[0] : &markers[1];
}
const AudioMarkerDialogueTiming *AudioTimingControllerDialogue::GetLeftMarker() const
{
return markers[0].GetPosition() < markers[1].GetPosition() ? &markers[0] : &markers[1];
return &std::min(markers[0], markers[1]);
}
AudioMarkerDialogueTiming *AudioTimingControllerDialogue::GetRightMarker()
{
return markers[0].GetPosition() < markers[1].GetPosition() ? &markers[1] : &markers[0];
return markers[0] < markers[1] ? &markers[1] : &markers[0];
}
const AudioMarkerDialogueTiming *AudioTimingControllerDialogue::GetRightMarker() const
{
return markers[0].GetPosition() < markers[1].GetPosition() ? &markers[1] : &markers[0];
return &std::max(markers[0], markers[1]);
}
void AudioTimingControllerDialogue::GetMarkers(const SampleRange &range, AudioMarkerVector &out_markers) const
{
if (range.contains(markers[0].GetPosition()))
if (range.contains(markers[0]))
out_markers.push_back(&markers[0]);
if (range.contains(markers[1].GetPosition()))
if (range.contains(markers[1]))
out_markers.push_back(&markers[1]);
keyframes_provider.GetMarkers(range, out_markers);
@ -331,49 +325,42 @@ void AudioTimingControllerDialogue::OnFileChanged(int type) {
}
}
wxString AudioTimingControllerDialogue::GetWarningMessage() const
{
// We have no warning messages currently, maybe add the old "Modified" message back later?
return wxString();
}
SampleRange AudioTimingControllerDialogue::GetIdealVisibleSampleRange() const
{
return GetPrimaryPlaybackRange();
}
SampleRange AudioTimingControllerDialogue::GetPrimaryPlaybackRange() const
{
return SampleRange(
GetLeftMarker()->GetPosition(),
GetRightMarker()->GetPosition());
return SampleRange(*GetLeftMarker(), *GetRightMarker());
}
void AudioTimingControllerDialogue::GetRenderingStyles(AudioRenderingStyleRanges &ranges) const
{
ranges.AddRange(*GetLeftMarker(), *GetRightMarker(), AudioStyle_Selected);
/// @todo Find inactive and non-selected lines to add to styles
}
void AudioTimingControllerDialogue::Next()
{
context->selectionController->NextLine();
}
void AudioTimingControllerDialogue::Prev()
{
context->selectionController->PrevLine();
}
void AudioTimingControllerDialogue::Commit()
{
int new_start_ms = context->audioController->MillisecondsFromSamples(GetLeftMarker()->GetPosition());
int new_end_ms = context->audioController->MillisecondsFromSamples(GetRightMarker()->GetPosition());
int new_start_ms = context->audioController->MillisecondsFromSamples(*GetLeftMarker());
int new_end_ms = context->audioController->MillisecondsFromSamples(*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
@ -420,8 +407,6 @@ void AudioTimingControllerDialogue::Commit()
}
}
void AudioTimingControllerDialogue::Revert()
{
if (AssDialogue *line = context->selectionController->GetActiveLine())
@ -439,16 +424,13 @@ void AudioTimingControllerDialogue::Revert()
}
}
bool AudioTimingControllerDialogue::IsNearbyMarker(int64_t sample, int sensitivity) const
{
SampleRange range(sample-sensitivity, sample+sensitivity);
return range.contains(markers[0].GetPosition()) || range.contains(markers[1].GetPosition());
return range.contains(markers[0]) || range.contains(markers[1]);
}
AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sensitivity)
{
assert(sensitivity >= 0);
@ -458,8 +440,8 @@ AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sen
AudioMarkerDialogueTiming *left = GetLeftMarker();
AudioMarkerDialogueTiming *right = GetRightMarker();
dist_l = tabs(left->GetPosition() - sample);
dist_r = tabs(right->GetPosition() - sample);
dist_l = tabs(*left - sample);
dist_r = tabs(*right - sample);
if (dist_l < dist_r && dist_l <= sensitivity)
{
@ -483,8 +465,6 @@ AudioMarker * AudioTimingControllerDialogue::OnLeftClick(int64_t sample, int sen
return right;
}
AudioMarker * AudioTimingControllerDialogue::OnRightClick(int64_t sample, int sensitivity)
{
AudioMarkerDialogueTiming *right = GetRightMarker();
@ -492,20 +472,16 @@ AudioMarker * AudioTimingControllerDialogue::OnRightClick(int64_t sample, int se
return right;
}
void AudioTimingControllerDialogue::OnMarkerDrag(AudioMarker *marker, int64_t new_position)
{
assert(marker == &markers[0] || marker == &markers[1]);
SetMarker(static_cast<AudioMarkerDialogueTiming*>(marker), new_position);
}
void AudioTimingControllerDialogue::UpdateSelection()
{
AnnounceUpdatedPrimaryRange();
AnnounceUpdatedStyleRanges();
}
void AudioTimingControllerDialogue::SetMarker(AudioMarkerDialogueTiming *marker, int64_t sample)

View File

@ -29,6 +29,7 @@
#include "ass_file.h"
#include "ass_karaoke.h"
#include "audio_marker_provider_keyframes.h"
#include "audio_renderer.h"
#include "audio_timing.h"
#include "include/aegisub/context.h"
#include "main.h"
@ -120,6 +121,7 @@ public:
void GetMarkers(const SampleRange &range, AudioMarkerVector &out_markers) const;
wxString GetWarningMessage() const { return ""; }
SampleRange GetIdealVisibleSampleRange() const;
void GetRenderingStyles(AudioRenderingStyleRanges &ranges) const;
SampleRange GetPrimaryPlaybackRange() const;
bool HasLabels() const { return true; }
void GetLabels(const SampleRange &range, std::vector<AudioLabel> &out_labels) const;
@ -199,6 +201,12 @@ void AudioTimingControllerKaraoke::Prev() {
}
}
void AudioTimingControllerKaraoke::GetRenderingStyles(AudioRenderingStyleRanges &ranges) const
{
SampleRange sr = GetPrimaryPlaybackRange();
ranges.AddRange(sr.begin(), sr.end(), AudioStyle_Selected);
}
SampleRange AudioTimingControllerKaraoke::GetPrimaryPlaybackRange() const {
return SampleRange(
cur_syl > 0 ? markers[cur_syl - 1] : start_marker,