[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[sc-dev] [commit] multichannel Buffer-plot and Function-plot
Hi all,
I've just committed changes to ArrayedCollection-plot, which add a numChannels argument. This treats the array as an interlaced multichannel dataset. The default is 1, and it comes last, so this should not break anything. At some point it would probably be good to move the code which draws the views to a separate method, as this would allow plotting nested arrays, but for the moment this works well enough with interlaced data such as one gets from SoundFile, etc. The option to express things like time rather than index would also be useful.
This allows for two things: Correct plotting of multichannel Buffers, and a rudimentary implementation of Function-plot. The latter is somewhat limited, and could probably be done better another way, but it's a start. At the moment it's audio rate only (as RecordBuf is as well...) and operates in realtime. Ideally it would be NRT, but given the lingering Panther popen bug I figured this was a better way to go. It also doesn't work with explicit Out UGens (need those Float-from32bits and Float-from64bits methods to get a SynthDesc without writing to disk) so your function should return a UGen or an Array of them. I suppose an alternative implementation would be to store the def and then just delete it afterwards, but in any case what I've committed is there and working. Help file is updated with examples.
Cheers from snowy Poland...
S.
________________
<x-tad-smaller>+ </x-tad-smaller><x-tad-smaller>ArrayedCollection</x-tad-smaller><x-tad-smaller>{
plot { </x-tad-smaller><x-tad-smaller>arg</x-tad-smaller><x-tad-smaller> name, bounds, discrete=</x-tad-smaller><x-tad-smaller>false</x-tad-smaller><x-tad-smaller>, numChannels = 1;
</x-tad-smaller><x-tad-smaller>var</x-tad-smaller><x-tad-smaller> plotter, txt, chanArray, unlaced, val, minval, maxval, window, thumbsize, zoom, width,
layout;
bounds = bounds ? </x-tad-smaller><x-tad-smaller>Rect</x-tad-smaller><x-tad-smaller>(200 , 140, 705, 410);
width = bounds.width-8;
zoom = (width / (</x-tad-smaller><x-tad-smaller>this</x-tad-smaller><x-tad-smaller>.size / numChannels));
if(discrete) {
thumbsize = max(1.0, zoom);
}{
thumbsize = 1;
};
name = name ? </x-tad-smaller><x-tad-smaller>"plot"</x-tad-smaller><x-tad-smaller>;
minval = </x-tad-smaller><x-tad-smaller>this</x-tad-smaller><x-tad-smaller>.minItem;
maxval = </x-tad-smaller><x-tad-smaller>this</x-tad-smaller><x-tad-smaller>.maxItem;
unlaced = </x-tad-smaller><x-tad-smaller>this</x-tad-smaller><x-tad-smaller>.unlace(numChannels);
chanArray = </x-tad-smaller><x-tad-smaller>Array</x-tad-smaller><x-tad-smaller>.newClear(numChannels);
unlaced.do({ </x-tad-smaller><x-tad-smaller>|chan, j|</x-tad-smaller><x-tad-smaller>
val = </x-tad-smaller><x-tad-smaller>Array</x-tad-smaller><x-tad-smaller>.newClear(width);
width.do { </x-tad-smaller><x-tad-smaller>arg</x-tad-smaller><x-tad-smaller> i;
</x-tad-smaller><x-tad-smaller>var</x-tad-smaller><x-tad-smaller> x;
x = chan.blendAt(i / zoom);
val[i] = x.linlin(minval, maxval, 0.0, 1.0);
};
chanArray[j] = val;
});
window = </x-tad-smaller><x-tad-smaller>SCWindow</x-tad-smaller><x-tad-smaller>(name, bounds);
txt = </x-tad-smaller><x-tad-smaller>SCStaticText</x-tad-smaller><x-tad-smaller>(window, </x-tad-smaller><x-tad-smaller>Rect</x-tad-smaller><x-tad-smaller>(8, 0, width, 18))
.string_(</x-tad-smaller><x-tad-smaller>"index: 0, value: "</x-tad-smaller><x-tad-smaller> ++ </x-tad-smaller><x-tad-smaller>this</x-tad-smaller><x-tad-smaller>[0].asString);
layout = </x-tad-smaller><x-tad-smaller>SCVLayoutView</x-tad-smaller><x-tad-smaller>(window, </x-tad-smaller><x-tad-smaller>Rect</x-tad-smaller><x-tad-smaller>(4, txt.bounds.height, width,
bounds.height - 30 - txt.bounds.height)).resize_(5);
numChannels.do({ </x-tad-smaller><x-tad-smaller>|i|</x-tad-smaller><x-tad-smaller>
plotter = </x-tad-smaller><x-tad-smaller>SCMultiSliderView</x-tad-smaller><x-tad-smaller>(layout, </x-tad-smaller><x-tad-smaller>Rect</x-tad-smaller><x-tad-smaller>(0, 0,
layout.bounds.width,layout.bounds.height))
.readOnly_(</x-tad-smaller><x-tad-smaller>true</x-tad-smaller><x-tad-smaller>)
.drawLines_(discrete.not)
.drawRects_(discrete)
.thumbSize_(thumbsize)
.valueThumbSize_(1)
.colors_(</x-tad-smaller><x-tad-smaller>Color</x-tad-smaller><x-tad-smaller>.black, </x-tad-smaller><x-tad-smaller>Color</x-tad-smaller><x-tad-smaller>.blue(1.0,1.0))
.action_({</x-tad-smaller><x-tad-smaller>|v|</x-tad-smaller><x-tad-smaller>
txt.string_(</x-tad-smaller><x-tad-smaller>"index: "</x-tad-smaller><x-tad-smaller> ++ (v.index / zoom).roundUp(0.01).asString ++
</x-tad-smaller><x-tad-smaller>", value: "</x-tad-smaller><x-tad-smaller> ++ v.currentvalue.linlin(0.0, 1.0, minval, maxval).asString) })
.value_(chanArray[i])
.resize_(5)
.elasticMode_(1);
});
^window.front;
}
}
+ </x-tad-smaller><x-tad-smaller>Function</x-tad-smaller><x-tad-smaller> {
plot { </x-tad-smaller><x-tad-smaller>arg</x-tad-smaller><x-tad-smaller> duration = 0.01, server, bounds;
</x-tad-smaller><x-tad-smaller>var</x-tad-smaller><x-tad-smaller> buffer, def, synth, name, value, numChannels;
server = server ? </x-tad-smaller><x-tad-smaller>Server</x-tad-smaller><x-tad-smaller>.default;
server.isLocal.not.if({</x-tad-smaller><x-tad-smaller>"Function-plot only works with a localhost server"</x-tad-smaller><x-tad-smaller>.warn; ^nil });
server.serverRunning.not.if({</x-tad-smaller><x-tad-smaller>"Server not running!"</x-tad-smaller><x-tad-smaller>.warn; ^nil });
value = </x-tad-smaller><x-tad-smaller>this</x-tad-smaller><x-tad-smaller>.value;
if(value.size == 0, { numChannels = 1 }, { numChannels = value.size });
buffer = </x-tad-smaller><x-tad-smaller>Buffer</x-tad-smaller><x-tad-smaller>.new(server, duration * server.sampleRate, numChannels);
</x-tad-smaller><x-tad-smaller>// no need to check for rate as RecordBuf is ar only</x-tad-smaller><x-tad-smaller>
name = </x-tad-smaller><x-tad-smaller>this</x-tad-smaller><x-tad-smaller>.hash.asString;
def = </x-tad-smaller><x-tad-smaller>SynthDef</x-tad-smaller><x-tad-smaller>(name, {
</x-tad-smaller><x-tad-smaller>this</x-tad-smaller><x-tad-smaller>.value, buffer.bufnum, loop:0);
</x-tad-smaller><x-tad-smaller>Line</x-tad-smaller><x-tad-smaller>.ar(dur: duration, doneAction: 2);
});
</x-tad-smaller><x-tad-smaller>Routine</x-tad-smaller><x-tad-smaller>.run({
</x-tad-smaller><x-tad-smaller>var</x-tad-smaller><x-tad-smaller> c;
c = </x-tad-smaller><x-tad-smaller>Condition</x-tad-smaller><x-tad-smaller>.new;
server.sendMsgSync(c, *buffer.allocMsg);
server.sendMsgSync(c, </x-tad-smaller><x-tad-smaller>"/d_recv"</x-tad-smaller><x-tad-smaller>, def.asBytes);
synth = </x-tad-smaller><x-tad-smaller>Synth</x-tad-smaller><x-tad-smaller>.basicNew(name, server);
</x-tad-smaller><x-tad-smaller>OSCpathResponder</x-tad-smaller><x-tad-smaller>(server.addr, [</x-tad-smaller><x-tad-smaller>'/n_end'</x-tad-smaller><x-tad-smaller>, synth.nodeID], {
buffer.loadToFloatArray(action: { </x-tad-smaller><x-tad-smaller>|array, buf|</x-tad-smaller><x-tad-smaller>
{array.plot(bounds: bounds, numChannels: buf.numChannels) }.defer;
buffer.free;
});
}).add.removeWhenDone;
server.listSendMsg(synth.newMsg);
});
}
}</x-tad-smaller>