Change AudioRenderer to use DataBlockCache.
Originally committed to SVN as r3414.
This commit is contained in:
parent
d29d267cce
commit
e9e3b2d107
3 changed files with 196 additions and 171 deletions
|
@ -35,161 +35,35 @@
|
||||||
|
|
||||||
|
|
||||||
#include "audio_renderer.h"
|
#include "audio_renderer.h"
|
||||||
|
#include "include/aegisub/audio_provider.h"
|
||||||
#include <wx/bitmap.h>
|
#include <wx/bitmap.h>
|
||||||
#include <wx/dcmemory.h>
|
#include <wx/dcmemory.h>
|
||||||
#include <map>
|
|
||||||
|
|
||||||
|
|
||||||
/// @class AudioRendererBitmapCache
|
|
||||||
/// @brief Caches bitmaps of rendered audio at a specific resolution
|
|
||||||
///
|
|
||||||
/// Used internally by the AudioRenderer class.
|
|
||||||
class AudioRendererBitmapCache {
|
|
||||||
/// Width of cached bitmaps
|
|
||||||
int width;
|
|
||||||
/// Height of cached bitmaps
|
|
||||||
int height;
|
|
||||||
|
|
||||||
/// Memory size of each cached image, for cache management
|
|
||||||
size_t bytes_per_image;
|
|
||||||
|
|
||||||
// Cached bitmaps
|
|
||||||
// Intentionally not doxygened, too internal
|
|
||||||
struct CachedBitmap {
|
|
||||||
// The bitmap itself
|
|
||||||
wxBitmap bmp;
|
|
||||||
// "Timestamp" of last access (not necessarily related to any clocks)
|
|
||||||
int last_access;
|
|
||||||
|
|
||||||
CachedBitmap(wxBitmap bmp = wxBitmap()) : bmp(bmp), last_access(0) { }
|
|
||||||
~CachedBitmap() { }
|
|
||||||
|
|
||||||
bool operator < (const CachedBitmap &other) const { return last_access < other.last_access; }
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::map<int, CachedBitmap> CacheType;
|
|
||||||
CacheType cache;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// @brief Constructor
|
|
||||||
///
|
|
||||||
/// Does nothing.
|
|
||||||
AudioRendererBitmapCache();
|
|
||||||
|
|
||||||
/// @brief Destructor
|
|
||||||
///
|
|
||||||
/// Does nothing.
|
|
||||||
~AudioRendererBitmapCache();
|
|
||||||
|
|
||||||
/// @brief Age the cache, purging old items
|
|
||||||
/// @param max_size Maximum allowed cache size, in bytes
|
|
||||||
///
|
|
||||||
/// Purges the least recently used bitmaps to bring the cache size below max_size.
|
|
||||||
/// Aging is a somewhat expensive operation and should only be done once in a while.
|
|
||||||
///
|
|
||||||
/// If max_size is specified to 0, the cache will be entirely cleared in a fast manner.
|
|
||||||
void Age(size_t max_size);
|
|
||||||
|
|
||||||
/// @brief Change the size of cached images
|
|
||||||
/// @param new_width New width of images to cache
|
|
||||||
/// @param new_height New height of images to cache
|
|
||||||
///
|
|
||||||
/// Clears and re-initialises the cache.
|
|
||||||
void Resize(int new_width, int new_height);
|
|
||||||
|
|
||||||
/// @brief Retrieve an image from cache
|
|
||||||
/// @param bmp [out] Bitmap to return the image in
|
|
||||||
/// @param key Key to request the image for
|
|
||||||
/// @param timestamp Timestamp to use for cache age management
|
|
||||||
/// @return Returns false if the image had to be created in cache; if the return is
|
|
||||||
/// false, the consumer must draw into the returned bitmap.
|
|
||||||
///
|
|
||||||
/// Example:
|
|
||||||
/// @code
|
|
||||||
/// wxBitmap bmp;
|
|
||||||
/// if (!cache->Get(bmp, key, timestamp))
|
|
||||||
/// RenderBitmap(bmp);
|
|
||||||
/// // Use bmp
|
|
||||||
/// @endcode
|
|
||||||
///
|
|
||||||
/// The timestamp passed should never decrease between calls to the same cache.
|
|
||||||
///
|
|
||||||
/// The key has no inherent meaning to the cache.
|
|
||||||
bool Get(wxBitmap &bmp, int key, int timestamp);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AudioRendererBitmapCacheBitmapFactory::AudioRendererBitmapCacheBitmapFactory(AudioRenderer *_renderer)
|
||||||
AudioRendererBitmapCache::AudioRendererBitmapCache()
|
|
||||||
{
|
{
|
||||||
Resize(0, 0);
|
assert(_renderer != 0);
|
||||||
|
renderer = _renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AudioRendererBitmapCache::~AudioRendererBitmapCache()
|
wxBitmap *AudioRendererBitmapCacheBitmapFactory::ProduceBlock(int i)
|
||||||
{
|
{
|
||||||
// Nothing to do
|
(void)i;
|
||||||
|
return new wxBitmap(renderer->cache_bitmap_width, renderer->pixel_height, 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioRendererBitmapCache::Age(size_t max_size)
|
void AudioRendererBitmapCacheBitmapFactory::DisposeBlock(wxBitmap *bmp)
|
||||||
{
|
{
|
||||||
if (max_size == 0)
|
delete bmp;
|
||||||
{
|
|
||||||
cache.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @todo Make this faster than O(n^2)
|
|
||||||
|
|
||||||
size_t max_items = max_size / bytes_per_image;
|
|
||||||
|
|
||||||
while (cache.size() > max_items)
|
|
||||||
{
|
|
||||||
// Find the oldest item and remove it
|
|
||||||
CacheType::iterator next = cache.begin();
|
|
||||||
CacheType::iterator oldest = next;
|
|
||||||
while (++next != cache.end())
|
|
||||||
{
|
|
||||||
if (next->second.last_access < oldest->second.last_access)
|
|
||||||
oldest = next;
|
|
||||||
}
|
|
||||||
cache.erase(oldest);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioRendererBitmapCache::Resize(int new_width, int new_height)
|
size_t AudioRendererBitmapCacheBitmapFactory::GetBlockSize() const
|
||||||
{
|
{
|
||||||
Age(0);
|
return sizeof(wxBitmap) + renderer->cache_bitmap_width * renderer->pixel_height * 4;
|
||||||
|
|
||||||
width = new_width;
|
|
||||||
height = new_height;
|
|
||||||
|
|
||||||
// Assuming 32 bpp
|
|
||||||
// This probably isn't completely accurate, but just a reasonable approximation
|
|
||||||
bytes_per_image = sizeof(CachedBitmap) + width*height*4;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool AudioRendererBitmapCache::Get(wxBitmap &bmp, int key, int timestamp)
|
|
||||||
{
|
|
||||||
CacheType::iterator item = cache.find(key);
|
|
||||||
bool found = true;
|
|
||||||
|
|
||||||
if (item == cache.end())
|
|
||||||
{
|
|
||||||
cache[key] = CachedBitmap(wxBitmap(width, height, 32));
|
|
||||||
item = cache.find(key);
|
|
||||||
assert(item != cache.end());
|
|
||||||
found = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
item->second.last_access = timestamp;
|
|
||||||
bmp = item->second.bmp;
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -197,9 +71,8 @@ bool AudioRendererBitmapCache::Get(wxBitmap &bmp, int key, int timestamp)
|
||||||
|
|
||||||
AudioRenderer::AudioRenderer()
|
AudioRenderer::AudioRenderer()
|
||||||
: cache_bitmap_width(32) // arbitrary value for now
|
: cache_bitmap_width(32) // arbitrary value for now
|
||||||
, bitmaps_normal(new AudioRendererBitmapCache)
|
, bitmaps_normal(256, AudioRendererBitmapCacheBitmapFactory(this))
|
||||||
, bitmaps_selected(new AudioRendererBitmapCache)
|
, bitmaps_selected(256, AudioRendererBitmapCacheBitmapFactory(this))
|
||||||
, cache_clock(0)
|
|
||||||
, cache_maxsize(0)
|
, cache_maxsize(0)
|
||||||
, renderer(0)
|
, renderer(0)
|
||||||
, provider(0)
|
, provider(0)
|
||||||
|
@ -218,7 +91,14 @@ AudioRenderer::~AudioRenderer()
|
||||||
|
|
||||||
void AudioRenderer::SetSamplesPerPixel(int _pixel_samples)
|
void AudioRenderer::SetSamplesPerPixel(int _pixel_samples)
|
||||||
{
|
{
|
||||||
|
if (pixel_samples == _pixel_samples) return;
|
||||||
|
|
||||||
pixel_samples = _pixel_samples;
|
pixel_samples = _pixel_samples;
|
||||||
|
|
||||||
|
if (renderer)
|
||||||
|
renderer->SetSamplesPerPixel(pixel_samples);
|
||||||
|
|
||||||
|
ResetBlockCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -227,8 +107,22 @@ void AudioRenderer::SetHeight(int _pixel_height)
|
||||||
if (pixel_height == _pixel_height) return;
|
if (pixel_height == _pixel_height) return;
|
||||||
|
|
||||||
pixel_height = _pixel_height;
|
pixel_height = _pixel_height;
|
||||||
bitmaps_normal->Resize(cache_bitmap_width, pixel_height);
|
Invalidate();
|
||||||
bitmaps_selected->Resize(cache_bitmap_width, pixel_height);
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioRenderer::SetAmplitudeScale(float _amplitude_scale)
|
||||||
|
{
|
||||||
|
if (amplitude_scale == _amplitude_scale) return;
|
||||||
|
|
||||||
|
// A scaling of 0 or a negative scaling makes no sense
|
||||||
|
assert(_amplitude_scale > 0);
|
||||||
|
|
||||||
|
amplitude_scale = _amplitude_scale;
|
||||||
|
|
||||||
|
if (renderer)
|
||||||
|
renderer->SetAmplitudeScale(amplitude_scale);
|
||||||
|
Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -240,11 +134,14 @@ void AudioRenderer::SetRenderer(AudioRendererBitmapProvider *_renderer)
|
||||||
renderer->SetProvider(0);
|
renderer->SetProvider(0);
|
||||||
|
|
||||||
renderer = _renderer;
|
renderer = _renderer;
|
||||||
bitmaps_normal->Age(0);
|
Invalidate();
|
||||||
bitmaps_selected->Age(0);
|
|
||||||
|
|
||||||
if (renderer)
|
if (renderer)
|
||||||
|
{
|
||||||
renderer->SetProvider(provider);
|
renderer->SetProvider(provider);
|
||||||
|
renderer->SetAmplitudeScale(amplitude_scale);
|
||||||
|
renderer->SetSamplesPerPixel(pixel_samples);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -253,11 +150,23 @@ void AudioRenderer::SetAudioProvider(AudioProvider *_provider)
|
||||||
if (provider == _provider) return;
|
if (provider == _provider) return;
|
||||||
|
|
||||||
provider = _provider;
|
provider = _provider;
|
||||||
bitmaps_normal->Age(0);
|
Invalidate();
|
||||||
bitmaps_selected->Age(0);
|
|
||||||
|
|
||||||
if (renderer)
|
if (renderer)
|
||||||
renderer->SetProvider(provider);
|
renderer->SetProvider(provider);
|
||||||
|
|
||||||
|
ResetBlockCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioRenderer::ResetBlockCount()
|
||||||
|
{
|
||||||
|
if (provider)
|
||||||
|
{
|
||||||
|
size_t num_bitmaps = (size_t)((provider->GetNumSamples() + pixel_samples - 1) / pixel_samples);
|
||||||
|
bitmaps_normal.SetBlockCount(num_bitmaps);
|
||||||
|
bitmaps_selected.SetBlockCount(num_bitmaps);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -267,16 +176,18 @@ wxBitmap AudioRenderer::GetCachedBitmap(int i, bool selected)
|
||||||
assert(renderer);
|
assert(renderer);
|
||||||
|
|
||||||
// Pick the cache to use
|
// Pick the cache to use
|
||||||
AudioRendererBitmapCache *cache = (selected ? bitmaps_selected : bitmaps_normal).get();
|
AudioRendererBitmapCache *cache = selected ? &bitmaps_selected : &bitmaps_normal;
|
||||||
|
|
||||||
wxBitmap bmp;
|
bool created = false;
|
||||||
if (!cache->Get(bmp, i, cache_clock))
|
wxBitmap *bmp = cache->Get(i, &created);
|
||||||
|
assert(bmp);
|
||||||
|
if (created)
|
||||||
{
|
{
|
||||||
renderer->Render(bmp, i*cache_bitmap_width, selected);
|
renderer->Render(*bmp, i*cache_bitmap_width, selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(bmp.IsOk());
|
assert(bmp->IsOk());
|
||||||
return bmp;
|
return *bmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -344,9 +255,16 @@ void AudioRenderer::Render(wxDC &dc, wxPoint origin, int start, int length, bool
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected)
|
if (selected)
|
||||||
bitmaps_selected->Age(cache_maxsize);
|
bitmaps_selected.Age(cache_maxsize);
|
||||||
else
|
else
|
||||||
bitmaps_normal->Age(cache_maxsize);
|
bitmaps_normal.Age(cache_maxsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioRenderer::Invalidate()
|
||||||
|
{
|
||||||
|
bitmaps_normal.Age(0);
|
||||||
|
bitmaps_selected.Age(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -371,3 +289,13 @@ void AudioRendererBitmapProvider::SetSamplesPerPixel(int _pixel_samples)
|
||||||
OnSetSamplesPerPixel();
|
OnSetSamplesPerPixel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AudioRendererBitmapProvider::SetAmplitudeScale(float _amplitude_scale)
|
||||||
|
{
|
||||||
|
if (amplitude_scale == _amplitude_scale) return;
|
||||||
|
|
||||||
|
amplitude_scale = _amplitude_scale;
|
||||||
|
|
||||||
|
OnSetAmplitudeScale();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,17 +37,51 @@
|
||||||
|
|
||||||
|
|
||||||
#include <wx/dc.h>
|
#include <wx/dc.h>
|
||||||
#include <wx/image.h>
|
|
||||||
#include <wx/gdicmn.h>
|
#include <wx/gdicmn.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "block_cache.h"
|
||||||
|
|
||||||
|
|
||||||
// Some forward declarations for outside stuff
|
// Some forward declarations for outside stuff
|
||||||
class AudioProvider;
|
class AudioProvider;
|
||||||
|
|
||||||
// Forwards declarations for internal stuff
|
// Forwards declarations for internal stuff
|
||||||
class AudioRendererBitmapCache;
|
|
||||||
class AudioRendererBitmapProvider;
|
class AudioRendererBitmapProvider;
|
||||||
|
class AudioRenderer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// @class AudioRendererBitmapCacheBitmapFactory
|
||||||
|
/// @brief Produces wxBitmap objects for DataBlockCache storage for the audio renderer
|
||||||
|
struct AudioRendererBitmapCacheBitmapFactory {
|
||||||
|
/// The audio renderer we're producing bitmaps for
|
||||||
|
AudioRenderer *renderer;
|
||||||
|
|
||||||
|
/// @brief Constructor
|
||||||
|
/// @param renderer The audio renderer to produce bitmaps for
|
||||||
|
AudioRendererBitmapCacheBitmapFactory(AudioRenderer *renderer);
|
||||||
|
|
||||||
|
/// @brief Create a new bitmap
|
||||||
|
/// @param i Unused
|
||||||
|
/// @return A fresh wxBitmap
|
||||||
|
///
|
||||||
|
/// Produces a wxBitmap with dimensions pulled from our master AudioRenderer.
|
||||||
|
wxBitmap *ProduceBlock(int i);
|
||||||
|
|
||||||
|
/// @brief Delete a bitmap
|
||||||
|
/// @param bmp The bitmap to delete
|
||||||
|
///
|
||||||
|
/// Deletes said bitmap.
|
||||||
|
void DisposeBlock(wxBitmap *bmp);
|
||||||
|
|
||||||
|
/// @brief Calculate the size of bitmaps
|
||||||
|
/// @return The size of bitmaps created
|
||||||
|
size_t GetBlockSize() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The type of a bitmap cache
|
||||||
|
typedef DataBlockCache<wxBitmap, 8, AudioRendererBitmapCacheBitmapFactory> AudioRendererBitmapCache;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// @class AudioRenderer
|
/// @class AudioRenderer
|
||||||
|
@ -57,20 +91,22 @@ class AudioRendererBitmapProvider;
|
||||||
///
|
///
|
||||||
/// To implement a new audio renderer, see AudioRendererBitmapProvider.
|
/// To implement a new audio renderer, see AudioRendererBitmapProvider.
|
||||||
class AudioRenderer {
|
class AudioRenderer {
|
||||||
|
friend AudioRendererBitmapCacheBitmapFactory;
|
||||||
|
|
||||||
/// Horizontal zoom level, samples per pixel
|
/// Horizontal zoom level, samples per pixel
|
||||||
int pixel_samples;
|
int pixel_samples;
|
||||||
/// Vertical zoom level, height in pixels
|
/// Rendering height in pixels
|
||||||
int pixel_height;
|
int pixel_height;
|
||||||
|
/// Vertical zoom level/amplitude scale
|
||||||
|
float amplitude_scale;
|
||||||
|
|
||||||
/// Width of bitmaps to store in cache
|
/// Width of bitmaps to store in cache
|
||||||
const int cache_bitmap_width;
|
const int cache_bitmap_width;
|
||||||
|
|
||||||
/// Cached bitmaps for normal audio ranges
|
/// Cached bitmaps for normal audio ranges
|
||||||
std::auto_ptr<AudioRendererBitmapCache> bitmaps_normal;
|
AudioRendererBitmapCache bitmaps_normal;
|
||||||
/// Cached bitmaps for marked (selected) audio ranges
|
/// Cached bitmaps for marked (selected) audio ranges
|
||||||
std::auto_ptr<AudioRendererBitmapCache> bitmaps_selected;
|
AudioRendererBitmapCache bitmaps_selected;
|
||||||
/// The "clock" used for cache aging, increased on each render operation
|
|
||||||
int cache_clock;
|
|
||||||
/// The maximum allowed size of the cache, in bytes
|
/// The maximum allowed size of the cache, in bytes
|
||||||
size_t cache_maxsize;
|
size_t cache_maxsize;
|
||||||
|
|
||||||
|
@ -89,6 +125,13 @@ class AudioRenderer {
|
||||||
/// if the cache doesn't have it.
|
/// if the cache doesn't have it.
|
||||||
wxBitmap GetCachedBitmap(int i, bool selected);
|
wxBitmap GetCachedBitmap(int i, bool selected);
|
||||||
|
|
||||||
|
/// @brief Update the block count in the bitmap caches
|
||||||
|
///
|
||||||
|
/// Should be called when the width of the virtual bitmap has changed, i.e.
|
||||||
|
/// when the samples-per-pixel resolution or the number of audio samples
|
||||||
|
/// has changed.
|
||||||
|
void ResetBlockCount();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
///
|
///
|
||||||
|
@ -108,20 +151,35 @@ public:
|
||||||
/// Changing the zoom level invalidates all cached bitmaps.
|
/// Changing the zoom level invalidates all cached bitmaps.
|
||||||
void SetSamplesPerPixel(int pixel_samples);
|
void SetSamplesPerPixel(int pixel_samples);
|
||||||
|
|
||||||
/// @brief Set vertical zoom
|
/// @brief Set rendering height
|
||||||
/// @param pixel_height Height in pixels to render at
|
/// @param pixel_height Height in pixels to render at
|
||||||
///
|
///
|
||||||
/// Changing the zoom level invalidates all cached bitmaps.
|
/// Changing the rendering height invalidates all cached bitmaps.
|
||||||
void SetHeight(int pixel_height);
|
void SetHeight(int pixel_height);
|
||||||
|
|
||||||
|
/// @brief Set vertical zoom
|
||||||
|
/// @param amplitude_scale Scaling factor
|
||||||
|
///
|
||||||
|
/// Changing the scaling factor invalidates all cached bitmaps.
|
||||||
|
///
|
||||||
|
/// A scaling factor of 1.0 is no scaling, a factor of 0.5 causes the audio to be
|
||||||
|
/// rendered as if it had half its actual amplitude, a factor of 2 causes the audio
|
||||||
|
/// to be rendered as if it had double amplitude. (The exact meaning of the scaling
|
||||||
|
/// depends on the bitmap provider used.)
|
||||||
|
void SetAmplitudeScale(float amplitude_scale);
|
||||||
|
|
||||||
/// @brief Get horizontal zoom
|
/// @brief Get horizontal zoom
|
||||||
/// @return Audio samples per pixel rendering at
|
/// @return Audio samples per pixel rendering at
|
||||||
int GetSamplesPerPixel() const { return pixel_samples; }
|
int GetSamplesPerPixel() const { return pixel_samples; }
|
||||||
|
|
||||||
/// @brief Get vertical zoom
|
/// @brief Get rendering height
|
||||||
/// @return Height in pixels rendering at
|
/// @return Height in pixels rendering at
|
||||||
int GetHeight() const { return pixel_height; }
|
int GetHeight() const { return pixel_height; }
|
||||||
|
|
||||||
|
/// @brief Get vertical zoom
|
||||||
|
/// @return The amplitude scaling factor
|
||||||
|
float GetAmplitudeScale() const { return amplitude_scale; }
|
||||||
|
|
||||||
/// @brief Change renderer
|
/// @brief Change renderer
|
||||||
/// @param renderer New renderer to use
|
/// @param renderer New renderer to use
|
||||||
///
|
///
|
||||||
|
@ -166,6 +224,16 @@ public:
|
||||||
/// The first audio sample rendered is start*pixel_samples, and the number
|
/// The first audio sample rendered is start*pixel_samples, and the number
|
||||||
/// of audio samples rendered is length*pixel_samples.
|
/// 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, bool selected);
|
||||||
|
|
||||||
|
/// @brief Invalidate all cached data
|
||||||
|
///
|
||||||
|
/// Invalidates all cached bitmaps for another reason, usually as a signal that
|
||||||
|
/// implementation-defined data in the bitmap provider have been changed.
|
||||||
|
///
|
||||||
|
/// If the consumer of audio rendering changes properties of the bitmap renderer
|
||||||
|
/// that will affect the rendered images, it should call this function to ensure
|
||||||
|
/// the cache is kept consistent.
|
||||||
|
void Invalidate();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -179,6 +247,8 @@ protected:
|
||||||
AudioProvider *provider;
|
AudioProvider *provider;
|
||||||
/// Horizontal zoom in samples per pixel
|
/// Horizontal zoom in samples per pixel
|
||||||
int pixel_samples;
|
int pixel_samples;
|
||||||
|
/// Vertical zoom/amplitude scale factor
|
||||||
|
float amplitude_scale;
|
||||||
|
|
||||||
/// @brief Called when the audio provider changes
|
/// @brief Called when the audio provider changes
|
||||||
///
|
///
|
||||||
|
@ -190,6 +260,11 @@ protected:
|
||||||
/// Implementations can override this method to do something when the horizontal zoom is changed
|
/// Implementations can override this method to do something when the horizontal zoom is changed
|
||||||
virtual void OnSetSamplesPerPixel() { }
|
virtual void OnSetSamplesPerPixel() { }
|
||||||
|
|
||||||
|
/// @brief Called when vertical zoom changes
|
||||||
|
///
|
||||||
|
/// Implementations can override this method to do something when the vertical zoom is changed
|
||||||
|
virtual void OnSetAmplitudeScale() { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @brief Constructor
|
/// @brief Constructor
|
||||||
AudioRendererBitmapProvider() : provider(0), pixel_samples(0) { };
|
AudioRendererBitmapProvider() : provider(0), pixel_samples(0) { };
|
||||||
|
@ -209,7 +284,12 @@ public:
|
||||||
/// @brief Change audio provider
|
/// @brief Change audio provider
|
||||||
/// @param provider Audio provider to change to
|
/// @param provider Audio provider to change to
|
||||||
void SetProvider(AudioProvider *provider);
|
void SetProvider(AudioProvider *provider);
|
||||||
|
|
||||||
/// @brief Change horizontal zoom
|
/// @brief Change horizontal zoom
|
||||||
/// @param pixel_samples Samples per pixel to zoom to
|
/// @param pixel_samples Samples per pixel to zoom to
|
||||||
void SetSamplesPerPixel(int pixel_samples);
|
void SetSamplesPerPixel(int pixel_samples);
|
||||||
|
|
||||||
|
/// @brief Change vertical zoom
|
||||||
|
/// @param amplitude_scale Scaling factor to zoom to
|
||||||
|
void SetAmplitudeScale(float amplitude_scale);
|
||||||
};
|
};
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,8 +105,11 @@ class DataBlockCache {
|
||||||
/// Type of an array of blocks
|
/// Type of an array of blocks
|
||||||
typedef std::vector<BlockT*> BlockArray;
|
typedef std::vector<BlockT*> BlockArray;
|
||||||
|
|
||||||
|
/// DOCME
|
||||||
struct MacroBlock {
|
struct MacroBlock {
|
||||||
|
/// How many times data in the macroblock has been accessed
|
||||||
int access_count;
|
int access_count;
|
||||||
|
/// The blocks contained in the macroblock
|
||||||
BlockArray blocks;
|
BlockArray blocks;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -131,7 +135,7 @@ class DataBlockCache {
|
||||||
MacroBlock &mb = data[mb_index];
|
MacroBlock &mb = data[mb_index];
|
||||||
mb.access_count = 0;
|
mb.access_count = 0;
|
||||||
|
|
||||||
for (size_t bi = 0; bi < blocks.size(); ++bi)
|
for (size_t bi = 0; bi < mb.blocks.size(); ++bi)
|
||||||
{
|
{
|
||||||
BlockT *b = mb.blocks[bi];
|
BlockT *b = mb.blocks[bi];
|
||||||
if (!b)
|
if (!b)
|
||||||
|
@ -153,11 +157,7 @@ public:
|
||||||
DataBlockCache(size_t block_count, BlockFactoryT factory = BlockFactoryT())
|
DataBlockCache(size_t block_count, BlockFactoryT factory = BlockFactoryT())
|
||||||
: factory(factory)
|
: factory(factory)
|
||||||
{
|
{
|
||||||
macroblock_size = 1 << MacroblockExponent;
|
SetBlockCount(block_count);
|
||||||
|
|
||||||
macroblock_index_mask = ~(((~0) >> MacroblockExponent) << MacroblockExponent);
|
|
||||||
|
|
||||||
data.resize( (block_count + macroblock_size - 1) >> MacroblockExponent );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -171,6 +171,23 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Change the number of blocks in cache
|
||||||
|
/// @param block_count New number of blocks to hold
|
||||||
|
///
|
||||||
|
/// This will completely de-allocate the cache and re-allocate it with the new block count.
|
||||||
|
void SetBlockCount(size_t block_count)
|
||||||
|
{
|
||||||
|
if (data.size() > 0)
|
||||||
|
Age(0);
|
||||||
|
|
||||||
|
macroblock_size = 1 << MacroblockExponent;
|
||||||
|
|
||||||
|
macroblock_index_mask = ~(((~0) >> MacroblockExponent) << MacroblockExponent);
|
||||||
|
|
||||||
|
data.resize( (block_count + macroblock_size - 1) >> MacroblockExponent );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// @brief Clean up the cache
|
/// @brief Clean up the cache
|
||||||
/// @param max_size Target maximum size of the cache in bytes
|
/// @param max_size Target maximum size of the cache in bytes
|
||||||
///
|
///
|
||||||
|
@ -202,7 +219,7 @@ public:
|
||||||
access_data.reserve(data.size());
|
access_data.reserve(data.size());
|
||||||
for (MacroBlockArray::iterator mb = data.begin(); mb != data.end(); ++mb)
|
for (MacroBlockArray::iterator mb = data.begin(); mb != data.end(); ++mb)
|
||||||
access_data.push_back(AccessData(mb));
|
access_data.push_back(AccessData(mb));
|
||||||
access_data.sort();
|
std::sort(access_data.begin(), access_data.end());
|
||||||
|
|
||||||
// Sum up data size until we hit the max
|
// Sum up data size until we hit the max
|
||||||
size_t cur_size = 0;
|
size_t cur_size = 0;
|
||||||
|
|
Loading…
Reference in a new issue