To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / onsetsds / onsetsds.h @ 0:635e8745ccc9
History | View | Annotate | Download (10.5 KB)
| 1 |
/*
|
|---|---|
| 2 |
OnsetsDS - real time musical onset detection library.
|
| 3 |
Copyright (c) 2007 Dan Stowell. All rights reserved.
|
| 4 |
|
| 5 |
This program is free software; you can redistribute it and/or modify
|
| 6 |
it under the terms of the GNU General Public License as published by
|
| 7 |
the Free Software Foundation; either version 2 of the License, or
|
| 8 |
(at your option) any later version.
|
| 9 |
|
| 10 |
This program is distributed in the hope that it will be useful,
|
| 11 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 12 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 13 |
GNU General Public License for more details.
|
| 14 |
|
| 15 |
You should have received a copy of the GNU General Public License
|
| 16 |
along with this program; if not, write to the Free Software
|
| 17 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
| 18 |
*/
|
| 19 |
|
| 20 |
/** \file */
|
| 21 |
|
| 22 |
#ifndef _OnsetsDS_
|
| 23 |
#define _OnsetsDS_
|
| 24 |
|
| 25 |
#ifdef __cplusplus
|
| 26 |
extern "C" { |
| 27 |
#endif
|
| 28 |
|
| 29 |
#include <stdio.h> |
| 30 |
#include <string.h> |
| 31 |
#include <stdbool.h> |
| 32 |
#include <math.h> |
| 33 |
|
| 34 |
|
| 35 |
////////////////////////////////////////////////////////////////////////////////
|
| 36 |
// Macros and consts
|
| 37 |
|
| 38 |
//log(0.1)
|
| 39 |
#define ods_log1 -2.30258509 |
| 40 |
|
| 41 |
#define PI 3.1415926535898f |
| 42 |
#define MINUSPI -3.1415926535898f |
| 43 |
#define TWOPI 6.28318530717952646f |
| 44 |
#define INV_TWOPI 0.1591549430919f |
| 45 |
|
| 46 |
#define ods_abs(a) ((a)<0? -(a) : (a)) |
| 47 |
#define ods_max(a,b) (((a) > (b)) ? (a) : (b))
|
| 48 |
#define ods_min(a,b) (((a) < (b)) ? (a) : (b))
|
| 49 |
|
| 50 |
#define ODS_LOG_LOWER_LIMIT 2e-42 |
| 51 |
#define ODS_LOGOF_LOG_LOWER_LIMIT -96.0154267 |
| 52 |
#define ODS_ABSINVOF_LOGOF_LOG_LOWER_LIMIT 0.010414993 |
| 53 |
|
| 54 |
////////////////////////////////////////////////////////////////////////////////
|
| 55 |
// Constants
|
| 56 |
|
| 57 |
/**
|
| 58 |
* Types of incoming FFT data format. OnsetsDS needs to know where the FFT
|
| 59 |
* data comes from in order to interpret it correctly.
|
| 60 |
*/
|
| 61 |
enum onsetsds_fft_types {
|
| 62 |
ODS_FFT_SC3_COMPLEX, ///< SuperCollider, cartesian co-ords ("SCComplexBuf") - NB it's more efficient to provide polar data from SC
|
| 63 |
ODS_FFT_SC3_POLAR, ///< SuperCollider, polar co-ords ("SCPolarBuf")
|
| 64 |
ODS_FFT_FFTW3_HC, ///< FFTW <a href="http://www.fftw.org/fftw3_doc/The-Halfcomplex_002dformat-DFT.html">"halfcomplex"</a> format
|
| 65 |
ODS_FFT_FFTW3_R2C ///< FFTW regular format, typically produced using <a href="http://www.fftw.org/fftw3_doc/One_002dDimensional-DFTs-of-Real-Data.html#One_002dDimensional-DFTs-of-Real-Data">real-to-complex</a> transform
|
| 66 |
}; |
| 67 |
|
| 68 |
/**
|
| 69 |
* Types of onset detection function
|
| 70 |
*/
|
| 71 |
enum onsetsds_odf_types {
|
| 72 |
ODS_ODF_POWER, ///< Power
|
| 73 |
ODS_ODF_MAGSUM, ///< Sum of magnitudes
|
| 74 |
ODS_ODF_COMPLEX, ///< Complex-domain deviation
|
| 75 |
ODS_ODF_RCOMPLEX, ///< Complex-domain deviation, rectified (only increases counted)
|
| 76 |
ODS_ODF_PHASE, ///< Phase deviation
|
| 77 |
ODS_ODF_WPHASE, ///< Weighted phase deviation
|
| 78 |
ODS_ODF_MKL ///< Modified Kullback-Liebler deviation
|
| 79 |
}; |
| 80 |
|
| 81 |
/**
|
| 82 |
* Types of whitening - may not all be implemented yet.
|
| 83 |
*/
|
| 84 |
enum onsetsds_wh_types {
|
| 85 |
ODS_WH_NONE, ///< No whitening - onsetsds_whiten() becomes a no-op
|
| 86 |
ODS_WH_ADAPT_MAX1, ///< Adaptive whitening - tracks recent-peak-magnitude in each bin, normalises that to 1
|
| 87 |
ODS_WH_NORMMAX, ///< Simple normalisation - each frame is normalised (independent of others) so largest magnitude becomes 1. Not implemented.
|
| 88 |
ODS_WH_NORMMEAN ///< Simple normalisation - each frame is normalised (independent of others) so mean magnitude becomes 1. Not implemented.
|
| 89 |
}; |
| 90 |
|
| 91 |
////////////////////////////////////////////////////////////////////////////////
|
| 92 |
// Structs
|
| 93 |
|
| 94 |
typedef struct OdsPolarBin { float mag, phase; } OdsPolarBin; |
| 95 |
|
| 96 |
typedef struct OdsPolarBuf { |
| 97 |
float dc, nyq;
|
| 98 |
OdsPolarBin bin[1];
|
| 99 |
} OdsPolarBuf; |
| 100 |
|
| 101 |
/// The main data structure for the onset detection routine
|
| 102 |
typedef struct OnsetsDS { |
| 103 |
/// "data" is a pointer to the memory that must be EXTERNALLY allocated.
|
| 104 |
/// Other pointers will point to locations within this memory.
|
| 105 |
float *data,
|
| 106 |
*psp, ///< Peak Spectral Profile - size is numbins+2, data is stored in order dc through to nyquist
|
| 107 |
*odfvals, // odfvals[0] will be the current val, odfvals[1] prev, etc
|
| 108 |
*sortbuf, // Used to calculate the median
|
| 109 |
*other; // Typically stores data about the previous frame
|
| 110 |
OdsPolarBuf* curr; // Current FFT frame, as polar
|
| 111 |
|
| 112 |
float
|
| 113 |
srate, ///< The sampling rate of the input audio. Set by onsetsds_init()
|
| 114 |
// Adaptive whitening params
|
| 115 |
relaxtime, ///< Do NOT set this directly. Use onsetsds_setrelax() which will also update relaxcoef.
|
| 116 |
relaxcoef, ///< Relaxation coefficient (memory coefficient). See also onsetsds_setrelax()
|
| 117 |
floor, ///< floor - the lowest value that a PSP magnitude can take.
|
| 118 |
/// A parameter for the ODF. For most this is a magnitude threshold for a single bin to be considered;
|
| 119 |
/// but for #ODS_ODF_MKL it is the "epsilon" parameter.
|
| 120 |
odfparam, |
| 121 |
/// Value used internally to scale ODF value according to the FFT frame size. Automatically set by onsetsds_init()
|
| 122 |
normfactor, |
| 123 |
// ODF val after median processing
|
| 124 |
odfvalpost, |
| 125 |
// Previous val is needed for threshold-crossing detection
|
| 126 |
odfvalpostprev, |
| 127 |
/// Threshold (of ODF value, after median processing) for detection.
|
| 128 |
/// Values between 0 and 1 are expected, but outside this range may
|
| 129 |
/// sometimes be appropriate too.
|
| 130 |
thresh; |
| 131 |
|
| 132 |
int odftype, ///< Choose from #onsetsds_odf_types |
| 133 |
whtype, ///< Choose from #onsetsds_wh_types
|
| 134 |
fftformat; ///< Choose from #onsetsds_fft_types
|
| 135 |
bool whiten, ///< Whether to apply whitening - onsetsds_init() decides this on your behalf |
| 136 |
detected,///< Output val - true if onset detected in curr frame
|
| 137 |
/**
|
| 138 |
NOT YET USED: Whether to convert magnitudes to log domain before processing. This is done as follows:
|
| 139 |
Magnitudes below a log-lower-limit threshold (ODS_LOG_LOWER_LIMIT) are pushed up to that threshold (to avoid log(0) infinity problems),
|
| 140 |
then the log is taken. The values are re-scaled to a similar range as the linear-domain values (assumed to lie
|
| 141 |
between zero and approximately one) by subtracting log(ODS_LOG_LOWER_LIMIT) and then dividing by abs(log(ODS_LOG_LOWER_LIMIT)).
|
| 142 |
*/
|
| 143 |
logmags, |
| 144 |
med_odd; ///< Whether median span is odd or not (used internally)
|
| 145 |
|
| 146 |
unsigned int |
| 147 |
/// Number of frames used in median calculation
|
| 148 |
medspan, |
| 149 |
/// Size of enforced gap between detections, measured in FFT frames.
|
| 150 |
mingap, gapleft; |
| 151 |
size_t fftsize, numbins; // numbins is the count not including DC/nyq
|
| 152 |
} OnsetsDS; |
| 153 |
|
| 154 |
|
| 155 |
////////////////////////////////////////////////////////////////////////////////
|
| 156 |
// Function prototypes
|
| 157 |
|
| 158 |
|
| 159 |
/**
|
| 160 |
* \defgroup MainUserFuncs Main user functions
|
| 161 |
*/
|
| 162 |
//@{
|
| 163 |
|
| 164 |
/**
|
| 165 |
* Determine how many bytes of memory must be allocated (e.g. using malloc) to
|
| 166 |
* accompany the OnsetsDS struct, operating using the specified settings (used to
|
| 167 |
* store part-processed FFT data etc). The user must
|
| 168 |
* call this, and then allocate the memory, BEFORE calling onsetsds_init().
|
| 169 |
* @param odftype Which onset detection function (ODF) you'll be using, chosen from #onsetsds_odf_types
|
| 170 |
* @param fftsize Size of FFT: 512 is recommended.
|
| 171 |
* @param medspan The number of past frames that will be used for median calculation during triggering
|
| 172 |
*/
|
| 173 |
size_t onsetsds_memneeded (int odftype, size_t fftsize, unsigned int medspan); |
| 174 |
|
| 175 |
/**
|
| 176 |
* Initialise the OnsetsDS struct and its associated memory, ready to detect
|
| 177 |
* onsets using the specified settings. Must be called before any call to
|
| 178 |
* onsetsds_process().
|
| 179 |
*
|
| 180 |
* Note: you can change the onset detection function type in mid-operation
|
| 181 |
* by calling onsetsds_init() again, but because memory will be reset this
|
| 182 |
* will behave as if starting from scratch (rather than being aware of the past
|
| 183 |
* few frames of sound). Do not attempt to change the
|
| 184 |
* onset detection function in a more hacky way (e.g. fiddling with the struct)
|
| 185 |
* because memory is set up differently for each of the different ODFs.
|
| 186 |
* @param ods An instance of the OnsetsDS struct
|
| 187 |
* @param odsdata A pointer to the memory allocated, size given by onsetsds_memneeded().
|
| 188 |
* @param fftformat Which format of FFT data is to be expected, chosen from #onsetsds_fft_types
|
| 189 |
* @param odftype Which onset detection function (ODF) you'll be using, chosen from #onsetsds_odf_types
|
| 190 |
* @param fftsize Size of FFT: 512 or 1024 is recommended.
|
| 191 |
* @param medspan The number of past frames that will be used for median calculation during triggering
|
| 192 |
* @param srate The sampling rate of the input audio
|
| 193 |
*/
|
| 194 |
void onsetsds_init(OnsetsDS* ods, float* odsdata, int fftformat, |
| 195 |
int odftype, size_t fftsize, unsigned int medspan, float srate); |
| 196 |
|
| 197 |
/**
|
| 198 |
* Process a single FFT data frame in the audio signal. Note that processing
|
| 199 |
* assumes that each call to onsetsds_process() is on a subsequent frame in
|
| 200 |
* the same audio stream - to handle multiple streams you must use separate
|
| 201 |
* OnsetsDS structs and memory!
|
| 202 |
*
|
| 203 |
* This function's main purpose is to call some of the library's other functions,
|
| 204 |
* in the expected sequence.
|
| 205 |
*/
|
| 206 |
bool onsetsds_process(OnsetsDS* ods, float* fftbuf); |
| 207 |
|
| 208 |
//@}
|
| 209 |
|
| 210 |
|
| 211 |
////////////////////////////////////////////////////////////////////////////////
|
| 212 |
// Function prototypes less commonly called by users
|
| 213 |
|
| 214 |
/**
|
| 215 |
* \defgroup LessCommonFuncs Other useful functions
|
| 216 |
*/
|
| 217 |
//@{
|
| 218 |
/**
|
| 219 |
* Set the "memory coefficient" indirectly via the time for the
|
| 220 |
* memory to decay by 60 dB.
|
| 221 |
* @param ods The OnsetsDS
|
| 222 |
* @param time The time in seconds
|
| 223 |
* @param hopsize The FFT frame hopsize (typically this will be half the FFT frame size)
|
| 224 |
*/
|
| 225 |
void onsetsds_setrelax(OnsetsDS* ods, float time, size_t hopsize); |
| 226 |
|
| 227 |
//@}
|
| 228 |
|
| 229 |
////////////////////////////////////////////////////////////////////////////////
|
| 230 |
// Function prototypes not typically called by users
|
| 231 |
|
| 232 |
/**
|
| 233 |
* \defgroup OtherFuncs Other functions, not typically called by users
|
| 234 |
*/
|
| 235 |
//@{
|
| 236 |
/**
|
| 237 |
* Load the current frame of FFT data into the OnsetsDS struct.
|
| 238 |
*
|
| 239 |
* Not typically called directly by users since onsetsds_process() calls this.
|
| 240 |
*/
|
| 241 |
void onsetsds_loadframe(OnsetsDS* ods, float* fftbuf); |
| 242 |
|
| 243 |
/**
|
| 244 |
* Apply adaptive whitening to the FFT data in the OnsetsDS struct.
|
| 245 |
*
|
| 246 |
* Not typically called directly by users since onsetsds_process() calls this.
|
| 247 |
*/
|
| 248 |
void onsetsds_whiten(OnsetsDS* ods);
|
| 249 |
|
| 250 |
/**
|
| 251 |
* Calculate the Onset Detection Function (includes scaling ODF outputs to
|
| 252 |
* similar range)
|
| 253 |
*
|
| 254 |
* Not typically called directly by users since onsetsds_process() calls this.
|
| 255 |
*/
|
| 256 |
void onsetsds_odf(OnsetsDS* ods);
|
| 257 |
|
| 258 |
/**
|
| 259 |
* Detects salient peaks in Onset Detection Function by removing the median,
|
| 260 |
* then thresholding. Afterwards, the member ods.detected will indicate whether
|
| 261 |
* or not an onset was detected.
|
| 262 |
*
|
| 263 |
* Not typically called directly by users since onsetsds_process() calls this.
|
| 264 |
*/
|
| 265 |
void onsetsds_detect(OnsetsDS* ods);
|
| 266 |
|
| 267 |
//@}
|
| 268 |
|
| 269 |
////////////////////////////////////////////////////////////////////////////////
|
| 270 |
|
| 271 |
#ifdef __cplusplus
|
| 272 |
} |
| 273 |
#endif
|
| 274 |
|
| 275 |
#endif
|