Play back a recorded sound file (sample). Sonic Pi comes with lots of great samples included (see the section under help) but you can also load and play .wav
, .wave
, .aif
, .aiff
, .ogg
, .oga
or .flac
files from anywhere on your computer too. To play a built-in sample use the corresponding keyword such as sample :bd_haus
. To play any file on your computer use a full path such as sample "/path/to/sample.wav"
.
There are many opts for manipulating the playback. For example, the rate:
opt affects both the speed and the pitch of the playback. To control the rate of the sample in a pitch-meaningful way take a look at the rpitch:
opt.
The sampler synth has three separate envelopes - one for amplitude, one for a low pass filter and another for a high pass filter. These work very similar to the standard synth envelopes except for two major differences. Firstly, the envelope times do not stretch or shrink to match the BPM. Secondly, the sustain time by default stretches to make the envelope fit the length of the sample. This is explained in detail in the tutorial.
Samples are loaded on-the-fly when first requested (and subsequently remembered). If the sample loading process takes longer than the schedule ahead time, the sample trigger will be skipped rather than be played late and out of time. To avoid this you may preload any samples you wish to work with using load_sample
or load_samples
.
Finally, the sampler supports a powerful filtering system to make it easier to work with large folders of samples. The filter commands must be used before the first standard opt. There are six kinds of filter parameters you may use:
By combining commands which add to the candidates and then filtering those candidates it is possible to work with folders full of samples in very powerful ways. Note that the specific ordering of filter parameters is irrelevant with the exception of the numbers - in which case the last number is the index. All the candidates will be gathered first before the filters are applied.
# Example 1 |
sample :loop_amen
|
# Play a built-in sample
# Plays the Amen break
|
# Example 2 |
sample :loop_amen
sample :ambi_lunar_land
|
# Play two samples at the same time
# with incredible timing accuracy
# Note, for timing guarantees select the pref:
# Studio -> Synths and FX -> Enforce timing guarantees
|
# Example 3 |
live_loop :bass do
sample :bd_haus
sleep 0.5
end
|
# Create a simple repeating bass drum
|
# Example 4 |
live_loop :rhythm do
sample :tabla_ghe3 if (spread 5, 7).tick
sleep 0.125
end
live_loop :bd, sync: :rhythm do
sample :bd_haus, lpf: 90, amp: 2
sleep 0.5
end
|
# Create a more complex rhythm with multiple live loops:
|
# Example 5 |
sample :loop_amen, rate: 0.5
|
# Change the playback speed of the sample using rate:
# Play the Amen break at half speed
# for old school hip-hop
|
# Example 6 |
sample :loop_amen, rate: 1.5
|
# Speed things up
# Play the Amen break at 1.5x speed
# for a jungle/gabba sound
|
# Example 7 |
sample :loop_amen, rate: -1
|
# Go backwards
# Negative rates play the sample backwards
|
# Example 8 |
sample :loop_amen, rate: -3
|
# Fast rewind
# Play backwards at 3x speed for a fast rewind effect
|
# Example 9 |
sample :loop_amen, start: 0.5
|
# Start mid sample
# Start playback half way through
|
# Example 10 |
sample :loop_amen, finish: 0.5
|
# Finish mid sample
# Finish playback half way through
|
# Example 11 |
sample :loop_amen, start: 0.125, finish: 0.25
|
# Play part of a sample
# Play the second eighth of the sample
|
# Example 12 |
sample :loop_amen, start: 0.25, finish: 0.125
|
# Finishing before the start plays backwards
# Play the second eighth of the sample backwards
|
# Example 13 |
sample :loop_amen, start: 0.125, finish: 0.25, rate: -0.25
|
# Play a section of a sample at quarter speed backwards
# Play the second eighth of the
# amen break backwards at a
# quarter speed
|
# Example 14 |
s = sample :loop_amen, lpf: 70
sleep 0.5
control s, lpf: 130
sleep 0.5
synth :dsaw, note: :e3
|
# Control a sample synchronously
# This is triggered 1s from start
|
# Example 15 |
sample :loop_amen, lpf: 70 do |s|
sleep 1
control s, lpf: 130
end
sleep 0.5
synth :dsaw, note: :e3
|
# Controlling a sample asynchronously
# This block is run in an implicit in_thread
# and therefore is asynchronous
# This is triggered 0.5s from start
|
# Example 16 |
sample :loop_garzul, slice: 0
sleep 0.5
4.times do
sample :loop_garzul, slice: 1
sleep 0.125
end
sample :loop_garzul, slice: 4, num_slices: 4, rate: -1
|
# Play with slices
# => play the first 16th of the sample
# => play the second 16th of the sample 4 times
# => play the final quarter backwards
|
# Example 17 |
use_sample_bpm :loop_amen
live_loop :beat_slicer do
n = 8
s = rand_i n
sample :loop_amen, slice: s, num_slices: n
sleep 1.0/n
end
|
# Build a simple beat slicer
# Set the BPM to match the amen break sample
# Specify number of slices
# (try changing to 2, 4, 6, 16 or 32)
# Choose a random slice within range
# Play the specific part of the sample
# Sleep for the duration of the slice
|
# Example 18 |
sample :loop_amen, lpf: 80, hpf: 70, compress: 1, pre_amp: 10
|
# Play with the built-in low pass filter, high pass filter and compressor
# Make the amen break sound punchy.
|
# Example 19 |
sample :loop_garzul, lpf_attack: 8
sleep 8
sample :loop_garzul, hpf_attack: 8
|
# Use the cutoff filter envelopes
# Sweep the low pass filter up over 8 beats
# Sweep the high pass filter down over 8 beats
|
# Example 20 |
puts sample_duration :loop_industrial
puts sample_duration :loop_industrial, beat_stretch: 1
live_loop :industrial do
sample :loop_industrial, beat_stretch: 1
sleep 1
end
|
# Sample stretching
# => 0.88347
# => 1
# Stretch the sample to make it 1 beat long
# This now loops perfectly.
# However, note that stretching/shrinking
# also modifies the pitch.
|
# Example 21 |
puts sample_duration :loop_garzul
puts sample_duration :loop_garzul, beat_stretch: 6
live_loop :garzul do
sample :loop_garzul, beat_stretch: 6
sleep 6
end
|
# Sample shrinking
# => 8
# => 6
# As :loop_garzul is longer than 6 beats
# it is shrunk to fit. This increases the
# pitch.
|
# Example 22 |
use_bpm 30
puts sample_duration :loop_garzul
puts sample_duration :loop_garzul, beat_stretch: 6
live_loop :garzul do
sample :loop_garzul, beat_stretch: 6
sleep 6
end
|
# Sample stretching matches the BPM
# Set the BPM to 30
# => 4.0 (at 30 BPM the sample lasts for 4 beats)
# => 6.0
# The sample is stretched to match 6 beats at 30 BPM
|
# Example 23 |
sample "/path/to/sample.wav"
|
# External samples
# Play any Wav, Aif, Ogg, Oga, or FLAC sample on your computer
# by simply passing a string representing the full
# path
|
# Example 24 |
dir = "/path/to/dir/of/samples"
sample dir
sample dir, 1
sample dir, 99
sample dir, "120"
sample dir, "120", 1
sample dir, /beat[0-9]/
sample dir, /beat[0-9]0/, "100"
|
# Sample pack filtering
# You can easily work with a directory of samples
# Play the first sample in the directory
# (it is sorted alphabetically)
# Play the second sample in the directory
# Play the 100th sample in the directory, or if there
# are fewer, treat the directory like a ring and keep
# wrapping the index round until a sample is found.
# For example, if there are 90 samples, the 10th sample
# is played (index 9).
# Play the first sample in the directory that contains
# the substring "120".
# For example, this may be "beat1_120_rave.wav"
# Play the second sample in the directory that contains
# the substring "120".
# For example, this may be "beat2_120_rave.wav"
# Play the first sample in the directory that matches
# the regular expression /beat[0-9]/.
# For example, this may be "beat0_100_trance.wav"
# You may use the full power of Ruby's regular expression
# system here: http://ruby-doc.org/core-2.1.1/Regexp.html
# Play the first sample in the directory that both matches
# the regular expression /beat[0-9]0/ and contains the
# the substring "100".
# For example, this may be "beat10_100_rave.wav"
|
# Example 25 |
sample "tabla_"
sample "tabla_", 2
|
# Filtering built-in samples
# If you don't pass a directory source, you can filter over
# the built-in samples.
# Play the first built-in sample that contains the substring
# "tabla"
# Play the third built-in sample that contains the substring
# "tabla"
|
# Example 26 |
load_samples "tabla_"
live_loop :tabla do
sample "tabla_", tick
sleep 0.125
end
|
# Play with whole directories of samples
# You may pass any of the source/filter options to load_samples
# to load all matching samples. This will load all the built-in
# samples containing the substring "tabla_"
# Treat the matching samples as a ring and tick through them
|
# Example 27 |
dir1 = "/path/to/sample/directory"
dir2 = "/path/to/other/sample/directory"
sample dir1, dir2, "foo"
|
# Specify multiple sources
# Match the first sample that contains the string "foo" out of
# all the samples in dir1 and dir2 combined.
# Note that the sources must be listed before any filters.
|
# Example 28 |
dir = "/path/to/sample/directory"
dir_recursive = "/path/to/sample/directory/**"
sample dir, 0
sample dir_recursive, 0
|
# List contents recursively
# By default the list of all top-level samples within the directory
# is considered.
# However, if you finish your directory string with ** then if that
# directory contains other directories then the samples within the
# subdirectories and their subsubdirectories in turn are considered.
# Play the first top-level sample in the directory
# Play the first sample found after combining all samples found in
# the directory and all directories within it recursively.
# Note that if there are many sub directories this may take some time
# to execute. However, the result is cached so subsequent calls will
# be fast.
|
# Example 29 |
filter = lambda do |candidates|
[candidates.choose]
end
8.times do
sample "drum_", filter
sleep 0.25
end
|
# Bespoke filters
# If the built-in String, Regexp and index filters are not sufficient
# you may write your own. They need to be a function which takes a list
# of paths to samples and return a list of samples. This one returns a
# list of a single randomly selected sample.
# Play 8 randomly selected samples from the built-in sample set that also
# contain the substring "drum_"
|
# Example 30 |
sample :loop_tabla, start: 0, finish: 0.00763
sleep 1
sample :loop_tabla, onset: 0
sleep 1
sample :loop_tabla, onset: 1
|
# Basic Onset Detection
# If you know the right start: and finish: values, you can extract a
# single drum hit from a longer sample. However, finding these values
# can be very time consuming.
# Instead of specifying the start: and finish: values manually you can
# use the onset: option to find them for you using an integer index.
# onset: 0 will set the start: and finish: values so that the first
# percussive sound (something that shifts from quiet to loud quickly)
# is picked out.
# We can easily find the second percussive sound in the sample with
# onset: 1
|
# Example 31 |
live_loop :tabla do
use_bpm 50
sample :loop_tabla, onset: tick
sleep [0.125, 0.25].choose
end
|
# Ticking through onsets
# The onsets are actually a ring so the index will wrap around. This
# means that if there are only 8 onsets in a sample, specifying an
# onset of 100 will still return one of the 8 onsets. This means we
# can use tick to work through each onset in sequence. This allows us
# to redefine the rhythm and tempo of a sample
# We can choose our own BPM here - it doesn't need to match the sample
# tick through each onset in sequence
# randomly choose a delay between onset triggers
|
# Example 32 |
use_bpm 50
live_loop :tabla do
sample :loop_tabla, onset: pick
sleep [0.125, 0.25].choose
end
|
# Random Onset Triggering
# We can easily pick a random onset using the pick fn
# Each time round the live loop we now trigger a random onset
# creating an infinite stream of randomly selected drums
|
# Example 33 |
live_loop :tabla do
use_random_seed 30000
8.times do
sample :loop_tabla, onset: pick
sleep [0.125, 0.25].choose
end
end
|
# Repeatable Random Onsets
# Instead of an infinite stream of choices, we can combine iteration
# and use_random_seed to create repeatable riffs:
# every 8 times, reset the random seed, this resets the riff
|
# Example 34 |
live_loop :tabla do
sample :loop_tabla, onset: pick, sustain: 0, release: 0.1
sleep [0.125, 0.25].choose
end
|
# Random Onset Duration
# Each onset has a variable length (determined by the sample contents).
# Therefore, if you wish to ensure each onset has a specific length it
# is necessary to use the sample's amplitude envelope.
# As the sample's envelope automatically changes the sustain: value to
# match the duration - you also need to override this with a value of 0.
# Each drum onset will now be no longer than 0.1. Note that the envelope
# for a sample only determines the maximum duration of a sample trigger.
# If the actual audible duration of the onset is smaller than 0.1 then
# it will *not* be extended.
|
# Example 35 |
l = lambda {|c| puts c ; c[0]}
sample :loop_tabla, onset: l
|
# Onset lambdas
# The onset index can be a lambda as well as an integer. If a lambda is
# given, it will be passed a ring of all of the onsets as an argument.
# This will be a ring of maps:
# define a lambda which accepts a single argument, prints it and
# returns the first value. This particular example is essentially
# the same as using onset: 0 with the side effect of also printing out
# the full ring of onsets:
# (ring {:start=>0.0, :finish=>0.0076}, {:start=>0.0076, :finish 0.015}...)
# We are therefore free to define this lambda to do anything we want.
# This gives us very powerful control over the choice of onset. It is
# unlikely you will use this frequently, but it is a powerful tool
# that's there when you need it.
|
# Example 36 |
sample :loop_tabla, onset: 1
|
# Plays the 2nd onset (the first onset would have index 0)
# Will override opts with: {start: 0.0151, finish: 0.0304}
# (these values are specific to the :loop_tabla sample and
# will vary for different samples)
|
# Example 37 |
sample :loop_tabla, onset: 1, slice: 0, num_slices: 1
|
# Plays the 2nd onset. This behaves the same as not specifying
# a slice as we select the first of one slices.
# Will override opts with: {start: 0.0151, finish: 0.0304}
# (these values are specific to the :loop_tabla sample and
# will vary for different samples)
|
# Example 38 |
sample :loop_tabla, onset: 1, slice: 0, num_slices: 2
|
# This plays the first half of the 2nd onset.
# This is because we split that onset into two slices and
# play just the first slice (with index 0).
# Will override opts with: {start: 0.0151, finish: 0.0227}
# (these values are specific to the :loop_tabla sample and
# will vary for different samples)
|
# Example 39 |
sample :loop_tabla, onset: 1, slice: 0, num_slices: 4
sample :loop_tabla, onset: 1, slice: 0, num_slices: 4, finish: 0.5
sample :loop_tabla, onset: 1, slice: 0, num_slices: 4, finish: 0.0, start: 0.5
|
# This plays the first quarter of the 2nd onset.
# This is because we split that onset into four slices and
# play just the first slice (with index 0).
# Will override opts with: {start: 0.0151, finish: 0.0189}
# (these values are specific to the :loop_tabla sample and
# will vary for different samples)
# Will play the first 1/8th of the 2nd onset.
# This is because we split that specific onset into 4 slices
# and then only play the first half of the first slice.
# Will override opts with: {start: 0.0151, finish: 0.017}
# (these values are specific to the :loop_tabla sample and
# will vary for different samples)
# Will play the first 1/8th of the 2nd onset backwards..
# This is because we split that specific onset into 4 slices
# and then only play from the first half of the first slice
# back to the beginning.
# Will override opts with: {start: 0.017, finish: 0.0151}
# (these values are specific to the :loop_tabla sample and
# will vary for different samples)
|