Add Doxygen documentation to audio spectrum code

Originally committed to SVN as r3343.
This commit is contained in:
Niels Martin Hansen 2009-08-01 01:55:17 +00:00
parent d8200c669e
commit e42d184ec4
2 changed files with 184 additions and 204 deletions

View file

@ -53,70 +53,82 @@
#include <wx/log.h> #include <wx/log.h>
// Audio spectrum FFT data cache
/// DOCME
/// @class AudioSpectrumCache /// @class AudioSpectrumCache
/// @brief DOCME /// @brief Base class for the frequency-power cache tree.
/// ///
/// DOCME /// The cached frequency-power are kept in a shallow tree-structure composed of
/// intermediate branches and final leaves, both accessed through a common
/// interface, which is this class.
///
/// The term "cache line" here means the frequency-power data derived from
/// some range of audio samples, calculated by a single FFT.
class AudioSpectrumCache { class AudioSpectrumCache {
public: public:
/// DOCME /// The type of frequency-power data at one point in time.
typedef std::vector<float> CacheLine; typedef std::vector<float> CacheLine;
/// DOCME /// The type of timestamps for last access.
typedef unsigned int CacheAccessTime; typedef unsigned int CacheAccessTime;
/// DOCME /// Holds last-access data for a range of range of cache lines.
/// Ranges can overlap, in case overlapping FFT's are used to increase precision.
struct CacheAgeData { struct CacheAgeData {
/// Last time this range of cache lines were accessed.
/// DOCME
CacheAccessTime access_time; CacheAccessTime access_time;
/// First line in the range.
/// DOCME
unsigned long first_line; unsigned long first_line;
/// Number of lines in the range.
unsigned long num_lines;
/// DOCME /// @brief Comparison operator for sorting age data by last access time.
unsigned long num_lines; // includes overlap-lines /// @param second The age data structure to compare against.
/// @return Returns true if last access time of this range is less than that of the other.
/// @brief DOCME
/// @param second
/// @return
///
bool operator< (const CacheAgeData& second) const { return access_time < second.access_time; } bool operator< (const CacheAgeData& second) const { return access_time < second.access_time; }
/// @brief DOCME /// @brief Constructor.
/// @param t /// @param t Initial access time to set.
/// @param first /// @param first First line in the range.
/// @param num /// @param num Number of lines in the range.
/// ///
CacheAgeData(CacheAccessTime t, unsigned long first, unsigned long num) : access_time(t), first_line(first), num_lines(num) { } CacheAgeData(CacheAccessTime t, unsigned long first, unsigned long num) : access_time(t), first_line(first), num_lines(num) { }
}; };
/// DOCME /// Type of a list of cache age data.
typedef std::vector<CacheAgeData> CacheAgeList; typedef std::vector<CacheAgeData> CacheAgeList;
// Get the overlap'th overlapping FFT in FFT group i, generating it if needed /// @brief Retrieve frequency-power data.
/// @param i Index of the block to get the line from.
/// @param overlap Index of the overlap in the block to get the line for.
/// @param created [out] Set to true if the data had to be calculated, false if the data
/// was found in cache.
/// @param access_time Timestamp to mark the cache data as accessed at.
/// @return Returns a reference to the frequency-power data requested.
///
/// The data are fetched from the cache if they are cached, otherwise the required
/// audio data are retrieved, the FFT derived, and power data calculated.
virtual CacheLine& GetLine(unsigned long i, unsigned int overlap, bool &created, CacheAccessTime access_time) = 0; virtual CacheLine& GetLine(unsigned long i, unsigned int overlap, bool &created, CacheAccessTime access_time) = 0;
// Get the total number of cache lines currently stored in this cache node's sub tree /// @brief Get the size of the cache subtree.
/// @return Number of lines stored in all nodes below this one in the tree.
virtual size_t GetManagedLineCount() = 0; virtual size_t GetManagedLineCount() = 0;
// Append to a list of last access times to the cache /// @brief Retrieve cache access times.
/// @param ages [in,out] List to append age data of managed lines to.
///
/// Existing contents of the list is kept, new entries are added to the end.
virtual void GetLineAccessTimes(CacheAgeList &ages) = 0; virtual void GetLineAccessTimes(CacheAgeList &ages) = 0;
// Delete the cache storage starting with the given line id /// @brief Remove data from the cache.
// Return true if the object called on is empty and can safely be deleted too /// @param line_id Index of the block the cache node to remove starts at.
/// @return Returns true if the object the method was called on no longer manages
// any cache lines and can safely be deleted.
virtual bool KillLine(unsigned long line_id) = 0; virtual bool KillLine(unsigned long line_id) = 0;
/// @brief // Set the FFT size used /// @brief Set the FFT size used globally.
/// @param new_length /// @param new_length Number of audio samples to use in calculation.
///
static void SetLineLength(unsigned long new_length) static void SetLineLength(unsigned long new_length)
{ {
line_length = new_length; line_length = new_length;
@ -124,62 +136,50 @@ public:
} }
/// @brief DOCME /// @brief Destructor, does nothing in base class.
///
virtual ~AudioSpectrumCache() {}; virtual ~AudioSpectrumCache() {};
protected: protected:
/// DOCME /// Global template for cache lines.
static CacheLine null_line; static CacheLine null_line;
/// Number of audio samples used for power calculation, determining the
/// DOCME /// frequency resolution of the frequency-power data.
static unsigned long line_length; static unsigned long line_length;
}; };
// Actual variables allocating memory for the static class members
/// DOCME
AudioSpectrumCache::CacheLine AudioSpectrumCache::null_line; AudioSpectrumCache::CacheLine AudioSpectrumCache::null_line;
/// DOCME
unsigned long AudioSpectrumCache::line_length; unsigned long AudioSpectrumCache::line_length;
// Bottom level FFT cache, holds actual power data itself
/// DOCME
/// @class FinalSpectrumCache /// @class FinalSpectrumCache
/// @brief DOCME /// @brief Leaf node in frequency-power cache tree, holds actual data.
/// ///
/// DOCME /// This class stores frequency-power data and is responsible for calculating it as well.
class FinalSpectrumCache : public AudioSpectrumCache { class FinalSpectrumCache : public AudioSpectrumCache {
private: private:
/// DOCME /// The stored data.
std::vector<CacheLine> data; std::vector<CacheLine> data;
/// DOCME unsigned long start, ///< Start of block range
length; ///< Number of blocks
unsigned int overlaps; ///< How many lines per block
/// DOCME /// Last access time for cache management.
unsigned long start, length; // start and end of range
/// DOCME
unsigned int overlaps;
/// DOCME
CacheAccessTime last_access; CacheAccessTime last_access;
public: public:
/// @brief DOCME /// @brief Returns stored frequency-power data.
/// @param i /// @param i Index of the block to get the line from.
/// @param overlap /// @param overlap Index of the overlap in the block to get the line for.
/// @param created /// @param created [out] Set to true if the data had to be calculated, false if the data
/// @param access_time /// was found in cache.
/// @return /// @param access_time Timestamp to mark the cache data as accessed at.
/// /// @return Returns a reference to the frequency-power data requested.
CacheLine& GetLine(unsigned long i, unsigned int overlap, bool &created, CacheAccessTime access_time) CacheLine& GetLine(unsigned long i, unsigned int overlap, bool &created, CacheAccessTime access_time)
{ {
last_access = access_time; last_access = access_time;
@ -192,40 +192,42 @@ public:
} }
/// @brief DOCME /// @brief Get number of lines in cache.
/// @return /// @return Number of lines stored at this leaf.
///
size_t GetManagedLineCount() size_t GetManagedLineCount()
{ {
return data.size(); return data.size();
} }
/// @brief DOCME /// @brief Add own cache age data to list of age data.
/// @param ages /// @param ages [in,out] List to add cache age data to.
/// ///
/// Produces a single cache age data object, representing the entire node,
/// and adds it to the list.
void GetLineAccessTimes(CacheAgeList &ages) void GetLineAccessTimes(CacheAgeList &ages)
{ {
ages.push_back(CacheAgeData(last_access, start, data.size())); ages.push_back(CacheAgeData(last_access, start, data.size()));
} }
/// @brief DOCME /// @brief Return true if this is the line to remove.
/// @param line_id /// @param line_id Index of the block the cache node to remove starts at.
/// @return /// @return Returns true if this is the cache block to remove.
/// ///
/// This function won't actually delete anything, instead it is the responsibility
/// of the caller to delete the cache node if this function returns true.
bool KillLine(unsigned long line_id) bool KillLine(unsigned long line_id)
{ {
return start == line_id; return start == line_id;
} }
/// @brief DOCME /// @brief Constructor, derives FFT and calculates frequency-power data.
/// @param provider /// @param provider Audio provider to get audio from.
/// @param _start /// @param _start Index of first block to calculate data for.
/// @param _length /// @param _length Number of blocks to calculate data for.
/// @param _overlaps /// @param _overlaps Number of lines to calculate per block.
///
FinalSpectrumCache(AudioProvider *provider, unsigned long _start, unsigned long _length, unsigned int _overlaps) FinalSpectrumCache(AudioProvider *provider, unsigned long _start, unsigned long _length, unsigned int _overlaps)
{ {
start = _start; start = _start;
@ -295,8 +297,10 @@ public:
} }
/// @brief DOCME /// @brief Destructor, does nothing.
/// ///
/// All data is managed by C++ types and gets deleted when those types'
/// destructors are implicitly run.
virtual ~FinalSpectrumCache() virtual ~FinalSpectrumCache()
{ {
} }
@ -304,48 +308,37 @@ public:
}; };
// Non-bottom-level cache, refers to other caches to do the work
/// DOCME
/// @class IntermediateSpectrumCache /// @class IntermediateSpectrumCache
/// @brief DOCME /// @brief Intermediate node in the spectrum cache tree.
/// ///
/// DOCME /// References further nodes in the spectrum cache tree and delegates operations to them.
class IntermediateSpectrumCache : public AudioSpectrumCache { class IntermediateSpectrumCache : public AudioSpectrumCache {
private: private:
/// DOCME /// The child-nodes in the cache tree.
std::vector<AudioSpectrumCache*> sub_caches; std::vector<AudioSpectrumCache*> sub_caches;
/// DOCME unsigned long start, ///< DOCME
length, ///< DOCME
subcache_length; ///< DOCME
unsigned int overlaps; ///< Number of overlaps used.
bool subcaches_are_final; ///< Are the children leaf nodes?
int depth; ///< How deep is this in the tree.
/// DOCME /// Audio provider to pass on to child nodes.
/// DOCME
unsigned long start, length, subcache_length;
/// DOCME
unsigned int overlaps;
/// DOCME
bool subcaches_are_final;
/// DOCME
int depth;
/// DOCME
AudioProvider *provider; AudioProvider *provider;
public: public:
/// @brief DOCME /// @brief Delegate line retrieval to a child node.
/// @param i /// @param i Index of the block to get the line from.
/// @param overlap /// @param overlap Index of the overlap in the block to get the line for.
/// @param created /// @param created [out] Set to true if the data had to be calculated, false if the data
/// @param access_time /// was found in cache.
/// @return /// @param access_time Timestamp to mark the cache data as accessed at.
/// @return Returns a reference to the frequency-power data requested.
/// ///
/// Will create the required child node if it doesn't exist yet.
CacheLine &GetLine(unsigned long i, unsigned int overlap, bool &created, CacheAccessTime access_time) CacheLine &GetLine(unsigned long i, unsigned int overlap, bool &created, CacheAccessTime access_time)
{ {
if (i >= start && i-start <= length) { if (i >= start && i-start <= length) {
@ -369,9 +362,8 @@ public:
} }
/// @brief DOCME /// @brief Iterate all direct children and return the sum of their managed line count.
/// @return /// @return Returns the sum of the managed line count of all children.
///
size_t GetManagedLineCount() size_t GetManagedLineCount()
{ {
size_t res = 0; size_t res = 0;
@ -383,9 +375,8 @@ public:
} }
/// @brief DOCME /// @brief Get access time data for all child nodes in cache tree.
/// @param ages /// @param ages [in,out] List for child nodes to add their data to.
///
void GetLineAccessTimes(CacheAgeList &ages) void GetLineAccessTimes(CacheAgeList &ages)
{ {
for (size_t i = 0; i < sub_caches.size(); ++i) { for (size_t i = 0; i < sub_caches.size(); ++i) {
@ -395,10 +386,14 @@ public:
} }
/// @brief DOCME /// @brief Remove block with given index from cache.
/// @param line_id /// @param line_id Index of the block the cache node to remove starts at.
/// @return /// @return Returns true if this node has no more live childs, false if
/// there is a least one line child.
/// ///
/// Iterates the child nodes, calls the method recursively on all live
/// nodes, deletes any node returning true, and counts number of nodes
/// still alive, returning true if any are alive.
bool KillLine(unsigned long line_id) bool KillLine(unsigned long line_id)
{ {
int sub_caches_left = 0; int sub_caches_left = 0;
@ -416,13 +411,15 @@ public:
} }
/// @brief DOCME /// @brief Constructor.
/// @param _provider /// @param _provider Audio provider to pass to child nodes.
/// @param _start /// @param _start Index of first block to manage.
/// @param _length /// @param _length Number of blocks to manage.
/// @param _overlaps /// @param _overlaps Number of lines per block.
/// @param _depth /// @param _depth Number of levels in the tree above this node.
/// ///
/// Determine how many sub-caches are required, how big they
/// should be and allocates memory to store their pointers.
IntermediateSpectrumCache(AudioProvider *_provider, unsigned long _start, unsigned long _length, unsigned int _overlaps, int _depth) IntermediateSpectrumCache(AudioProvider *_provider, unsigned long _start, unsigned long _length, unsigned int _overlaps, int _depth)
{ {
provider = _provider; provider = _provider;
@ -446,8 +443,7 @@ public:
} }
/// @brief DOCME /// @brief Destructor, deletes all still-live sub caches.
///
virtual ~IntermediateSpectrumCache() virtual ~IntermediateSpectrumCache()
{ {
for (size_t i = 0; i < sub_caches.size(); ++i) for (size_t i = 0; i < sub_caches.size(); ++i)
@ -460,35 +456,32 @@ public:
/// DOCME
/// @class AudioSpectrumCacheManager /// @class AudioSpectrumCacheManager
/// @brief DOCME /// @brief Manages a frequency-power cache tree.
/// ///
/// DOCME /// The primary task of this class is to manage the amount of memory consumed by
/// the cache and delete items when it grows too large.
class AudioSpectrumCacheManager { class AudioSpectrumCacheManager {
private: private:
/// DOCME /// Root node of the cache tree.
IntermediateSpectrumCache *cache_root; IntermediateSpectrumCache *cache_root;
/// DOCME unsigned long cache_hits, ///< Number of times the cache was used to retrieve data
cache_misses; ///< Number of times data had to be calculated
/// DOCME /// Current time, used for cache aging purposes.
unsigned long cache_hits, cache_misses;
/// DOCME
AudioSpectrumCache::CacheAccessTime cur_time; AudioSpectrumCache::CacheAccessTime cur_time;
/// Maximum number of lines to keep in cache.
/// DOCME
unsigned long max_lines_cached; unsigned long max_lines_cached;
public: public:
/// @brief DOCME /// @brief Wrapper around cache tree, to get frequency-power data
/// @param i /// @param i Block to get data from.
/// @param overlap /// @param overlap Line in block to get data from.
/// @return /// @return Returns a reference to the requested line.
/// ///
AudioSpectrumCache::CacheLine &GetLine(unsigned long i, unsigned int overlap) AudioSpectrumCache::CacheLine &GetLine(unsigned long i, unsigned int overlap)
{ {
@ -502,9 +495,10 @@ public:
} }
/// @brief DOCME /// @brief Remove old data from the cache.
/// @return
/// ///
/// Ages the cache by finding the least recently accessed data and removing cache data
/// until the total number of lines stored in the tree is less than the maximum.
void Age() void Age()
{ {
wxLogDebug(_T("AudioSpectrumCacheManager stats: hits=%u, misses=%u, misses%%=%f, managed lines=%u (max=%u)"), cache_hits, cache_misses, cache_misses/float(cache_hits+cache_misses)*100, cache_root->GetManagedLineCount(), max_lines_cached); wxLogDebug(_T("AudioSpectrumCacheManager stats: hits=%u, misses=%u, misses%%=%f, managed lines=%u (max=%u)"), cache_hits, cache_misses, cache_misses/float(cache_hits+cache_misses)*100, cache_root->GetManagedLineCount(), max_lines_cached);
@ -551,12 +545,14 @@ public:
} }
/// @brief DOCME /// @brief Constructor
/// @param provider /// @param provider Audio provider to pass to cache tree nodes.
/// @param line_length /// @param line_length Number of audio samples to use per block.
/// @param num_lines /// @param num_lines Number of blocks to produce in total from the audio.
/// @param num_overlaps /// @param num_overlaps Number of overlaps per block.
/// ///
/// Initialises the cache tree root and calculates the maximum number of cache lines
/// to keep based on the Audio Spectrum Memory Max configuration setting.
AudioSpectrumCacheManager(AudioProvider *provider, unsigned long line_length, unsigned long num_lines, unsigned int num_overlaps) AudioSpectrumCacheManager(AudioProvider *provider, unsigned long line_length, unsigned long num_lines, unsigned int num_overlaps)
{ {
cache_hits = cache_misses = 0; cache_hits = cache_misses = 0;
@ -573,8 +569,7 @@ public:
} }
/// @brief DOCME /// @brief Destructor, deletes the cache tree root node.
///
~AudioSpectrumCacheManager() ~AudioSpectrumCacheManager()
{ {
delete cache_root; delete cache_root;
@ -582,12 +577,9 @@ public:
}; };
// AudioSpectrum // AudioSpectrum, documented in .h file
/// @brief DOCME
/// @param _provider
///
AudioSpectrum::AudioSpectrum(AudioProvider *_provider) AudioSpectrum::AudioSpectrum(AudioProvider *_provider)
{ {
provider = _provider; provider = _provider;
@ -677,26 +669,12 @@ AudioSpectrum::AudioSpectrum(AudioProvider *_provider)
} }
/// @brief DOCME
///
AudioSpectrum::~AudioSpectrum() AudioSpectrum::~AudioSpectrum()
{ {
delete cache; delete cache;
} }
/// @brief DOCME
/// @param range_start
/// @param range_end
/// @param selected
/// @param img
/// @param imgleft
/// @param imgwidth
/// @param imgpitch
/// @param imgheight
///
void AudioSpectrum::RenderRange(int64_t range_start, int64_t range_end, bool selected, unsigned char *img, int imgleft, int imgwidth, int imgpitch, int imgheight) void AudioSpectrum::RenderRange(int64_t range_start, int64_t range_end, bool selected, unsigned char *img, int imgleft, int imgwidth, int imgpitch, int imgheight)
{ {
unsigned long first_line = (unsigned long)(fft_overlaps * range_start / line_length / 2); unsigned long first_line = (unsigned long)(fft_overlaps * range_start / line_length / 2);
@ -746,8 +724,7 @@ void AudioSpectrum::RenderRange(int64_t range_start, int64_t range_end, bool sel
} }
} }
/// @internal Macro that stores pixel data, depends on local variables in AudioSpectrum::RenderRange
/// DOCME
#define WRITE_PIXEL \ #define WRITE_PIXEL \
if (intensity < 0) intensity = 0; \ if (intensity < 0) intensity = 0; \
if (intensity > 255) intensity = 255; \ if (intensity > 255) intensity = 255; \
@ -796,8 +773,7 @@ void AudioSpectrum::RenderRange(int64_t range_start, int64_t range_end, bool sel
} }
} }
/// @internal The WRITE_PIXEL macro is only defined inside AudioSpectrum::RenderRange
/// DOCME
#undef WRITE_PIXEL #undef WRITE_PIXEL
} }
@ -808,10 +784,6 @@ void AudioSpectrum::RenderRange(int64_t range_start, int64_t range_end, bool sel
} }
/// @brief DOCME
/// @param _power_scale
///
void AudioSpectrum::SetScaling(float _power_scale) void AudioSpectrum::SetScaling(float _power_scale)
{ {
power_scale = _power_scale; power_scale = _power_scale;

View file

@ -34,10 +34,12 @@
/// @see audio_spectrum.cpp /// @see audio_spectrum.cpp
/// @ingroup audio_ui /// @ingroup audio_ui
/// ///
/// Calculate and render a frequency-power spectrum for PCM audio data.
#ifndef AUDIO_SPECTRUM_H #ifndef AUDIO_SPECTRUM_H
/// DOCME /// Include guard for audio_spectrum.h
#define AUDIO_SPECTRUM_H #define AUDIO_SPECTRUM_H
#include <wx/wxprec.h> #include <wx/wxprec.h>
@ -49,54 +51,60 @@
class AudioSpectrumCacheManager; class AudioSpectrumCacheManager;
/// DOCME
/// @class AudioSpectrum /// @class AudioSpectrum
/// @brief DOCME /// @brief Render frequency-power spectrum graphs for audio data.
/// ///
/// DOCME /// Renders frequency-power spectrum graphs of PCM audio data using a fast fourier transform
/// to derive the data. The frequency-power data are cached to avoid re-computing them
/// frequently, and the cache size is limited by a configuration setting.
///
/// The spectrum image is rendered to a 32 bit RGB bitmap. Power data is scaled linearly
/// and not logarithmically, since the rendering is done with limited precision, but
/// an amplification factor can be specified to see different ranges.
class AudioSpectrum { class AudioSpectrum {
private: private:
/// DOCME /// Internal cache management for the spectrum
AudioSpectrumCacheManager *cache; AudioSpectrumCacheManager *cache;
/// Colour table used for regular rendering
/// DOCME
unsigned char colours_normal[256*3]; unsigned char colours_normal[256*3];
/// DOCME /// Colour table used for rendering the audio selection
unsigned char colours_selected[256*3]; unsigned char colours_selected[256*3];
/// The audio provider to use as source
/// DOCME
AudioProvider *provider; AudioProvider *provider;
unsigned long line_length; ///< Number of frequency components per line (half of number of samples)
/// DOCME unsigned long num_lines; ///< Number of lines needed for the audio
unsigned long line_length; // number of frequency components per line (half of number of samples) unsigned int fft_overlaps; ///< Number of overlaps used in FFT
float power_scale; ///< Amplification of displayed power
/// DOCME int minband; ///< Smallest frequency band displayed
unsigned long num_lines; // number of lines needed for the audio int maxband; ///< Largest frequency band displayed
/// DOCME
unsigned int fft_overlaps; // number of overlaps used in FFT
/// DOCME
float power_scale; // amplification of displayed power
/// DOCME
int minband; // smallest frequency band displayed
/// DOCME
int maxband; // largest frequency band displayed
public: public:
/// @brief Constructor
/// @param _provider Audio provider to render spectrum data for.
///
/// Reads configuration data for the spectrum display and initialises itself following that.
AudioSpectrum(AudioProvider *_provider); AudioSpectrum(AudioProvider *_provider);
/// @brief Destructor
~AudioSpectrum(); ~AudioSpectrum();
/// @brief Render a range of audio spectrum to a bitmap buffer.
/// @param range_start First audio sample in the range to render.
/// @param range_end Last audio sample in the range to render.
/// @param selected Use the alternate colour palette?
/// @param img Pointer to 32 bit RGBX data
/// @param imgleft Offset from left edge of bitmap to render to, in pixels
/// @param imgwidth Width of bitmap to render, in pixels
/// @param imgpitch Offset from one scanline to the next in the bitmap, in bytes
/// @param imgheight Number of lines in the bitmap
void RenderRange(int64_t range_start, int64_t range_end, bool selected, unsigned char *img, int imgleft, int imgwidth, int imgpitch, int imgheight); void RenderRange(int64_t range_start, int64_t range_end, bool selected, unsigned char *img, int imgleft, int imgwidth, int imgpitch, int imgheight);
/// @brief Set the amplification to use when rendering.
/// @param _power_scale Amplification factor to use.
void SetScaling(float _power_scale); void SetScaling(float _power_scale);
}; };