To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Revision:

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