*** empty log message ***
[chuck-blob.git] / exile / v1 / src / ugen_osc.cpp
blob0a1cb9e4de2a95ac949c96e742a2ee85bf3e3752
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 <math.h>
36 #include <stdio.h>
39 #define TWO_PI (2.0 * 3.14159265358979323846)
40 static t_CKUINT g_srate = 0;
42 //-----------------------------------------------------------------------------
43 // name: osc_query()
44 // desc: ...
45 //-----------------------------------------------------------------------------
46 DLL_QUERY osc_query( Chuck_DL_Query * QUERY )
48 // srate
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 );
57 // set funcs
58 QUERY->ugen_func( QUERY, phasor_ctor, osc_dtor, osc_tick, osc_pmsg );
59 // add ctrls / cgets
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)
67 //! sine oscillator
68 //! (see \example osc.ck)
69 QUERY->ugen_add( QUERY, "sinosc", NULL );
70 // set funcs
71 QUERY->ugen_func( QUERY, osc_ctor, osc_dtor, sinosc_tick, osc_pmsg );
72 // add ctrls / cgets
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)
79 //! pulse oscillators
80 //! a pulse wave oscillator with variable width.
81 QUERY->ugen_add( QUERY, "pulseosc", NULL );
82 // set funcs
83 QUERY->ugen_func( QUERY, osc_ctor, osc_dtor, pulseosc_tick, osc_pmsg );
84 // add ctrls / cgets
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 );
94 // set funcs
95 QUERY->ugen_func( QUERY, osc_ctor, osc_dtor, sqrosc_tick, osc_pmsg );
96 // add ctrls / cgets
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 );
105 // set funcs
106 QUERY->ugen_func( QUERY, osc_ctor, osc_dtor, triosc_tick, osc_pmsg );
107 // add ctrls / cgets
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 );
117 // set funcs
118 QUERY->ugen_func( QUERY, osc_ctor, osc_dtor, sawosc_tick, osc_pmsg );
119 // add ctrls / cgets
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 )
127 return TRUE;
133 //-----------------------------------------------------------------------------
134 // name: struct Osc_Data
135 // desc: ...
136 //-----------------------------------------------------------------------------
137 struct Osc_Data
139 double t;
140 double num;
141 double freq;
142 double phase_offset;
143 int sync;
144 t_CKUINT srate;
145 double width;
147 double phase;
149 Osc_Data( )
151 t = 0.0;
152 num = 0.0;
153 freq = 220.0;
154 sync = 0; //internal
155 width = 0.5;
156 phase_offset = 0.0;
157 srate = g_srate;
158 osc_ctrl_freq( 0, this, &freq );
159 osc_ctrl_phase_offset( 0, this, &phase_offset );
161 phase = 0.0;
166 //-----------------------------------------------------------------------------
167 // name: sinosc_ctor()
168 // desc: ...
169 //-----------------------------------------------------------------------------
170 UGEN_CTOR osc_ctor( t_CKTIME now )
172 // return data to be used later
173 return new Osc_Data;
176 //-----------------------------------------------------------------------------
177 // name: sinosc_ctor()
178 // desc: ...
179 //-----------------------------------------------------------------------------
180 UGEN_CTOR phasor_ctor( t_CKTIME now )
182 // return data to be used later
183 Osc_Data * d = new Osc_Data;
184 d->width = 1.0;
185 return d;
191 //-----------------------------------------------------------------------------
192 // name: osc_dtor()
193 // desc: ...
194 //-----------------------------------------------------------------------------
195 UGEN_DTOR osc_dtor( t_CKTIME now, void * data )
197 // delete
198 delete (Osc_Data *)data;
204 //-----------------------------------------------------------------------------
205 // name: osc_tick()
206 // desc: ...
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;
216 ph -= floor ( ph );
217 *out = (SAMPLE) ( d->width != 0.0 && ph <= d->width ) ? ph / d->width : 0.0 ;
219 if ( !d->sync ) d->t += 1.0;
221 return TRUE;
225 //-----------------------------------------------------------------------------
226 // name: sinosc_tick()
227 // desc: ...
228 //-----------------------------------------------------------------------------
229 UGEN_TICK sinosc_tick( t_CKTIME now, void * data, SAMPLE in, SAMPLE * out )
231 // get this
232 Osc_Data * d = (Osc_Data *)data;
233 // sync to now
234 if( d->sync == 1 ) d->phase = now * d->num;
235 // compute
236 *out = (SAMPLE) ( d->sync == 2 ) ? sin( TWO_PI * in ) : sin( TWO_PI * d->phase );
237 // move phase
238 if( d->sync == 0 ) d->phase += d->num;
239 // unwrap
240 if( d->phase > TWO_PI ) fmod( d->phase, TWO_PI );
242 return TRUE;
245 //-----------------------------------------------------------------------------
246 // name: sinosc_tick()
247 // desc: ...
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;
258 ph -= floor ( ph );
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;
265 return TRUE;
269 //-----------------------------------------------------------------------------
270 // name: pulseosc_tick()
271 // desc: ...
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;
282 ph -= floor ( ph );
283 if ( ph < d->width ) *out = -1.0;
284 else *out = 1.0;
286 if ( !d->sync ) d->t += 1.0;
288 return TRUE;
291 //-----------------------------------------------------------------------------
292 // name: sqrosc_tick()
293 // desc: ...
294 //-----------------------------------------------------------------------------
295 UGEN_TICK sqrosc_tick( t_CKTIME now, void * data, SAMPLE in, SAMPLE * out )
297 Osc_Data * d = (Osc_Data *)data;
298 d->width = 0.5;
299 return pulseosc_tick ( now, data, in , out );
302 //-----------------------------------------------------------------------------
303 // name: sawosc_tick()
304 // desc: ...
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;
322 d->phase = 0.0;
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()
344 // desc: ...
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()
366 // desc: ...
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()
390 // desc: ...
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()
411 // desc: ...
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()
432 // desc: get 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()
442 // desc: get sync
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()
466 // desc: ...
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 );
474 return TRUE;
477 // didn't handle
478 return FALSE;