;; Sampling example ;; First, let's find the cello sound file ;; You can download this from: ;; https://icm.music.cs.cmu.edu/icm-online/sounds/cello.wav ;; Put it in the same directory as this sampling.sal file. ; set CELLO-FILE = "./cello.wav" ;; Make sure the file is there ; exec play-file(CELLO-FILE) ;; Now, load the file in Audacity and look for a good clean ;; place to make a loop. Considering the large vibrato in the ;; signal, I decided to take 1 period of vibrato as the loop. ;; The loop runs roughly from 3.24 to 3.41s. ;; I copied the track and used the <-> tool to slide one track ;; so that the end of the loop around 3.41 is lined up with the ;; start of the loop around 3.21. Then I zoomed in and searched ;; for a way to make the signals almost match by further ;; adjustments with <->. ;; ;; Using the drop down menu at the bottom of the screen below ;; "Selection Start:", I picked "samples" as the display unit. ;; I picked sample number 143232 as a good start point. To get ;; the end point, I deleted from sample 143232 to the end of ;; the signal that I shifted with <->. Then, I shifted it back ;; to normal (If you zoom in enough, Audacity will snap the track ;; into place when you shift it back close to normal.) Now, the ;; end of the track is found to be at sample 150564. ;; ;; Play the loop once: ; set SR = 44100.0 ; play s-read(CELLO-FILE, time-offset: 143232 / SR, dur: (150564 - 143232) / SR) ;; Now, save the sound as a sample: ; set cello-samp = s-read(CELLO-FILE, time-offset: 143232 / SR, dur: (150564 - 143232) / SR) ;; use SAMPLER to loop it: ; play sampler(F4, const(0, 3), list(cello-samp, F4, 0)) ;; There's a click at the splice -- maybe there's a better loop ;; point, but I'll try a cross fade at the splice point. ;; Sample-level processing in Nyquist is tricky. Cutting and ;; splicing with sample accuracy takes a lot of care. I decided ;; to write a general "cross-fade the ends" function that can ;; turn any sound into a smoothly cross-faded loop: ;; Cross-fade the end of the sound into the beginning. ;; Cross-fade length is given by len. ;; This will shorten the sound by len. function cross-fade-ends-1(snd, len) begin with sr = snd-srate(snd), snd-len = snd-length(snd, 1000000), n = round(len * sr), n-s = n / sr, ; n in seconds dur = (snd-len - n) / sr, ; final duration in seconds result = pwl(n-s, 1, dur, 1, dur) * cue(snd), fade = pwl(0, 1, dur, 1, snd-len / sr, 0) * cue(snd) if snd-len = 1000000 then print "WARNING: cross-fade-ends limits sounds to 1M samples" ;; now result is snd with a fade-in of len and duration reduced by len ;; and fade is the original snd with the last len fading out ;; Extract the final len of fade: set fade = extract(dur, snd-len / sr, cue(fade)) exec s-save(result, "result.wav") exec s-save(fade, "fade.wav") return result + fade end ;; The code in cross-fade-ends-1 is not written to allow stretching, ;; so we execute it in the default evironment (ABS-ENV) but with ;; the control rate set to match snd so that PWL envelopes will be ;; sample-accurate (not computed at the default lower sample rate): function cross-fade-ends(snd, len) return abs-env(control-srate-abs(snd-srate(snd), cross-fade-ends-1(snd, len))) ;; Now we build the sample. We start reading from the file FADE/2 samples ;; early, and read an extra FADE samples for the cross-fade. We use ;; cross-fade-ends to use the extra FADE samples to build a cross-fade. function sample-demo() begin set SAMP-START = 143232, SAMP-DUR = 150564 - 143232, FADE = 800 ;; cross-fade time in samples set cello-samp = s-read(CELLO-FILE, time-offset: (SAMP-START - (FADE / 2)) / SR, dur: (SAMP-DUR + FADE) / SR) ;; now make the cross-fade: set cello-samp = cross-fade-ends(cello-samp, FADE / SR) ;; Use SAMPLER to loop the sound, const(0) means no frequency ;; modulation (because the vibrato is built-in), and the duration ;; is 1 second (the default duration of CONST()). return sampler(f4, const(0), list(cello-samp, F4, 0)) end play (sample-demo() * env(0.05, 0.1, 1, 0.2, 0.5, 0.4)) ~ 3