2 Onset detector for SuperCollider
3 Copyright (c) 2007 Dan Stowell. All rights reserved.
4 http://onsetsds.sourceforge.net
8 SuperCollider real time audio synthesis system
9 Copyright (c) 2002 James McCartney. All rights reserved.
10 http://www.audiosynth.com
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "SC_PlugIn.h"
28 #include "SCComplex.h"
29 #include "FFT_UGens.h"
33 //////////////////////////////////////////////////////////////////////////////////////////////////
35 // for operation on one buffer
36 // almost like PV_GET_BUF except it outputs unit->outval rather than -1 when FFT not triggered
37 #define Onsets_GET_BUF \
38 float fbufnum = ZIN0(0); \
39 if (fbufnum < 0.f) { ZOUT0(0) = unit->outval; return; } \
41 uint32 ibufnum = (uint32)fbufnum; \
42 World *world = unit->mWorld; \
44 if (ibufnum >= world->mNumSndBufs) { \
45 int localBufNum = ibufnum - world->mNumSndBufs; \
46 Graph *parent = unit->mParent; \
47 if(localBufNum <= parent->localBufNum) { \
48 buf = parent->mLocalSndBufs + localBufNum; \
50 buf = world->mSndBufs; \
53 buf = world->mSndBufs + ibufnum; \
58 //////////////////////////////////////////////////////////////////////////////////////////////////
61 ////////////////////////////////////////////////////////////////////////////////////////////////////////
63 void Onsets_Ctor(Onsets
*unit
)
66 SETCALC(Onsets_next_rawodf
);
70 unit
->m_needsinit
= true;
71 unit
->m_ods
= (OnsetsDS
*) RTAlloc(unit
->mWorld
, sizeof(OnsetsDS
) );
73 ZOUT0(0) = unit
->outval
= 0.f
;
76 void Onsets_next(Onsets
*unit
, int inNumSamples
)
80 // In practice, making the polar conversion here in SC is more efficient because SC provides a lookup table method.
81 SCPolarBuf
*p
= ToPolarApx(buf
);
83 OnsetsDS
*ods
= unit
->m_ods
;
85 int odftype
= (int)ZIN0(2);
86 float relaxtime
= ZIN0(3);
87 int medspan
= (int)ZIN0(6);
89 if(unit
->m_needsinit
){
90 // Init happens here because we need to be sure about FFT size.
91 unit
->m_odsdata
= (float*) RTAlloc(unit
->mWorld
, onsetsds_memneeded(odftype
, buf
->samples
, medspan
) );
93 onsetsds_init(ods
, unit
->m_odsdata
, ODS_FFT_SC3_POLAR
, odftype
, buf
->samples
, medspan
, FULLRATE
);
94 onsetsds_setrelax(ods
, relaxtime
, buf
->samples
>>1);
96 unit
->m_needsinit
= false;
99 // Here is the best place to set parameters - after init is ensured
100 // These are "painless" to set:
101 ods
->thresh
= ZIN0(1);
102 ods
->floor
= ZIN0(4);
103 ods
->mingap
= (int)ZIN0(5);
104 ods
->whtype
= (int)ZIN0(7);
107 unit
->outval
= onsetsds_process(ods
, (float*) p
);
109 ZOUT0(0) = unit
->outval
;
112 void Onsets_next_rawodf(Onsets
*unit
, int inNumSamples
)
116 // In practice, making the polar conversion here in SC is more efficient because SC provides a lookup table method.
117 SCPolarBuf
*p
= ToPolarApx(buf
);
119 OnsetsDS
*ods
= unit
->m_ods
;
121 int odftype
= (int)ZIN0(2);
122 float relaxtime
= ZIN0(3);
123 int medspan
= (int)ZIN0(6);
125 if(unit
->m_needsinit
){
126 // Init happens here because we need to be sure about FFT size.
127 unit
->m_odsdata
= (float*) RTAlloc(unit
->mWorld
, onsetsds_memneeded(odftype
, buf
->samples
, medspan
) );
129 onsetsds_init(ods
, unit
->m_odsdata
, ODS_FFT_SC3_POLAR
, odftype
, buf
->samples
, medspan
, FULLRATE
);
130 onsetsds_setrelax(ods
, relaxtime
, buf
->samples
>>1);
132 unit
->m_needsinit
= false;
135 // Here is the best place to set parameters - after init is ensured
136 // These are "painless" to set:
137 ods
->thresh
= ZIN0(1);
138 ods
->floor
= ZIN0(4);
139 ods
->mingap
= (int)ZIN0(5);
140 ods
->whtype
= (int)ZIN0(7);
143 onsetsds_process(ods
, (float*) p
);
144 // But we want the ODF, not the triggers, for this special mode...
145 //unit->outval = ods->odfvalpost;
146 unit
->outval
= ods
->odfvals
[0];
148 ZOUT0(0) = unit
->outval
;
151 void Onsets_Dtor(Onsets
*unit
)
153 if(!unit
->m_needsinit
){
154 RTFree(unit
->mWorld
, unit
->m_odsdata
);
156 RTFree(unit
->mWorld
, unit
->m_ods
);