FluidBufOnsetSlice: how to save the slices into .wav files

hi all,

I am looking into the FluidBufOnsetSlice class, I am wondering how I can save the analysed frames of the resulting buffer into single sliced .wav files.

Here an example:

(
//prep some buffers
b = Buffer.read(s,File.realpath("/path/to/my/audiofile.wav"));
c = Buffer.new(s);
)

(
// with basic params
Routine{
t = Main.elapsedTime;
FluidBufOnsetSlice.process(s,b, indices: c, threshold:0.5);
(Main.elapsedTime - t).postln;
}.play
)

c.query;
// post
bufnum: 12
numFrames: 41
numChannels: 1
sampleRate: 48000.0

How can I now save the resulting “c” buffer into the sliced different audiofiles?

thanks!

What i would do is the following:

  • I would import your c as an array (let’s name it ~indices) using c.getn

  • I would then indices.doAdjacentPairs({|start,stop| b.write(use start as startframe and (stop-start) as numFrames)} and you’re done. Don’t forget to sync between each write (it is async on the server)

I hope this helps.

pa

thanks a lot for your answer, I will look it into it and report back!

hi again,

I created some code based on your suggestion, doing what I wanted to achieve.
I post some example code here underneath, maybe it can be useful for someone else too.

Two more questions:

  1. once I analysed the files, I would like to sort them in a linear way in an array, based on their analysis. How can I do that?
  2. when I run the FluidCorpusMap methods (loadBuffers, map, scatterplot) in the example below, the s.sync(cond) function does not seem to have any effect. How can I have a wait/sync function between such methods?

thank you!

=================

// first evaluate the functions below

(
~sample = "path/to/your/wave/file.wav";
~sliceFolder = "path/to/your/folder/where/to/store/the/slices/";
)
~splitFiles.value(~sample , ~sliceFolder);
~analyseSlices.value(~sliceFolder);

~generateMap.value(~sliceFolder, "ae.ds");
~generateMap.value(~sliceFolder, "mfcc.ds");

(
~splitFiles = { | filename, folderWithSlices |
	Routine.run({
		var  cond = Condition.new, bufferToSplit, slicesInFrames, indices, corpusMap, time;
		s.sync(cond);

		bufferToSplit = Buffer.read(s, File.realpath(filename));
		s.sync(cond);

		slicesInFrames = Buffer.new(s);

		s.sync(cond);
		// FluidBufOnsetSlice.process(s, bufferToSplit, metric:2, indices:slicesInFrames, threshold:0.1);

		// with basic params
		time = Main.elapsedTime;
		FluidBufOnsetSlice.process(s, bufferToSplit, metric:2, indices:slicesInFrames, threshold:0.5);
		s.sync(cond);

		s.sync(cond);
		slicesInFrames.query;

		(Main.elapsedTime - time).postln;

		s.sync(cond);
		File.mkdir( folderWithSlices );
		if( slicesInFrames.numFrames > 0, {
			slicesInFrames.getn(0, slicesInFrames.numFrames,{|item|indices = item;});

			s.sync(cond);

			indices.doAdjacentPairs({|start,stop, i|
				"start: %\n".postf(start);
				"stop: %\n".postf(stop);
				i.postln;
				bufferToSplit.write(folderWithSlices++"slice_"++i++".wav", startFrame: start, numFrames:(stop-start) );
				s.sync(cond);
			});
		});
		bufferToSplit.free;
		s.sync(cond);

		slicesInFrames.free;
		s.sync(cond);

		"DONE!".postln;

	}, clock: AppClock);
};

~analyseSlices = { | folderWithSlices |

	Routine.run({
		var cond = Condition.new;

		FluidCorpusMap.python = "/usr/bin/python3";
		FluidCorpusMap.indexFolder = folderWithSlices;

		FluidCorpusMap.analyzeFolder( folderWithSlices, feature:0);
		s.sync(cond);
		FluidCorpusMap.analyzeFolder( folderWithSlices, feature:1);
		s.sync(cond);
		"DONE!".postln;

	}, clock: AppClock);
};

~generateMap = { | folderWithSlices, analysisFile="ae.ds"|
	Routine.run({
		var cond = Condition.new, corpusMap;
		corpusMap = FluidCorpusMap.new(folderWithSlices++analysisFile);
		s.sync(cond);

		corpusMap.map(4);
		s.sync(cond);
	
	       corpusMap.loadBuffers;
		s.sync(cond);

		corpusMap.scatterplot(0);
		s.sync(cond);

	}, clock: AppClock);
};

)

Thanks for sharing!

Your questions:

The sorting/distance measuring is done in Python in this example, after dimension reduction, which is the point of this paper (exploring the effects of various dimension reductions to design interface). So either you tackle the Python bit (the n_comps parameter in compute_projection) but this is venturing in ‘research code’ land. I hope you like reading SC classes as this should help you understand how the data is passed to Python and then back from a file which has the reduced dimensions. Reduce to 1 and see how it reacts… no guarantee here!

It seems SC is not waiting the way I expected it would indeed. But @weefuzzy and @groma keep reminding me how convoluted the language-server dance is in SC.

I’m curious now: did you install the beta02 of all the Fluid Decomposition toolbox, as well as this repo? If yes, it means you have 2 versions of the extensions, so that might explain the problem.

We also know that the interface of Fluid Corpus Map will have to be updated to support the public release of the toolbox, and all of this is in progress, in the very end of it actually, so soon all of it will gel like magic.

ok, thanks!
This is how I solved it:


(
a = FluidCorpusMap.new( "/path/to/my/ae/file/ae.ds");

l = List();
a.positions.do{ | value,  i |
	l.add(value.mean);
};
l.sort

)

[quote=“tremblap, post:5, topic:407”]
It seems SC is not waiting the way I expected it would indeed. But @weefuzzy and @groma keep reminding me how convoluted the language-server dance is in SC.

I’m curious now: did you install the beta02 of all the Fluid Decomposition toolbox, as well as this repo? If yes, it means you have 2 versions of the extensions, so that might explain the problem.

We also know that the interface of Fluid Corpus Map will have to be updated to support the public release of the toolbox, and all of this is in progress, in the very end of it actually, so soon all of it will gel like magic.
[\quote]

yes, you are right, I did install the beta02 and then the FluidCorpusMap repo.
Thanks for the information, I am looking forward for the new version :slight_smile:

1 Like