Public
Edited
Jan 17, 2023
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Play((t) => Math.sin(2*Math.PI*1*t))
Insert cell
Insert cell
function tone(frequency, offset=0) {
return (time) => Math.sin(frequency*(time-offset)*Math.PI*2)
}
Insert cell
Insert cell
Play(tone(frequency), 1)
Insert cell
Insert cell
function doubletone (first_frequency, second_frequency) {
return (time) => Math.sin(first_frequency*time*Math.PI*2) + Math.sin(second_frequency*time*Math.PI*2)
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Play(beep(tone_frequency, note_duration), note_duration)
Insert cell
beep = (frequency, duration, offset=0) => compose('*', clamp(duration, offset), envelope(duration, offset), tone(frequency, offset))
Insert cell
Insert cell
function bell({frequency, duration=1, offset=0, harmonics_range=[0,6]}) {
let harmonic_series = [1, 2, 3, 4.2, 5.4, 6.8].slice(...harmonics_range);
let proportions = [1, 0.6, 0.4, 0.25, 0.2, 0.15].slice(...harmonics_range);

function component(harmonic, proportion) {
return (time) => proportion * beep((harmonic * frequency), duration, offset)(time);
}
return (time) =>
_.sum(
_.map(
_.zip(harmonic_series, proportions),
([harmonic, proportion]) => component(harmonic, proportion)(time)
)
)
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Play(bell({frequency: 600, duration: note_duration, harmonics_range: [0,6]}), note_duration)
Insert cell
Insert cell
Play(bell({frequency: 500, duration: note_duration, harmonics_range: [1,6]}), note_duration)
Insert cell
Insert cell
Play(bell({frequency: 400, duration: note_duration, harmonics_range: [2,6]}), note_duration)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
ding = (midi, offset=0, duration=1) => { return bell({frequency: midi_to_hz(midi), duration: duration, offset: offset})}
Insert cell
Insert cell
Insert cell
Play(ding(midi_note), 1)
Insert cell
Insert cell
function play_sequence(notes) {
return (time) =>
_.sum(
_.map(
_.map(notes,
(note) => ding(note.pitch, note.time, note.duration)),
(d) => d(time)
)
)
}
Insert cell
even_melody = (steps, duration=0.35) => {
return [
play_sequence(steps.map((step, index) => note(step, index*duration, duration))),
duration*steps.length
]}
Insert cell
Play(...even_melody(_.range(70, 81, 1), 1/3))
Insert cell
Insert cell
function scale(intervals) {
return (degree) => {
return degree >= 0
? _.sum(_.range(0, degree).map(index => intervals[index % intervals.length]))
: -1*scale(intervals.reverse())(-degree)
}
}
Insert cell
scales = {
return {
"major": scale([2, 2, 1, 2, 2, 2, 1]),
"minor": scale([2, 1, 2, 2, 1, 2, 2]),
"blues": scale([3, 2, 1, 1, 3, 2]),
"pentatonic": scale([3, 2, 2, 3, 2]),
"chromatic": scale(_.fill(Array(8), 1))
}
}
Insert cell
notes = _.zipObject(['C', 'D', 'E', 'F', 'G', 'A', 'B'], _.range(0, 7).map(_.flowRight(from, make_key(C, scales.major))))
Insert cell
modifier = _.zipObject(['sharp', 'flat'], [_.partial(_.add, 1), _.partial(_.add, -1)])
Insert cell
make_key = (start_note, scale, modifier=null) => modifier ? _.flowRight(modifier, start_note, scale) : _.flowRight(start_note, scale)
Insert cell
C = from(60)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function midi_to_hz(midi) { return 8.1757989156 * Math.pow(2, midi / 12) }
Insert cell
where = (key, offset, items) => {return _.map(items, (item) => { item[key] += offset; return item })}
Insert cell
from = (partial, offset) => { return (offset) => partial + offset }
Insert cell
Insert cell
function envelope(duration=1, offset=0) {
return (t) => Math.cos((((t-offset) * Math.PI) / (2.5 * duration)) % (Math.PI/2))
}
Insert cell
Insert cell
function clamp(duration=1, offset=0) {
return (t) => offset <= t && t <= duration + offset ? 1 : 0
}
Insert cell
Insert cell
function compose(operator='*', ...funcs) {
return (time) => _.reduce(funcs.map(func => func(time)), (acc, current) => operator === '*' ? current * acc : current + acc)
}
Insert cell
thread_map = (iterable, fns) => _.map(iterable, _.flow(...fns))
Insert cell
thread_map([note(1,1),note(2,2),note(3,3)], [(x) => note(x.pitch, x.time+1)])
Insert cell
Insert cell
midi_to_hz(69)
Insert cell
note(4, 3)
Insert cell
from(60)(1)
Insert cell
where("time", from(60)(0), [note(1,1), note(2,2), note(3,3)])
Insert cell
make_key(C, scales["major"], modifier.flat)(6)
Insert cell
clamp(1, 1)(1.5)
Insert cell
compose('+', (x)=>x+1, (x)=>x+2, clamp(1,0))(2)
Insert cell
Insert cell
import {slider} from "@jashkenas/inputs"
Insert cell
import {toc} from "@nebrius/indented-toc"
Insert cell
import {Play, Draw} from "@debanjum/sound-widgets"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more