;;; -*- syntax: Sal2; font-size: 18; theme: "Emacs"; -*- ; ;; 'Sin'ful composition ; ; Lots of math functions also perform mapping. For example 'sin' ; (sine) maps radians values into amplitudes between -1 and 1. ; Recall that radians are simply another way to measure angles: ; degrees chop the unit circle up int 360 equal parts and radians chop ; the circle up into 2pi parts. In other words 360 degrees equals 2pi ; radians. Let's use rescale to show this: loop for deg from 0 to 360 by 45 for rad = rescale(deg, 0, 360, 0, 2 * pi) print(deg, " degrees = ", rad, " radians.") end ; Now forget about degrees, lets just move 2pi radians in 8 steps from ; 0 to 1 see what sine gives us: loop for x from 0 to 1 by 1/8 for rad = rescale(x, 0, 1, 0, 2 * pi) for amp = sin(rad) print("x=", x, " radians=", rad, " sin=", amp) end ; so as x goes from 0 to 1, radians goes from 0 to 2pi and sin returns ; the amplitude. if we plot these values of sine left to right we get ; a perfectly symmetrical 'wave figure' (called the sine wave) with a ; shape that looks something like this: ; +1 | * * ; | * * ; 0 |*--------*--------*-----> ; | * * ; -1 | * * ;X : 0 1/4 1/2 3/4 1 ;Rad: 0 pi/2 pi 3pi/2 2pi ; Since sin values range from -1 to 1 all we have to do is use the ; 'rescale' function to map sin values to appropriate ranges for ; musical parameters. For example, this loop maps sin values to key ; numbers between 60 and 84: loop for x from 0 to 1 by 1/8 for rad = rescale(x, 0, 1, 0, 2 * pi) for amp = sin(rad) for key = rescale(amp, -1, 1, 60, 84) print("x=", x, " radians=", rad, " keynum=", key) end ; So we've mapped x from 0:1 to a sine wave shape of key numbers ; between 60 and 84! What would this sound like? ; ;; Using sin in a musical process ; ; How can we use sin to control the evolution of a musical process? ; The loop example above hints at how we can solve at least one ; approach to the problem. Imagine that we want to control the key ; numbers of a process that runs for 100 iterations of a counter ; variable i. On each iteration we want to calculate the current value ; of sin and output a corresponding keynum. Calculating the keynum ; from the output value of sin is easy (we use rescale), but how do we ; convert the process iteration variable 'i' into a radian value 'r' ; that we can pass into sin? A moments reflection will tell that ; something like this will work: ; [1] r = 2 * pi * (i / 100)) ; formula [1] says that as counter i moves from 0 to 100 the radians r ; moves from 0 to 2pi. For example: ; when i=0 then i/100=0 so r=2pi*0 and r=0; ; when i=50 then i/100=.5 so r=2pi*.5 and r=pi ; when i=100 then i/100=1 so r=2pi*1 and r=2pi and so on. ; lets implement the 100 event test process: process sine1 () for i below 100 for r = 2 * pi * (i / 100) for a = sin(r) send("mp:midi", key: rescale(a, -1, 1, 21, 21 + 88)) wait .1 end sprout( sine1() ) ; TODO: This example can be generalized! Copy/paste the definition ; to create a new process called sine2 that accept four arguments: ; reps, rate, low and high. The process should run for reps ; iterations, output keynums between low and high, and wait rate ; seconds between iterations. For example here are two calls to the ; function you will create: sprout( sine2(100, .1, 0, 127) ) sprout( sine2(100, .1, 30, 90) ) ; How can we make the process generate more than one cycle of the wave ; as i goes from 0 to num? Perhaps we can see if we compare formula ; [1] with a second version: ; [1] r = 2 * pi * (i / 100)) ; [2] r = 2 * pi * 10 * (i / 100) ; As i goes from 1 to 100, formula [1] goes 1 trip around 2pi radians ; and formula [2] goes 10 trips around 2 pi radians. Since [2] make ; ten trips from 0-pi in the same time [1] makes 1 trip, the frequency ; of [2] is ten times that of [1] ; Lets generalize this by adding a new parameter 'cycs' just after the ; 'num' parameter use that parameter as a "frequency" for radian ; calculation. process sine3 (len, cycs, low, hi, rhy, dur, amp) with 2pi = 2 * pi for i below len for a = sin ( (2pi * cycs * (i / len)) ) send("mp:midi", key: rescale(a ,-1, 1, low, hi), amp: amp, dur: dur) wait rhy end ;; we test it out by specify 4 cycles in 100 notes: sprout( sine3(100, 4, 20, 100, .1, .1, .6) ) ; lastly, we can "dirty up" the deterministic motion of sin by adding a ; random component to its values: process sine4 (len, cycs, low, hi, dirty, rhy, dur, amp) with 2pi = 2 * pi for i below len for a = sin ( (2pi * cycs * (i / len)) ) for r = between(- dirty, dirty) send("mp:midi", key: rescale( a + r ,-1 - dirty, 1 + dirty, low, hi), amp: amp, dur: dur) wait rhy end sprout (sine4(100, 4, 20, 100, .2, .1, .1, .6)) ; and lastly, here is a process that uses sin to generate ; "oscillating" rhythmic patterns, ie moving faster and slower around ; a central rhythmic value. process sinrhy (num, cycs, fast, slow, lb, ub) for x to num for s = sin( 2 * pi * cycs * (x / num)) for k = between(lb, ub) send( "mp:midi", key: k, dur: .1 ) wait rescale( s, -1, 1, slow, fast) end sprout( sinrhy(40, 3, .05, .6, 60, 80) ) ;; the discrete function is like rescale but it maps floating point ;; values onto integers, or lists of values. loop repeat 20 for x = ran(1.0) for d = discrete(x, 0.0, 1.0, 48, 90) print( "x=", x, " d=", d ) end ;; you can also map onto lists of discrete values process sine5 (len, cycs, scal, rhy, dur, amp) with 2pi = 2 * pi for i below len for a = sin ( (2pi * cycs * (i / len)) ) send("mp:midi", key: discrete(a ,-1, 1, scal), amp: amp, dur: dur) wait rhy end begin with scal = scale(50, 20, 1, 2) sprout( sine5(100, 4, scal, .1, .1, .6) ) end