*** empty log message ***
[chuck-blob.git] / v2 / ulib_math.cpp
blob1ac1ada84f8d221f26b2a07e14dfb0f311aae7a7
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
22 U.S.A.
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
26 // file: ulib_math.cpp
27 // desc: ...
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
31 // date: Spring 2004
32 //-----------------------------------------------------------------------------
33 #include "chuck_type.h"
34 #include "ulib_math.h"
35 #include "util_math.h"
36 #include "ulib_std.h"
38 #include <limits.h>
39 #include <float.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 };
52 // query
53 DLL_QUERY libmath_query( Chuck_DL_Query * QUERY )
55 // get global
56 Chuck_Env * env = Chuck_Env::instance();
57 // name
58 QUERY->setname( QUERY, "Math" );
60 /*! \example
61 math.sin( math.pi /2.0 ) => stdout;
64 // register deprecate
65 type_engine_register_deprecate( env, "math", "Math" );
67 // add class
68 QUERY->begin_class( QUERY, "Math", "Object" );
70 // add abs
71 QUERY->add_sfun( QUERY, abs_impl, "int", "abs" );
72 QUERY->add_arg( QUERY, "int", "value" );
74 // add fabs
75 QUERY->add_sfun( QUERY, fabs_impl, "float", "fabs" );
76 QUERY->add_arg( QUERY, "float", "value" );
78 // add sgn
79 QUERY->add_sfun( QUERY, sgn_impl, "float", "sgn" );
80 QUERY->add_arg( QUERY, "float", "value" );
82 // sin
83 QUERY->add_sfun( QUERY, sin_impl, "float", "sin" );
84 QUERY->add_arg( QUERY, "float", "x" );
86 // cos
87 QUERY->add_sfun( QUERY, cos_impl, "float", "cos" );
88 QUERY->add_arg( QUERY, "float", "x" );
90 // tan
91 QUERY->add_sfun( QUERY, tan_impl, "float", "tan" );
92 QUERY->add_arg( QUERY, "float", "x" );
94 // asin
95 QUERY->add_sfun( QUERY, asin_impl, "float", "asin" );
96 QUERY->add_arg( QUERY, "float", "x" );
98 // acos
99 QUERY->add_sfun( QUERY, acos_impl, "float", "acos" );
100 QUERY->add_arg( QUERY, "float", "x" );
102 // atan
103 QUERY->add_sfun( QUERY, atan_impl, "float", "atan" );
104 QUERY->add_arg( QUERY, "float", "x" );
106 // atan2
107 QUERY->add_sfun( QUERY, atan2_impl, "float", "atan2" );
108 QUERY->add_arg( QUERY, "float", "y" );
109 QUERY->add_arg( QUERY, "float", "x" );
111 // sinh
112 QUERY->add_sfun( QUERY, sinh_impl, "float", "sinh" );
113 QUERY->add_arg( QUERY, "float", "x" );
115 // cosh
116 QUERY->add_sfun( QUERY, cosh_impl, "float", "cosh" );
117 QUERY->add_arg( QUERY, "float", "x" );
119 // tanh
120 QUERY->add_sfun( QUERY, tanh_impl, "float", "tanh" );
121 QUERY->add_arg( QUERY, "float", "x" );
123 // hypot
124 QUERY->add_sfun( QUERY, hypot_impl, "float", "hypot" );
125 QUERY->add_arg( QUERY, "float", "x" );
126 QUERY->add_arg( QUERY, "float", "y" );
128 // pow
129 QUERY->add_sfun( QUERY, pow_impl, "float", "pow" );
130 QUERY->add_arg( QUERY, "float", "x" );
131 QUERY->add_arg( QUERY, "float", "y" );
133 // sqrt
134 QUERY->add_sfun( QUERY, sqrt_impl, "float", "sqrt" );
135 QUERY->add_arg( QUERY, "float", "x" );
137 // exp
138 QUERY->add_sfun( QUERY, exp_impl, "float", "exp" );
139 QUERY->add_arg( QUERY, "float", "x" );
141 // log
142 QUERY->add_sfun( QUERY, log_impl, "float", "log" );
143 QUERY->add_arg( QUERY, "float", "x" );
145 // log2
146 QUERY->add_sfun( QUERY, log2_impl, "float", "log2" );
147 QUERY->add_arg( QUERY, "float", "x" );
149 // log10
150 QUERY->add_sfun( QUERY, log10_impl, "float", "log10" );
151 QUERY->add_arg( QUERY, "float", "x" );
153 // floor
154 QUERY->add_sfun( QUERY, floor_impl, "float", "floor" );
155 QUERY->add_arg( QUERY, "float", "x" );
157 // ceil
158 QUERY->add_sfun( QUERY, ceil_impl, "float", "ceil" );
159 QUERY->add_arg( QUERY, "float", "x" );
161 // round
162 QUERY->add_sfun( QUERY, round_impl, "float", "round" );
163 QUERY->add_arg( QUERY, "float", "x" );
165 // trunc
166 QUERY->add_sfun( QUERY, trunc_impl, "float", "trunc" );
167 QUERY->add_arg( QUERY, "float", "x" );
169 // fmod
170 QUERY->add_sfun( QUERY, fmod_impl, "float", "fmod" );
171 QUERY->add_arg( QUERY, "float", "x" );
172 QUERY->add_arg( QUERY, "float", "y" );
174 // remainder
175 QUERY->add_sfun( QUERY, remainder_impl, "float", "remainder" );
176 QUERY->add_arg( QUERY, "float", "x" );
177 QUERY->add_arg( QUERY, "float", "y" );
179 // min
180 QUERY->add_sfun( QUERY, min_impl, "float", "min" );
181 QUERY->add_arg( QUERY, "float", "x" );
182 QUERY->add_arg( QUERY, "float", "y" );
184 // max
185 //! see \example powerup.ck
186 QUERY->add_sfun( QUERY, max_impl, "float", "max" );
187 QUERY->add_arg( QUERY, "float", "x" );
188 QUERY->add_arg( QUERY, "float", "y" );
190 // isinf
191 QUERY->add_sfun( QUERY, isinf_impl, "int", "isinf" );
192 QUERY->add_arg( QUERY, "float", "x" );
194 // isnan
195 QUERY->add_sfun( QUERY, isnan_impl, "int", "isnan" );
196 QUERY->add_arg( QUERY, "float", "x" );
198 // floatMax
199 // QUERY->add_sfun( QUERY, floatMax_impl, "float", "floatMax" );
201 // intMax
202 // QUERY->add_sfun( QUERY, intMax_impl, "int", "intMax" );
204 // nextpow2
205 QUERY->add_sfun( QUERY, nextpow2_impl, "int", "nextpow2" );
206 QUERY->add_arg( QUERY, "int", "n" );
208 // ensurepow2
209 QUERY->add_sfun( QUERY, ensurepow2_impl, "int", "ensurePow2" );
210 QUERY->add_arg( QUERY, "int", "n" );
212 // rand
213 QUERY->add_sfun( QUERY, rand_impl, "int", "rand" ); //! return int between 0 and RAND_MAX
215 // rand2
216 QUERY->add_sfun( QUERY, rand2_impl, "int", "rand2" ); //! integer between [min,max]
217 QUERY->add_arg( QUERY, "int", "min" );
218 QUERY->add_arg( QUERY, "int", "max" );
220 // randf
221 QUERY->add_sfun( QUERY, randf_impl, "float", "randf" ); //! rand between -1.0,1.0
223 // rand2f
224 QUERY->add_sfun( QUERY, rand2f_impl, "float", "rand2f" ); //! rand between min and max
225 QUERY->add_arg( QUERY, "float", "min" );
226 QUERY->add_arg( QUERY, "float", "max" );
228 // add mtof
229 //! see \example mand-o-matic.ck
230 QUERY->add_sfun( QUERY, mtof_impl, "float", "mtof" ); //! midi note to frequency
231 QUERY->add_arg( QUERY, "float", "value" );
233 // add ftom
234 QUERY->add_sfun( QUERY, ftom_impl, "float", "ftom" ); //! frequency to midi note
235 QUERY->add_arg( QUERY, "float", "value" );
237 // add powtodb
238 QUERY->add_sfun( QUERY, powtodb_impl, "float", "powtodb" ); //! linear power to decibel
239 QUERY->add_arg( QUERY, "float", "value" );
241 // add rmstodb
242 QUERY->add_sfun( QUERY, rmstodb_impl, "float", "rmstodb" ); //! rms to decibel
243 QUERY->add_arg( QUERY, "float", "value" );
245 // add dbtopow
246 QUERY->add_sfun( QUERY, dbtopow_impl, "float", "dbtopow" ); //! decibel to linear
247 QUERY->add_arg( QUERY, "float", "value" );
249 // add dbtorms
250 QUERY->add_sfun( QUERY, dbtorms_impl, "float", "dbtorms" ); //! decibel to rms
251 QUERY->add_arg( QUERY, "float", "value" );
253 // add re
254 QUERY->add_sfun( QUERY, re_impl, "float", "re" ); //! real component of complex
255 QUERY->add_arg( QUERY, "complex", "value" );
257 // add im
258 QUERY->add_sfun( QUERY, im_impl, "float", "im" ); //! imaginary component of complex
259 QUERY->add_arg( QUERY, "complex", "value" );
261 // add mag
262 QUERY->add_sfun( QUERY, modulus_impl, "float", "mag" ); //! mag
263 QUERY->add_arg( QUERY, "polar", "value" );
265 // add phase
266 QUERY->add_sfun( QUERY, phase_impl, "float", "phase" ); //! phase
267 QUERY->add_arg( QUERY, "polar", "value" );
269 // add rtop
270 QUERY->add_sfun( QUERY, rtop_impl, "int", "rtop" ); // rect to polar
271 QUERY->add_arg( QUERY, "complex[]", "from" );
272 QUERY->add_arg( QUERY, "polar[]", "to" );
274 // add ptor
275 QUERY->add_sfun( QUERY, ptor_impl, "int", "ptor" ); // polar to rect
276 QUERY->add_arg( QUERY, "polar[]", "from" );
277 QUERY->add_arg( QUERY, "complex[]", "to" );
279 // pi
280 //! see \example math.ck
281 QUERY->add_svar( QUERY, "float", "PI", TRUE, &g_pi );
283 // twopi
284 QUERY->add_svar( QUERY, "float", "TWO_PI", TRUE, &g_twopi );
286 // e
287 QUERY->add_svar( QUERY, "float", "E", TRUE, &g_e );
288 // e
289 QUERY->add_svar( QUERY, "float", "e", TRUE, &g_e );
291 // float max
292 assert( sizeof(t_CKFLOAT) == sizeof(double) );
293 QUERY->add_svar( QUERY, "float", "FLOAT_MAX", TRUE, &g_floatMax );
295 // float min
296 QUERY->add_svar( QUERY, "float", "FLOAT_MIN_MAG", TRUE, &g_floatMin );
298 // int max
299 assert( sizeof(t_CKINT) == sizeof(long) );
300 QUERY->add_svar( QUERY, "int", "INT_MAX", TRUE, &g_intMax );
302 // infinity
303 double zero = 0.0;
304 g_inf = 1.0 / zero;
305 QUERY->add_svar( QUERY, "float", "INFINITY", TRUE, &g_inf );
307 // i
308 QUERY->add_svar( QUERY, "complex", "I", TRUE, &g_i );
309 QUERY->add_svar( QUERY, "complex", "i", TRUE, &g_i );
311 // j
312 QUERY->add_svar( QUERY, "complex", "J", TRUE, &g_i );
313 QUERY->add_svar( QUERY, "complex", "j", TRUE, &g_i );
315 // done
316 QUERY->end_class( QUERY );
318 return TRUE;
321 // sin
322 CK_DLL_SFUN( sin_impl )
324 RETURN->v_float = ::sin( GET_CK_FLOAT(ARGS) );
327 // cos
328 CK_DLL_SFUN( cos_impl )
330 RETURN->v_float = ::cos( GET_CK_FLOAT(ARGS) );
333 // tan
334 CK_DLL_SFUN( tan_impl )
336 RETURN->v_float = ::tan( GET_CK_FLOAT(ARGS) );
339 // asin
340 CK_DLL_SFUN( asin_impl )
342 RETURN->v_float = ::asin( GET_CK_FLOAT(ARGS) );
345 // acos
346 CK_DLL_SFUN( acos_impl )
348 RETURN->v_float = ::acos( GET_CK_FLOAT(ARGS) );
351 // atan
352 CK_DLL_SFUN( atan_impl )
354 RETURN->v_float = ::atan( GET_CK_FLOAT(ARGS) );
357 // atan2
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 );
365 // sinh
366 CK_DLL_SFUN( sinh_impl )
368 RETURN->v_float = ::sinh( GET_CK_FLOAT(ARGS) );
371 // cosh
372 CK_DLL_SFUN( cosh_impl )
374 RETURN->v_float = ::cosh( GET_CK_FLOAT(ARGS) );
377 // tanh
378 CK_DLL_SFUN( tanh_impl )
380 RETURN->v_float = ::tanh( GET_CK_FLOAT(ARGS) );
383 // hypot
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 );
391 // pow
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 );
399 // sqrt
400 CK_DLL_SFUN( sqrt_impl )
402 RETURN->v_float = ::sqrt( GET_CK_FLOAT(ARGS) );
405 // exp
406 CK_DLL_SFUN( exp_impl )
408 RETURN->v_float = ::exp( GET_CK_FLOAT(ARGS) );
411 // log
412 CK_DLL_SFUN( log_impl )
414 RETURN->v_float = ::log( GET_CK_FLOAT(ARGS) );
417 // log2
418 CK_DLL_SFUN( log2_impl )
420 RETURN->v_float = ::log( GET_CK_FLOAT(ARGS) )/::log( 2.0 );
423 // log10
424 CK_DLL_SFUN( log10_impl )
426 RETURN->v_float = ::log10( GET_CK_FLOAT(ARGS) );
429 // floor
430 CK_DLL_SFUN( floor_impl )
432 RETURN->v_float = ::floor( GET_CK_FLOAT(ARGS) );
435 // ceil
436 CK_DLL_SFUN( ceil_impl )
438 RETURN->v_float = ::ceil( GET_CK_FLOAT(ARGS) );
441 // round
442 CK_DLL_SFUN( round_impl )
444 RETURN->v_float = round( GET_CK_FLOAT(ARGS) );
447 // trunc
448 CK_DLL_SFUN( trunc_impl )
450 RETURN->v_float = trunc( GET_CK_FLOAT(ARGS) );
453 // fmod
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 );
461 // remainder
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 );
469 // min
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;
477 // max
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;
485 // isinf
486 CK_DLL_SFUN( isinf_impl )
488 t_CKFLOAT x = GET_CK_FLOAT(ARGS);
489 #ifdef __PLATFORM_WIN32__
490 RETURN->v_int = !_finite( x );
491 #else
492 RETURN->v_int = isinf( x );
493 #endif
496 // isnan
497 CK_DLL_SFUN( isnan_impl )
499 t_CKFLOAT x = GET_CK_FLOAT(ARGS);
500 #ifdef __PLATFORM_WIN32__
501 RETURN->v_int = _isnan( x );
502 #else
503 RETURN->v_int = isnan( x );
504 #endif
507 // floatMax
508 CK_DLL_SFUN( floatMax_impl )
510 // check size
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;
515 else
517 // error
518 fprintf( stderr, "[chuck]: internal error determining size of 'float' in floatMax()\n" );
519 RETURN->v_float = 0; // TODO: return NaN?
523 // intMax
524 CK_DLL_SFUN( intMax_impl )
526 // check size
527 if( sizeof(t_CKINT) == 4 )
528 RETURN->v_int = LONG_MAX;
529 else
531 // error
532 fprintf( stderr, "[chuck]: internal error determining size of 'int' in intMax()\n" );
533 RETURN->v_int = 0;
537 // nextpow2 - thanks to Niklas Werner, via music-dsp
538 CK_DLL_SFUN( nextpow2_impl )
540 t_CKINT x = GET_CK_INT(ARGS);
541 t_CKINT xx = x;
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);
550 t_CKINT xx = --x;
551 for( ; x &= x-1; xx = x );
552 RETURN->v_int = xx * 2;
555 // re
556 CK_DLL_SFUN( re_impl )
558 t_CKCOMPLEX x = GET_NEXT_COMPLEX(ARGS);
559 RETURN->v_float = x.re;
562 // im
563 CK_DLL_SFUN( im_impl )
565 t_CKCOMPLEX x = GET_NEXT_COMPLEX(ARGS);
566 RETURN->v_float = x.im;
569 // modulus
570 CK_DLL_SFUN( modulus_impl )
572 t_CKPOLAR x = GET_NEXT_POLAR(ARGS);
573 RETURN->v_float = x.modulus;
576 // phase
577 CK_DLL_SFUN( phase_impl )
579 t_CKPOLAR x = GET_NEXT_POLAR(ARGS);
580 RETURN->v_float = x.phase;
584 // rtop
585 CK_DLL_SFUN( rtop_impl )
587 // get array
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
592 if( !from || !to )
594 // log
595 EM_log( CK_LOG_WARNING, "Math.rtop( ... ) was given one or more NULL arrays..." );
596 return;
599 // find how much to copy
600 t_CKUINT count = ck_min( from->size(), to->size() );
601 t_CKCOMPLEX c;
602 t_CKCOMPLEX p;
604 // convert
605 for( t_CKUINT i = 0; i < count; i++ )
607 // go for it
608 from->get( i, &c );
609 p.re = ::hypot( c.re, c.im );
610 p.im = ::atan2( c.im, c.re );
611 to->set( i, p );
614 // zero out the rest
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;
623 // ptor
624 CK_DLL_SFUN( ptor_impl )
626 // get array
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
631 if( !from || !to )
633 // log
634 EM_log( CK_LOG_WARNING, "Math.ptor( ... ) was given one or more NULL arrays..." );
635 return;
638 // find how much to copy
639 t_CKUINT count = ck_min( from->size(), to->size() );
640 t_CKCOMPLEX c;
641 t_CKPOLAR p;
643 // convert
644 for( t_CKUINT i = 0; i < count; i++ )
646 // go for it
647 from->get( i, (t_CKCOMPLEX *)&p );
648 c.re = p.modulus * ::cos( p.phase );
649 c.im = p.modulus * ::sin( p.phase );
650 to->set( i, c );
653 // zero out the rest
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;