*** empty log message ***
[chuck-blob.git] / v2 / ulib_math.cpp
blob4dea9d6eeb8857a175c4fbe925b61d47a47bab9d
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 };
50 static t_CKFLOAT fzero() { return 0.0; }
53 // query
54 DLL_QUERY libmath_query( Chuck_DL_Query * QUERY )
56 // get global
57 Chuck_Env * env = Chuck_Env::instance();
58 // name
59 QUERY->setname( QUERY, "Math" );
61 /*! \example
62 math.sin( math.pi /2.0 ) => stdout;
65 // register deprecate
66 type_engine_register_deprecate( env, "math", "Math" );
68 // add class
69 QUERY->begin_class( QUERY, "Math", "Object" );
71 // add abs
72 QUERY->add_sfun( QUERY, abs_impl, "int", "abs" );
73 QUERY->add_arg( QUERY, "int", "value" );
75 // add fabs
76 QUERY->add_sfun( QUERY, fabs_impl, "float", "fabs" );
77 QUERY->add_arg( QUERY, "float", "value" );
79 // add sgn
80 QUERY->add_sfun( QUERY, sgn_impl, "float", "sgn" );
81 QUERY->add_arg( QUERY, "float", "value" );
83 // sin
84 QUERY->add_sfun( QUERY, sin_impl, "float", "sin" );
85 QUERY->add_arg( QUERY, "float", "x" );
87 // cos
88 QUERY->add_sfun( QUERY, cos_impl, "float", "cos" );
89 QUERY->add_arg( QUERY, "float", "x" );
91 // tan
92 QUERY->add_sfun( QUERY, tan_impl, "float", "tan" );
93 QUERY->add_arg( QUERY, "float", "x" );
95 // asin
96 QUERY->add_sfun( QUERY, asin_impl, "float", "asin" );
97 QUERY->add_arg( QUERY, "float", "x" );
99 // acos
100 QUERY->add_sfun( QUERY, acos_impl, "float", "acos" );
101 QUERY->add_arg( QUERY, "float", "x" );
103 // atan
104 QUERY->add_sfun( QUERY, atan_impl, "float", "atan" );
105 QUERY->add_arg( QUERY, "float", "x" );
107 // atan2
108 QUERY->add_sfun( QUERY, atan2_impl, "float", "atan2" );
109 QUERY->add_arg( QUERY, "float", "y" );
110 QUERY->add_arg( QUERY, "float", "x" );
112 // sinh
113 QUERY->add_sfun( QUERY, sinh_impl, "float", "sinh" );
114 QUERY->add_arg( QUERY, "float", "x" );
116 // cosh
117 QUERY->add_sfun( QUERY, cosh_impl, "float", "cosh" );
118 QUERY->add_arg( QUERY, "float", "x" );
120 // tanh
121 QUERY->add_sfun( QUERY, tanh_impl, "float", "tanh" );
122 QUERY->add_arg( QUERY, "float", "x" );
124 // hypot
125 QUERY->add_sfun( QUERY, hypot_impl, "float", "hypot" );
126 QUERY->add_arg( QUERY, "float", "x" );
127 QUERY->add_arg( QUERY, "float", "y" );
129 // pow
130 QUERY->add_sfun( QUERY, pow_impl, "float", "pow" );
131 QUERY->add_arg( QUERY, "float", "x" );
132 QUERY->add_arg( QUERY, "float", "y" );
134 // sqrt
135 QUERY->add_sfun( QUERY, sqrt_impl, "float", "sqrt" );
136 QUERY->add_arg( QUERY, "float", "x" );
138 // exp
139 QUERY->add_sfun( QUERY, exp_impl, "float", "exp" );
140 QUERY->add_arg( QUERY, "float", "x" );
142 // log
143 QUERY->add_sfun( QUERY, log_impl, "float", "log" );
144 QUERY->add_arg( QUERY, "float", "x" );
146 // log2
147 QUERY->add_sfun( QUERY, log2_impl, "float", "log2" );
148 QUERY->add_arg( QUERY, "float", "x" );
150 // log10
151 QUERY->add_sfun( QUERY, log10_impl, "float", "log10" );
152 QUERY->add_arg( QUERY, "float", "x" );
154 // floor
155 QUERY->add_sfun( QUERY, floor_impl, "float", "floor" );
156 QUERY->add_arg( QUERY, "float", "x" );
158 // ceil
159 QUERY->add_sfun( QUERY, ceil_impl, "float", "ceil" );
160 QUERY->add_arg( QUERY, "float", "x" );
162 // round
163 QUERY->add_sfun( QUERY, round_impl, "float", "round" );
164 QUERY->add_arg( QUERY, "float", "x" );
166 // trunc
167 QUERY->add_sfun( QUERY, trunc_impl, "float", "trunc" );
168 QUERY->add_arg( QUERY, "float", "x" );
170 // fmod
171 QUERY->add_sfun( QUERY, fmod_impl, "float", "fmod" );
172 QUERY->add_arg( QUERY, "float", "x" );
173 QUERY->add_arg( QUERY, "float", "y" );
175 // remainder
176 QUERY->add_sfun( QUERY, remainder_impl, "float", "remainder" );
177 QUERY->add_arg( QUERY, "float", "x" );
178 QUERY->add_arg( QUERY, "float", "y" );
180 // min
181 QUERY->add_sfun( QUERY, min_impl, "float", "min" );
182 QUERY->add_arg( QUERY, "float", "x" );
183 QUERY->add_arg( QUERY, "float", "y" );
185 // max
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" );
191 // isinf
192 QUERY->add_sfun( QUERY, isinf_impl, "int", "isinf" );
193 QUERY->add_arg( QUERY, "float", "x" );
195 // isnan
196 QUERY->add_sfun( QUERY, isnan_impl, "int", "isnan" );
197 QUERY->add_arg( QUERY, "float", "x" );
199 // floatMax
200 // QUERY->add_sfun( QUERY, floatMax_impl, "float", "floatMax" );
202 // intMax
203 // QUERY->add_sfun( QUERY, intMax_impl, "int", "intMax" );
205 // nextpow2
206 QUERY->add_sfun( QUERY, nextpow2_impl, "int", "nextpow2" );
207 QUERY->add_arg( QUERY, "int", "n" );
209 // ensurepow2
210 QUERY->add_sfun( QUERY, ensurepow2_impl, "int", "ensurePow2" );
211 QUERY->add_arg( QUERY, "int", "n" );
213 // rand
214 QUERY->add_sfun( QUERY, rand_impl, "int", "rand" ); //! return int between 0 and RAND_MAX
216 // rand2
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" );
221 // randf
222 QUERY->add_sfun( QUERY, randf_impl, "float", "randf" ); //! rand between -1.0,1.0
224 // rand2f
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" );
229 // add mtof
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" );
234 // add ftom
235 QUERY->add_sfun( QUERY, ftom_impl, "float", "ftom" ); //! frequency to midi note
236 QUERY->add_arg( QUERY, "float", "value" );
238 // add powtodb
239 QUERY->add_sfun( QUERY, powtodb_impl, "float", "powtodb" ); //! linear power to decibel
240 QUERY->add_arg( QUERY, "float", "value" );
242 // add rmstodb
243 QUERY->add_sfun( QUERY, rmstodb_impl, "float", "rmstodb" ); //! rms to decibel
244 QUERY->add_arg( QUERY, "float", "value" );
246 // add dbtopow
247 QUERY->add_sfun( QUERY, dbtopow_impl, "float", "dbtopow" ); //! decibel to linear
248 QUERY->add_arg( QUERY, "float", "value" );
250 // add dbtorms
251 QUERY->add_sfun( QUERY, dbtorms_impl, "float", "dbtorms" ); //! decibel to rms
252 QUERY->add_arg( QUERY, "float", "value" );
254 // add re
255 QUERY->add_sfun( QUERY, re_impl, "float", "re" ); //! real component of complex
256 QUERY->add_arg( QUERY, "complex", "value" );
258 // add im
259 QUERY->add_sfun( QUERY, im_impl, "float", "im" ); //! imaginary component of complex
260 QUERY->add_arg( QUERY, "complex", "value" );
262 // add mag
263 QUERY->add_sfun( QUERY, modulus_impl, "float", "mag" ); //! mag
264 QUERY->add_arg( QUERY, "polar", "value" );
266 // add phase
267 QUERY->add_sfun( QUERY, phase_impl, "float", "phase" ); //! phase
268 QUERY->add_arg( QUERY, "polar", "value" );
270 // add rtop
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" );
275 // add ptor
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" );
280 // pi
281 //! see \example math.ck
282 QUERY->add_svar( QUERY, "float", "PI", TRUE, &g_pi );
284 // twopi
285 QUERY->add_svar( QUERY, "float", "TWO_PI", TRUE, &g_twopi );
287 // e
288 QUERY->add_svar( QUERY, "float", "E", TRUE, &g_e );
289 // e
290 QUERY->add_svar( QUERY, "float", "e", TRUE, &g_e );
292 // float max
293 assert( sizeof(t_CKFLOAT) == sizeof(double) );
294 QUERY->add_svar( QUERY, "float", "FLOAT_MAX", TRUE, &g_floatMax );
296 // float min
297 QUERY->add_svar( QUERY, "float", "FLOAT_MIN_MAG", TRUE, &g_floatMin );
299 // int max
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 );
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;