Slice buffer at regular length ? - Supercollider

Hey guys,

I’m studying how to parse a corpus of entire audio files and not chunks of them.

I have a sound database with 5 files of the same duration (5 seconds for each file, 48000 SR).

Following the tutorials, I am able to concatenate all the audio files and convert them into mono as follows:

~loader = FluidLoadFolder("audio_folder");
~loader.play(s, {"done".postln;});
FluidWaveform(~loader.buffer);

~src = Buffer(s);
(
FluidBufCompose.processBlocking(s, ~loader.buffer,startChan:0, numChans:1, destination:~src, destStartChan:0, gain: -6.dbamp);
FluidBufCompose.processBlocking(s, ~loader.buffer,startChan:1, numChans:1, destination:~src, destStartChan:0, gain: -6.dbamp,destGain:1);
)

Next, how could I extract, for example, all 5 audio files from this concatenated list?

I think “FluidBufOnsetSlice” is not interesting as there is onset variation of each audio file. Nor with “FluidBufAmpSlice”.

I tried using “FluidBufSelectEvery” but I couldn’t find a list with the segments. It returns me a list with negative numbers.

I thought about using FluidBufCompose but I didn’t find parameters to configure the size of each slice.

Thank you for all the support,

Best

Hi @ieysimurra and welcome!

If you can tell me more about your overall ambitions, I can give a more detailed answer. But the short version: (almost) all the FluidBuf objects have startFrame and numFrames parameters (in samples). So if you wanted to decompose a 25 second file @ 48kHz into 5 equal chunks you could use FluidBufCompose. Something along the lines of

(
fork{
    // a dummy big buffer
    ~big_one = Buffer.alloc(s,25 * s.sampleRate); 
    //chop it up
    ~small_ones = 5.collect{ |i|
        var b = Buffer.new(s); 
        var offset = i * 5 * s.sampleRate;  
        var n = 5  * s.sampleRate;     
        FluidBufCompose.process(s,~big_one, startFrame:offset,numFrames:n,destination: b).wait; 
        b 
    }; 
    //just to check
    ~small_ones.do{ |buf|
        buf.numFrames.postln
    }    
}
)

However, you probably have some further analysis in mind?

1 Like

@weefuzzy
Thank you so much!

However, you probably have some further analysis in mind?

You are completely right!
My goal is to interact sound analysis of entire audio files for live performance of extended instrumental techniques audio files with digital audio processing technique. As I’m not interested in small bits of audio analysis for this, I think taking, for example, the average of the audio characteristics of the entire files can plot the entire files.

Anyway, your suggestion was a great insight to work with entire files with FluCoMa.

one question further, if I may: Is it possible to get the indexes of each start and end points in that big audio buffer such for examples for every 5 seconds duration length?

Thank you so much!

Yes, this is simple enough to do language side because the sample rate of the source buffer is known, and the slices are regular.

(   
/******************************************************************************
returns a 2D array of [start, end] in samples for slices of dur seconds length across buf
******************************************************************************/
~equal_slice_points = { |buf, dur, include_remainder| //pass a buffer and a slice duration in seconds
    
    var frames_per_slice = dur * buf.sampleRate; 
    var num_whole_slices = (buf.numFrames / frames_per_slice).floor.asInteger; 
    var remainder = (buf.numFrames - (num_whole_slices * frames_per_slice)).asInteger; 
    
    var result = num_whole_slices.collect{|i|
        [i * frames_per_slice, (i + 1) * frames_per_slice]            
    }; 
    
    if(include_remainder && (remainder > 0)) {
        result = result ++ [[num_whole_slices * frames_per_slice, buf.numFrames]]; 
    } {};   
    result.asInteger        
};

/******************************************************************************
simple case with a big buffer that divides neatly into chunks of the required duration
******************************************************************************/
~big_one = Buffer.alloc(s,25 * s.sampleRate);  //strictly, we should probably do the alloc in a routine and wait  
~five_second_slices = ~equal_slice_points.value(~big_one, 5, true); 
("Regular slices:" + ~five_second_slices).postln; 

/******************************************************************************
less simple case where there's some leftovers at the end
******************************************************************************/
~odd_big_one = Buffer.alloc(s, 26.5 * s.sampleRate);     
~five_second_slices = ~equal_slice_points.value(~odd_big_one, 5, true); 
("Regular slices and remainder:" + ~five_second_slices).postln; 

/******************************************************************************
Then in flucoma-land, you could just iterate over the array of slice points
******************************************************************************/
fork{
    ~mean_analysis = ~five_second_slices.collect{ |start_end|
        /* e.g... */ 
        var featureBuf = Buffer.new(s); 
        var meanBuf = Buffer.new(s); 
        var start = start_end[0]; 
        var dur = start_end[1] - start_end[0];         
        FluidBufPitch.processBlocking(s,~odd_big_one, start, dur, features:featureBuf).wait;
        FluidBufStats.processBlocking(s,featureBuf,stats:meanBuf,select:[\mean]).wait; 
        featureBuf.free; 
        meanBuf; //just return the buffer, but if you wanted the data you could do loadToFloatArray here and return that instead
    };
    s.sync; 
    ("Analysed buffers:" + ~mean_analysis).postln;    
}
)
1 Like

@weefuzzy

Very readable and understandable.
It’s exactly what I was looking for to study audio file samples with FluCoMa-land
:slight_smile:
Thank you very much for your kind and quick attention.

2 Likes