1 /*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.cs.princeton.edu/
7 http://soundlab.cs.princeton.edu/
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
26 // file: uana_extract.cpp
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Rebecca Fiebrink (fiebrink@cs.princeton.edu)
31 // date: 20 November 2007
32 //-----------------------------------------------------------------------------
33 #include "uana_extract.h"
34 #include "chuck_type.h"
36 #include "chuck_instr.h"
37 #include "chuck_lang.h"
38 #include "chuck_errmsg.h"
39 #include "util_math.h"
40 #include "util_xforms.h"
46 CK_DLL_TICK( Centroid_tick
);
47 CK_DLL_TOCK( Centroid_tock
);
48 CK_DLL_PMSG( Centroid_pmsg
);
49 CK_DLL_SFUN( Centroid_compute
);
52 CK_DLL_CTOR( Flux_ctor
);
53 CK_DLL_DTOR( Flux_dtor
);
54 CK_DLL_TICK( Flux_tick
);
55 CK_DLL_TOCK( Flux_tock
);
56 CK_DLL_PMSG( Flux_pmsg
);
57 CK_DLL_MFUN( Flux_ctrl_reset
);
58 CK_DLL_SFUN( Flux_compute
);
59 CK_DLL_SFUN( Flux_compute2
);
61 static t_CKUINT Flux_offset_data
= 0;
64 CK_DLL_TICK( RMS_tick
);
65 CK_DLL_TOCK( RMS_tock
);
66 CK_DLL_PMSG( RMS_pmsg
);
67 CK_DLL_SFUN( RMS_compute
);
70 CK_DLL_CTOR( RollOff_ctor
);
71 CK_DLL_DTOR( RollOff_dtor
);
72 CK_DLL_TICK( RollOff_tick
);
73 CK_DLL_TOCK( RollOff_tock
);
74 CK_DLL_PMSG( RollOff_pmsg
);
75 CK_DLL_SFUN( RollOff_compute
);
76 CK_DLL_MFUN( RollOff_ctrl_percent
);
77 CK_DLL_MFUN( RollOff_cget_percent
);
79 static t_CKUINT RollOff_offset_percent
= 0;
82 CK_DLL_TICK( FeatureCollector_tick
);
83 CK_DLL_TOCK( FeatureCollector_tock
);
84 CK_DLL_PMSG( FeatureCollector_pmsg
);
87 CK_DLL_CTOR( AutoCorr_ctor
);
88 CK_DLL_DTOR( AutoCorr_dtor
);
89 CK_DLL_TICK( AutoCorr_tick
);
90 CK_DLL_TOCK( AutoCorr_tock
);
91 CK_DLL_PMSG( AutoCorr_pmsg
);
92 CK_DLL_SFUN( AutoCorr_compute
);
93 CK_DLL_MFUN( AutoCorr_ctrl_normalize
);
94 CK_DLL_MFUN( AutoCorr_cget_normalize
);
96 static t_CKUINT AutoCorr_offset_data
= 0;
99 CK_DLL_CTOR( XCorr_ctor
);
100 CK_DLL_DTOR( XCorr_dtor
);
101 CK_DLL_TICK( XCorr_tick
);
102 CK_DLL_TOCK( XCorr_tock
);
103 CK_DLL_PMSG( XCorr_pmsg
);
104 CK_DLL_SFUN( XCorr_compute
);
105 CK_DLL_MFUN( XCorr_ctrl_normalize
);
106 CK_DLL_MFUN( XCorr_cget_normalize
);
108 static t_CKUINT XCorr_offset_data
= 0;
111 CK_DLL_CTOR( ZeroX_ctor
);
112 CK_DLL_DTOR( ZeroX_dtor
);
113 CK_DLL_TICK( ZeroX_tick
);
114 CK_DLL_TOCK( ZeroX_tock
);
115 CK_DLL_PMSG( ZeroX_pmsg
);
116 CK_DLL_SFUN( ZeroX_compute
);
118 static t_CKUINT ZeroX_offset_data
= 0;
121 CK_DLL_CTOR( LPC_ctor
);
122 CK_DLL_DTOR( LPC_dtor
);
123 CK_DLL_TICK( LPC_tick
);
124 CK_DLL_TOCK( LPC_tock
);
125 CK_DLL_PMSG( LPC_pmsg
);
126 CK_DLL_SFUN( LPC_compute
);
127 CK_DLL_MFUN( LPC_ctrl_pitch
);
128 CK_DLL_MFUN( LPC_cget_pitch
);
129 CK_DLL_MFUN( LPC_ctrl_power
);
130 CK_DLL_MFUN( LPC_cget_power
);
131 CK_DLL_MFUN( LPC_ctrl_coefs
);
132 CK_DLL_MFUN( LPC_cget_coefs
);
134 static t_CKUINT LPC_offset_data
= 0;
138 void xcorr_fft( SAMPLE
* f
, t_CKINT fs
, SAMPLE
* g
, t_CKINT gs
, SAMPLE
* buffer
, t_CKINT bs
);
139 void xcorr_normalize( SAMPLE
* buffy
, t_CKINT bs
, SAMPLE
* f
, t_CKINT fs
, SAMPLE
* g
, t_CKINT gs
);
144 //-----------------------------------------------------------------------------
145 // name: extract_query()
147 //-----------------------------------------------------------------------------
148 DLL_QUERY
extract_query( Chuck_DL_Query
* QUERY
)
150 Chuck_Env
* env
= Chuck_Env::instance();
152 Chuck_DL_Func
* func
= NULL
;
154 //---------------------------------------------------------------------
155 // init as base class: FeatureCollector
156 //---------------------------------------------------------------------
157 if( !type_engine_import_uana_begin( env
, "FeatureCollector", "UAna", env
->global(),
159 FeatureCollector_tick
, FeatureCollector_tock
, FeatureCollector_pmsg
) )
162 // end the class import
163 type_engine_import_class_end( env
);
165 //---------------------------------------------------------------------
166 // init as base class: Centroid
167 //---------------------------------------------------------------------
168 if( !type_engine_import_uana_begin( env
, "Centroid", "UAna", env
->global(),
170 Centroid_tick
, Centroid_tock
, Centroid_pmsg
) )
174 func
= make_new_sfun( "float", "compute", Centroid_compute
);
175 func
->add_arg( "float[]", "input" );
176 if( !type_engine_import_sfun( env
, func
) ) goto error
;
178 // end the class import
179 type_engine_import_class_end( env
);
181 //---------------------------------------------------------------------
182 // init as base class: Flux
183 //---------------------------------------------------------------------
184 if( !type_engine_import_uana_begin( env
, "Flux", "UAna", env
->global(),
185 Flux_ctor
, Flux_dtor
,
186 Flux_tick
, Flux_tock
, Flux_pmsg
) )
190 Flux_offset_data
= type_engine_import_mvar( env
, "int", "@Flux_data", FALSE
);
191 if( Flux_offset_data
== CK_INVALID_OFFSET
) goto error
;
194 func
= make_new_mfun( "void", "reset", Flux_ctrl_reset
);
195 if( !type_engine_import_mfun( env
, func
) ) goto error
;
198 func
= make_new_sfun( "float", "compute", Flux_compute
);
199 func
->add_arg( "float[]", "lhs" );
200 func
->add_arg( "float[]", "rhs" );
201 if( !type_engine_import_sfun( env
, func
) ) goto error
;
204 func
= make_new_sfun( "float", "compute", Flux_compute2
);
205 func
->add_arg( "float[]", "lhs" );
206 func
->add_arg( "float[]", "rhs" );
207 func
->add_arg( "float[]", "diff" );
208 if( !type_engine_import_sfun( env
, func
) ) goto error
;
210 // end the class import
211 type_engine_import_class_end( env
);
213 //---------------------------------------------------------------------
214 // init as base class: RMS
215 //---------------------------------------------------------------------
216 if( !type_engine_import_uana_begin( env
, "RMS", "UAna", env
->global(),
218 RMS_tick
, RMS_tock
, RMS_pmsg
) )
222 func
= make_new_sfun( "float", "compute", RMS_compute
);
223 func
->add_arg( "float[]", "input" );
224 if( !type_engine_import_sfun( env
, func
) ) goto error
;
226 // end the class import
227 type_engine_import_class_end( env
);
229 //---------------------------------------------------------------------
230 // init as base class: RollOff
231 //---------------------------------------------------------------------
232 if( !type_engine_import_uana_begin( env
, "RollOff", "UAna", env
->global(),
233 RollOff_ctor
, RollOff_dtor
,
234 RollOff_tick
, RollOff_tock
, RollOff_pmsg
) )
238 RollOff_offset_percent
= type_engine_import_mvar( env
, "float", "@RollOff_data", FALSE
);
239 if( RollOff_offset_percent
== CK_INVALID_OFFSET
) goto error
;
242 func
= make_new_mfun( "float", "percent", RollOff_ctrl_percent
);
243 func
->add_arg( "float", "percent" );
244 if( !type_engine_import_mfun( env
, func
) ) goto error
;
247 func
= make_new_mfun( "float", "percent", RollOff_cget_percent
);
248 if( !type_engine_import_mfun( env
, func
) ) goto error
;
251 func
= make_new_sfun( "float", "compute", RollOff_compute
);
252 func
->add_arg( "float[]", "input" );
253 func
->add_arg( "float", "percent" );
254 if( !type_engine_import_sfun( env
, func
) ) goto error
;
256 // end the class import
257 type_engine_import_class_end( env
);
259 //---------------------------------------------------------------------
260 // init as base class: AutoCorr
261 //---------------------------------------------------------------------
262 if( !type_engine_import_uana_begin( env
, "AutoCorr", "UAna", env
->global(),
263 AutoCorr_ctor
, AutoCorr_dtor
,
264 AutoCorr_tick
, AutoCorr_tock
, AutoCorr_pmsg
) )
268 AutoCorr_offset_data
= type_engine_import_mvar( env
, "float", "@AutoCorr_data", FALSE
);
269 if( AutoCorr_offset_data
== CK_INVALID_OFFSET
) goto error
;
272 func
= make_new_mfun( "int", "normalize", AutoCorr_ctrl_normalize
);
273 func
->add_arg( "int", "flag" );
274 if( !type_engine_import_mfun( env
, func
) ) goto error
;
277 func
= make_new_mfun( "int", "normalize", AutoCorr_cget_normalize
);
278 if( !type_engine_import_mfun( env
, func
) ) goto error
;
281 func
= make_new_sfun( "float[]", "compute", AutoCorr_compute
);
282 func
->add_arg( "float[]", "input" );
283 func
->add_arg( "int", "normalize" );
284 func
->add_arg( "float[]", "output" );
285 if( !type_engine_import_sfun( env
, func
) ) goto error
;
287 // end the class import
288 type_engine_import_class_end( env
);
290 //---------------------------------------------------------------------
291 // init as base class: XCorr
292 //---------------------------------------------------------------------
293 if( !type_engine_import_uana_begin( env
, "XCorr", "UAna", env
->global(),
294 XCorr_ctor
, XCorr_dtor
,
295 XCorr_tick
, XCorr_tock
, XCorr_pmsg
) )
299 XCorr_offset_data
= type_engine_import_mvar( env
, "float", "@XCorr_data", FALSE
);
300 if( XCorr_offset_data
== CK_INVALID_OFFSET
) goto error
;
303 func
= make_new_mfun( "int", "normalize", XCorr_ctrl_normalize
);
304 func
->add_arg( "int", "flag" );
305 if( !type_engine_import_mfun( env
, func
) ) goto error
;
308 func
= make_new_mfun( "int", "normalize", XCorr_cget_normalize
);
309 if( !type_engine_import_mfun( env
, func
) ) goto error
;
312 func
= make_new_sfun( "float[]", "compute", XCorr_compute
);
313 func
->add_arg( "float[]", "f" );
314 func
->add_arg( "float[]", "g" );
315 func
->add_arg( "int", "normalize" );
316 func
->add_arg( "float[]", "y" );
317 if( !type_engine_import_sfun( env
, func
) ) goto error
;
319 // end the class import
320 type_engine_import_class_end( env
);
322 //---------------------------------------------------------------------
323 // init as base class: zerox
324 //---------------------------------------------------------------------
325 if( !type_engine_import_uana_begin( env
, "ZeroX", "UAna", env
->global(),
326 ZeroX_ctor
, ZeroX_dtor
,
327 ZeroX_tick
, ZeroX_tock
, NULL
) )
331 ZeroX_offset_data
= type_engine_import_mvar( env
, "int", "@ZeroX_data", FALSE
);
332 if( ZeroX_offset_data
== CK_INVALID_OFFSET
) goto error
;
335 func
= make_new_sfun( "float", "compute", ZeroX_compute
);
336 func
->add_arg( "float[]", "input" );
337 if( !type_engine_import_sfun( env
, func
) ) goto error
;
340 if( !type_engine_import_class_end( env
) )
348 // end the class import
349 type_engine_import_class_end( env
);
354 CK_DLL_TICK( FeatureCollector_tick
)
360 // FeatureCollector_tock creates a flat vector from its upstream UAnae
361 // TODO: Stick complex features in Blob, too? But what about fft? (don't want duplication)
362 CK_DLL_TOCK( FeatureCollector_tock
)
364 //t_CKFLOAT * features;
365 t_CKINT num_feats
= 0;
366 t_CKINT num_incoming
= UANA
->numIncomingUAnae();
370 // Get all incoming features and agglomerate into one vector
371 if( num_incoming
> 0 )
373 //count the number of features in the array we're making
374 for( i
= 0; i
< num_incoming
; i
++ )
377 Chuck_UAnaBlobProxy
* BLOB_IN
= UANA
->getIncomingBlob( i
);
379 assert( BLOB_IN
!= NULL
);
380 // count number of features from this UAna
381 Chuck_Array8
& these_fvals
= BLOB_IN
->fvals();
382 num_feats
+= these_fvals
.size();
385 // get fvals of output BLOB
386 Chuck_Array8
& fvals
= BLOB
->fvals();
387 if( fvals
.size() != num_feats
)
388 fvals
.set_size( num_feats
);
390 t_CKINT next_index
= 0;
391 for( i
= 0; i
< num_incoming
; i
++ )
394 Chuck_UAnaBlobProxy
* BLOB_IN
= UANA
->getIncomingBlob( i
);
395 Chuck_Array8
& these_fvals
= BLOB_IN
->fvals();
396 t_CKINT num_these
= these_fvals
.size();
397 for( j
= 0; j
< num_these
; j
++ )
400 these_fvals
.get( j
, &v
);
401 fvals
.set( next_index
, v
);
406 // no input to collect
407 BLOB
->fvals().set_size(0);
413 CK_DLL_PMSG( FeatureCollector_pmsg
)
419 static t_CKFLOAT
compute_centroid( Chuck_Array8
& buffer
, t_CKUINT size
)
427 // Compute centroid using moments
428 for( i
= 0; i
< size
; i
++ )
438 centroid
= size
/ 2.0; // Perfectly balanced
440 return centroid
/ size
;
444 CK_DLL_TICK( Centroid_tick
)
450 CK_DLL_TOCK( Centroid_tock
)
452 t_CKFLOAT result
= 0.0;
454 // TODO: get buffer from stream, and set in ifft
455 if( UANA
->numIncomingUAnae() > 0 )
458 Chuck_UAnaBlobProxy
* BLOB_IN
= UANA
->getIncomingBlob( 0 );
460 assert( BLOB_IN
!= NULL
);
462 Chuck_Array8
& mag
= BLOB_IN
->fvals();
464 result
= compute_centroid( mag
, mag
.size() );
466 // otherwise zero out
473 // get fvals of output BLOB
474 Chuck_Array8
& fvals
= BLOB
->fvals();
475 // ensure size == resulting size
476 if( fvals
.size() != 1 )
478 // copy the result in
479 fvals
.set( 0, result
);
484 CK_DLL_PMSG( Centroid_pmsg
)
490 CK_DLL_SFUN( Centroid_compute
)
493 Chuck_Array8
* array
= (Chuck_Array8
*)GET_NEXT_OBJECT(ARGS
);
498 RETURN
->v_float
= 0.0;
503 RETURN
->v_float
= compute_centroid( *array
, array
->size() );
513 t_CKBOOL initialized
;
523 static void compute_norm_rms( Chuck_Array8
& curr
, Chuck_Array8
& norm
)
526 t_CKFLOAT energy
= 0.0;
530 if( norm
.size() != curr
.size() )
531 norm
.set_size( curr
.size() );
534 for( i
= 0; i
< curr
.size(); i
++ )
544 norm
.zero( 0, norm
.size() );
548 energy
= ::sqrt( energy
);
550 for( i
= 0; i
< curr
.size(); i
++ )
554 norm
.set( i
, v
/ energy
);
561 static t_CKFLOAT
compute_flux( Chuck_Array8
& curr
, Chuck_Array8
& prev
, Chuck_Array8
* write
)
564 assert( curr
.size() == prev
.size() );
567 if( write
!= NULL
&& (write
->size() != curr
.size()) )
568 write
->set_size( curr
.size() );
571 t_CKFLOAT v
, w
, result
= 0.0;
572 for( t_CKUINT i
= 0; i
< curr
.size(); i
++ )
576 // accumulate into flux
577 result
+= (v
- w
)*(v
- w
);
579 if( write
!= NULL
) write
->set( i
, v
);
583 return ::sqrt( result
);
587 static t_CKFLOAT
compute_flux( Chuck_Array8
& curr
, StateOfFlux
& sof
)
590 t_CKFLOAT result
= 0.0;
594 if( curr
.size() != sof
.prev
.size() )
596 sof
.initialized
= FALSE
;
598 sof
.prev
.set_size( curr
.size() );
602 if( sof
.initialized
)
604 // compute normalize rms
605 compute_norm_rms( curr
, sof
.norm
);
607 result
= compute_flux( sof
.norm
, sof
.prev
, &sof
.prev
);
611 for( t_CKUINT i
= 0; i
< curr
.size(); i
++ )
614 sof
.norm
.get( i
, &v
);
616 sof
.prev
.set( i
, v
);
620 sof
.initialized
= TRUE
;
626 CK_DLL_CTOR( Flux_ctor
)
628 // allocate the flux state
629 StateOfFlux
* state
= new StateOfFlux();
630 OBJ_MEMBER_UINT( SELF
, Flux_offset_data
) = (t_CKUINT
)state
;
634 CK_DLL_DTOR( Flux_dtor
)
637 StateOfFlux
* state
= (StateOfFlux
*)OBJ_MEMBER_UINT( SELF
, Flux_offset_data
);
638 SAFE_DELETE( state
);
639 OBJ_MEMBER_UINT( SELF
, Flux_offset_data
) = 0;
643 CK_DLL_TICK( Flux_tick
)
650 CK_DLL_TOCK( Flux_tock
)
652 t_CKFLOAT result
= 0.0;
655 StateOfFlux
* state
= (StateOfFlux
*)OBJ_MEMBER_UINT( SELF
, Flux_offset_data
);
657 // TODO: get buffer from stream, and set in ifft
658 if( UANA
->numIncomingUAnae() > 0 )
661 Chuck_UAnaBlobProxy
* BLOB_IN
= UANA
->getIncomingBlob( 0 );
663 assert( BLOB_IN
!= NULL
);
665 Chuck_Array8
& mag
= BLOB_IN
->fvals();
667 result
= compute_flux( mag
, *state
);
669 // otherwise zero out
676 // get fvals of output BLOB
677 Chuck_Array8
& fvals
= BLOB
->fvals();
678 // ensure size == resulting size
679 if( fvals
.size() != 1 )
681 // copy the result in
682 fvals
.set( 0, result
);
687 CK_DLL_PMSG( Flux_pmsg
)
693 CK_DLL_MFUN( Flux_ctrl_reset
)
696 StateOfFlux
* state
= (StateOfFlux
*)OBJ_MEMBER_UINT( SELF
, Flux_offset_data
);
698 state
->initialized
= FALSE
;
701 CK_DLL_SFUN( Flux_compute
)
704 Chuck_Array8
* lhs
= (Chuck_Array8
*)GET_NEXT_OBJECT(ARGS
);
705 Chuck_Array8
* rhs
= (Chuck_Array8
*)GET_NEXT_OBJECT(ARGS
);
711 RETURN
->v_float
= 0.0;
716 if( lhs
->size() != rhs
->size() )
719 EM_error3( "(via Flux): compute() expects two arrays of equal size" );
721 RETURN
->v_float
= 0.0;
726 RETURN
->v_float
= compute_flux( *lhs
, *rhs
, NULL
);
731 CK_DLL_SFUN( Flux_compute2
)
734 Chuck_Array8
* lhs
= (Chuck_Array8
*)GET_NEXT_OBJECT(ARGS
);
735 Chuck_Array8
* rhs
= (Chuck_Array8
*)GET_NEXT_OBJECT(ARGS
);
736 Chuck_Array8
* diff
= (Chuck_Array8
*)GET_NEXT_OBJECT(ARGS
);
742 RETURN
->v_float
= 0.0;
747 if( lhs
->size() != rhs
->size() )
750 EM_error3( "(via Flux): compute() expects two arrays of equal size" );
752 RETURN
->v_float
= 0.0;
757 RETURN
->v_float
= compute_flux( *lhs
, *rhs
, diff
);
763 static t_CKFLOAT
compute_rms( Chuck_Array8
& buffer
, t_CKUINT size
)
769 // get sum of squares
770 for( i
= 0; i
< size
; i
++ )
784 CK_DLL_TICK( RMS_tick
)
790 CK_DLL_TOCK( RMS_tock
)
792 t_CKFLOAT result
= 0.0;
794 // TODO: get buffer from stream, and set in ifft
795 if( UANA
->numIncomingUAnae() > 0 )
798 Chuck_UAnaBlobProxy
* BLOB_IN
= UANA
->getIncomingBlob( 0 );
800 assert( BLOB_IN
!= NULL
);
802 Chuck_Array8
& mag
= BLOB_IN
->fvals();
804 result
= compute_rms( mag
, mag
.size() );
806 // otherwise zero out
813 // get fvals of output BLOB
814 Chuck_Array8
& fvals
= BLOB
->fvals();
815 // ensure size == resulting size
816 if( fvals
.size() != 1 )
818 // copy the result in
819 fvals
.set( 0, result
);
824 CK_DLL_PMSG( RMS_pmsg
)
830 CK_DLL_SFUN( RMS_compute
)
833 Chuck_Array8
* array
= (Chuck_Array8
*)GET_NEXT_OBJECT(ARGS
);
838 RETURN
->v_float
= 0.0;
843 RETURN
->v_float
= compute_rms( *array
, array
->size() );
848 static t_CKFLOAT
compute_rolloff( Chuck_Array8
& buffer
, t_CKUINT size
, t_CKFLOAT percent
)
850 t_CKFLOAT sum
= 0.0, v
, target
;
854 assert( percent
>= 0 && percent
<= 1 );
857 for( i
= 0; i
< size
; i
++ )
864 target
= sum
* percent
;
868 for( i
= 0; i
< size
; i
++ )
872 if( sum
>= target
) break;
875 return i
/(t_CKFLOAT
)size
;
879 CK_DLL_CTOR( RollOff_ctor
)
881 OBJ_MEMBER_FLOAT( SELF
, RollOff_offset_percent
) = .85;
884 CK_DLL_DTOR( RollOff_dtor
)
888 CK_DLL_TICK( RollOff_tick
)
894 CK_DLL_TOCK( RollOff_tock
)
896 t_CKFLOAT result
= 0.0;
899 t_CKFLOAT percent
= OBJ_MEMBER_FLOAT( SELF
, RollOff_offset_percent
);
901 // TODO: get buffer from stream, and set in ifft
902 if( UANA
->numIncomingUAnae() > 0 )
905 Chuck_UAnaBlobProxy
* BLOB_IN
= UANA
->getIncomingBlob( 0 );
907 assert( BLOB_IN
!= NULL
);
909 Chuck_Array8
& mag
= BLOB_IN
->fvals();
911 result
= compute_rolloff( mag
, mag
.size(), percent
);
913 // otherwise zero out
920 // get fvals of output BLOB
921 Chuck_Array8
& fvals
= BLOB
->fvals();
922 // ensure size == resulting size
923 if( fvals
.size() != 1 )
925 // copy the result in
926 fvals
.set( 0, result
);
931 CK_DLL_PMSG( RollOff_pmsg
)
937 CK_DLL_CTRL( RollOff_ctrl_percent
)
940 t_CKFLOAT percent
= GET_NEXT_FLOAT(ARGS
);
942 if( percent
< 0.0 ) percent
= 0.0;
943 else if( percent
> 1.0 ) percent
= 1.0;
945 OBJ_MEMBER_FLOAT(SELF
, RollOff_offset_percent
) = percent
;
947 RETURN
->v_float
= percent
;
950 CK_DLL_CGET( RollOff_cget_percent
)
953 RETURN
->v_float
= OBJ_MEMBER_FLOAT(SELF
, RollOff_offset_percent
);
956 CK_DLL_SFUN( RollOff_compute
)
959 Chuck_Array8
* array
= (Chuck_Array8
*)GET_NEXT_OBJECT(ARGS
);
961 t_CKFLOAT percent
= GET_NEXT_FLOAT(ARGS
);
967 RETURN
->v_float
= 0.0;
972 RETURN
->v_float
= compute_rolloff( *array
, array
->size(), percent
);
982 // whether to normalize
994 // static corr instance
995 static Corr_Object
* ourCorr
;
1000 // default: do normalize
1002 // zero out pointers
1003 fbuf
= gbuf
= buffy
= NULL
;
1004 fcap
= gcap
= bufcap
= 0;
1019 SAFE_DELETE_ARRAY( fbuf
);
1020 SAFE_DELETE_ARRAY( gbuf
);
1021 SAFE_DELETE_ARRAY( buffy
);
1022 fcap
= gcap
= bufcap
= 0;
1028 if( fbuf
) memset( fbuf
, 0, fcap
* sizeof(SAMPLE
) );
1029 if( gbuf
) memset( gbuf
, 0, gcap
* sizeof(SAMPLE
) );
1030 if( buffy
) memset( buffy
, 0, bufcap
* sizeof(SAMPLE
) );
1034 t_CKBOOL
resize( t_CKINT fs
, t_CKINT gs
)
1037 t_CKINT mincap
= fs
+ gs
- 1;
1038 // ensure power of two
1039 mincap
= ensurepow2( mincap
);
1041 EM_log( CK_LOG_FINE
, "Corr resizing to %d-element buffers...", mincap
);
1046 SAFE_DELETE_ARRAY( fbuf
);
1047 fbuf
= new SAMPLE
[mincap
];
1052 SAFE_DELETE_ARRAY( gbuf
);
1053 gbuf
= new SAMPLE
[mincap
];
1056 if( bufcap
< mincap
)
1058 SAFE_DELETE_ARRAY( buffy
);
1059 buffy
= new SAMPLE
[mincap
];
1064 if( fbuf
== NULL
|| gbuf
== NULL
|| buffy
== NULL
)
1067 fprintf( stderr
, "[chuck]: Corr failed to allocate %d-element buffer(s)...",
1081 // get our singleton
1082 static Corr_Object
* getOurObject()
1084 // instantiate, if needed
1085 if( ourCorr
== NULL
)
1087 ourCorr
= new Corr_Object();
1088 assert( ourCorr
!= NULL
);
1091 // return new instance
1096 // static initialization
1097 Corr_Object
* Corr_Object::ourCorr
= NULL
;
1099 // compute correlation
1100 static void compute_corr( Corr_Object
* corr
, Chuck_Array8
& f
, t_CKINT fs
,
1101 Chuck_Array8
& g
, t_CKINT gs
, Chuck_Array8
& buffy
)
1108 corr
->resize( fs
, gs
);
1110 // copy into buffers
1111 for( i
= 0; i
< fs
; i
++ )
1116 for( i
= 0; i
< gs
; i
++ )
1123 xcorr_fft( corr
->fbuf
, corr
->fcap
, corr
->gbuf
, corr
->gcap
,
1124 corr
->buffy
, corr
->bufcap
);
1127 if( corr
->normalize
)
1130 xcorr_normalize( corr
->buffy
, corr
->bufcap
,
1131 corr
->fbuf
, corr
->fcap
, corr
->gbuf
, corr
->gcap
);
1136 buffy
.set_size( size
);
1137 for( i
= 0; i
< size
; i
++ )
1139 buffy
.set( i
, corr
->buffy
[i
] );
1144 CK_DLL_CTOR( AutoCorr_ctor
)
1146 Corr_Object
* ac
= new Corr_Object();
1147 OBJ_MEMBER_UINT( SELF
, AutoCorr_offset_data
) = (t_CKUINT
)ac
;
1150 CK_DLL_DTOR( AutoCorr_dtor
)
1152 Corr_Object
* ac
= (Corr_Object
*)OBJ_MEMBER_UINT( SELF
, AutoCorr_offset_data
);
1154 OBJ_MEMBER_UINT( SELF
, AutoCorr_offset_data
) = 0;
1157 CK_DLL_TICK( AutoCorr_tick
)
1163 CK_DLL_TOCK( AutoCorr_tock
)
1166 Corr_Object
* ac
= (Corr_Object
*)OBJ_MEMBER_UINT( SELF
, AutoCorr_offset_data
);
1168 // TODO: get buffer from stream, and set
1169 if( UANA
->numIncomingUAnae() > 0 )
1172 Chuck_UAnaBlobProxy
* BLOB_IN
= UANA
->getIncomingBlob( 0 );
1174 assert( BLOB_IN
!= NULL
);
1176 Chuck_Array8
& mag
= BLOB_IN
->fvals();
1177 // get fvals of output BLOB
1178 Chuck_Array8
& fvals
= BLOB
->fvals();
1180 compute_corr( ac
, mag
, mag
.size(), mag
, mag
.size(), fvals
);
1182 // otherwise zero out
1185 // get fvals of output BLOB
1186 Chuck_Array8
& fvals
= BLOB
->fvals();
1188 fvals
.set_size( 0 );
1194 CK_DLL_PMSG( AutoCorr_pmsg
)
1200 CK_DLL_CTRL( AutoCorr_ctrl_normalize
)
1203 Corr_Object
* ac
= (Corr_Object
*)OBJ_MEMBER_UINT( SELF
, AutoCorr_offset_data
);
1205 ac
->normalize
= GET_NEXT_INT(ARGS
) != 0;
1207 RETURN
->v_int
= ac
->normalize
;
1210 CK_DLL_CGET( AutoCorr_cget_normalize
)
1213 Corr_Object
* ac
= (Corr_Object
*)OBJ_MEMBER_UINT( SELF
, AutoCorr_offset_data
);
1215 RETURN
->v_int
= ac
->normalize
;
1218 CK_DLL_SFUN( AutoCorr_compute
)
1221 Chuck_Array8
* input
= (Chuck_Array8
*)GET_NEXT_OBJECT(ARGS
);
1222 // get normalize flag
1223 t_CKINT normalize
= GET_NEXT_INT(ARGS
) != 0;
1225 Chuck_Array8
* output
= (Chuck_Array8
*)GET_NEXT_OBJECT(ARGS
);
1228 Corr_Object::getOurObject()->normalize
= normalize
;
1230 compute_corr( Corr_Object::getOurObject(), *input
, input
->size(),
1231 *input
, input
->size(), *output
);
1236 CK_DLL_CTOR( XCorr_ctor
)
1238 Corr_Object
* xc
= new Corr_Object();
1239 OBJ_MEMBER_UINT( SELF
, XCorr_offset_data
) = (t_CKUINT
)xc
;
1242 CK_DLL_DTOR( XCorr_dtor
)
1244 Corr_Object
* xc
= (Corr_Object
*)OBJ_MEMBER_UINT( SELF
, XCorr_offset_data
);
1246 OBJ_MEMBER_UINT( SELF
, XCorr_offset_data
) = 0;
1249 CK_DLL_TICK( XCorr_tick
)
1255 CK_DLL_TOCK( XCorr_tock
)
1258 Corr_Object
* xc
= (Corr_Object
*)OBJ_MEMBER_UINT( SELF
, XCorr_offset_data
);
1260 // TODO: get buffer from stream, and set
1261 if( UANA
->numIncomingUAnae() > 1 )
1264 Chuck_UAnaBlobProxy
* BLOB_F
= UANA
->getIncomingBlob( 0 );
1266 Chuck_UAnaBlobProxy
* BLOB_G
= UANA
->getIncomingBlob( 1 );
1268 assert( BLOB_F
!= NULL
&& BLOB_G
!= NULL
);
1270 Chuck_Array8
& mag_f
= BLOB_F
->fvals();
1271 Chuck_Array8
& mag_g
= BLOB_G
->fvals();
1272 // get fvals of output BLOB
1273 Chuck_Array8
& fvals
= BLOB
->fvals();
1275 compute_corr( xc
, mag_f
, mag_f
.size(), mag_g
, mag_g
.size(), fvals
);
1277 // otherwise zero out
1280 // get fvals of output BLOB
1281 Chuck_Array8
& fvals
= BLOB
->fvals();
1283 fvals
.set_size( 0 );
1289 CK_DLL_PMSG( XCorr_pmsg
)
1295 CK_DLL_CTRL( XCorr_ctrl_normalize
)
1298 Corr_Object
* ac
= (Corr_Object
*)OBJ_MEMBER_UINT( SELF
, XCorr_offset_data
);
1300 ac
->normalize
= GET_NEXT_INT(ARGS
) != 0;
1302 RETURN
->v_int
= ac
->normalize
;
1305 CK_DLL_CGET( XCorr_cget_normalize
)
1308 Corr_Object
* ac
= (Corr_Object
*)OBJ_MEMBER_UINT( SELF
, XCorr_offset_data
);
1310 RETURN
->v_int
= ac
->normalize
;
1313 CK_DLL_SFUN( XCorr_compute
)
1316 Chuck_Array8
* f
= (Chuck_Array8
*)GET_NEXT_OBJECT(ARGS
);
1317 Chuck_Array8
* g
= (Chuck_Array8
*)GET_NEXT_OBJECT(ARGS
);
1318 // get normalize flag
1319 t_CKINT normalize
= GET_NEXT_INT(ARGS
) != 0;
1321 Chuck_Array8
* output
= (Chuck_Array8
*)GET_NEXT_OBJECT(ARGS
);
1324 Corr_Object::getOurObject()->normalize
= normalize
;
1326 compute_corr( Corr_Object::getOurObject(), *f
, f
->size(),
1327 *g
, g
->size(), *output
);
1333 //-----------------------------------------------------------------------------
1334 // name: xcorr_fft()
1335 // desc: FFT-based cross correlation
1336 //-----------------------------------------------------------------------------
1337 void xcorr_fft( SAMPLE
* f
, t_CKINT fsize
, SAMPLE
* g
, t_CKINT gsize
, SAMPLE
* buffy
, t_CKINT size
)
1340 assert( fsize
== gsize
== size
);
1343 rfft( f
, size
/2, FFT_FORWARD
);
1344 rfft( g
, size
/2, FFT_FORWARD
);
1347 t_CKCOMPLEX_SAMPLE
* F
= (t_CKCOMPLEX_SAMPLE
*)f
;
1348 t_CKCOMPLEX_SAMPLE
* G
= (t_CKCOMPLEX_SAMPLE
*)g
;
1349 t_CKCOMPLEX_SAMPLE
* Y
= (t_CKCOMPLEX_SAMPLE
*)buffy
;
1352 for( t_CKINT i
= 0; i
< size
/2; i
++ )
1357 Y
[i
].re
= F
[i
].re
*G
[i
].re
- F
[i
].im
*G
[i
].im
;
1358 Y
[i
].im
= F
[i
].im
*G
[i
].re
+ F
[i
].re
*G
[i
].im
;
1362 rfft( buffy
, size
/2, FFT_INVERSE
);
1368 //-----------------------------------------------------------------------------
1369 // name: xcorr_normalize()
1371 //-----------------------------------------------------------------------------
1372 void xcorr_normalize( SAMPLE
* buffy
, t_CKINT size
, SAMPLE
* f
, t_CKINT fs
, SAMPLE
* g
, t_CKINT gs
)
1374 float sum
= 0.000001f
;
1377 for( long i
= 0; i
< fs
; i
++ )
1380 for( long j
= 0; j
< gs
; j
++ )
1382 // normalize: taking coherence into account
1383 for( long k
= 0; k
< size
; k
++ )
1391 #define __SGN(x) (x >= 0.0f ? 1.0f : -1.0f )
1392 static t_CKINT
compute_zerox( Chuck_Array8
& buffer
, t_CKUINT size
)
1394 t_CKUINT i
, xings
= 0;
1395 t_CKFLOAT v
= 0, p
= 0;
1396 buffer
.get( 0, &p
);
1398 // Compute centroid using moments
1399 for( i
= 0; i
< size
; i
++ )
1401 buffer
.get( i
, &v
);
1402 xings
+= __SGN(v
) != __SGN(p
);
1409 CK_DLL_CTOR( ZeroX_ctor
)
1411 OBJ_MEMBER_UINT(SELF
, ZeroX_offset_data
) = (t_CKUINT
)new SAMPLE( 0.0f
);
1414 CK_DLL_DTOR( ZeroX_dtor
)
1416 delete (SAMPLE
*)OBJ_MEMBER_UINT(SELF
, ZeroX_offset_data
);
1417 OBJ_MEMBER_UINT(SELF
, ZeroX_offset_data
) = 0;
1420 CK_DLL_TICK( ZeroX_tick
)
1422 SAMPLE
* d
= (SAMPLE
*)OBJ_MEMBER_UINT(SELF
, ZeroX_offset_data
);
1423 *out
= __SGN(in
) != __SGN(*d
);
1430 CK_DLL_TOCK( ZeroX_tock
)
1432 t_CKFLOAT result
= 0.0;
1434 // TODO: get buffer from stream, and set in ifft
1435 if( UANA
->numIncomingUAnae() > 0 )
1438 Chuck_UAnaBlobProxy
* BLOB_IN
= UANA
->getIncomingBlob( 0 );
1440 assert( BLOB_IN
!= NULL
);
1442 Chuck_Array8
& mag
= BLOB_IN
->fvals();
1444 result
= (t_CKFLOAT
)( compute_zerox( mag
, mag
.size() ) + .5 );
1446 // otherwise zero out
1453 // get fvals of output BLOB
1454 Chuck_Array8
& fvals
= BLOB
->fvals();
1455 // ensure size == resulting size
1456 if( fvals
.size() != 1 )
1457 fvals
.set_size( 1 );
1458 // copy the result in
1459 fvals
.set( 0, result
);
1464 CK_DLL_PMSG( ZeroX_pmsg
)
1470 CK_DLL_SFUN( ZeroX_compute
)
1473 Chuck_Array8
* array
= (Chuck_Array8
*)GET_NEXT_OBJECT(ARGS
);
1478 RETURN
->v_float
= 0.0;
1483 RETURN
->v_float
= (t_CKFLOAT
)( compute_centroid( *array
, array
->size() ) + .5 );