avoiding loops, allocation using arrays and ranges
Basile B. via Digitalmars-d
digitalmars-d at puremagic.com
Mon Mar 28 01:01:44 PDT 2016
On Monday, 28 March 2016 at 07:07:47 UTC, Danni Coy wrote:
> Something just clicked in my head in the last week in terms of
> component based programming.
>
> I am currently porting a C++ realtime audio app to D.
> The app uses jackd.
> I have a series of float[] buffers I read and write audio data
> from.
>
> lets say I want to crossfade to audio buffers I would do the
> following
>
> float[1024] a; //actually these allocated by jackd in C but for
> purposes of illustration
> float[1024] b;
>
> length = min(length,a.length,b.length);
>
> foreach(i; 0..nframes)
> {
> /* calculations */
> a[i] = a[i]*ratio + b[i] * (1-ratio);
> }
>
> I can do :
>
> auto crossfade = sequence(/*calculations*/)(a[],b[],length);
> foreach(i; 0..length) a[i] = crossfade[i];
>
> but it would be nice if I could do :
>
> auto crossfade = sequence(/*calculations*/)(a[],b[],length);
> a[0..length] = crossfade[0..length];
>
> or even better
> auto ramp = sequence(/*calculations*/)(length); // create once
> and
> store for later
> a[] = a[]*ramp[] + b[]*(1.0-ramp[]);
>
> I know I can use array but that allocates memory and I don't
> want to
> do that in my realtime thread.
> I could store the ramp as a static array but I want to option
> to do
> this lazily, particularly if I end up with a lot of different
> permutations.
I would see a complete lazy processing a bit like that:
auto process(alias fun, R0, R1)(R0 r0, R1 r1, size_t len)
if (isInputRange!R0 && isInputRange!R1 && is(ElementType!R0 ==
ElementType!R1))
{
struct Processor
{
size_t i;
bool empty()
{
return r0.empty || r1.empty;
}
void popFront()
{
++i;
r0.popFront;
r1.popFront;
}
auto front()
{
return fun(i, len, r0.front, r1.front);
}
}
Processor proc;
return proc;
}
void main(string[] args)
{
float[] a = [0.0,0.0,0.0,0.0];
float[] b = [1.0,1.0,1.0,1.0];
float xfade(size_t i, size_t len, float sa, float sb)
{
auto ramp = (1.0 / --len) * i;
return sa * ramp + (1.0 - ramp) * sb;
}
auto r = process!(xfade)(a, b, 4); // not evaluated
auto v = process!(xfade)(r, b, 4); // still not...
writeln(v.array); // everything gets eval by .array
}
So that you can get rid of all operators in the processing loop.
This is only a demo, I think this could be more elegant and
verstatile (for example the fact that the ramp could itself be a
lazy range).
There's probably some interesting stuff that covers this in
std.range. Look at the functions that take some "Range Of Ranges"
(RoR) as parameter. like transpose, transversal, etc.
More information about the Digitalmars-d
mailing list