How to get the selection of a FluidWaveform and set the color

How can I get the values of the selected area of a FluidWaveform and set the color of the selection? If using SoundFileView the user can get the selected frames of the view with .selection(indexOfSelection) but that method does not work on a FluidWaveform, however, a section of the waveform can still be highlighted with the mouse. Maybe @tedmoore knows?

(
p = Platform.resourceDir +/+ "sounds/a11wlk01.wav";
b = Buffer.read(s, p); 
FluidWaveform(b, bounds:Rect(0,0,1200,300));
)

Here is how it works for a SoundFileView:

(
w = Window.new("soundfile test", Rect(200, 300, 740, 100));
a = SoundFileView.new(w, Rect(20,20, 700, 60));

f = SoundFile.new;
f.openRead(Platform.resourceDir +/+ "sounds/a11wlk01.wav");
a.soundfile = f;
a.read(0, f.numFrames);
w.front;
/// Select some section of the whole waveform, then a.selection(0) returns the left and and right edge given in frames
)

Hi @Thor_Madsen,

I’m sorry to say that functionality isn’t implemented, although, as you probably know, FluidWaveform is built on top of SoundFileView, so it would be very possible to pass that information through!

If you add this functionality, we’d love to have it included in a PR to add to the object!

Cheers,

Ted

1 Like

Yes I did look into the implementation and saw that FluidWaveForm is built on SoundFileView and that it involves saving the buffer to disk in order for SoundFileView to be able to read it, and then delete it afterwards. Since I don’t really need the other (very cool) overlay featured in FluidWaveform for this project, I will be probably just do the same trick using SoundFileView.

Now, what I am really looking for is a method to dynamically update the waveform of a buffer being filled or a soundFile being written to, like in a DAW, but I suspect this would be hard, maybe impossible to implement in SC. I dabbled a bit with the Pen tool in an animated Userview at a frame rate of 30 (I would be ok with a downsampled approximation of a waveform) but the problem is, that there is not way to scale the content of a Userview, as far as I can tell - once you change the bounds, all content is lost.

hjh

1 Like

Wow, what an elegant solution, you saved my day!

I am using this basic structure below to play a pre-recorded soundFile. The section of the display selected will loop the audio and setting the curser to a specific point or a selecting a very short duration will stop the playback.

Now I would like to record into a buffer (or write a soundFile) of same length as the mastertrack using a modified version of your code. My problem is that the resolution of the selection and cursor position in your code is different from that of the mastertrack in my code - in your code the selection is relative to the screenbounds and in my example (modded from the helpfile), the selection is relative to the number of frames in the mastertrack.

Is there a way to link the update of the live-recording buffer/soundFile to the phasor in my Synth(\playBack) which would allow me to start loop recording anywhere in the mastertrack in way where the track can be ‘record enabled’ (overwriting existing audio in the buffer/soundFile and updating the view) or not (showing what has already been recorded without overwriting with new content)?

(
v = SoundFileView();
w =View(nil, Rect(200, 300, 1040, 100)).layout_(HLayout(v)).front;
b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");	
v.soundfile = b;
v.read(0, b.numFrames);
v.timeCursorOn = true;
v.timeCursorColor = Color.white;
v.gridOn = false;
s.waitForBoot{
	SynthDef(\playBack, {|buf, start = 0, end = 48000, loop = 1, gate = 1, t_trig = 1|
		var phasor = Phasor.ar(t_trig, 1, start, end, start);
		var play = BufRd.ar(1, buf, phasor, loop);
		var env = Env.asr(0.01, 1, 0.01).kr(2, gate);
		SendReply.ar(Impulse.ar(20), '/reply', phasor);
		Out.ar(\out.kr(0), play!2 * env);
	}).add;
	
	
	s.sync;
	
	v.mouseUpAction = {
		if (v.selection(0)[1] > 6000)
		{
			if ( ~play.isPlaying )
			{ ~play.set(\gate, 0) };
			~play = Synth(\playBack, [buf: b, start: v.selection(0)[0], end: v.selection(0)[0] + v.selection(0)[1]]).register;
		}
		{ if ( ~play.isPlaying ) { ~play.set(\gate, 0) } }
	};
	
	o = OSCFunc({|val|
		{ v.timeCursorPosition = val[3] }.defer;
	}, '/reply');
}
)