Hi, this may be a little off topic as it concerns an Extension (the FluCoMa toolkit), and maybe you are seeking answers with the native Supercollider tools.
FluCoMa has a handy tool for visualizing sound and its analysis data, the FluidWaveform. It less flexible than the native SC Views, but is a fast way to achieve what I think you’re looking for.
Installing FluCoMa just for the FluidWaveform is kind of like buying a smart fridge to use the clock, but maybe it could interest you to look into their work anyway, as it is very useful for working with grains.
Here’s some sample code that does what you describe.
The next step (playing the grain) is pretty easy, since you have the slice frames saved in the global variable ~currentSlice
, which you can use as control input for a Synth using the GrainBuf
UGen, or anything else! The temp buffers created for visualization aren’t a good idea for playing, as they are interfered with quite regularly.
s.boot;
(
//Create a buffer filled with *something*
~src = Buffer.loadCollection(s,
Env([0.0]++({rrand(-1.0, 1.0)}!30)++[0, 0],
{rrand(0.1, 1)}!31,
\sin
).asSignal(4096);
);
)
(
~currentSlice = [0, ~src.numFrames - 1]; // starting slice: whole buffer
//FluidWaverform reads 2 channel buffers as containing onsets and offsets
//Its useful for many other FluCoMa tools to have the slices stored on the server as well
~sliceFrames = Buffer.alloc(s, numFrames: 1, numChannels: 2);
)
//set channels 1 and 2, as the buffer only has 1 frame.
~sliceFrames.setn(0, ~currentSlice);
(
~view = View(bounds:Rect(0, 0, 512, 400)).alwaysOnTop_(true).name_("Dynamic Waveform Viewing");
~srcWf = FluidWaveform.new(~src, ~sliceFrames, standalone:false);
~sliceWf = FluidWaveform.new(~src, standalone:false); //we start with the original buffer
~view.layout = VLayout(~srcWf, ~sliceWf);
~srcWf.asView.acceptsMouse = false; //FluidWaveform responds unexpectedly to mouse events
~sliceWf.asView.acceptsMouse = false;
~view.front;
//The two waveforms are equal at first
)
(//here we determine mouse behaviour: click and hold to determine start frame, release to determine end frame and update view.
//it would not be complicated to make the view update also when the mouse is moving while pressed!
//we could also dynamically "compose" the slice buffer as the mouse moves, making visuals update much faster
//(using mouseMoveAction, conditionals, and FluidBufCompose's startChan/numChan) arguments)
var sliceSelection = [0, 0];
var sliceBuf; //here we will store the slices
var prevBuf; //useful for freeing buffers we aren't using anymore
~view.mouseDownAction = {|view, x, y ...args|
sliceSelection[0] = ~src.numFrames * x / view.bounds.width;
};
~view.mouseUpAction = {|view, x, y ...args|
sliceSelection[1] = ~src.numFrames * x / view.bounds.width;
~currentSlice = sliceSelection.sort.copy; //we always want to make sure the first frame is smaller
~sliceFrames.setn(0, ~currentSlice);
prevBuf = sliceBuf;
sliceBuf = Buffer(s);
FluidBufCompose.processBlocking(s, ~src,
startFrame: ~currentSlice[0], numFrames: ~currentSlice[1] - ~currentSlice[0],
destination: sliceBuf, action: {
~sliceWf.layers.pop;
~sliceWf.addAudioLayer(sliceBuf);
[~srcWf, ~sliceWf].do(_.refresh); // refresh the waveforms to draw the new buffers
prevBuf.free;
});
}
)
Other analysis tools in FluCoMa could quickly analyse data in your selected slice and display it on the waveform also!