little troubles with the DSP basics part 1 doc

45 views
Skip to first unread message

contest...@gmail.com

unread,
Nov 25, 2015, 10:55:12 PM11/25/15
to Extempore
Hi everyone,

I recently started to try Extempore, and I have been reading and testing what is in the documentation. I just finished the DSP basics part 1 but had some troubles. I read everything before that, but it is very likely that I missed important concepts, since I am in no way an experienced programmer.

First, the first sine example:
(bind-func dsp
  (lambda (in:SAMPLE time:i64 chan:i64 data:SAMPLE*)
    (sin (/ (* STWOPI 440.0 (convert time SAMPLE))
          44100.0))))


worked, but the sine was very distorted, and I really don't know why. I replaced it by

(bind-func dsp:DSP
(lambda (in:SAMPLE time:i64 chan:i64 data:SAMPLE*)
(* 0.5 (sin (* STWOPI 440.0 (/ (i64tof (modulo time (convert SR))) SR))))))

that I took from examples/audio_101.xtm, and it seemd to work fine.

I was wondering if the distortion in the first example was normal, or if something is wrong with my system.

I also had a few troubles with the abstraction examples, but found that inc is now a function, and simply changed it to incr and it worked. However,


(bind-func osc_c
(lambda (phase)
(lambda (amp freq)
(let ((incr (* STWOPI (/ freq SR))))
(set! phase (+ phase incr))
(* amp (sin phase))))))

(bind-func dsp
(let ((osc1 (osc_c 0.0)))
(lambda (in:SAMPLE time:i64 channel:i64 data:SAMPLE*)
(osc1 0.5 200.0))))

Seemed to work fine at first, but I get a strange pitch-shift every 10-15 seconds. Something like a 25 cents shift, sometimes up, sometimes down. Is this normal ? What should I do to avoid this ?
The examples from polysynth.xtm and fmsynth.xtm seemed to work fine.

Thanks !

Fabien

Andrew Sorensen

unread,
Nov 25, 2015, 11:37:32 PM11/25/15
to extemp...@googlegroups.com
Hi Fabien,

In your first example you are creating a sine wave with a large amplitude (i.e. 1.0) better to scale it back a little as you did in the second example (i.e. (* 0.5 ... )).  Remembering that you can change the gain of a signal by multiplying by a constant.

The second example - osc_c - is a 32bit float precision problem - long story ;)  This code will work:

(bind-func osc_c
  (lambda (phase)
    (let ((t (/ STWOPI SAMPLERATE)))
      (lambda (amp freq)
        (set! phase (+ phase (* t (clamp freq (- 0.0 SRf) SRf)))) 
        (if (> phase SPI) (set! phase (- phase STWOPI)))
        (* amp (_sin phase))))))


Hopefully Ben will update the example to reflect the move from 64bit to 32bit. 

Cheers,
Andrew.
  



--
You received this message because you are subscribed to the Google Groups "Extempore" group.
To unsubscribe from this group and stop receiving emails from it, send an email to extemporelan...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Ben Swift

unread,
Nov 25, 2015, 11:43:51 PM11/25/15
to extemp...@googlegroups.com
Hi guys

Yep, I was just updating the blog post - done. But you beat me to the reply :)

Cheers,
Ben

Fabien

unread,
Nov 26, 2015, 1:24:04 PM11/26/15
to Extempore
Hi Andrew, thanks for the quick answer

I tried to multiply the first example with a scalar, but it doesn't change the distortion.

(bind-func dsp
  (lambda (in:SAMPLE time:i64 chan:i64 data:SAMPLE*)
    (* 0.1 (sin (/ (* STWOPI 440.0 (convert time SAMPLE))
          44100.0)))))

is still distorted.

For the abstraction, I tried your example, but I get :

Compiler Error cannot find symbol  clamp

Is clamp part of a file I should have loaded ? What does it do ? SRf is also unbound, is it simply a shortcut for sample rate ?

Ben Swift

unread,
Nov 26, 2015, 5:57:00 PM11/26/15
to extemp...@googlegroups.com
Hi Fabien

=clamp= is just a function (well, a macro actually) for clamping an
input value into a certain range. It has recently been moved, so while
Andy's code snipped will work in the latest Extempore from git master,
but it won't work without pulling in a library in 0.6.0. Sorry about
that.

Anyway, I've pushed a few more changes to the blog post so that it
should work on both 0.6.0 and master. Have another look at it and see if
that helps.

Thanks for the comments - I'm sure there are a few other blog posts
which are now out of date with the 0.6.0 changes, so I'll try and fix
them up as I find them.

Happy hacking.

Cheers,
Ben
>> On Thu, Nov 26, 2015 at 1:55 PM, <contest...@gmail.com <javascript:>>
>>> email to extemporelan...@googlegroups.com <javascript:>.

Andrew Sorensen

unread,
Nov 26, 2015, 6:03:42 PM11/26/15
to extemp...@googlegroups.com
Hi Fabien,

The "distortion" that you are hearing is still the 'expected' 32bit precision problem/behaviour.  Try walking through this series of changes:

;; worst 32bit 'artifacting'
(bind-func dsp
  (lambda (in:SAMPLE time:i64 chan:i64 data:SAMPLE*)
    (* 0.2
       (sin (/ (* (* 2.0 3.141592) 440.0 (convert time SAMPLE))
               44100.0)))))

;; better but not good
(bind-func dsp
  (lambda (in:SAMPLE time:i64 chan:i64 data:SAMPLE*)
    (* 0.2
       (sin (* (/ 1.0 44100.0) 2.0 3.141592 440.0 (convert time SAMPLE))))))

;; double precision (dtof ensures that sin calculations are double precision) removes artifacts
(bind-func dsp
  (lambda (in:SAMPLE time:i64 chan:i64 data:SAMPLE*)
    (* 0.2
       (dtof (sin (* (/ 1.0 44100.0) 2.0 3.141592 440.0 (convert time)))))))

;; single precision *without* artifacts
;; keep phase within -pi - +pi range
(bind-func dsp
  (let ((phase 0.0:f))
    (lambda (in:SAMPLE time:i64 chan:i64 data:SAMPLE*)
      (if (= chan 0)
          (begin
            (set! phase (+ phase (* (/ (* 2.0 3.141592) 44100.0) 440.0)))
            (if (> phase 3.141592) (set! phase (- phase (* 2.0 3.141592))))))
      (* 0.2 (sin phase)))))

;; single precision with abstracted 'standalone' osc (i.e. no need to load extra libraries)
(bind-func osc_c
  (lambda (phase:float)
    (let ((t (/ (* 2.0 3.141592) 44100.0)))
      (lambda (amp freq)
        (set! phase (+ phase (* t freq))) 
        (if (> phase 3.141592) (set! phase (- phase (* 2.0 3.141592))))
        (* amp (sin phase))))))

(bind-func dsp:DSP
  (let ((o1 (osc_c 0.0))
        (o2 (osc_c 0.0)))
    (lambda (in time chan dat)
      (if (= chan 0)
          (o1 0.5 440.0)
          (o2 0.4 440.0)))))

The reason the latter examples don't result in 'distortion' is because we limit the range of the float to between -pi and +pi (i.e. keep it close to 0.0).  In the earlier examples the 32bit float values get very large - primarily because of the conversion of the sample number 'time'.  

To understand why precision matters in this case I'll direct you to wikipedia ;)



Cheers,
Andrew. 



Fabien

unread,
Nov 27, 2015, 12:29:30 AM11/27/15
to Extempore
 Hi Ben,

The new version of DSP basics part 1 worked perfectly! Thanks a lot. I intend to continue through the rest of the tutorials in the next few days, I'll let you know if I can't make something work.

Andrew,

Thanks for the explanation! I tried the changes and if I understand correctly, the value sent as argument for phase being very large, there is a sort of (random ?) gap between the real value of time at the moment of execution and the value received as argument. The sine is therefore always calculated for values maybe close, but not quite what it is supposed to be, causing unwanted frequencies. That was very helpful!

 
Reply all
Reply to author
Forward
0 new messages