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 / onsetsdshelpers.c @ 0:635e8745ccc9

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
}