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 //-----------------------------------------------------------------------------
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
31 // Philip L. Davidson (philipd@alumni.princeton.edu)
33 //-----------------------------------------------------------------------------
39 #define TWO_PI (2.0 * 3.14159265358979323846)
40 static t_CKUINT g_srate
= 0;
42 //-----------------------------------------------------------------------------
45 //-----------------------------------------------------------------------------
46 DLL_QUERY
osc_query( Chuck_DL_Query
* QUERY
)
49 g_srate
= QUERY
->srate
;
51 //! \sectionMain oscillators
53 //! phasor - simple ramp generator ( 0 to 1 )
54 //! this can be fed into other oscillators ( with sync mode of 2 )
55 //! as a phase control. see \example sixty.ck for an example
56 QUERY
->ugen_add( QUERY
, "phasor", NULL
);
58 QUERY
->ugen_func( QUERY
, phasor_ctor
, osc_dtor
, osc_tick
, osc_pmsg
);
60 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_freq
, osc_cget_freq
, "float", "freq" ); //! oscillator frequency ( Hz )
61 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_sfreq
, osc_cget_freq
, "float", "sfreq" ); //! oscillator frequency ( Hz ) , phase-matched
62 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_phase_offset
, osc_cget_phase_offset
, "float", "phase_offset" ); //! phase offset
63 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_phase
, osc_cget_phase
, "float", "phase" ); //! current phase
64 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_sync
, osc_cget_sync
, "int", "sync" ); //! sync to global ( 1 ) or self ( 0 )
65 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_width
, osc_cget_width
, "float", "width" ); //! set duration of the ramp in each cycle. ( default 1.0)
68 //! (see \example osc.ck)
69 QUERY
->ugen_add( QUERY
, "sinosc", NULL
);
71 QUERY
->ugen_func( QUERY
, osc_ctor
, osc_dtor
, sinosc_tick
, osc_pmsg
);
73 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_freq
, osc_cget_freq
, "float", "freq" ); //! oscillator frequency ( Hz )
74 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_sfreq
, osc_cget_freq
, "float", "sfreq" ); //! oscillator frequency ( Hz ) , phase-matched
75 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_phase_offset
, osc_cget_phase_offset
, "float", "phase_offset" ); //! phase offset
76 QUERY
->ugen_ctrl( QUERY
, sinosc_ctrl_phase
, sinosc_cget_phase
, "float", "phase" ); //! current phase
77 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_sync
, osc_cget_sync
, "int", "sync" ); //! sync to self(0), global(1), input(2)
80 //! a pulse wave oscillator with variable width.
81 QUERY
->ugen_add( QUERY
, "pulseosc", NULL
);
83 QUERY
->ugen_func( QUERY
, osc_ctor
, osc_dtor
, pulseosc_tick
, osc_pmsg
);
85 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_freq
, osc_cget_freq
, "float", "freq" ); //! oscillator frequency ( Hz )
86 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_sfreq
, osc_cget_freq
, "float", "sfreq" ); //! oscillator frequency ( Hz ) , phase-matched
87 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_phase_offset
, osc_cget_phase_offset
, "float", "phase_offset" ); //! phase offset
88 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_phase
, osc_cget_phase
, "float", "phase" ); //! current phase
89 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_sync
, osc_cget_sync
, "int", "sync" ); //! sync to self(0), global(1), input(2)
90 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_width
, osc_cget_width
, "float", "width" ); //! length of duty cycle ( 0-1 )
92 //! square wave oscillator ( pulse with fixed width of 0.5 )
93 QUERY
->ugen_add( QUERY
, "sqrosc", NULL
);
95 QUERY
->ugen_func( QUERY
, osc_ctor
, osc_dtor
, sqrosc_tick
, osc_pmsg
);
97 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_freq
, osc_cget_freq
, "float", "freq" ); //! oscillator frequency ( Hz )
98 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_sfreq
, osc_cget_freq
, "float", "sfreq" ); //! oscillator frequency ( Hz ) , phase-matched
99 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_phase_offset
, osc_cget_phase_offset
, "float", "phase_offset" ); //! phase offset
100 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_phase
, osc_cget_phase
, "float", "phase" ); //! current phase
101 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_sync
, osc_cget_sync
, "int", "sync" ); //! sync to self(0), global(1), input(2)
103 //! triangle wave oscillator
104 QUERY
->ugen_add( QUERY
, "triosc", NULL
);
106 QUERY
->ugen_func( QUERY
, osc_ctor
, osc_dtor
, triosc_tick
, osc_pmsg
);
108 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_freq
, osc_cget_freq
, "float", "freq" ); //! oscillator frequency ( Hz )
109 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_sfreq
, osc_cget_freq
, "float", "sfreq" ); //! oscillator frequency ( Hz ) , phase-matched
110 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_phase_offset
, osc_cget_phase_offset
, "float", "phase_offset" ); //! phase offset
111 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_phase
, osc_cget_phase
, "float", "phase" ); //! current phase
112 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_sync
, osc_cget_sync
, "int", "sync" ); //! sync to self(0), global(1), input(2)
113 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_width
, osc_cget_width
, "float", "width" ); //! control midpoint of triangle ( 0 to 1 )
115 //! sawtooth wave oscillator ( triangle, width forced to 0.0 or 1.0 )
116 QUERY
->ugen_add( QUERY
, "sawosc", NULL
);
118 QUERY
->ugen_func( QUERY
, osc_ctor
, osc_dtor
, sawosc_tick
, osc_pmsg
);
120 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_freq
, osc_cget_freq
, "float", "freq" ); //! oscillator frequency ( Hz )
121 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_sfreq
, osc_cget_freq
, "float", "sfreq" ); //! oscillator frequency ( Hz ) , phase-matched
122 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_phase_offset
, osc_cget_phase_offset
, "float", "phase_offset" ); //! phase offset
123 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_phase
, osc_cget_phase
, "float", "phase" ); //! current phase
124 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_sync
, osc_cget_sync
, "int", "sync" ); //! sync to self(0), global(1), input(2)
125 QUERY
->ugen_ctrl( QUERY
, osc_ctrl_width
, osc_cget_width
, "float", "width" ); //! increasing ( w > 0.5 ) or decreasing ( w < 0.5 )
133 //-----------------------------------------------------------------------------
134 // name: struct Osc_Data
136 //-----------------------------------------------------------------------------
158 osc_ctrl_freq( 0, this, &freq
);
159 osc_ctrl_phase_offset( 0, this, &phase_offset
);
166 //-----------------------------------------------------------------------------
167 // name: sinosc_ctor()
169 //-----------------------------------------------------------------------------
170 UGEN_CTOR
osc_ctor( t_CKTIME now
)
172 // return data to be used later
176 //-----------------------------------------------------------------------------
177 // name: sinosc_ctor()
179 //-----------------------------------------------------------------------------
180 UGEN_CTOR
phasor_ctor( t_CKTIME now
)
182 // return data to be used later
183 Osc_Data
* d
= new Osc_Data
;
191 //-----------------------------------------------------------------------------
194 //-----------------------------------------------------------------------------
195 UGEN_DTOR
osc_dtor( t_CKTIME now
, void * data
)
198 delete (Osc_Data
*)data
;
204 //-----------------------------------------------------------------------------
207 //-----------------------------------------------------------------------------
208 UGEN_TICK
osc_tick( t_CKTIME now
, void * data
, SAMPLE in
, SAMPLE
* out
)
210 Osc_Data
* d
= (Osc_Data
*)data
;
211 //phase offsets don't mean so much when oscillators are keeping
212 //track of their own ticks, unless they are created at the same time..
214 if ( d
->sync
== 1 ) d
->t
= (double) now
;
215 float ph
= ( d
->sync
== 2 ) ? in
: d
->phase_offset
+ d
->t
* d
->num
;
217 *out
= (SAMPLE
) ( d
->width
!= 0.0 && ph
<= d
->width
) ? ph
/ d
->width
: 0.0 ;
219 if ( !d
->sync
) d
->t
+= 1.0;
225 //-----------------------------------------------------------------------------
226 // name: sinosc_tick()
228 //-----------------------------------------------------------------------------
229 UGEN_TICK
sinosc_tick( t_CKTIME now
, void * data
, SAMPLE in
, SAMPLE
* out
)
232 Osc_Data
* d
= (Osc_Data
*)data
;
234 if( d
->sync
== 1 ) d
->phase
= now
* d
->num
;
236 *out
= (SAMPLE
) ( d
->sync
== 2 ) ? sin( TWO_PI
* in
) : sin( TWO_PI
* d
->phase
);
238 if( d
->sync
== 0 ) d
->phase
+= d
->num
;
240 if( d
->phase
> TWO_PI
) fmod( d
->phase
, TWO_PI
);
245 //-----------------------------------------------------------------------------
246 // name: sinosc_tick()
248 //-----------------------------------------------------------------------------
249 UGEN_TICK
triosc_tick( t_CKTIME now
, void * data
, SAMPLE in
, SAMPLE
* out
)
251 Osc_Data
* d
= (Osc_Data
*)data
;
252 //phase offsets don't mean so much when oscillators are keeping
253 //track of their own ticks, unless they are created at the same time..
255 if ( d
->sync
== 1 ) d
->t
= (double) now
;
257 float ph
= ( d
->sync
== 2 ) ? in
: d
->phase_offset
+ d
->t
* d
->num
;
259 float width
= d
->width
;
260 if ( ph
< width
) *out
= ( width
== 0.0 ) ? 1.0 : -1.0 + 2.0 * ph
/ width
;
261 else *out
= ( width
== 1.0 ) ? 0 : 1.0 - 2.0 * (ph
- width
) / (1.0 - width
);
263 if ( !d
->sync
) d
->t
+= 1.0;
269 //-----------------------------------------------------------------------------
270 // name: pulseosc_tick()
272 //-----------------------------------------------------------------------------
273 UGEN_TICK
pulseosc_tick( t_CKTIME now
, void * data
, SAMPLE in
, SAMPLE
* out
)
275 Osc_Data
* d
= (Osc_Data
*)data
;
276 //phase offsets don't mean so much when oscillators are keeping
277 //track of their own ticks, unless they are created at the same time..
279 if ( d
->sync
== 1 ) d
->t
= (double) now
;
281 float ph
= ( d
->sync
== 2 ) ? in
: d
->phase_offset
+ d
->t
* d
->num
;
283 if ( ph
< d
->width
) *out
= -1.0;
286 if ( !d
->sync
) d
->t
+= 1.0;
291 //-----------------------------------------------------------------------------
292 // name: sqrosc_tick()
294 //-----------------------------------------------------------------------------
295 UGEN_TICK
sqrosc_tick( t_CKTIME now
, void * data
, SAMPLE in
, SAMPLE
* out
)
297 Osc_Data
* d
= (Osc_Data
*)data
;
299 return pulseosc_tick ( now
, data
, in
, out
);
302 //-----------------------------------------------------------------------------
303 // name: sawosc_tick()
305 //-----------------------------------------------------------------------------
306 UGEN_TICK
sawosc_tick( t_CKTIME now
, void * data
, SAMPLE in
, SAMPLE
* out
)
308 Osc_Data
* d
= (Osc_Data
*)data
;
309 d
->width
= ( d
->width
< 0.5 ) ? 0.0 : 1.0;
310 return triosc_tick ( now
, data
, in
, out
);
313 //-----------------------------------------------------------------------------
314 // name: osc_ctrl_freq()
315 // desc: set oscillator frequency
316 //-----------------------------------------------------------------------------
317 UGEN_CTRL
osc_ctrl_freq( t_CKTIME now
, void * data
, void * value
)
319 Osc_Data
* d
= (Osc_Data
*)data
;
320 d
->freq
= GET_CK_FLOAT(value
);
321 d
->num
= d
->freq
/ d
->srate
;
326 //-----------------------------------------------------------------------------
327 // name: sinosc_ctrl_sfreq()
328 // desc: sets oscillator frequency, implicitly adjusts phase offset to match
329 // avoid signal discontinuity. - pld
330 //-----------------------------------------------------------------------------
331 UGEN_CTRL
osc_ctrl_sfreq( t_CKTIME now
, void * data
, void * value
)
333 //phase matching freq adjust
334 Osc_Data
* d
= (Osc_Data
*)data
;
335 double curnum
= d
->num
;
336 d
->freq
= (float)GET_CK_FLOAT(value
);
337 d
->num
= d
->freq
/ d
->srate
;
338 double nphase
= d
->phase_offset
+ d
->t
* ( curnum
- d
->num
);
339 d
->phase_offset
= nphase
- floor ( nphase
);
342 //-----------------------------------------------------------------------------
343 // name: sinosc_cget_freq()
345 //-----------------------------------------------------------------------------
346 UGEN_CGET
osc_cget_freq( t_CKTIME now
, void * data
, void * out
)
348 Osc_Data
* d
= (Osc_Data
*)data
;
349 SET_NEXT_FLOAT( out
, (t_CKFLOAT
)d
->freq
);
354 //-----------------------------------------------------------------------------
355 // name: sinosc_ctrl_phase_offset()
356 // desc: explicitly set oscillator phase-offset -pld
357 //-----------------------------------------------------------------------------
358 UGEN_CTRL
osc_ctrl_phase_offset( t_CKTIME now
, void * data
, void * value
)
360 Osc_Data
* d
= (Osc_Data
*)data
;
361 d
->phase_offset
= (float)GET_CK_FLOAT(value
);
364 //-----------------------------------------------------------------------------
365 // name: sinosc_cget_phase_offset()
367 //-----------------------------------------------------------------------------
368 UGEN_CGET
osc_cget_phase_offset( t_CKTIME now
, void * data
, void * out
)
370 Osc_Data
* d
= (Osc_Data
*)data
;
371 SET_NEXT_FLOAT( out
, (t_CKFLOAT
)d
->phase_offset
);
376 //-----------------------------------------------------------------------------
377 // name: osc_ctrl_phase()
378 // desc: explicitly set oscillator phase -pld
379 //-----------------------------------------------------------------------------
380 UGEN_CTRL
osc_ctrl_phase ( t_CKTIME now
, void * data
, void * value
)
382 Osc_Data
* d
= (Osc_Data
*)data
;
383 t_CKFLOAT phase
= GET_CK_FLOAT(value
);
384 double cphase
= phase
- ( d
->t
* d
->num
);
385 d
->phase_offset
= cphase
- floor ( cphase
);
388 //-----------------------------------------------------------------------------
389 // name: osc_cget_phase()
391 //-----------------------------------------------------------------------------
392 UGEN_CGET
osc_cget_phase ( t_CKTIME now
, void * data
, void * out
)
394 Osc_Data
* d
= (Osc_Data
*)data
;
395 SET_NEXT_FLOAT( out
, (t_CKFLOAT
) d
->phase_offset
+ d
->t
* d
->num
);
399 //-----------------------------------------------------------------------------
400 // name: osc_ctrl_phase()
401 // desc: explicitly set oscillator phase -pld
402 //-----------------------------------------------------------------------------
403 UGEN_CTRL
sinosc_ctrl_phase ( t_CKTIME now
, void * data
, void * value
)
405 Osc_Data
* d
= (Osc_Data
*)data
;
406 d
->phase
= GET_CK_FLOAT(value
) / TWO_PI
;
409 //-----------------------------------------------------------------------------
410 // name: osc_cget_phase()
412 //-----------------------------------------------------------------------------
413 UGEN_CGET
sinosc_cget_phase ( t_CKTIME now
, void * data
, void * out
)
415 Osc_Data
* d
= (Osc_Data
*)data
;
416 SET_NEXT_FLOAT( out
, (t_CKFLOAT
) TWO_PI
* d
->phase
);
419 //-----------------------------------------------------------------------------
420 // name: sinosc_ctrl_sync()
421 // desc: set sync -pld
422 //-----------------------------------------------------------------------------
423 UGEN_CTRL
osc_ctrl_sync ( t_CKTIME now
, void * data
, void * value
)
425 Osc_Data
* d
= (Osc_Data
*)data
;
426 d
->sync
= GET_CK_INT(value
);
430 //-----------------------------------------------------------------------------
431 // name: sinosc_cget_sync()
433 //-----------------------------------------------------------------------------
434 UGEN_CGET
osc_cget_sync ( t_CKTIME now
, void * data
, void * out
)
436 Osc_Data
* d
= (Osc_Data
*)data
;
437 SET_NEXT_INT( out
, d
->sync
);
440 //-----------------------------------------------------------------------------
441 // name: sinosc_cget_width()
443 //-----------------------------------------------------------------------------
444 UGEN_CGET
osc_cget_width ( t_CKTIME now
, void * data
, void * out
)
446 Osc_Data
* d
= (Osc_Data
*)data
;
447 SET_NEXT_FLOAT( out
, d
->width
);
451 //-----------------------------------------------------------------------------
452 // name: sinosc_ctrl_width()
453 // desc: set sync -pld
454 //-----------------------------------------------------------------------------
455 UGEN_CTRL
osc_ctrl_width ( t_CKTIME now
, void * data
, void * value
)
457 Osc_Data
* d
= (Osc_Data
*)data
;
458 d
->width
= GET_CK_FLOAT(value
);
459 d
->width
-= floor ( d
->width
);
464 //-----------------------------------------------------------------------------
465 // name: sinosc_pmsg()
467 //-----------------------------------------------------------------------------
468 UGEN_PMSG
osc_pmsg( t_CKTIME now
, void * data
, const char * msg
, void * value
)
470 Osc_Data
* d
= (Osc_Data
*)data
;
471 if( !strcmp( msg
, "print" ) )
473 fprintf( stdout
, "sinosc: (freq=%f)", d
->freq
);