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: ulib_math.cpp
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
32 //-----------------------------------------------------------------------------
33 #include "chuck_type.h"
34 #include "ulib_math.h"
35 #include "util_math.h"
42 static double g_pi
= ONE_PI
;
43 static double g_twopi
= TWO_PI
;
44 static double g_e
= ::exp( 1.0 );
45 static t_CKFLOAT g_floatMax
= DBL_MAX
;
46 static t_CKFLOAT g_floatMin
= DBL_MIN
;
47 static t_CKFLOAT g_inf
= 0.0;
48 static t_CKINT g_intMax
= LONG_MAX
;
49 static t_CKCOMPLEX g_i
= { 0.0, 1.0 };
50 static t_CKFLOAT
fzero() { return 0.0; }
54 DLL_QUERY
libmath_query( Chuck_DL_Query
* QUERY
)
57 Chuck_Env
* env
= Chuck_Env::instance();
59 QUERY
->setname( QUERY
, "Math" );
62 math.sin( math.pi /2.0 ) => stdout;
66 type_engine_register_deprecate( env
, "math", "Math" );
69 QUERY
->begin_class( QUERY
, "Math", "Object" );
72 QUERY
->add_sfun( QUERY
, abs_impl
, "int", "abs" );
73 QUERY
->add_arg( QUERY
, "int", "value" );
76 QUERY
->add_sfun( QUERY
, fabs_impl
, "float", "fabs" );
77 QUERY
->add_arg( QUERY
, "float", "value" );
80 QUERY
->add_sfun( QUERY
, sgn_impl
, "float", "sgn" );
81 QUERY
->add_arg( QUERY
, "float", "value" );
84 QUERY
->add_sfun( QUERY
, sin_impl
, "float", "sin" );
85 QUERY
->add_arg( QUERY
, "float", "x" );
88 QUERY
->add_sfun( QUERY
, cos_impl
, "float", "cos" );
89 QUERY
->add_arg( QUERY
, "float", "x" );
92 QUERY
->add_sfun( QUERY
, tan_impl
, "float", "tan" );
93 QUERY
->add_arg( QUERY
, "float", "x" );
96 QUERY
->add_sfun( QUERY
, asin_impl
, "float", "asin" );
97 QUERY
->add_arg( QUERY
, "float", "x" );
100 QUERY
->add_sfun( QUERY
, acos_impl
, "float", "acos" );
101 QUERY
->add_arg( QUERY
, "float", "x" );
104 QUERY
->add_sfun( QUERY
, atan_impl
, "float", "atan" );
105 QUERY
->add_arg( QUERY
, "float", "x" );
108 QUERY
->add_sfun( QUERY
, atan2_impl
, "float", "atan2" );
109 QUERY
->add_arg( QUERY
, "float", "y" );
110 QUERY
->add_arg( QUERY
, "float", "x" );
113 QUERY
->add_sfun( QUERY
, sinh_impl
, "float", "sinh" );
114 QUERY
->add_arg( QUERY
, "float", "x" );
117 QUERY
->add_sfun( QUERY
, cosh_impl
, "float", "cosh" );
118 QUERY
->add_arg( QUERY
, "float", "x" );
121 QUERY
->add_sfun( QUERY
, tanh_impl
, "float", "tanh" );
122 QUERY
->add_arg( QUERY
, "float", "x" );
125 QUERY
->add_sfun( QUERY
, hypot_impl
, "float", "hypot" );
126 QUERY
->add_arg( QUERY
, "float", "x" );
127 QUERY
->add_arg( QUERY
, "float", "y" );
130 QUERY
->add_sfun( QUERY
, pow_impl
, "float", "pow" );
131 QUERY
->add_arg( QUERY
, "float", "x" );
132 QUERY
->add_arg( QUERY
, "float", "y" );
135 QUERY
->add_sfun( QUERY
, sqrt_impl
, "float", "sqrt" );
136 QUERY
->add_arg( QUERY
, "float", "x" );
139 QUERY
->add_sfun( QUERY
, exp_impl
, "float", "exp" );
140 QUERY
->add_arg( QUERY
, "float", "x" );
143 QUERY
->add_sfun( QUERY
, log_impl
, "float", "log" );
144 QUERY
->add_arg( QUERY
, "float", "x" );
147 QUERY
->add_sfun( QUERY
, log2_impl
, "float", "log2" );
148 QUERY
->add_arg( QUERY
, "float", "x" );
151 QUERY
->add_sfun( QUERY
, log10_impl
, "float", "log10" );
152 QUERY
->add_arg( QUERY
, "float", "x" );
155 QUERY
->add_sfun( QUERY
, floor_impl
, "float", "floor" );
156 QUERY
->add_arg( QUERY
, "float", "x" );
159 QUERY
->add_sfun( QUERY
, ceil_impl
, "float", "ceil" );
160 QUERY
->add_arg( QUERY
, "float", "x" );
163 QUERY
->add_sfun( QUERY
, round_impl
, "float", "round" );
164 QUERY
->add_arg( QUERY
, "float", "x" );
167 QUERY
->add_sfun( QUERY
, trunc_impl
, "float", "trunc" );
168 QUERY
->add_arg( QUERY
, "float", "x" );
171 QUERY
->add_sfun( QUERY
, fmod_impl
, "float", "fmod" );
172 QUERY
->add_arg( QUERY
, "float", "x" );
173 QUERY
->add_arg( QUERY
, "float", "y" );
176 QUERY
->add_sfun( QUERY
, remainder_impl
, "float", "remainder" );
177 QUERY
->add_arg( QUERY
, "float", "x" );
178 QUERY
->add_arg( QUERY
, "float", "y" );
181 QUERY
->add_sfun( QUERY
, min_impl
, "float", "min" );
182 QUERY
->add_arg( QUERY
, "float", "x" );
183 QUERY
->add_arg( QUERY
, "float", "y" );
186 //! see \example powerup.ck
187 QUERY
->add_sfun( QUERY
, max_impl
, "float", "max" );
188 QUERY
->add_arg( QUERY
, "float", "x" );
189 QUERY
->add_arg( QUERY
, "float", "y" );
192 QUERY
->add_sfun( QUERY
, isinf_impl
, "int", "isinf" );
193 QUERY
->add_arg( QUERY
, "float", "x" );
196 QUERY
->add_sfun( QUERY
, isnan_impl
, "int", "isnan" );
197 QUERY
->add_arg( QUERY
, "float", "x" );
200 // QUERY->add_sfun( QUERY, floatMax_impl, "float", "floatMax" );
203 // QUERY->add_sfun( QUERY, intMax_impl, "int", "intMax" );
206 QUERY
->add_sfun( QUERY
, nextpow2_impl
, "int", "nextpow2" );
207 QUERY
->add_arg( QUERY
, "int", "n" );
210 QUERY
->add_sfun( QUERY
, ensurepow2_impl
, "int", "ensurePow2" );
211 QUERY
->add_arg( QUERY
, "int", "n" );
214 QUERY
->add_sfun( QUERY
, rand_impl
, "int", "rand" ); //! return int between 0 and RAND_MAX
217 QUERY
->add_sfun( QUERY
, rand2_impl
, "int", "rand2" ); //! integer between [min,max]
218 QUERY
->add_arg( QUERY
, "int", "min" );
219 QUERY
->add_arg( QUERY
, "int", "max" );
222 QUERY
->add_sfun( QUERY
, randf_impl
, "float", "randf" ); //! rand between -1.0,1.0
225 QUERY
->add_sfun( QUERY
, rand2f_impl
, "float", "rand2f" ); //! rand between min and max
226 QUERY
->add_arg( QUERY
, "float", "min" );
227 QUERY
->add_arg( QUERY
, "float", "max" );
230 //! see \example mand-o-matic.ck
231 QUERY
->add_sfun( QUERY
, mtof_impl
, "float", "mtof" ); //! midi note to frequency
232 QUERY
->add_arg( QUERY
, "float", "value" );
235 QUERY
->add_sfun( QUERY
, ftom_impl
, "float", "ftom" ); //! frequency to midi note
236 QUERY
->add_arg( QUERY
, "float", "value" );
239 QUERY
->add_sfun( QUERY
, powtodb_impl
, "float", "powtodb" ); //! linear power to decibel
240 QUERY
->add_arg( QUERY
, "float", "value" );
243 QUERY
->add_sfun( QUERY
, rmstodb_impl
, "float", "rmstodb" ); //! rms to decibel
244 QUERY
->add_arg( QUERY
, "float", "value" );
247 QUERY
->add_sfun( QUERY
, dbtopow_impl
, "float", "dbtopow" ); //! decibel to linear
248 QUERY
->add_arg( QUERY
, "float", "value" );
251 QUERY
->add_sfun( QUERY
, dbtorms_impl
, "float", "dbtorms" ); //! decibel to rms
252 QUERY
->add_arg( QUERY
, "float", "value" );
255 QUERY
->add_sfun( QUERY
, re_impl
, "float", "re" ); //! real component of complex
256 QUERY
->add_arg( QUERY
, "complex", "value" );
259 QUERY
->add_sfun( QUERY
, im_impl
, "float", "im" ); //! imaginary component of complex
260 QUERY
->add_arg( QUERY
, "complex", "value" );
263 QUERY
->add_sfun( QUERY
, modulus_impl
, "float", "mag" ); //! mag
264 QUERY
->add_arg( QUERY
, "polar", "value" );
267 QUERY
->add_sfun( QUERY
, phase_impl
, "float", "phase" ); //! phase
268 QUERY
->add_arg( QUERY
, "polar", "value" );
271 QUERY
->add_sfun( QUERY
, rtop_impl
, "int", "rtop" ); // rect to polar
272 QUERY
->add_arg( QUERY
, "complex[]", "from" );
273 QUERY
->add_arg( QUERY
, "polar[]", "to" );
276 QUERY
->add_sfun( QUERY
, ptor_impl
, "int", "ptor" ); // polar to rect
277 QUERY
->add_arg( QUERY
, "polar[]", "from" );
278 QUERY
->add_arg( QUERY
, "complex[]", "to" );
281 //! see \example math.ck
282 QUERY
->add_svar( QUERY
, "float", "PI", TRUE
, &g_pi
);
285 QUERY
->add_svar( QUERY
, "float", "TWO_PI", TRUE
, &g_twopi
);
288 QUERY
->add_svar( QUERY
, "float", "E", TRUE
, &g_e
);
290 QUERY
->add_svar( QUERY
, "float", "e", TRUE
, &g_e
);
293 assert( sizeof(t_CKFLOAT
) == sizeof(double) );
294 QUERY
->add_svar( QUERY
, "float", "FLOAT_MAX", TRUE
, &g_floatMax
);
297 QUERY
->add_svar( QUERY
, "float", "FLOAT_MIN_MAG", TRUE
, &g_floatMin
);
300 assert( sizeof(t_CKINT
) == sizeof(long) );
301 QUERY
->add_svar( QUERY
, "int", "INT_MAX", TRUE
, &g_intMax
);
303 // infinity, using function to avoid potential "smart" compiler warning
304 g_inf
= 1.0 / fzero();
305 QUERY
->add_svar( QUERY
, "float", "INFINITY", TRUE
, &g_inf
);
308 QUERY
->add_svar( QUERY
, "complex", "I", TRUE
, &g_i
);
309 QUERY
->add_svar( QUERY
, "complex", "i", TRUE
, &g_i
);
312 QUERY
->add_svar( QUERY
, "complex", "J", TRUE
, &g_i
);
313 QUERY
->add_svar( QUERY
, "complex", "j", TRUE
, &g_i
);
316 QUERY
->end_class( QUERY
);
322 CK_DLL_SFUN( sin_impl
)
324 RETURN
->v_float
= ::sin( GET_CK_FLOAT(ARGS
) );
328 CK_DLL_SFUN( cos_impl
)
330 RETURN
->v_float
= ::cos( GET_CK_FLOAT(ARGS
) );
334 CK_DLL_SFUN( tan_impl
)
336 RETURN
->v_float
= ::tan( GET_CK_FLOAT(ARGS
) );
340 CK_DLL_SFUN( asin_impl
)
342 RETURN
->v_float
= ::asin( GET_CK_FLOAT(ARGS
) );
346 CK_DLL_SFUN( acos_impl
)
348 RETURN
->v_float
= ::acos( GET_CK_FLOAT(ARGS
) );
352 CK_DLL_SFUN( atan_impl
)
354 RETURN
->v_float
= ::atan( GET_CK_FLOAT(ARGS
) );
358 CK_DLL_SFUN( atan2_impl
)
360 t_CKFLOAT x
= GET_CK_FLOAT(ARGS
);
361 t_CKFLOAT y
= *((t_CKFLOAT
*)ARGS
+ 1 );
362 RETURN
->v_float
= ::atan2( x
, y
);
366 CK_DLL_SFUN( sinh_impl
)
368 RETURN
->v_float
= ::sinh( GET_CK_FLOAT(ARGS
) );
372 CK_DLL_SFUN( cosh_impl
)
374 RETURN
->v_float
= ::cosh( GET_CK_FLOAT(ARGS
) );
378 CK_DLL_SFUN( tanh_impl
)
380 RETURN
->v_float
= ::tanh( GET_CK_FLOAT(ARGS
) );
384 CK_DLL_SFUN( hypot_impl
)
386 t_CKFLOAT x
= GET_CK_FLOAT(ARGS
);
387 t_CKFLOAT y
= *((t_CKFLOAT
*)ARGS
+ 1);
388 RETURN
->v_float
= ::hypot( x
, y
);
392 CK_DLL_SFUN( pow_impl
)
394 t_CKFLOAT x
= GET_CK_FLOAT(ARGS
);
395 t_CKFLOAT y
= *((t_CKFLOAT
*)ARGS
+ 1);
396 RETURN
->v_float
= ::pow( x
, y
);
400 CK_DLL_SFUN( sqrt_impl
)
402 RETURN
->v_float
= ::sqrt( GET_CK_FLOAT(ARGS
) );
406 CK_DLL_SFUN( exp_impl
)
408 RETURN
->v_float
= ::exp( GET_CK_FLOAT(ARGS
) );
412 CK_DLL_SFUN( log_impl
)
414 RETURN
->v_float
= ::log( GET_CK_FLOAT(ARGS
) );
418 CK_DLL_SFUN( log2_impl
)
420 RETURN
->v_float
= ::log( GET_CK_FLOAT(ARGS
) )/::log( 2.0 );
424 CK_DLL_SFUN( log10_impl
)
426 RETURN
->v_float
= ::log10( GET_CK_FLOAT(ARGS
) );
430 CK_DLL_SFUN( floor_impl
)
432 RETURN
->v_float
= ::floor( GET_CK_FLOAT(ARGS
) );
436 CK_DLL_SFUN( ceil_impl
)
438 RETURN
->v_float
= ::ceil( GET_CK_FLOAT(ARGS
) );
442 CK_DLL_SFUN( round_impl
)
444 RETURN
->v_float
= round( GET_CK_FLOAT(ARGS
) );
448 CK_DLL_SFUN( trunc_impl
)
450 RETURN
->v_float
= trunc( GET_CK_FLOAT(ARGS
) );
454 CK_DLL_SFUN( fmod_impl
)
456 t_CKFLOAT x
= GET_CK_FLOAT(ARGS
);
457 t_CKFLOAT y
= *((t_CKFLOAT
*)ARGS
+ 1);
458 RETURN
->v_float
= fmod( x
, y
);
462 CK_DLL_SFUN( remainder_impl
)
464 t_CKFLOAT x
= GET_CK_FLOAT(ARGS
);
465 t_CKFLOAT y
= *((t_CKFLOAT
*)ARGS
+ 1);
466 RETURN
->v_float
= remainder( x
, y
);
470 CK_DLL_SFUN( min_impl
)
472 t_CKFLOAT x
= GET_CK_FLOAT(ARGS
);
473 t_CKFLOAT y
= *((t_CKFLOAT
*)ARGS
+ 1);
474 RETURN
->v_float
= x
< y
? x
: y
;
478 CK_DLL_SFUN( max_impl
)
480 t_CKFLOAT x
= GET_CK_FLOAT(ARGS
);
481 t_CKFLOAT y
= *((t_CKFLOAT
*)ARGS
+ 1);
482 RETURN
->v_float
= x
> y
? x
: y
;
486 CK_DLL_SFUN( isinf_impl
)
488 t_CKFLOAT x
= GET_CK_FLOAT(ARGS
);
489 #ifdef __PLATFORM_WIN32__
490 RETURN
->v_int
= !_finite( x
);
492 RETURN
->v_int
= isinf( x
);
497 CK_DLL_SFUN( isnan_impl
)
499 t_CKFLOAT x
= GET_CK_FLOAT(ARGS
);
500 #ifdef __PLATFORM_WIN32__
501 RETURN
->v_int
= _isnan( x
);
503 RETURN
->v_int
= isnan( x
);
508 CK_DLL_SFUN( floatMax_impl
)
511 if( sizeof(t_CKFLOAT
) == 8 )
512 RETURN
->v_float
= DBL_MAX
;
513 else if( sizeof(t_CKFLOAT
) == 4 )
514 RETURN
->v_float
= FLT_MAX
;
518 fprintf( stderr
, "[chuck]: internal error determining size of 'float' in floatMax()\n" );
519 RETURN
->v_float
= 0; // TODO: return NaN?
524 CK_DLL_SFUN( intMax_impl
)
527 if( sizeof(t_CKINT
) == 4 )
528 RETURN
->v_int
= LONG_MAX
;
532 fprintf( stderr
, "[chuck]: internal error determining size of 'int' in intMax()\n" );
537 // nextpow2 - thanks to Niklas Werner, via music-dsp
538 CK_DLL_SFUN( nextpow2_impl
)
540 t_CKINT x
= GET_CK_INT(ARGS
);
542 for( ; x
&= x
-1; xx
= x
);
543 RETURN
->v_int
= xx
* 2;
546 // ensurepow2 - thanks to Niklas Werner, via music-dsp
547 CK_DLL_SFUN( ensurepow2_impl
)
549 t_CKINT x
= GET_CK_INT(ARGS
);
551 for( ; x
&= x
-1; xx
= x
);
552 RETURN
->v_int
= xx
* 2;
556 CK_DLL_SFUN( re_impl
)
558 t_CKCOMPLEX x
= GET_NEXT_COMPLEX(ARGS
);
559 RETURN
->v_float
= x
.re
;
563 CK_DLL_SFUN( im_impl
)
565 t_CKCOMPLEX x
= GET_NEXT_COMPLEX(ARGS
);
566 RETURN
->v_float
= x
.im
;
570 CK_DLL_SFUN( modulus_impl
)
572 t_CKPOLAR x
= GET_NEXT_POLAR(ARGS
);
573 RETURN
->v_float
= x
.modulus
;
577 CK_DLL_SFUN( phase_impl
)
579 t_CKPOLAR x
= GET_NEXT_POLAR(ARGS
);
580 RETURN
->v_float
= x
.phase
;
585 CK_DLL_SFUN( rtop_impl
)
588 Chuck_Array16
* from
= (Chuck_Array16
*)GET_NEXT_OBJECT(ARGS
);
589 Chuck_Array16
* to
= (Chuck_Array16
*)GET_NEXT_OBJECT(ARGS
);
591 // make sure not null
595 EM_log( CK_LOG_WARNING
, "Math.rtop( ... ) was given one or more NULL arrays..." );
599 // find how much to copy
600 t_CKUINT count
= ck_min( from
->size(), to
->size() );
605 for( t_CKUINT i
= 0; i
< count
; i
++ )
609 p
.re
= ::hypot( c
.re
, c
.im
);
610 p
.im
= ::atan2( c
.im
, c
.re
);
615 // if( count < to->size() ) to->zero( count, to->size() );
616 if( count
< to
->size() ) to
->set_size( count
);
618 // return number of elements done
619 RETURN
->v_int
= count
;
624 CK_DLL_SFUN( ptor_impl
)
627 Chuck_Array16
* from
= (Chuck_Array16
*)GET_NEXT_OBJECT(ARGS
);
628 Chuck_Array16
* to
= (Chuck_Array16
*)GET_NEXT_OBJECT(ARGS
);
630 // make sure not null
634 EM_log( CK_LOG_WARNING
, "Math.ptor( ... ) was given one or more NULL arrays..." );
638 // find how much to copy
639 t_CKUINT count
= ck_min( from
->size(), to
->size() );
644 for( t_CKUINT i
= 0; i
< count
; i
++ )
647 from
->get( i
, (t_CKCOMPLEX
*)&p
);
648 c
.re
= p
.modulus
* ::cos( p
.phase
);
649 c
.im
= p
.modulus
* ::sin( p
.phase
);
654 // if( count < to->capacity() ) to->zero( count, to->size() );
655 if( count
< to
->size() ) to
->set_size( count
);
657 // return number of elements done
658 RETURN
->v_int
= count
;