‹ Work with Mark: Inaugural Talk Work with Mark: Old System Design 2 ›

Work with Mark: SuperCollider Sampler

2006-09-17 17:12 research, supercollider

For my work together with Mark d'Inverno I coded a few tools. One of the things that came up was a need for a neutral but nice-sounding way to test aspects of our musical-agents systems. So we got hold of a grand-piano sample library and I wrote a 'giga sampler' like class for SuperCollider. This allowed us to use this massive sample library (2.5GB) and let the agents play high-quality samples instead of cheap MIDI or boring synthesised sounds. So for testing melodies, harmonies and such, this was a good thing.

The trick with the giga sampler is that it preloads a bit from each sound file into RAM and then streams the rest from disk when needed. Or at least this is how I understand it. So using this technique, one can get quick access to a lot more samples than normally would fit in the memory of a sampler. A massive library like ours with full 88keys range, sampled in many different velocities, would occupy ~5GB of RAM (SuperCollider uses 32bit internally), nor could it be streamed from disk (the harddrive would be too slow to access and load the headers to play fast chords progressions without staggering etc).

I spent some time to make my class all-round useful and it can be downloaded from github.com/redFrik/redSampler or simply install by typing Quarks.install("redSampler") in SuperCollider. The class of interest in that package is called RedDiskInSampler.

And here is some testcode for it...

s.boot;
d= ();  /*for mapping midinote to filename*/
r.free;
r= RedDiskInSamplerGiga(s);  /*sampler*/
(
var folder= "/Users/asdf/Documents/soundfiles/bosen44100/";  //edit to match your samplebank
var velocities= #[40, 96];  /*velocities to load*/
var octavesToLoad= #[2, 3];  /*how many octaves to load*/
var scale= #['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
/*so number of samples to load is octavesToLoad.size*12*velocities.size*/
/*lowest note C2= midi 36*/
velocities.do{|x, i|
  var tempDict= ();
  d.put(x, tempDict);
  octavesToLoad.do{|y, j|
    scale.do{|z, k|
      var midinote, pathname, key;
      midinote= y*12+12+k;
      key= z++y;
      pathname= folder+/+x+/+key++".aif";
      key= (key++"_"++x).asSymbol;
      tempDict.put(midinote, key);  /*like (45 : A2_96)*/
      ("loading key"+key+"from file"+pathname).postln;
      r.preload(key, pathname);
    };
  };
};
)
r.play(\C2_96, 0, 3, 1)
r.play(\D2_40, 0, 3, 1)
Tdef(\test).play
a= r.loadedKeys;
(Tdef(\test, {
  inf.do{|i|
    r.play(a.choose, 0, 0.45, 0.1);
    0.5.wait;
  }
}))
(Tdef(\test, {
  b= a.asArray.scramble;
  inf.do{|i|
    b.do{|x, j|
      r.play(x, 0, 0.35, 0.1);
      0.15.wait;
    };
    2.wait;
  }
}))
(Tdef(\test, {
  b= a.asArray.sort;
  inf.do{|i|
    b.do{|x, j|
      r.play(x, 0, 0.25, 0.08, amp: 0.6);
      0.1.wait;
    };
    1.wait;
  }
}))
Tdef(\test).stop
r.free

‹ Work with Mark: Inaugural Talk Work with Mark: Old System Design 2 ›