SND in 'From Scratch audio DSP' video

47 views
Skip to first unread message

Cian O'Connor

unread,
Nov 13, 2017, 2:05:39 PM11/13/17
to Extempore
https://youtu.be/PrGFr56mKAE

So I was trying to follow along at home  and of course there is no datatype SND defined in my extempore.

Should this be using DSP - or is there something else going on?

Cian O'Connor

unread,
Nov 13, 2017, 2:16:21 PM11/13/17
to Extempore
And another question while I'm thinking about it.

For the DSP alias there are the types:
(in:SAMPLE time:i64 chan:i64 data:SAMPLE*)
What is the purpose of data?

Andrew Sorensen

unread,
Nov 13, 2017, 6:04:38 PM11/13/17
to extemp...@googlegroups.com
data is a story in three parts :)

1) The original purpose of *data* was to carry a user defined payload.
2) Sample-by-sample output is a nice way to work - less than optimal machine efficiency but nice human efficiency. However, sample-by-sample input is not so great.  What happens when we want to send input channel 10 to output 1?  So locking the input channels to output channels is really unhelpful in practice (also what happens when you have uneven input and output channels??).
3) So ... data got re-purposed to to fix this problem by carrying *all* input channels through to each output.

Here's an example that takes 'n' number of input channels (assumed to be grouped as stereo pairs), and sums them to a single stereo (2 channel) output.

;; sum with stride and offset
(bind-func sum
  (let ((out 0.0) (i 0))      
    (lambda (dat:SAMPLE* num:i32 offset:i32 stride:i32)
      (set! out 0.0)
      (dotimes (i num)
        (inc out (pref dat (+ (* i stride) offset))))
      out)))

;; sum all input pairs to a single stereo output
(bind-func dsp:DSP
  (let ((pairs (/ IN_CHANNELS 2)))
    (lambda (in time chan dat)
      (if (< chan 2)
          (sum dat pairs chan 2)
          0.0)))) ;; should not have more than stereo output


*FYI this is off the top of my head - so not tested*

What really needs to happen of course is that we should change in:SAMPLE to in:SAMPLE* and get rid of the data argument completely. So dsp's signature would become [SAMPLE,SAMPLE*,i64,i64]*

This has been on the cards for a while, I just haven't gotten around to it yet.

-----

snd was simply a convenience wrapper for dsp:DSP that removed *in* and *data* that were not used in the example.  snd:SND also used doubles rather than floats - again for convenience in the example.

(bind-alias SND [double,i64,i64]*)

(bind-func snd:SND
  (lambda (time chan)
    0.0))

(bind-func dsp:DSP
  (lambda (in time chan dat)
    (dtof (snd time chan))))

(dsp:set! dsp)








--
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 extemporelang+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Cian

unread,
Nov 14, 2017, 9:56:37 AM11/14/17
to extemp...@googlegroups.com
On Mon, Nov 13, 2017 at 6:04 PM, Andrew Sorensen <dig...@gmail.com> wrote:
data is a story in three parts :)

1) The original purpose of *data* was to carry a user defined payload.

That was my first assumption. Good to know I wasn't completely off base.
 
2) Sample-by-sample output is a nice way to work - less than optimal machine efficiency but nice human efficiency. However, sample-by-sample input is not so great.

Interesting. My understanding was that there were two reasons for working with sample by sample input, rather than blocks:
1) It's easier conceptually (for livecoding, and sound exploration generally, I think this is a significant advantage).
2) It reduces latency (as control signals can be aligned exactly with the relevant audio signal, rather having to be delayed by a block size)

I'd actually love to see some numbers on what it does to efficiency. Or maybe even explore ways of combining the two approaches (adds to tottering pile of future projects).

What happens when we want to send input channel 10 to output 1?  So locking the input channels to output channels is really unhelpful in practice (also what happens when you have uneven input and output channels??).

Couldn't you do that with an array of buffer queues that are setup as part of the dsp closure's environment (which could be called buses for those of us who grew up using DAWs)? That way you could even run input on a separate thread to output, or have an an effects bus on a separate thread (with a reverb, or something equally resource heavy) which read from that channel.

What really needs to happen of course is that we should change in:SAMPLE to in:SAMPLE* and get rid of the data argument completely. So dsp's signature would become [SAMPLE,SAMPLE*,i64,i64]*

How would that affect DSPMC and DSPMCMT?
 

This has been on the cards for a while, I just haven't gotten around to it yet.

-----

snd was simply a convenience wrapper for dsp:DSP that removed *in* and *data* that were not used in the example.  snd:SND also used doubles rather than floats - again for convenience in the example.

Ah. Helps with the example, but does make it a little tricky to play around with at home :)

Cheers,
Cian 

Toby Gifford

unread,
Nov 15, 2017, 9:17:38 PM11/15/17
to extemp...@googlegroups.com

>> Interesting. My understanding was that there were two reasons for working with sample by sample input, rather than blocks:
>> 1) It's easier conceptually (for livecoding, and sound exploration generally, I think this is a significant advantage).
>> 2) It reduces latency (as control signals can be aligned exactly with the relevant audio signal, rather having to be delayed by a block size)

Hi Cian, I don't think you can reduce the latency any further than the block size, even when using a sample-by-sample DSP signature, since the hardware still puts/gets the audio buffer in blocks. The sample-by-sample DSP signature is just a convenience wrapper for block-by-block processing.

--

Cian

unread,
Nov 16, 2017, 9:34:25 AM11/16/17
to extemp...@googlegroups.com
Well you could, but it would require your software to delay each sample by a sample period after it received a block. Which probably isn't very realistic.

Julian Rohrhuber

unread,
Nov 18, 2017, 10:49:16 AM11/18/17
to extemp...@googlegroups.com
The main and great advantage is that you can do single sample feedback loops. In terms of efficiency, blockwise calculation tends to use your processor caching levels better. But the compiler might do some of that by itself.
> 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.
>
>
> --
> 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.
>
>
> --
> 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.
signature.asc

Cian O'Connor

unread,
Nov 20, 2017, 10:41:38 AM11/20/17
to Extempore
You can still do single sample feedback loops with blockwise calculation. The nice thing in Extempore is that you can do it in the language, rather than having to go out and write a Ugen in C++ (as in PureData/SuperCollider/etc).

Julian Rohrhuber

unread,
Nov 24, 2017, 8:07:55 AM11/24/17
to extemp...@googlegroups.com
yes, of course, that is what I meant - thanks for the tweak!
signature.asc
Reply all
Reply to author
Forward
0 new messages