Samples
A sample is a recorded sound in a file beside your program: a .wav, or an .mp3 or .ogg.
const meow = loadSample("meow.wav")
function onMouseDown() {
meow.play() // as it was recorded
}There is nothing to wait for. Play it straight away, and it sounds as soon as the file has arrived.
A sample is a synth
So it plays at any pitch, and it has the same settings:
const meow = loadSample("meow.wav")
meow.play("E4") // higher: "C4" is its own pitch
meow.play("C3", 2) // an octave lower, for two seconds
meow.reverb = 0.3
meow.playNotes("C4 E4 G4 C5", 0.25)A tune played on a recording of one note is an instrument made from that sound.
A sample that goes round
const hum = loadSample("hum.wav", { loop: true, note: "A3" })
hum.play("E4", 2)| Option | What it does |
|---|---|
loop | The sound goes round for as long as a note lasts |
note | The note it was recorded at, so that other notes come out in tune. "C4" unless you say |
Any setting of a synth can be given too: loadSample("kick.wav", { volume: 0.8, reverb: 0.2 }).
A synth made from a sample
Any synth can have a sample for its wave. The recording then goes through that synth's filter, its envelope and its effects, so one recorded note becomes an instrument you can shape:
const lead = makeSynth("pad")
lead.sample = loadSample("piano.wav") // its wave is now "sample"; lead.wave = "saw" goes back
const keys = makeSynth({ sample: "piano.wav", note: "C4", cutoff: 1800, release: 0.6 }) // or all in one line
function onMouseDown() {
keys.play(["C4", "E4", "G4"], 1)
}sample takes a sample from loadSample, a recording, or the name of a sound file. note is the note the recording is at.
The wave "sample" is only for a synth that has one. On a synth with none it is not among the choices that select("wave", lead, "wave") offers, and lead.wave = "sample" says how to give it one and leaves the wave as it was.
An instrument from several samples
One recording stretched over a whole keyboard sounds thin at one end and muddy at the other. A real instrument is several recordings, each playing the keys near the note it was recorded at. loadSamples makes one from them (load_samples in Python).
This is a piano of nine recordings, one every half octave from C2 to C6. Each key plays the nearest recording, moved to its pitch, so no note is stretched by more than three keys:
// The note each was played at is in its name: C2, Fs2 (F sharp), C3 …
const piano = loadSamples([
"piano/piano-C2.wav", "piano/piano-Fs2.wav", "piano/piano-C3.wav", "piano/piano-Fs3.wav", "piano/piano-C4.wav",
"piano/piano-Fs4.wav", "piano/piano-C5.wav", "piano/piano-Fs5.wav", "piano/piano-C6.wav",
], { crossfade: 2 })
piano.reverb = 0.25 // a synth like any other: settings, dials, a tune, an arpeggio
dial("reverb", piano, "reverb")
scope(piano)
keyboard(piano, { octave: 3, octaves: 3 })The nine recordings are in the synths.js repository, in examples/piano: put the folder beside your program. They are from the University of Iowa Musical Instrument Samples, which may be downloaded and used for any project, without restrictions.
Saying which note each is
The plain way is a note for each file:
const piano = loadSamples({ C2: "piano-C2.wav", "F#2": "piano-Fs2.wav", C3: "piano-C3.wav" }) // the note each was played at
piano.play("E2") // the nearest recording (F#2), moved down to EThe keys are split halfway between neighbours, and every key plays, below the lowest recording and above the highest too.
With the notes in the files' names there is less to write. A list of names is enough, as the piano above has: C2, Fs2 (or F#2, Gb2) and C3 are read from the names, and a number alone (60.wav) is that key. A name with no note in it is refused, with what to do about it.
A drum kit
A drum kit is the same with kit. Each key is its own sound, played as it was recorded whatever the key, to its end, and the keys between are silent.
const kit = loadSamples({ C2: "kick.wav", D2: "snare.wav", "F#2": "hat.wav" }, { kit: true })
function onMouseDown() {
kit.playNotes("C2 F#2 D2 F#2", 0.25, { repeat: true })
}What else can be said
| To do this | Write this |
|---|---|
| Fade neighbouring recordings into each other over three keys, where a change from one to the next would be heard | { crossfade: 3 } (crossfade=3). { crossfade: { keys: 3, loud: 0.1 } } fades the loudness layers too |
| Give every recording the same release | loadSamples(files, { release: 1 }) (release=1). With nothing said each recording has a release that suits its note, longer for the low ones, as a piano's are |
| Make every recording go round, or play to its end | { loop: true }, { oneShot: true } (loop=True, one_shot=True) |
Layers by how hard a note is played. In the explicit form each recording is written out, and loud is the note's volume, from and to:
const snare = loadSamples([
{ file: "soft-C4.wav", note: "C4", loud: [0, 0.5] },
{ file: "hard-C4.wav", note: "C4", loud: [0.5, 1] },
])
snare.play("C4", 0.3, 0.9) // loud enough for the hard oneIn that form each recording may also say from and to (its keys), tune (hundredths of a semitone), volume, pan, release (seconds), oneShot, asRecorded, loop and start (frames). In Python they are keys of the dictionary: "one_shot", "as_recorded".
Takes that go in turn. Several files for one note, and each hit plays the next, so a drum does not sound like a machine:
const snare = loadSamples({ C4: ["snare-1.wav", "snare-2.wav"] })On an ordinary synth. The recordings then go through that synth's filter and envelope:
const lead = makeSynth("lead")
lead.samples = { C3: "a.wav", C4: "b.wav" }
lead.setSamples({ C3: "a.wav", C4: "b.wav" }, { crossfade: 3 }) // the same, with options
const soft = makeSynth({ samples: { C3: "a.wav", C4: "b.wav" }, cutoff: 1800 })
lead.samples = null // takes them awaylead.samples(), called, is still the wave for a scope.
Reading it back. piano.zones() is the list of recordings as it stands. In JavaScript each has its file, note, from, to, loud, tune, volume, pan, release, oneShot, asRecorded and take. In Python it is the list as you gave it, each with its file and its note; the keys each was worked out to play are the page's to know.
The files are fetched together, and each recording plays as soon as it has arrived. If one cannot be loaded it is said once, and its neighbours take its keys. piano.remove() lets go of the recordings as well as the synth. An instrument may have 512 recordings, and a note plays at most 4 at once.
Where the file is
The path is from the program's own file, so save the program in the folder that holds the sound, or in the one above it: loadSample("sounds/kick.wav"). A new document that has not been saved has no folder yet.
A file that is missing does not stop the program. It is said once, and the sample plays nothing.
Drums from recordings
const thud = loadSample("sounds/thud.wav")
const clap = loadSample("sounds/clap.wav")
let playing = false
function onMouseDown() {
playing = !playing
if (!playing) return stopSound()
thud.playNotes("C4 - - - C4 - - -", 0.125, { repeat: true })
clap.playNotes("- - - - C4 - - -", 0.125, { repeat: true })
}Recording your own
A sample does not have to come from a file. recordSound(3) records three seconds of the microphone and recordOutput(10) records what the program plays, each as a sample that plays at any pitch, and saveSound(meow, "meow.wav") saves one as a WAV file. See Recording.
Related
- Recording
- Synths and their settings
- Songs: a whole piece of music from one file