This is a pedagogic question. The discussion below (forwarded with permission) is basically about the best way to find the maximum value in a vector of length four million, a.k.a. a sound file. Non-tail recursion is problematic; I blow a 512M-limited evaluator in about 14 seconds without finding the answer, where tail-calling gets me the answer in about 2 seconds.
So! Here’s the question. Is it better to give students an “rs-foldl” that performs a fold over sound, or to show them accumulator-style programming? I was a bit surprised to see that in HtDP 2e, foldl (a.k.a. “Programming to an Abstraction”) appears much earlier (section 18.4) than accumulator-style (section 35). I suppose this could be because using an abstraction can be easier than devising it, although in the case of (say) map, the book takes care to ensure that students can implement map-like functions in their sleep before showing them the abstraction. Opinions appreciated! Many thanks, John Begin forwarded message: > From: John Clements <cleme...@brinckerhoff.org> > Subject: Re: Rsound question > Date: March 25, 2015 at 9:48:09 AM PDT > To: James Vanderhyde <jvanderh...@benedictine.edu> > > > On Mar 25, 2015, at 5:54 AM, James Vanderhyde <jvanderh...@benedictine.edu> > wrote: > >> John, >> >> There are some sound processing tasks I’m not sure how to do with Rsound. >> For example, to normalize the sound (make it as loud as possible with no >> clipping), I need to find the maximum absolute sample value, and then >> multiply everything by 1 over that value. I can use rs-map for the second >> part, but I don’t know how to find the max in a sound (or do other audio >> analysis). It seems like I need something like rs-fold. What would you >> recommend? > > I see two ways to solve this. The first is “by the book”. > > FIRST: > > This problem requires two medium-advanced concepts. First, the notion of > recursion over the natural numbers, introduced in section 10.3 of HtDP2e > > http://www.ccs.neu.edu/home/matthias/HtDP2e/part_two.html#%28part._sec~3anats%29 > > … and, more challenging, the notion of an accumulator: > > http://www.ccs.neu.edu/home/matthias/HtDP2e/part_six.html > > Here’s the resulting code: > > (require rsound) > > ;; given a sound, return the maximum value > ;; of a sample in that sound > ;; rsound -> number > (define (max-volume rs) > (max-volume-helper rs 0 0.0)) > > ;; given a sound, an index, and a maximum-so-far, > ;; compute the maximum volume of the sound > (define (max-volume-helper rs idx max-so-far) > (cond [(<= (rs-frames rs) idx) max-so-far] > [else (max-volume-helper rs (add1 idx) > (max (abs (rs-ith/left rs idx)) > (abs (rs-ith/right rs idx)) > max-so-far))])) > > (define test-sound (mono 101 x (* -0.0025 x))) > > (check-within (max-volume-helper test-sound 50 0.0) 0.25 1e-4) > (check-within (max-volume-helper test-sound 50 0.96) 0.96 1e-4) > (check-within (max-volume test-sound) 0.25 1e-4) > > In this case, the accumulator isn’t really necessary, but if you want to run > the program on more than a few hundred samples, it’s going to be important. > > SECOND: > > We could certainly add rs-fold. It would require students to define a more > challenging higher-order function, but perhaps that’s simpler than writing it > in accumulator style? I’d be interested to hear what you have to say. > > P.S.: mind if I forward this question to the racket-users mailing list? > > John > > > >> >> James >> -- >> Dr. James Vanderhyde >> Math and Computer Science >> Benedictine College >> jvanderh...@benedictine.edu >> http://vanderhyde.us/~james/pro/ >> >> >> >>> On Mar 18, 2015, at 2:24 PM, John Clements <cleme...@brinckerhoff.org> >>> wrote: >>> >>> >>> On Mar 18, 2015, at 6:28 AM, James Vanderhyde <jvanderh...@benedictine.edu> >>> wrote: >>> >>>> Thank you, John. You are so helpful. I’ve really appreciated your quick >>>> responses. I don’t really like mono because it introduces additional >>>> syntax, and signals introduce additional structures. But either one will >>>> give me a much better approach than what I was going to do. >>> >>> Thanks for the thanks! Also, I’d like to point out that if you use >>> indexed-signal, you certainly don’t need to get into details; you can >>> describe a signal as a box with a function in it. >>> >>> HOWEVER… after looking at this for a while longer, I see that a >>> ‘build-sound’ function such as the one you describe is probably a good >>> addition to the library. So, I added it. (I also >>> added some other documentation, and fixed one long-term documentation >>> niggle). >>> >>> I’ve pushed this to the github repo, and poked pkgs.racket-lang.org. I’m >>> not sure how long it’ll take for the catalog to reflect the change. >>> >>> Thanks again, >>> >>> John Clements >>> >>> >>>> >>>> By the way, rs-map is also undocumented. >>>> >>>> James >>>> -- >>>> Dr. James Vanderhyde >>>> Math and Computer Science >>>> Benedictine College >>>> jvanderh...@benedictine.edu >>>> http://vanderhyde.us/~james/pro/ >>>> >>>> >>>> >>>>> On Mar 18, 2015, at 1:23 AM, John Clements <cleme...@brinckerhoff.org> >>>>> wrote: >>>>> >>>>> >>>>> On Mar 17, 2015, at 6:30 PM, James Vanderhyde >>>>> <jvanderh...@benedictine.edu> wrote: >>>>> >>>>>> John, >>>>>> >>>>>> I am using your Rsound package in my Media Computation class. I am also >>>>>> using Stephen Bloch’s Picturing Programs. For image processing and >>>>>> synthesis, I have the students using map3-image and build3-image, >>>>>> respectively. >>>>>> http://docs.racket-lang.org/picturing-programs/index.html?q=do#%28def._%28%28lib._picturing-programs%2Fprivate%2Fmap-image..rkt%29._build3-image%29%29 >>>>>> >>>>>> For sounds, I would like to do similar things. I can use rs-map and >>>>>> rearrange for some things, but there does not seem to be an equivalent >>>>>> of build3-image. I want a function that takes a length and a function as >>>>>> parameters. This second function takes a frame number and returns a >>>>>> value. For example, say the function I want is called build-sound. Then >>>>>> the students can enter this: >>>>>> >>>>>> (define (sine/440 f) >>>>>> (sin (* 2 pi 440 (/ f 44100)))) >>>>>> >>>>>> (play (build-sound sine/440 44100)) >>>>>> >>>>>> Is there any existing function like this in the rsound library? I >>>>>> realize the signal metaphor is the route you took to do this, but I >>>>>> don’t want to get into networks and all of that. I want to build sounds >>>>>> out of functions, in an analogous way to the way we built images for >>>>>> Picturing Programs. >>>>>> >>>>>> The best I could come up with is pasted below. (I’m not very good at >>>>>> Racket/Scheme yet.) I can have the students enter this into their >>>>>> programs at the top, but I’d rather not move them out of the Beginning >>>>>> Student Language until absolutely necessary. >>>>>> >>>>>> Thank you for your help. >>>>> >>>>> Good to hear from you! >>>>> >>>>> I have two answers for you. >>>>> >>>>> The first one is the undocumented “mono” syntax. It bundles together most >>>>> of what you want to do, so that you can e.g. just run this program: >>>>> >>>>> (require rsound) >>>>> >>>>> (play (mono 44100 f (sin (* 2 pi 440 (/ f 44100))))) >>>>> >>>>> mono needs >>>>> - a number of samples, >>>>> - a variable name, and >>>>> - an expression, where the variable name is taken to refer to the frame. >>>>> >>>>> Beyond this, you can also use the (documented but easy-to-miss) function >>>>> ‘indexed-signal’, which transforms a function such as your ‘sine/440’ >>>>> above into a signal: >>>>> >>>>> (require rsound) >>>>> >>>>> (define (sine/440 f) >>>>> (sin (* 2 pi 440 (/ f 44100)))) >>>>> >>>>> (play (signal->rsound (indexed-signal sine/440) 44100)) >>>>> >>>>> Unfortunately, this function (indexed-signal) isn’t labeled as a >>>>> beginner-friendly-higher-order-function. You may recall that we made this >>>>> change earlier for rs-map and friends. I’ve now made this change to >>>>> indexed-signal, as well, and pushed the change; it should be visible >>>>> tomorrow, if pkg.racket-lang.orgpicks it up. >>>>> >>>>> Either way, you may actually prefer the first “mono” form, which should >>>>> work right now. >>>>> >>>>> Thanks for writing! >>>>> >>>>> Best, >>>>> >>>>> John Clements >>>> >>> >> > -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.