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

The primary repository for this project is hosted at svn://svn.code.sf.net/p/onsetsds/code/ .
This repository is a read-only copy which is updated automatically every hour.

Statistics Download as Zip
| Branch: | Revision:

root / src / onsetsds.h @ 3:15345ae708d6

History | View | Annotate | Download (10.6 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") [dc, nyq, real[1], imag[1], real[2], imag[2]...] - NB it's more efficient to provide polar data from SC
63
        ODS_FFT_SC3_POLAR,          ///< SuperCollider, polar co-ords ("SCPolarBuf") [dc, nyq, mag[1], phase[1], mag[2], phase[2]...]
64
        ODS_FFT_FFTW3_HC, ///< FFTW <a href="http://www.fftw.org/fftw3_doc/The-Halfcomplex_002dformat-DFT.html">"halfcomplex"</a> format - [dc, real[1], real[2] ... nyq, imag[nyq-1] ... imag[1]]
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