*** empty log message ***
[chuck-blob.git] / v2 / ugen_osc.cpp
blob90eb71d6a3af5a4362aa458fac58b265a7bc50dc
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: ugen_osc.cpp
27 // desc: ...
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
31 // Philip L. Davidson (philipd@alumni.princeton.edu)
32 // date: Summer 2004
33 //-----------------------------------------------------------------------------
34 #include "ugen_osc.h"
35 #include "chuck_type.h"
36 #include "chuck_ugen.h"
37 #include <math.h>
38 #include <stdio.h>
40 static t_CKUINT g_srate = 0;
41 // for member data offset
42 static t_CKUINT osc_offset_data = 0;
45 //-----------------------------------------------------------------------------
46 // name: osc_query()
47 // desc: ...
48 //-----------------------------------------------------------------------------
49 DLL_QUERY osc_query( Chuck_DL_Query * QUERY )
51 // srate
52 g_srate = QUERY->srate;
53 // get the env
54 Chuck_Env * env = Chuck_Env::instance();
56 Chuck_DL_Func * func = NULL;
58 // register deprecate
59 type_engine_register_deprecate( env, "osc", "Osc" );
60 type_engine_register_deprecate( env, "phasor", "Phasor" );
61 type_engine_register_deprecate( env, "sinosc", "SinOsc" );
62 type_engine_register_deprecate( env, "triosc", "TriOsc" );
63 type_engine_register_deprecate( env, "sawosc", "SawOsc" );
64 type_engine_register_deprecate( env, "pulseosc", "PulseOsc" );
65 type_engine_register_deprecate( env, "sqrosc", "SqrOsc" );
67 //---------------------------------------------------------------------
68 // init as base class: osc
69 //---------------------------------------------------------------------
70 if( !type_engine_import_ugen_begin( env, "Osc", "UGen", env->global(),
71 osc_ctor, osc_dtor, osc_tick, osc_pmsg ) )
72 return FALSE;
74 // add member variable
75 osc_offset_data = type_engine_import_mvar( env, "int", "@osc_data", FALSE );
76 if( osc_offset_data == CK_INVALID_OFFSET ) goto error;
78 // add ctrl: freq
79 func = make_new_mfun( "float", "freq", osc_ctrl_freq );
80 func->add_arg( "float", "hz" );
81 if( !type_engine_import_mfun( env, func ) ) goto error;
82 func = make_new_mfun( "float", "freq", osc_cget_freq );
83 if( !type_engine_import_mfun( env, func ) ) goto error;
85 // add ctrl: period
86 func = make_new_mfun( "dur", "period", osc_ctrl_period );
87 func->add_arg( "dur", "value" );
88 if( !type_engine_import_mfun( env, func ) ) goto error;
89 func = make_new_mfun( "dur", "period", osc_cget_period );
90 if( !type_engine_import_mfun( env, func ) ) goto error;
92 // add ctrl: sfreq ( == freq )
93 func = make_new_mfun( "float", "sfreq", osc_ctrl_freq );
94 func->add_arg( "float", "hz" );
95 if( !type_engine_import_mfun( env, func ) ) goto error;
97 // add ctrl: phase
98 func = make_new_mfun( "float", "phase", osc_ctrl_phase );
99 func->add_arg( "float", "phase" );
100 if( !type_engine_import_mfun( env, func ) ) goto error;
101 func = make_new_mfun( "float", "phase", osc_cget_phase );
102 if( !type_engine_import_mfun( env, func ) ) goto error;
104 // add ctrl: sync
105 func = make_new_mfun( "int", "sync", osc_ctrl_sync );
106 func->add_arg( "int", "type" );
107 if( !type_engine_import_mfun( env, func ) ) goto error;
108 func = make_new_mfun( "int", "sync", osc_cget_sync );
109 if( !type_engine_import_mfun( env, func ) ) goto error;
111 // end the class import
112 type_engine_import_class_end( env );
115 //---------------------------------------------------------------------
116 // phasor
117 //---------------------------------------------------------------------
118 if( !type_engine_import_ugen_begin( env, "Phasor", "Osc", env->global(),
119 NULL, NULL, osc_tick, NULL ) )
120 return FALSE;
122 // end the class import
123 type_engine_import_class_end( env );
125 //---------------------------------------------------------------------
126 // sinosc
127 //---------------------------------------------------------------------
128 if( !type_engine_import_ugen_begin( env, "SinOsc", "Osc", env->global(),
129 NULL, NULL, sinosc_tick, NULL ) )
130 return FALSE;
132 // end the class import
133 type_engine_import_class_end( env );
136 //---------------------------------------------------------------------
137 // triosc - triangle oscillator
138 //---------------------------------------------------------------------
139 if( !type_engine_import_ugen_begin( env, "TriOsc", "Osc", env->global(),
140 NULL, NULL, triosc_tick, NULL ) )
141 return FALSE;
143 func = make_new_mfun( "float", "width", osc_ctrl_width );
144 func->add_arg( "float", "width" );
145 if( !type_engine_import_mfun( env, func ) ) goto error;
147 // end the class import
148 type_engine_import_class_end( env );
151 //---------------------------------------------------------------------
152 // sawosc - sawtooth oscillator ( 0 | 1 triangle wave )
153 //---------------------------------------------------------------------
154 if( !type_engine_import_ugen_begin( env, "SawOsc", "TriOsc", env->global(),
155 sawosc_ctor, NULL, NULL, NULL ) )
156 return FALSE;
158 func = make_new_mfun( "float", "width", sawosc_ctrl_width );
159 func->add_arg( "float", "width" );
160 if( !type_engine_import_mfun( env, func ) ) goto error;
162 // end the class import
163 type_engine_import_class_end( env );
166 //---------------------------------------------------------------------
167 // pulseosc - pulse-width oscillator
168 //---------------------------------------------------------------------
169 if( !type_engine_import_ugen_begin( env, "PulseOsc", "Osc", env->global(),
170 NULL, NULL, pulseosc_tick, NULL ) )
171 return FALSE;
173 func = make_new_mfun( "float", "width", osc_ctrl_width );
174 func->add_arg( "float", "width" );
175 if( !type_engine_import_mfun( env, func ) ) goto error;
177 // end the class import
178 type_engine_import_class_end( env );
181 //---------------------------------------------------------------------
182 // sqrosc - square_wave oscillator ( 0.5 pulse )
183 //---------------------------------------------------------------------
184 if( !type_engine_import_ugen_begin( env, "SqrOsc", "PulseOsc", env->global(),
185 sqrosc_ctor, NULL, NULL, NULL ) )
186 return FALSE;
188 func = make_new_mfun( "float", "width", sqrosc_ctrl_width );
189 func->add_arg( "float", "width" );
190 if( !type_engine_import_mfun( env, func ) ) goto error;
192 // end the class import
193 type_engine_import_class_end( env );
195 // include GenX!!!
196 if( !genX_query( QUERY ) )
197 return FALSE;
199 return TRUE;
201 error:
203 // end the class import
204 type_engine_import_class_end( env );
206 return FALSE;
212 //-----------------------------------------------------------------------------
213 // name: struct Osc_Data
214 // desc: ...
215 //-----------------------------------------------------------------------------
216 struct Osc_Data
218 t_CKFLOAT num;
219 t_CKFLOAT freq;
220 int sync;
221 t_CKUINT srate;
222 t_CKFLOAT width;
224 t_CKFLOAT phase;
226 Osc_Data()
228 num = 0.0;
229 freq = 220.0;
230 sync = 0; // internal
231 width = 0.5;
232 srate = g_srate;
233 phase = 0.0;
240 //-----------------------------------------------------------------------------
241 // name: osc_ctor()
242 // desc: ...
243 //-----------------------------------------------------------------------------
244 CK_DLL_CTOR( osc_ctor )
246 Osc_Data * d = new Osc_Data;
247 Chuck_DL_Return r;
248 // return data to be used later
249 OBJ_MEMBER_UINT(SELF, osc_offset_data) = (t_CKUINT)d;
250 osc_ctrl_freq( SELF, &(d->freq), &r, SHRED );
256 //-----------------------------------------------------------------------------
257 // name: osc_dtor()
258 // desc: ...
259 //-----------------------------------------------------------------------------
260 CK_DLL_DTOR( osc_dtor )
262 // get the data
263 Osc_Data * data = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data );
264 // delete
265 delete data;
266 // set to NULL
267 OBJ_MEMBER_UINT(SELF, osc_offset_data) = 0;
273 //-----------------------------------------------------------------------------
274 // name: osc_tick()
275 // desc: ...
277 // basic osx is a phasor...
278 // we use a duty-cycle rep ( 0 - 1 ) rather than angular ( 0 - TWOPI )
279 // sinusoidal oscillators are special
281 // (maybe) as a rule, we store external phase control values
282 // so that we can have a smooth change back to internal control -pld
284 // technically this should happen even with external phase control
285 // that we'd be in the right place when translating back to internal...
286 // this was decidely inefficient and nit-picky. -pld
288 //-----------------------------------------------------------------------------
289 CK_DLL_TICK( osc_tick )
291 // get the data
292 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data );
293 Chuck_UGen * ugen = (Chuck_UGen *)SELF;
294 t_CKBOOL inc_phase = TRUE;
296 // if input
297 if( ugen->m_num_src )
299 // sync frequency to input
300 if( d->sync == 0 )
302 // set freq
303 d->freq = in;
304 // phase increment
305 d->num = d->freq / d->srate;
306 // bound it
307 if( d->num >= 1.0 ) d->num -= floor( d->num );
308 else if( d->num <= 1.0 ) d->num += floor( d->num );
310 // synch phase to input
311 else if( d->sync == 1 )
313 // set phase
314 d->phase = in;
315 // no update
316 inc_phase = FALSE;
318 // fm synthesis
319 else if( d->sync == 2 )
321 // set freq
322 t_CKFLOAT freq = d->freq + in;
323 // phase increment
324 d->num = freq / d->srate;
325 // bound it
326 if( d->num >= 1.0 ) d->num -= floor( d->num );
327 else if( d->num <= 1.0 ) d->num += floor( d->num );
329 // sync to now
330 // else if( d->sync == 3 )
331 // {
332 // d->phase = now * d->num;
333 // inc_phase = FALSE;
334 // }
337 // set output to current phase
338 *out = (SAMPLE)d->phase;
340 // check
341 if( inc_phase )
343 // step the phase.
344 d->phase += d->num;
345 // keep the phase between 0 and 1
346 if( d->phase > 1.0 ) d->phase -= 1.0;
349 return TRUE;
355 //-----------------------------------------------------------------------------
356 // name: sinosc_tick()
357 // desc: ...
358 //-----------------------------------------------------------------------------
359 CK_DLL_TICK( sinosc_tick )
361 // get the data
362 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data );
363 Chuck_UGen * ugen = (Chuck_UGen *)SELF;
364 t_CKBOOL inc_phase = TRUE;
366 // if input
367 if( ugen->m_num_src )
369 // sync frequency to input
370 if( d->sync == 0 )
372 // set freq
373 d->freq = in;
374 // phase increment
375 d->num = d->freq / d->srate;
376 // bound it
377 if( d->num >= 1.0 ) d->num -= floor( d->num );
378 else if( d->num <= 1.0 ) d->num += floor( d->num );
380 // sync phase to input
381 else if( d->sync == 1 )
383 // set freq
384 d->phase = in;
385 inc_phase = FALSE;
387 // FM synthesis
388 else if( d->sync == 2 )
390 // set freq
391 t_CKFLOAT freq = d->freq + in;
392 // phase increment
393 d->num = freq / d->srate;
394 // bound it
395 if( d->num >= 1.0 ) d->num -= floor( d->num );
396 else if( d->num <= 1.0 ) d->num += floor( d->num );
398 // sync phase to now
399 // else if( d->sync == 3 )
400 // {
401 // d->phase = now * d->num;
402 // inc_phase = FALSE;
403 // }
406 // set output
407 *out = (SAMPLE) ::sin( d->phase * TWO_PI );
409 if( inc_phase )
411 // next phase
412 d->phase += d->num;
413 // keep the phase between 0 and 1
414 if( d->phase > 1.0 ) d->phase -= 1.0;
417 return TRUE;
423 //-----------------------------------------------------------------------------
424 // name: triosc_tick()
425 // desc: ...
426 //-----------------------------------------------------------------------------
427 CK_DLL_TICK( triosc_tick )
429 // get the data
430 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data );
431 Chuck_UGen * ugen = (Chuck_UGen *)SELF;
432 t_CKBOOL inc_phase = TRUE;
434 // if input
435 if( ugen->m_num_src )
437 // sync frequency to input
438 if( d->sync == 0 )
440 // set freq
441 d->freq = in;
442 // phase increment
443 d->num = d->freq / d->srate;
444 // bound it
445 if( d->num >= 1.0 ) d->num -= floor( d->num );
446 else if( d->num <= 1.0 ) d->num += floor( d->num );
448 // sync phase to input
449 else if( d->sync == 1 )
451 // set freq
452 d->phase = in;
453 inc_phase = FALSE;
455 // FM synthesis
456 else if( d->sync == 2 )
458 // set freq
459 t_CKFLOAT freq = d->freq + in;
460 // phase increment
461 d->num = freq / d->srate;
462 // bound it
463 if( d->num >= 1.0 ) d->num -= floor( d->num );
464 else if( d->num <= 1.0 ) d->num += floor( d->num );
466 // sync to now
467 // if( d->sync == 3 )
468 // {
469 // d->phase = now * d->num;
470 // inc_phase = FALSE;
471 // }
474 // compute
475 t_CKFLOAT phase = d->phase + .25; if( phase > 1.0 ) phase -= 1.0;
476 if( phase < d->width ) *out = (SAMPLE) (d->width == 0.0) ? 1.0 : -1.0 + 2.0 * phase / d->width;
477 else *out = (SAMPLE) (d->width == 1.0) ? 0 : 1.0 - 2.0 * (phase - d->width) / (1.0 - d->width);
479 // advance internal phase
480 if( inc_phase )
482 d->phase += d->num;
483 // keep the phase between 0 and 1
484 if( d->phase > 1.0 ) d->phase -= 1.0;
487 return TRUE;
491 // sawosc_tick is tri_osc tick with width=0.0 or width=1.0 -pld
494 //-----------------------------------------------------------------------------
495 // name: pulseosc_tick()
496 // desc: ...
497 //-----------------------------------------------------------------------------
498 CK_DLL_TICK( pulseosc_tick )
500 // get the data
501 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data );
502 Chuck_UGen * ugen = (Chuck_UGen *)SELF;
503 t_CKBOOL inc_phase = TRUE;
505 // if input
506 if( ugen->m_num_src )
508 // sync frequency to input
509 if( d->sync == 0 )
511 // set freq
512 d->freq = in;
513 // phase increment
514 d->num = d->freq / d->srate;
515 // bound it
516 if( d->num >= 1.0 ) d->num -= floor( d->num );
517 else if( d->num <= 1.0 ) d->num += floor( d->num );
519 // sync phase to input
520 else if( d->sync == 1 )
522 // set freq
523 d->phase = in;
524 inc_phase = FALSE;
526 // FM synthesis
527 else if( d->sync == 2 )
529 // set freq
530 t_CKFLOAT freq = d->freq + in;
531 // phase increment
532 d->num = freq / d->srate;
533 // bound it
534 if( d->num >= 1.0 ) d->num -= floor( d->num );
535 else if( d->num <= 1.0 ) d->num += floor( d->num );
537 // sync to now
538 // if( d->sync == 3 )
539 // {
540 // d->phase = now * d->num;
541 // inc_phase = FALSE;
542 // }
545 // compute
546 *out = (SAMPLE) (d->phase < d->width) ? 1.0 : -1.0;
548 // move phase
549 if( inc_phase )
551 d->phase += d->num;
552 // keep the phase between 0 and 1
553 if( d->phase > 1.0 ) d->phase -= 1.0;
556 return TRUE;
560 // sqrosc_tick is pulseosc_tick at width=0.5 -pld;
563 //-----------------------------------------------------------------------------
564 // name: osc_ctrl_freq()
565 // desc: set oscillator frequency
566 //-----------------------------------------------------------------------------
567 CK_DLL_CTRL( osc_ctrl_freq )
569 // get data
570 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data);
571 // set freq
572 d->freq = GET_CK_FLOAT(ARGS);
573 // phase increment
574 d->num = d->freq / d->srate;
575 // bound it
576 if( d->num >= 1.0 ) d->num -= ::floor( d->num );
577 // return
578 RETURN->v_float = (t_CKFLOAT)d->freq;
584 //-----------------------------------------------------------------------------
585 // name: osc_cget_freq()
586 // desc: get oscillator frequency
587 //-----------------------------------------------------------------------------
588 CK_DLL_CGET( osc_cget_freq )
590 // get data
591 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data);
592 // return
593 RETURN->v_float = (t_CKFLOAT)d->freq;
599 //-----------------------------------------------------------------------------
600 // name: osc_ctrl_period()
601 // desc: set oscillator period
602 //-----------------------------------------------------------------------------
603 CK_DLL_CTRL( osc_ctrl_period )
605 // get data
606 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data);
607 t_CKDUR period = GET_CK_DUR(ARGS);
608 // test
609 if( period == 0.0 ) d->freq = 0.0;
610 // set freq
611 else d->freq = 1 / (period / d->srate);
612 d->num = d->freq / d->srate;
613 // bound it
614 if( d->num >= 1.0 ) d->num -= ::floor( d->num );
615 // return
616 RETURN->v_dur = period;
622 //-----------------------------------------------------------------------------
623 // name: osc_cget_period()
624 // desc: get oscillator period
625 //-----------------------------------------------------------------------------
626 CK_DLL_CGET( osc_cget_period )
628 // get data
629 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data);
630 t_CKDUR period = 0;
632 // get period
633 if( d->freq != 0.0 ) period = 1 / d->freq * d->srate;
635 // return
636 RETURN->v_dur = period;
642 //-----------------------------------------------------------------------------
643 // name: osc_ctrl_phase()
644 // desc: set oscillator phase wrapped to ( 0 - 1 )
645 //-----------------------------------------------------------------------------
646 CK_DLL_CTRL( osc_ctrl_phase )
648 // get data
649 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data );
650 // set freq
651 d->phase = GET_CK_FLOAT(ARGS);
652 //bound ( this could be set arbitrarily high or low )
653 if ( d->phase >= 1.0 || d->phase < 0.0 ) d->phase -= floor( d->num );
654 // return
655 RETURN->v_float = (t_CKFLOAT)d->phase;
661 //-----------------------------------------------------------------------------
662 // name: osc_cget_phase()
663 // desc: get oscillator phase wrapped to ( 0 - 1 )
664 //-----------------------------------------------------------------------------
665 CK_DLL_CGET( osc_cget_phase )
667 // get data
668 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data );
669 // return
670 RETURN->v_float = (t_CKFLOAT)d->phase;
676 //-----------------------------------------------------------------------------
677 // name: osc_ctrl_width()
678 // desc: set width of active phase ( bound 0.0 - 1.0 );
679 //-----------------------------------------------------------------------------
680 CK_DLL_CTRL( osc_ctrl_width )
682 // get data
683 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data );
684 // set freq
685 d->width = GET_CK_FLOAT(ARGS);
686 //bound ( this could be set arbitrarily high or low )
687 d->width = ck_max( 0.0, ck_min( 1.0, d->width ) );
688 // return
689 RETURN->v_float = (t_CKFLOAT)d->width;
695 //-----------------------------------------------------------------------------
696 // name: osc_cget_width()
697 // desc: get width of active phase ( bound 0.0 - 1.0 );
698 //-----------------------------------------------------------------------------
699 CK_DLL_CGET( osc_cget_width )
701 // get data
702 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data );
703 // return
704 RETURN->v_float = (t_CKFLOAT)d->width;
710 //-----------------------------------------------------------------------------
711 // name: sqrosc_ctor()
712 // desc: ...
713 //-----------------------------------------------------------------------------
714 CK_DLL_CTOR( sqrosc_ctor )
716 Osc_Data * d = new Osc_Data;
717 Chuck_DL_Return r;
718 sqrosc_ctrl_width( SELF, &(d->width), &r, SHRED );
724 //-----------------------------------------------------------------------------
725 // name: sqrosc_ctrl_width()
726 // desc: force width to 0.5;
727 //-----------------------------------------------------------------------------
728 CK_DLL_CTRL( sqrosc_ctrl_width )
730 // get data
731 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data );
732 // force value
733 d->width = 0.5;
734 // return
735 RETURN->v_float = (t_CKFLOAT)d->width;
741 //-----------------------------------------------------------------------------
742 // name: sawosc_ctor()
743 // desc: ...
744 //-----------------------------------------------------------------------------
745 CK_DLL_CTOR( sawosc_ctor )
747 Osc_Data * d = new Osc_Data;
748 Chuck_DL_Return r;
749 sawosc_ctrl_width( SELF, &(d->width), &r, SHRED );
755 //-----------------------------------------------------------------------------
756 // name: sawosc_ctrl_width()
757 // force width to 0.0 ( falling ) or 1.0 ( rising )
758 //-----------------------------------------------------------------------------
759 CK_DLL_CTRL( sawosc_ctrl_width )
761 // get data
762 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data );
763 // set freq
764 d->width = GET_CK_FLOAT(ARGS);
765 //bound ( this could be set arbitrarily high or low )
766 d->width = ( d->width < 0.5 ) ? 0.0 : 1.0; //rising or falling
767 // return
768 RETURN->v_float = (t_CKFLOAT)d->width;
774 //-----------------------------------------------------------------------------
775 // name: osc_ctrl_sync()
776 // desc: select sync mode for oscillator
777 //-----------------------------------------------------------------------------
778 CK_DLL_CTRL( osc_ctrl_sync )
780 // get data
781 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data );
782 // set sync
783 t_CKINT psync = d->sync;
784 d->sync = GET_CK_INT(ARGS);
786 // bound ( this could be set arbitrarily high or low )
787 if( d->sync < 0 || d->sync > 2 )
788 d->sync = 0;
790 if( d->sync == 0 && psync != d->sync )
792 // if we are switching to internal tick
793 // we need to pre-advance the phase...
794 // this is probably stupid. -pld
795 d->phase += d->num;
796 // keep the phase between 0 and 1
797 if( d->phase > 1.0 ) d->phase -= 1.0;
799 // return
800 RETURN->v_int = (t_CKINT)d->sync;
806 //-----------------------------------------------------------------------------
807 // name: osc_cget_sync()
808 // desc: get sync mode for oscillator
809 //-----------------------------------------------------------------------------
810 CK_DLL_CGET( osc_cget_sync )
812 // get data
813 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data );
814 // return
815 RETURN->v_int = (t_CKINT)d->sync;
821 //-----------------------------------------------------------------------------
822 // name: osc_pmsg()
823 // desc: ...
824 //-----------------------------------------------------------------------------
825 CK_DLL_PMSG( osc_pmsg )
827 Osc_Data * d = (Osc_Data *)OBJ_MEMBER_UINT(SELF, osc_offset_data );
828 if( !strcmp( MSG, "print" ) )
830 fprintf( stdout, "SinOsc: (freq=%f)", d->freq );
831 return TRUE;
834 // didn't handle
835 return FALSE;
841 //-----------------------------------------------------------------------------
842 // file: ugen_genX.cpp
843 // desc: thought it would be a good way to learn the fascinating innards of
844 // ChucK by porting some of the classic lookup table functions and adding
845 // a few new ones that might be of use.
846 // mostly ported from RTcmix (all by WarpTable)
848 // author: Dan Trueman (dtrueman.princeton.edu)
849 // date: Winter 2007
850 //-----------------------------------------------------------------------------
851 // for member data offset
852 static t_CKUINT genX_offset_data = 0;
853 // for internal usage
854 static void _transition( t_CKDOUBLE a, t_CKDOUBLE alpha, t_CKDOUBLE b,
855 t_CKINT n, t_CKDOUBLE * output );
859 //-----------------------------------------------------------------------------
860 // name: genX_query()
861 // desc: ...
862 //-----------------------------------------------------------------------------
863 DLL_QUERY genX_query( Chuck_DL_Query * QUERY )
865 // srate
866 g_srate = QUERY->srate;
867 // get the env
868 Chuck_Env * env = Chuck_Env::instance();
870 Chuck_DL_Func * func = NULL;
872 //---------------------------------------------------------------------
873 // init as base class: genX
874 //---------------------------------------------------------------------
875 if( !type_engine_import_ugen_begin( env, "GenX", "UGen", env->global(),
876 genX_ctor, genX_dtor, genX_tick, genX_pmsg ) )
877 return FALSE;
879 // add member variable
880 genX_offset_data = type_engine_import_mvar( env, "int", "@GenX_data", FALSE );
881 if( genX_offset_data == CK_INVALID_OFFSET ) goto error;
883 func = make_new_mfun( "float", "lookup", genX_lookup ); //lookup table value
884 func->add_arg( "float", "which" );
885 if( !type_engine_import_mfun( env, func ) ) goto error;
887 func = make_new_mfun( "float[]", "coefs", genX_coeffs ); //load table
888 func->add_arg( "float", "v[]" );
889 if( !type_engine_import_mfun( env, func ) ) goto error;
891 // end the class import
892 type_engine_import_class_end( env );
895 //---------------------------------------------------------------------
896 // gen5
897 //---------------------------------------------------------------------
898 if( !type_engine_import_ugen_begin( env, "Gen5", "GenX", env->global(),
899 NULL, NULL, genX_tick, NULL ) )
900 return FALSE;
902 func = make_new_mfun( "float[]", "coefs", gen5_coeffs ); //load table
903 func->add_arg( "float", "v[]" );
904 if( !type_engine_import_mfun( env, func ) ) goto error;
906 // end the class import
907 type_engine_import_class_end( env );
911 //---------------------------------------------------------------------
912 // gen7
913 //---------------------------------------------------------------------
914 if( !type_engine_import_ugen_begin( env, "Gen7", "GenX", env->global(),
915 NULL, NULL, genX_tick, NULL ) )
916 return FALSE;
918 func = make_new_mfun( "float[]", "coefs", gen7_coeffs ); //load table
919 func->add_arg( "float", "v[]" );
920 if( !type_engine_import_mfun( env, func ) ) goto error;
922 // end the class import
923 type_engine_import_class_end( env );
926 //---------------------------------------------------------------------
927 // gen9
928 //---------------------------------------------------------------------
929 if( !type_engine_import_ugen_begin( env, "Gen9", "GenX", env->global(),
930 NULL, NULL, genX_tick, NULL ) )
931 return FALSE;
933 func = make_new_mfun( "float[]", "coefs", gen9_coeffs ); //load table
934 func->add_arg( "float", "v[]" );
935 if( !type_engine_import_mfun( env, func ) ) goto error;
937 // end the class import
938 type_engine_import_class_end( env );
942 //---------------------------------------------------------------------
943 // gen10
944 //---------------------------------------------------------------------
945 if( !type_engine_import_ugen_begin( env, "Gen10", "GenX", env->global(),
946 NULL, NULL, genX_tick, NULL ) )
947 return FALSE;
949 func = make_new_mfun( "float[]", "coefs", gen10_coeffs ); //load table
950 func->add_arg( "float", "v[]" );
951 if( !type_engine_import_mfun( env, func ) ) goto error;
953 // end the class import
954 type_engine_import_class_end( env );
957 //---------------------------------------------------------------------
958 // gen17
959 //---------------------------------------------------------------------
960 if( !type_engine_import_ugen_begin( env, "Gen17", "GenX", env->global(),
961 NULL, NULL, genX_tick, NULL ) )
962 return FALSE;
964 func = make_new_mfun( "float[]", "coefs", gen17_coeffs ); //load table
965 func->add_arg( "float", "v[]" );
966 if( !type_engine_import_mfun( env, func ) ) goto error;
968 // end the class import
969 type_engine_import_class_end( env );
971 //---------------------------------------------------------------------
972 // Curve
973 //---------------------------------------------------------------------
974 if( !type_engine_import_ugen_begin( env, "CurveTable", "GenX", env->global(),
975 NULL, NULL, genX_tick, NULL ) )
976 return FALSE;
978 func = make_new_mfun( "float[]", "coefs", curve_coeffs ); //load table
979 func->add_arg( "float", "v[]" );
980 if( !type_engine_import_mfun( env, func ) ) goto error;
982 // end the class import
983 type_engine_import_class_end( env );
985 //---------------------------------------------------------------------
986 // Warp
987 //---------------------------------------------------------------------
988 if( !type_engine_import_ugen_begin( env, "WarpTable", "GenX", env->global(),
989 NULL, NULL, genX_tick, NULL ) )
990 return FALSE;
992 func = make_new_mfun( "float[]", "coefs", warp_coeffs ); //load table
993 func->add_arg( "float", "v[]" );
994 if( !type_engine_import_mfun( env, func ) ) goto error;
997 func = make_new_mfun( "float", "coefs", warp_coeffs ); //load table
998 func->add_arg( "float", "asym" );
999 func->add_arg( "float", "sym" );
1000 if( !type_engine_import_mfun( env, func ) ) goto error;
1003 // end the class import
1004 type_engine_import_class_end( env );
1007 return TRUE;
1009 error:
1011 // end the class import
1012 type_engine_import_class_end( env );
1014 return FALSE;
1020 //-----------------------------------------------------------------------------
1021 // name: struct genX_Data
1022 // desc: ...
1023 //-----------------------------------------------------------------------------
1024 #define genX_tableSize 4096
1025 #define genX_MAX_COEFFS 100
1027 struct genX_Data
1029 t_CKUINT genX_type;
1030 t_CKDOUBLE genX_table[genX_tableSize];
1031 // gewang: was int
1032 t_CKINT sync;
1033 t_CKUINT srate;
1034 t_CKFLOAT xtemp;
1035 t_CKDOUBLE coeffs[genX_MAX_COEFFS];
1037 genX_Data()
1039 //initialize data here
1040 sync = 0;
1041 srate = g_srate;
1043 t_CKINT i;
1044 for( i=0; i<genX_MAX_COEFFS; i++ ) coeffs[i] = 0.;
1045 for( i=0; i<genX_tableSize; i++ ) genX_table[i] = 0.;
1052 //-----------------------------------------------------------------------------
1053 // name: genX_ctor()
1054 // desc: ...
1055 //-----------------------------------------------------------------------------
1056 CK_DLL_CTOR( genX_ctor )
1058 genX_Data * d = new genX_Data;
1059 Chuck_DL_Return r;
1060 // return data to be used later
1061 OBJ_MEMBER_UINT(SELF, genX_offset_data) = (t_CKUINT)d;
1062 //gen10_coeffs( SELF, &(d->xtemp), &r );
1068 //-----------------------------------------------------------------------------
1069 // name: genX_dtor()
1070 // desc: ...
1071 //-----------------------------------------------------------------------------
1072 CK_DLL_DTOR( genX_dtor )
1074 // get the data
1075 genX_Data * data = (genX_Data *)OBJ_MEMBER_UINT(SELF, genX_offset_data );
1076 // delete
1077 SAFE_DELETE(data);
1078 // set to NULL
1079 OBJ_MEMBER_UINT(SELF, genX_offset_data) = 0;
1085 //-----------------------------------------------------------------------------
1086 // name: genX_tick()
1087 // desc: ...
1088 //-----------------------------------------------------------------------------
1089 CK_DLL_TICK( genX_tick )
1091 // get the data
1092 genX_Data * d = (genX_Data *)OBJ_MEMBER_UINT(SELF, genX_offset_data );
1093 Chuck_UGen * ugen = (Chuck_UGen *)SELF;
1094 t_CKBOOL inc_phase = TRUE;
1096 t_CKDOUBLE in_index = 0.0;
1097 t_CKDOUBLE scaled_index = 0.0;
1098 t_CKDOUBLE alpha = 0.0, omAlpha = 0.0;
1099 t_CKUINT lowIndex = 0, hiIndex = 0;
1100 t_CKDOUBLE outvalue = 0.0;
1102 // if input
1103 if( ugen->m_num_src ) {
1104 in_index = in;
1105 // gewang: moved this to here
1106 if( in_index < 0. ) in_index = -in_index;
1107 //scaled_index = (in_index + 1.) * 0.5 * genX_tableSize; //drive with oscillator, [-1, 1]
1108 scaled_index = in_index * genX_tableSize; //drive with phasor [0, 1]
1109 } else {
1110 scaled_index = 0.;
1113 // set up interpolation parameters
1114 lowIndex = (t_CKUINT)scaled_index;
1115 hiIndex = lowIndex + 1;
1116 alpha = scaled_index - lowIndex;
1117 omAlpha = 1. - alpha;
1119 // check table index ranges
1120 while(lowIndex >= genX_tableSize) lowIndex -= genX_tableSize;
1121 while(hiIndex >= genX_tableSize) hiIndex -= genX_tableSize;
1123 // could just call
1124 // outvalue = genX_lookup(in_index);?
1126 // calculate output value with linear interpolation
1127 outvalue = d->genX_table[lowIndex]*omAlpha + d->genX_table[hiIndex]*alpha;
1129 // set output
1130 *out = (SAMPLE)outvalue;
1132 return TRUE;
1136 //-----------------------------------------------------------------------------
1137 // name: genX_lookup()
1138 // desc: lookup call for all gens
1139 //-----------------------------------------------------------------------------
1140 CK_DLL_CTRL( genX_lookup )
1142 // get the data
1143 genX_Data * d = (genX_Data *)OBJ_MEMBER_UINT(SELF, genX_offset_data );
1145 t_CKFLOAT in_index;
1146 t_CKFLOAT scaled_index;
1147 t_CKFLOAT alpha, omAlpha;
1148 t_CKUINT lowIndex, hiIndex;
1149 t_CKFLOAT outvalue;
1151 in_index = GET_NEXT_FLOAT(ARGS);
1153 // gewang: moved to here
1154 if (in_index < 0.) in_index = -in_index;
1155 scaled_index = in_index * (genX_tableSize - 1); //drive with phasor [0, 1]
1157 //set up interpolation parameters
1158 lowIndex = (t_CKUINT)scaled_index;
1159 hiIndex = lowIndex + 1;
1160 alpha = scaled_index - lowIndex;
1161 omAlpha = 1. - alpha;
1163 //check table index ranges
1164 while(lowIndex >= genX_tableSize) lowIndex -= genX_tableSize;
1165 while(hiIndex >= genX_tableSize) hiIndex -= genX_tableSize;
1167 //calculate output value with linear interpolation
1168 outvalue = d->genX_table[lowIndex]*omAlpha + d->genX_table[hiIndex]*alpha;
1170 RETURN->v_float = (t_CKFLOAT)outvalue;
1175 //-----------------------------------------------------------------------------
1176 // name: gen5_coeffs()
1177 // desc: setup table for gen5
1178 //-----------------------------------------------------------------------------
1179 CK_DLL_CTRL( gen5_coeffs )
1181 // get data
1182 genX_Data * d = (genX_Data *)OBJ_MEMBER_UINT(SELF, genX_offset_data);
1183 t_CKINT i = 0, j, k, l, size;
1184 t_CKFLOAT wmax, xmax=0.0, c, amp2, amp1, coeffs[genX_MAX_COEFFS];
1186 Chuck_Array8 * in_args = (Chuck_Array8 *)GET_CK_OBJECT(ARGS);
1188 // fprintf(stdout, "calling gen10coeffs, %d\n", weights);
1189 if(in_args<0) return;
1190 size = in_args->size();
1191 if(size >= genX_MAX_COEFFS) size = genX_MAX_COEFFS - 1;
1193 t_CKFLOAT v;
1194 for(t_CKUINT ii = 0; ii<size; ii++) {
1195 in_args->get(ii, &v);
1196 // fprintf( stdout, "weight %d = %f...\n", ii, v );
1197 coeffs[ii] = v;
1200 amp2 = coeffs[0];
1201 if (amp2 <= 0.0) amp2 = 0.000001;
1202 for(k = 1; k < size; k += 2) {
1203 amp1 = amp2;
1204 amp2 = coeffs[k+1];
1205 if (amp2 <= 0.0) amp2 = 0.000001;
1206 j = i + 1;
1207 d->genX_table[i] = amp1;
1208 c = (t_CKFLOAT) pow((amp2/amp1),(1./(coeffs[k]*genX_tableSize)));
1209 i = (t_CKINT)((j - 1) + coeffs[k]*genX_tableSize);
1210 for(l = j; l < i; l++) {
1211 if(l < genX_tableSize)
1212 d->genX_table[l] = d->genX_table[l-1] * c;
1216 for(j = 0; j < genX_tableSize; j++) {
1217 if ((wmax = fabs(d->genX_table[j])) > xmax) xmax = wmax;
1218 // fprintf( stdout, "table current = %f\n", wmax);
1220 // fprintf( stdout, "table max = %f\n", xmax);
1221 for(j = 0; j < genX_tableSize; j++) {
1222 d->genX_table[j] /= xmax;
1225 // return
1226 RETURN->v_object = in_args;
1230 //-----------------------------------------------------------------------------
1231 // name: gen7_coeffs()
1232 // desc: setup table for gen7
1233 //-----------------------------------------------------------------------------
1234 CK_DLL_CTRL( gen7_coeffs )
1236 // get data
1237 genX_Data * d = (genX_Data *)OBJ_MEMBER_UINT(SELF, genX_offset_data);
1238 t_CKINT i=0, j, k, l, size;
1239 t_CKFLOAT wmax, xmax = 0.0, amp2, amp1, coeffs[genX_MAX_COEFFS];
1241 Chuck_Array8 * in_args = (Chuck_Array8 *)GET_CK_OBJECT(ARGS);
1243 // fprintf(stdout, "calling gen10coeffs, %d\n", weights);
1244 if(in_args<0) return;
1245 size = in_args->size();
1246 if(size >= genX_MAX_COEFFS) size = genX_MAX_COEFFS - 1;
1248 t_CKFLOAT v;
1249 for(t_CKUINT ii = 0; ii<size; ii++) {
1250 in_args->get(ii, &v);
1251 // fprintf( stdout, "weight %d = %f...\n", ii, v );
1252 coeffs[ii] = v;
1255 amp2 = coeffs[0];
1256 for (k = 1; k < size; k += 2) {
1257 amp1 = amp2;
1258 amp2 = coeffs[k + 1];
1259 j = i + 1;
1260 i = (t_CKINT)(j + coeffs[k]*genX_tableSize - 1);
1261 for (l = j; l <= i; l++) {
1262 if (l <= genX_tableSize)
1263 d->genX_table[l - 1] = amp1 +
1264 (amp2 - amp1) * (double) (l - j) / (i - j + 1);
1268 for(j = 0; j < genX_tableSize; j++) {
1269 if ((wmax = fabs(d->genX_table[j])) > xmax) xmax = wmax;
1270 // fprintf( stdout, "table current = %f\n", wmax);
1272 // fprintf( stdout, "table max = %f\n", xmax);
1273 for(j = 0; j < genX_tableSize; j++) {
1274 d->genX_table[j] /= xmax;
1277 // return
1278 RETURN->v_object = in_args;
1282 //-----------------------------------------------------------------------------
1283 // name: gen9_coeffs()
1284 // desc: setup table for gen9
1285 //-----------------------------------------------------------------------------
1286 CK_DLL_CTRL( gen9_coeffs )
1288 // get data
1289 genX_Data * d = (genX_Data *)OBJ_MEMBER_UINT(SELF, genX_offset_data);
1290 t_CKINT i, j, size;
1291 t_CKDOUBLE wmax, xmax=0.0;
1292 t_CKFLOAT coeffs[genX_MAX_COEFFS];
1294 Chuck_Array8 * weights = (Chuck_Array8 *)GET_CK_OBJECT(ARGS);
1296 // fprintf(stdout, "calling gen10coeffs, %d\n", weights);
1297 if(weights<0) return;
1298 size = weights->size();
1299 if(size >= genX_MAX_COEFFS) size = genX_MAX_COEFFS - 1;
1302 t_CKFLOAT v;
1303 for(t_CKUINT ii = 0; ii<size; ii++) {
1304 weights->get(ii, &v);
1305 // fprintf( stdout, "weight %d = %f...\n", ii, v );
1306 coeffs[ii] = v;
1309 for(j = size - 1; j > 0; j -= 3) {
1310 if(coeffs[j - 1] != 0) {
1311 for(i = 0; i < genX_tableSize; i++) {
1312 t_CKDOUBLE val = sin(TWO_PI * ((t_CKDOUBLE) i / ((t_CKDOUBLE) (genX_tableSize)
1313 / coeffs[j - 2]) + coeffs[j] / 360.));
1314 d->genX_table[i] += val * coeffs[j - 1];
1319 for(j = 0; j < genX_tableSize; j++) {
1320 if ((wmax = fabs(d->genX_table[j])) > xmax) xmax = wmax;
1321 // fprintf( stdout, "table current = %f\n", wmax);
1323 // fprintf( stdout, "table max = %f\n", xmax);
1324 for(j = 0; j < genX_tableSize; j++) {
1325 d->genX_table[j] /= xmax;
1328 // return
1329 RETURN->v_object = weights;
1333 //-----------------------------------------------------------------------------
1334 // name: gen10_coeffs()
1335 // desc: setup table for gen10
1336 //-----------------------------------------------------------------------------
1337 CK_DLL_CTRL( gen10_coeffs )
1339 // get data
1340 genX_Data * d = (genX_Data *)OBJ_MEMBER_UINT(SELF, genX_offset_data);
1341 t_CKINT i, j, size;
1342 t_CKDOUBLE wmax, xmax=0.0;
1344 Chuck_Array8 * weights = (Chuck_Array8 *)GET_CK_OBJECT(ARGS);
1346 // fprintf(stdout, "calling gen10coeffs, %d\n", weights);
1347 if(weights<0) return;
1348 size = weights->size();
1349 if(size >= genX_MAX_COEFFS) size = genX_MAX_COEFFS - 1;
1351 t_CKFLOAT v;
1352 for(t_CKUINT ii = 0; ii<size; ii++) {
1353 weights->get(ii, &v);
1354 // fprintf( stdout, "weight %d = %f...\n", ii, v );
1355 d->coeffs[ii] = v;
1358 j = genX_MAX_COEFFS;
1359 while (j--) {
1360 if (d->coeffs[j] != 0) {
1361 for (i = 0; i < genX_tableSize; i++) {
1362 t_CKDOUBLE val = (t_CKDOUBLE) (TWO_PI * (t_CKDOUBLE) i / (genX_tableSize / (j + 1)));
1363 d->genX_table[i] += sin(val) * d->coeffs[j];
1368 for(j = 0; j < genX_tableSize; j++) {
1369 if ((wmax = fabs(d->genX_table[j])) > xmax) xmax = wmax;
1370 // fprintf( stdout, "table current = %f\n", wmax);
1373 // fprintf( stdout, "table max = %f\n", xmax);
1374 for(j = 0; j < genX_tableSize; j++) {
1375 d->genX_table[j] /= xmax;
1378 // return
1379 RETURN->v_object = weights;
1383 //-----------------------------------------------------------------------------
1384 // name: gen17_coeffs()
1385 // desc: setup table for gen17
1386 //-----------------------------------------------------------------------------
1387 CK_DLL_CTRL( gen17_coeffs )
1389 // get data
1390 genX_Data * d = (genX_Data *)OBJ_MEMBER_UINT(SELF, genX_offset_data);
1391 t_CKINT i, j, size;
1392 t_CKDOUBLE Tn, Tn1, Tn2, dg, x, wmax = 0.0, xmax = 0.0;
1393 t_CKFLOAT coeffs[genX_MAX_COEFFS];
1395 Chuck_Array8 * weights = (Chuck_Array8 *)GET_CK_OBJECT(ARGS);
1397 // fprintf(stdout, "calling gen17coeffs, %d\n", weights);
1398 if(weights<0) return;
1399 size = weights->size();
1400 if(size >= genX_MAX_COEFFS) size = genX_MAX_COEFFS - 1;
1402 dg = (t_CKDOUBLE) (genX_tableSize / 2. - .5);
1404 t_CKFLOAT v;
1405 for(t_CKUINT ii = 0; ii<size; ii++) {
1406 weights->get(ii, &v);
1407 // fprintf( stdout, "weight %d = %f...\n", ii, v );
1408 coeffs[ii] = v;
1411 for (i = 0; i < genX_tableSize; i++) {
1412 x = (t_CKDOUBLE)(i / dg - 1.);
1413 d->genX_table[i] = 0.0;
1414 Tn1 = 1.0;
1415 Tn = x;
1416 for (j = 0; j < size; j++) {
1417 d->genX_table[i] = coeffs[j] * Tn + d->genX_table[i];
1418 Tn2 = Tn1;
1419 Tn1 = Tn;
1420 Tn = 2.0 * x * Tn1 - Tn2;
1424 for(j = 0; j < genX_tableSize; j++) {
1425 if ((wmax = fabs(d->genX_table[j])) > xmax) xmax = wmax;
1426 // fprintf( stdout, "table current = %f\n", wmax);
1428 // fprintf( stdout, "table max = %f\n", xmax);
1429 for(j = 0; j < genX_tableSize; j++) {
1430 d->genX_table[j] /= xmax;
1431 // fprintf( stdout, "table current = %f\n", d->genX_table[j]);
1434 // return
1435 RETURN->v_object = weights;
1439 //-----------------------------------------------------------------------------
1440 // name: curve_coeffs()
1441 // desc: setup table for Curve
1442 // ported from RTcmix
1443 //-----------------------------------------------------------------------------
1444 #define MAX_CURVE_PTS 256
1445 CK_DLL_CTRL( curve_coeffs )
1447 // get data
1448 genX_Data * d = (genX_Data *)OBJ_MEMBER_UINT(SELF, genX_offset_data);
1449 t_CKINT i, points, nargs, seglen = 0, len = genX_tableSize;
1450 t_CKDOUBLE factor, *ptr, xmax=0.0;
1451 t_CKDOUBLE time[MAX_CURVE_PTS], value[MAX_CURVE_PTS], alpha[MAX_CURVE_PTS];
1452 t_CKFLOAT coeffs[genX_MAX_COEFFS];
1453 t_CKUINT ii = 0;
1454 t_CKFLOAT v = 0.0;
1456 Chuck_Array8 * weights = (Chuck_Array8 *)GET_CK_OBJECT(ARGS);
1458 // fprintf(stdout, "calling gen17coeffs, %d\n", weights);
1459 if(weights<0) goto done;
1461 nargs = weights->size();
1462 if (nargs < 5 || (nargs % 3) != 2) { // check number of args
1463 fprintf( stderr, "[chuck](via CurveTable): usage: \n size, time1, value1, curvature1, [ timeN-1, valueN-1, curvatureN-1, ] timeN, valueN)\n" );
1464 goto done;
1466 if ((nargs / 3) + 1 > MAX_CURVE_PTS) {
1467 fprintf(stderr, ("[chuck](via CurveTable): too many arguments.\n"));
1468 goto done;
1471 for(ii = 0; ii<nargs; ii++) {
1472 weights->get(ii, &v);
1473 // fprintf( stdout, "weight %d = %f...\n", ii, v );
1474 coeffs[ii] = v;
1477 if (coeffs[0] != 0.0) {
1478 fprintf(stderr, "[chuck](via CurveTable): first time must be zero.\n");
1479 goto done;
1482 for (i = points = 0; i < nargs; points++) {
1483 time[points] = (t_CKDOUBLE) coeffs[i++];
1484 if (points > 0 && time[points] < time[points - 1])
1485 goto time_err;
1486 value[points] = (t_CKDOUBLE) coeffs[i++];
1487 if (i < nargs)
1488 alpha[points] = (t_CKDOUBLE) coeffs[i++];
1491 factor = (t_CKDOUBLE) (len - 1) / time[points - 1];
1492 for (i = 0; i < points; i++)
1493 time[i] *= factor;
1495 ptr = d->genX_table;
1496 for (i = 0; i < points - 1; i++) {
1497 seglen = (t_CKINT) (floor(time[i + 1] + 0.5) - floor(time[i] + 0.5)) + 1;
1498 _transition(value[i], alpha[i], value[i + 1], seglen, ptr);
1499 ptr += seglen - 1;
1502 done:
1503 // return
1504 RETURN->v_object = weights;
1506 return;
1508 time_err:
1509 fprintf(stderr, "[chuck](via CurveTable): times must be in ascending order.\n");
1511 // return
1512 RETURN->v_object = weights;
1514 return;
1518 static void _transition(t_CKDOUBLE a, t_CKDOUBLE alpha, t_CKDOUBLE b, t_CKINT n, t_CKDOUBLE *output)
1520 t_CKINT i;
1521 t_CKDOUBLE delta, interval = 0.0;
1523 delta = b - a;
1525 if (n <= 1) {
1526 //warn("maketable (curve)", "Trying to transition over 1 array slot; "
1527 // "time between points is too short");
1528 *output = a;
1529 return;
1531 interval = 1.0 / (n - 1.0);
1533 if (alpha != 0.0) {
1534 t_CKDOUBLE denom = 1.0 / (1.0 - exp(alpha));
1535 for (i = 0; i < n; i++)
1536 *output++ = (a + delta
1537 * (1.0 - exp((double) i * alpha * interval)) * denom);
1539 else
1540 for (i = 0; i < n; i++)
1541 *output++ = a + delta * i * interval;
1545 //-----------------------------------------------------------------------------
1546 // name: warp_coeffs()
1547 // desc: setup table for warp
1548 //-----------------------------------------------------------------------------
1549 CK_DLL_CTRL( warp_coeffs )
1551 // get data
1552 genX_Data * d = (genX_Data *)OBJ_MEMBER_UINT(SELF, genX_offset_data);
1553 t_CKINT i = 0;
1555 t_CKFLOAT k_asym = 1.;
1556 t_CKFLOAT k_sym = 1.;
1558 // gewang:
1559 Chuck_Array8 * weights = (Chuck_Array8 *)GET_CK_OBJECT(ARGS);
1560 // check for size
1561 if( weights->size() != 2 )
1563 // error
1564 fprintf( stderr, "[chuck](via WarpTable): expects array of exactly 2 elements.\n" );
1565 goto done;
1568 weights->get( 0, &k_asym ); // (t_CKDOUBLE) GET_NEXT_FLOAT(ARGS);
1569 weights->get( 1, &k_sym ); // (t_CKDOUBLE) GET_NEXT_FLOAT(ARGS);
1571 for (i = 0; i < genX_tableSize; i++) {
1572 t_CKDOUBLE inval = (t_CKDOUBLE) i/(genX_tableSize - 1);
1573 if(k_asym == 1 && k_sym == 1) {
1574 d->genX_table[i] = inval;
1575 } else if(k_sym == 1) {
1576 d->genX_table[i] = _asymwarp(inval, k_asym);
1577 } else if(k_asym == 1) {
1578 d->genX_table[i] = _symwarp(inval, k_sym);
1579 } else {
1580 inval = _asymwarp(inval, k_asym);
1581 d->genX_table[i] = _symwarp(inval, k_sym);
1583 // fprintf(stdout, "table %d = %f\n", i, d->genX_table[i]);
1586 done:
1588 // return
1589 RETURN->v_object = weights;
1593 t_CKDOUBLE _asymwarp(t_CKDOUBLE inval, t_CKDOUBLE k)
1595 return (pow(k, inval) - 1.) / (k - 1.);
1599 t_CKDOUBLE _symwarp(t_CKDOUBLE inval, t_CKDOUBLE k)
1601 t_CKDOUBLE sym_warped;
1602 if(inval >= 0.5) {
1603 sym_warped = pow(2.*inval - 1., 1./k);
1604 return (sym_warped + 1.) * 0.5;
1607 inval = 1. - inval; // for S curve
1608 sym_warped = pow(2.*inval - 1., 1./k);
1609 sym_warped = (sym_warped + 1.) * 0.5;
1611 return 1. - sym_warped;
1615 // also do RTcmix "spline" on a rainy day
1618 //-----------------------------------------------------------------------------
1619 // name: genX_pmsg()
1620 // desc: ...
1621 //-----------------------------------------------------------------------------
1622 CK_DLL_PMSG( genX_pmsg )
1624 genX_Data * d = (genX_Data *)OBJ_MEMBER_UINT(SELF, genX_offset_data );
1625 if( !strcmp( MSG, "print" ) )
1627 // fprintf( stdout, "genX:" );
1628 return TRUE;
1631 // didn't handle
1632 return FALSE;
1636 //-----------------------------------------------------------------------------
1637 // name: genX_coeffs()
1638 // desc: ...
1639 //-----------------------------------------------------------------------------
1640 CK_DLL_CTRL( genX_coeffs )
1642 // nope
1643 fprintf( stderr, "[chuck](via GenX): .coeffs called on abstract base class!\n" );
1645 // return
1646 RETURN->v_object = GET_NEXT_OBJECT(ARGS);
1648 return;