;; granular.sal -- basic code for granular synthesis ;; ;; Alex Limpaecher and Roger B. Dannenberg ;; Feb 2013 ;; The file to process with granular synthesis is a global ;; to save passing (probably) the same parameter to many ;; thousands of grains variable *gs-filename* = "./sample.wav" ;; grain creates a grain sampled from a file located at *gs-filename* ;; offset is the time in seconds where the grain will start ;; the stretch factor controls the grain duration ;; ;; raised-cosine is an envelope used to fade the grain in and out ;; define function grain(offset: 0, fileName: *gs-filename*) begin with grain = s-read(fileName, time-offset: offset, dur: get-duration(1)) * raised-cosine() ;; set grain = sound(grain) ~~ 1.5 ; see project description return grain end ;; make-granulate-score makes a score of grains ;; Grains are selected by scanning through the file from ;; file-offset to file-end, but the file location is perturbed ;; by a random number in the range from 0 to randomness. ;; The grain duration is grain-dur. ;; The output grains are uniformly spaced with an inter-onset ;; interval of ioi. The file is scanned by adding ioi / stretch ;; to the file-offset for each grain, so if stretch > 1, the ;; file is scanned slowly and the output sounds stretched. If ;; stretch < 1, the output will sound compressed in time. ;; define function make-granulate-score(file-offset: 0, randomness: 1, file-end: 10, grain-dur: 0.05, ioi: 0.025, stretch: 1.0) loop with score, score-time = 0 while file-offset < file-end set score @= list(score-time, grain-dur, list(quote(grain), :offset, file-offset + rrandom() * randomness)) set score-time += ioi, file-offset += ioi / stretch finally begin display "score computed", length(score) return reverse(score) end end ;; raised-cosine or "Hanning" window. The cosine is generated by LFO, ;; so it is at the control sample rate (default = 2205 Hz). Since LFO is ;; normally a sine, we set the initial phase to 270 to make it a negative ;; cosine. The duration obeys the current stretch factor. function raised-cosine() return 0.5 * (1 + lfo(1.0 / get-duration(1), 1, *sine-table*, 270)) ;; Test: (comment this out or change it as needed) play timed-seq(make-granulate-score(randomness: 1.0, ioi: 0.025, grain-dur: 0.05, stretch: 2.0))