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 / 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
}