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.
root / src / onsetsdshelpers.c @ 0:a7c2bda0dfd9
History | View | Annotate | Download (5.84 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 |
#include "onsetsdshelpers.h" |
| 21 |
|
| 22 |
#include <stdlib.h> |
| 23 |
#include <sndfile.h> |
| 24 |
#include <fftw3.h> |
| 25 |
|
| 26 |
void onsetsds_init_audiodata(OnsetsDSAudioBuf *odsbuf, OnsetsDS *ods, /* size_t framesize, */ size_t hopsize){ |
| 27 |
|
| 28 |
odsbuf->ods = ods; |
| 29 |
odsbuf->buflen = ods->fftsize; |
| 30 |
odsbuf->hopsize = hopsize; |
| 31 |
|
| 32 |
size_t framesizebytes = ods->fftsize * sizeof(float); |
| 33 |
|
| 34 |
// malloc odsbuf.data, odsbuf.window, odsbuf.windoweddata
|
| 35 |
odsbuf->data = (float*) malloc(framesizebytes);
|
| 36 |
odsbuf->window = (float*) malloc(framesizebytes);
|
| 37 |
odsbuf->windoweddata = (float*) fftwf_malloc(framesizebytes);
|
| 38 |
odsbuf->fftbuf = (float*) fftwf_malloc(framesizebytes);
|
| 39 |
|
| 40 |
// Create the FFTW plan
|
| 41 |
odsbuf->fftplan = fftwf_plan_r2r_1d(ods->fftsize, odsbuf->windoweddata, odsbuf->fftbuf, FFTW_R2HC, FFTW_ESTIMATE); |
| 42 |
|
| 43 |
// zero odsbuf.data
|
| 44 |
memset(odsbuf->data, 0, framesizebytes);
|
| 45 |
|
| 46 |
// Create the FFT window
|
| 47 |
double pi = acos(-1.); |
| 48 |
double winc = pi / ods->fftsize;
|
| 49 |
int i;
|
| 50 |
for (i=0; i<ods->fftsize; ++i) { |
| 51 |
double w = i * winc;
|
| 52 |
odsbuf->window[i] = sin(w); |
| 53 |
} |
| 54 |
|
| 55 |
odsbuf->sampsElapsed = 0L;
|
| 56 |
odsbuf->writepos = 0;
|
| 57 |
} |
| 58 |
void onsetsds_destroy_audiodata(OnsetsDSAudioBuf *odsbuf){
|
| 59 |
// take down the FFTW stuff
|
| 60 |
fftwf_destroy_plan(odsbuf->fftplan); |
| 61 |
// free mem
|
| 62 |
free(odsbuf->data); |
| 63 |
free(odsbuf->window); |
| 64 |
fftwf_free(odsbuf->windoweddata); |
| 65 |
fftwf_free(odsbuf->fftbuf); |
| 66 |
} |
| 67 |
|
| 68 |
void onsetsds_process_audiodata(OnsetsDSAudioBuf* odsbuf, float* data, size_t datalen, |
| 69 |
ODSDataCallback callback){
|
| 70 |
|
| 71 |
if(datalen==0){ |
| 72 |
printf("onsetsds_process_audiodata GRRRRRR: no audio data sent (datalen==0)\n");
|
| 73 |
return;
|
| 74 |
}else{
|
| 75 |
} |
| 76 |
|
| 77 |
size_t datareadpos = 0;
|
| 78 |
size_t dataleft = datalen; |
| 79 |
size_t numtocopy; |
| 80 |
int i;
|
| 81 |
while(dataleft > 0){ |
| 82 |
// Read the smaller of how-much-available and how-much-to-fill-the-buffer
|
| 83 |
numtocopy = ods_min(dataleft, odsbuf->buflen - odsbuf->writepos); |
| 84 |
// printf("onsetsds_process_audiodata: datalen = %i, dataleft = %i, buflen = %i, about to copy %i values to position %i\n",
|
| 85 |
// datalen, dataleft, odsbuf->buflen, numtocopy, odsbuf->writepos);
|
| 86 |
memcpy(&odsbuf->data[odsbuf->writepos], &data[datareadpos], numtocopy * sizeof(float)); |
| 87 |
|
| 88 |
odsbuf->writepos += numtocopy; |
| 89 |
|
| 90 |
// If the buffer is full, do all the FFT and stuff
|
| 91 |
if(odsbuf->writepos >= odsbuf->buflen){
|
| 92 |
|
| 93 |
// Copy the data into the buffer where windowing and FFT takes place
|
| 94 |
memcpy(odsbuf->windoweddata, odsbuf->data, odsbuf->buflen * sizeof(float)); |
| 95 |
|
| 96 |
// Shunt the audio data (and the writepos) down to make room for the next lot
|
| 97 |
memcpy(odsbuf->data, &odsbuf->data[odsbuf->hopsize], (odsbuf->buflen - odsbuf->hopsize) * sizeof(float)); |
| 98 |
//printf("onsetsds_process_audiodata: moving writepos from %i to %i(==hopsize)\n", odsbuf->writepos, odsbuf->hopsize);
|
| 99 |
odsbuf->writepos = odsbuf->hopsize; |
| 100 |
|
| 101 |
// Windowing
|
| 102 |
for(i=0; i<odsbuf->buflen; i++){ |
| 103 |
odsbuf->windoweddata[i] *= odsbuf->window[i]; |
| 104 |
} |
| 105 |
|
| 106 |
// FFT
|
| 107 |
fftwf_execute(odsbuf->fftplan); |
| 108 |
|
| 109 |
// Onset detection
|
| 110 |
if(onsetsds_process(odsbuf->ods, odsbuf->fftbuf)){
|
| 111 |
// Call the callback!
|
| 112 |
callback(odsbuf, datareadpos); |
| 113 |
} |
| 114 |
|
| 115 |
} // End buffer-is-filled
|
| 116 |
|
| 117 |
datareadpos += numtocopy; |
| 118 |
dataleft -= numtocopy; |
| 119 |
} // End of still-some-data-to-push
|
| 120 |
|
| 121 |
} |
| 122 |
|
| 123 |
|
| 124 |
void onsetsds_process_audiofile_CALLBACK(OnsetsDSAudioBuf* odsbuf, size_t onsetsamplepos);
|
| 125 |
void onsetsds_process_audiofile_CALLBACK(OnsetsDSAudioBuf* odsbuf, size_t onsetsamplepos){
|
| 126 |
// Convert the sample pos into a seconds position through the whole file
|
| 127 |
double secs = (odsbuf->sampsElapsed + onsetsamplepos) / odsbuf->samplerate;
|
| 128 |
|
| 129 |
// Now call the file-level callback
|
| 130 |
(odsbuf->filecallback)(odsbuf->ods, secs); |
| 131 |
} |
| 132 |
|
| 133 |
int onsetsds_process_audiofile(OnsetsDSAudioBuf* odsbuf, const char *infilename, |
| 134 |
ODSFileCallback callback){
|
| 135 |
|
| 136 |
SNDFILE *insndfile ; |
| 137 |
SF_INFO sfinfo ; |
| 138 |
memset (&sfinfo, 0, sizeof (sfinfo)); |
| 139 |
|
| 140 |
// Attempt to get the input file
|
| 141 |
if ((insndfile = sf_open (infilename, SFM_READ, &sfinfo)) == NULL){ |
| 142 |
printf ("onsetsds_process_audiofile ERROR: Not able to open input file %s.\n", infilename) ;
|
| 143 |
fflush (stdout) ; |
| 144 |
return 100; |
| 145 |
} |
| 146 |
if(sfinfo.channels != 1){ |
| 147 |
printf("onsetsds_process_audiofile ERROR: Only mono audio files can be processed. Num channels = %i. Exiting.\n", sfinfo.channels);
|
| 148 |
sf_close(insndfile); |
| 149 |
return 200; |
| 150 |
}else{
|
| 151 |
printf("onsetsds_process_audiofile: mono audio file, sample rate %i Hz.\n", sfinfo.samplerate);
|
| 152 |
} |
| 153 |
|
| 154 |
odsbuf->sampsElapsed = 0L;
|
| 155 |
odsbuf->samplerate = (double) sfinfo.samplerate;
|
| 156 |
odsbuf->filecallback = callback; |
| 157 |
|
| 158 |
// Create a buffer for reading the raw data into
|
| 159 |
float* data = malloc(odsbuf->buflen * sizeof(float)); |
| 160 |
|
| 161 |
sf_count_t numread; |
| 162 |
//printf("onsetsds_process_audiofile: Processing audio data\n", numread);
|
| 163 |
while((numread = sf_read_float(insndfile, data, odsbuf->buflen)) > 0){ |
| 164 |
//printf("Read %i audio frames (requested %i)\n", numread, odsbuf->buflen);
|
| 165 |
|
| 166 |
//printf("Calling onsetsds_process_audiodata\n");
|
| 167 |
onsetsds_process_audiodata(odsbuf, data, numread, onsetsds_process_audiofile_CALLBACK); |
| 168 |
//printf("Called onsetsds_process_audiodata\n");
|
| 169 |
odsbuf->sampsElapsed += numread; |
| 170 |
} |
| 171 |
|
| 172 |
sf_close(insndfile); |
| 173 |
free(data); |
| 174 |
|
| 175 |
// Indicate success
|
| 176 |
return 0; |
| 177 |
} |