linux: shared memory interface - link with librt
[supercollider.git] / HelpSource / Classes / Shaper.schelp
blob1985253e89c3b431799f2c6b72c770b8688184f0
1 class:: Shaper
2 summary:: Wave shaper.
3 related:: Classes/Index, Classes/WrapIndex
4 categories::  UGens>Buffer
6 Description::
7 Performs waveshaping on the input signal by indexing into the table.
9 classmethods::
10 method::ar, kr
12 argument::bufnum
13 The number of a buffer filled in wavetable format containing the
14 transfer function.
16 argument::in
17 The input signal.
20 Examples::
21 Examples use the Internal Server to show the effect of waveshaping via a scope. Use .play instead if necessary.
22 code::
23 Server.default = s = Server.internal; s.boot;
25 b = Buffer.alloc(s, 512, 1, { |buf| buf.chebyMsg([1,0,1,1,0,1])});
29         Shaper.ar(
30                 b,
31                 SinOsc.ar(300, 0, Line.kr(0,1,6)),
32                 0.5
33         )
34 }.scope;
37 b.free;
40 image::chebyshevpolynomials.png::
42 Wave shaping transfer functions are typically designed by using Chebyshev polynomials to control which harmonics are generated when a cosine wave is passed in. The implementation in SuperCollider compensates for the DC offset due to even polynomial terms, making sure that when 0 is put into the transfer function, you get 0 out. By default, normalization is set to true, which avoids output overload. If you want to construct a transfer function without this, you need to be careful with the final output scaling, since it could easily overload the -1 to 1 range for audio.
43 code::
44 // I want the first harmonic at 0.25 amplitude, second at 0.5, third at 0.25
45 b = Buffer.alloc(s, 512, 1, {arg buf; buf.chebyMsg([0.25,0.5,0.25], false)});
49         Shaper.ar(
50                 b,
51                 SinOsc.ar(440, 0.5pi, Line.kr(0,1,6)), //input cosine wave
52                 0.5 //scale output down because otherwise it goes between -1.05 and 0.5, distorting...
53         )
54 }.scope;
57 b.free;
60 For those who like to make their own wavetables for arbitrary shapers, your buffer must be in wavetable format to have a valid transfer function. Wavetable format is a special representation to make linear interpolation faster (see at the bottom of this file). You don't have to worry about this directly, because there are two straight forward ways to get wavetables into a server buffer. First, the server can generate them (see the Buffer help file for the methods sine1, sine2, sine3 and cheby):
61 code::
62 b = Buffer.alloc(s, 1024, 1);
63 b.cheby([1, 0.5, 1, 0.125]);
66 {       var     sig = Shaper.ar(b, SinOsc.ar(440, 0, 0.4));
67         sig ! 2
68 }.scope;
71 b.free;
73 Or, you can calculate the transfer function in a client-side array (Signal class) then convert it to a wavetable and send the data over.
74 code::
75 b = Buffer.alloc(s, 1024, 1);
77 //size must be power of two plus 1
78 t = Signal.chebyFill(513,[1, 0.5, 1, 0.125]);
80 // linear function
81 t.plot
83 // t.asWavetableNoWrap will convert it to the official Wavetable format at next power of two size
84 b.sendCollection(t.asWavetableNoWrap);  // may also use loadCollection here
86 b.plot
89 {       var     sig = Shaper.ar(b, SinOsc.ar(440, 0, 0.4));
90         sig ! 2
91 }.scope;
94 b.free;
97 This way of working then allows you to get creative with your transfer functions!
98 code::
99 b = Buffer.alloc(s, 1024, 1);
101 // or, for an arbitrary transfer function, create the data at 1/2 buffer size + 1
102 t = Signal.fill(513, { |i| i.linlin(0.0, 512.0, -1.0, 1.0) });
104 // linear function
105 t.plot
107 // t.asWavetable will convert it to the official Wavetable format at twice the size
108 b.sendCollection(t.asWavetableNoWrap);  // may also use loadCollection here
110 // shaper has no effect because of the linear transfer function
112 {       var     sig = Shaper.ar(b, SinOsc.ar(440, 0, 0.4));
113         sig ! 2
114 }.scope;
118 // now for a twist
120 a = Signal.fill(256, { |i|
121         var t = i/255.0;
122         t + (0.1 * (max(t, 0.1) - 0.1) * sin(2pi * t * 80 + sin(2pi * 25.6 * t)))
126 a.plot
128 d = (a.copy.reverse.neg) ++(Signal[0])++ a;
130 d.plot
132 d.size  //must be buffer size/2 + 1, so 513 is fine
134 b.sendCollection(d.asWavetableNoWrap);  // may also use loadCollection here
136 b.plot // wavetable format!
138 // test shaper
141         Shaper.ar(
142                 b,
143                 SinOsc.ar(440, 0.5, Line.kr(0,0.9,6))
144         )
145 }.scope
149 subsection:: Advanced notes: wavetable format
150 code::
151 Signal: [a0, a1, a2...]
152 Wavetable: [2*a0-a1, a1-a0, 2*a1-a2, a2-a1, 2*a2-a3, a3-a2...]
154 This strange format is not a standard linear interpolation (integer + frac), but for (integer part -1) and (1+frac))  due to some efficient maths for integer to float conversion in the underlying C code.