How to match an object in a list

Hi all,

I load a folder full of samples as Buffers into a List:

var smpPath = PathName(thisProcess.nowExecutingPath.dirname +/+ "smp");
~smpBuffers = List();
	
smpPath.filesDo({ |smpfile,i|
	~smpBuffers.add(Buffer.readChannel(s, 
			smpfile.fullPath, channels:[0]));
});

I end up with a List that contains Buffer objects. Something like

~smpBuffers.postln;

-> List[ Buffer(0, 600, 1, 44100.0, /path/to/bassdrum.wav), 
         Buffer(1, 600, 1, 44100.0, /path/to/fieldrecording.wav),
         Buffer(2, 600, 1, 44100.0, /path/to/flute.wav) ]

I can access it in a synth with .at() method:

y = Synth(\granulator, [\bufnum, ~smpBuffers.at(0)])

But if in the process of working on larger work, I add more samples in the folder (or remove them because they are not in use), indices in the list will get messed up.

Is there a way to ‘match’ a filename that Buffer objects in the list actually know about? So, in above context I would ideally love to do something like:

y = Synth(\granulator, [\bufnum, ~smpBuffers.match('*fieldrec*')])

I know how to create a separate parallel List with just filenames and then cross-match indices with a full filename, but I’m looking for specific way to match within that single list of Buffer objects.
Or is there a better way to work with big collections of samples?

Ok, one way of solving this, at least partially, is to use Dictionary:

~smpBuffers = Dictionary();
	
smpPath.filesDo({ |smpfile,i|
	~smpBuffers.add(smpfile.fileName -> Buffer.readChannel(s, 
				smpfile.fullPath, channels:[0]));
});

This way I can access a Buffer like this:

z = Synth(\bufPlayer, [\bufnum, ~smpBuffers.at("fieldrecording.wav")])

But it has to be exact filename. Is there a way to do some regex or wildcard matching?

It’s O(n) so not as efficient for access as a Dictionary, but this will work:

~smpBuffers.detect { |buf| buf.path == .... }

… will return the first matching item.

hjh

Which led me to use .matchRegexp in that fuction for .detect:

z = Synth(\bufPlayer, [\bufnum, 
    ~smpBuffers.detect { |buf| "fieldrec".matchRegexp(buf.path) }])

I found it a rather ‘mouthful’ (too much code), so I turned it into a function:

~getSample = {|regexp| ~smpBuffers.detect {|buf| regexp.matchRegexp(buf.path)}};

So the use in that case would be:

z = Synth(\bufPlayer, [\bufnum, ~getSample.value("fieldrec")])

I have a sample loading class I used for… loading samples. I implement a custom at method, which takes over behavior for the samples[10] indexed access. In my case, store the samples in a fixed array and look-up indexically if I pass a number, e.g. samples[10], or look up using detect with a regex, if I pass a string, samples["snare*"].

The class is probably too suited to my personal workflow to be of use out of the box, but feel free to borrow concepts from it. It requires the Singleton and Require quarks.

1 Like

Interesting. Thank you for this @scztt, it seems simple, though I still need to wrap my head around writing and using classes. Soon.