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)