12.1 Loading a sample into an array
You can load a sample into an array with the object soundfiler. To do this we need to do some work. First, lets create a new folder with whatever name you want. At the top level of this folder there must be a patch (in which you want to load the sample) and also a subfolder called samples. Inside this subfolder you can place any files with extension .wav and .aif or .aiff which are standard non-compressed formats.
Once your audio files are inside this folder you an load them with the message “read -resize ./sample-subfolder/filename.wav arrayname” to the object soundfiler. As you might expect, you need to replace the subfolder name with the appropriate name. The same is true for the filename and arrayname. The “-resize” flag changes the size of the array to the size of the sample that is being loaded.
The output of soundfiler is the length in samples. To obtain the duration in seconds we divide the length in samples by the sample rate. In this case, assuming a 44.1KHz sample rate, we divide the length in samples by 44.1 to obtain the duration in milliseconds.
This process of loading a sample is shown in Figure 12.1.
12.2 Reading a sample: tabread4~ and line~
The point of this section is that we can in fact read a sample a single time from start to finish. To do that, we need to ask a line~ to go from 0 to 1 over the time of its duration in milliseconds. This line~ signal is used as the index for reading the array.
The ouput range of line~ thus needs to be adapted to the input required by tabread4~, which as we have already seen in the section on wavetable oscillators is “1 to size-2”. To map the output range of line~ to the required input range of tabread4~ we need to perform two steps.
First, multiply the output of line~ times “size-3” thus changing the output range from 0 to size-3.
Second, add 1, thereby pushing the range to “1 to size-2”.
With this range we can now send the line~ signal to tabread4~ as seen in Figure 12.2 and we should be able to hear the sample we loaded in Figure 12.1.
12.3 Changing the pitch of the sample
tabread4~ needs to read the full size of the sample from the start to the end of the array in the range specified above. However, in order to reproduce the sample at the correct pitch, the line~ signal used as an index must move from start to end in the matching duration (size/samplerate).
If line~ takes twice to play as it took to record (duration in milliseconds times 2), then we will hear a change in pitch to an octave lower.
Conversely, if line~ takes half the time to it took to record (duration in milliseconds times 1/2 or .5) then we will hear our sample an octave higher in pitch.
In Figure 12.3 we can see how this is implemented in a patch.
12.3 Transposing in half-steps.
In order to transpose a sample in semitones we need to convert it into playback speed. Thus, we need a function where inputting “12” (half-steps) outputs “.5” (octave up), and inputting “-12” outputs “2” (octave down), and inputting “0” outputs “1” (no transposition).
This function uses a constant which is 0.0577623… or ln(2)/12.
The transposition to playback speed function is:
playback-speed = e (-0.0577623*transposition-in-half-steps)
Using this function we can now construct a keyboard sampler.
12.4 Keyboard Sampler
Here is a screenshot of our keyboard sample player. If you want it to tune correctly, you need to use the pitch of the sample as the reference pitch. This one is designed to stop playing at note-off like a mellotron.
12.5 Sample Sequencer
Here is a screenshot of our sample sequencer. It has a 16-step sequence in this case. Also we are introducing our textfile object. Also we are using “array define” instead of actually putting an array; you can still see it if you click on “array define”; this is a more convenient way to work with arrays, check out the help file! We are also using “array get”, and introducing the family of list objects, starting with “list prepend”, and “list trim”, check those help files too! Finally, you probably know this already, but you can pack symbols and floats together by specifying their types as we do below with “pack s f”.
12.5 Granulator
Here is a screenshot of our granulator. The algorithm driving the samples is very rudimentary, but you can imagine other approaches!