├── .ruby-version
├── mise.toml
├── website
├── _layouts
│ └── raw.html
├── .gitignore
├── images
│ ├── .gitattributes
│ ├── dac.jpg
│ ├── eq.png
│ ├── delay.png
│ ├── hihat.jpg
│ ├── hihat.png
│ ├── mixer.png
│ ├── notch.png
│ ├── notes.png
│ ├── wave.jpg
│ ├── Envelope.png
│ ├── Filter.png
│ ├── airwaves.jpg
│ ├── audio_flow.svg:Zone.Identifier
│ ├── bandpass.png
│ ├── highpass.png
│ ├── kickdrum.jpg
│ ├── kickdrum.png
│ ├── lowpass.png
│ ├── nyquist.jpg
│ ├── SquareWave.png
│ ├── depfu_mike.png
│ ├── reverb_raw.png
│ ├── roland_808.jpg
│ ├── snare_drum.png
│ ├── snaredrum.png
│ ├── waveshaper.png
│ ├── StateVarBlock.gif
│ ├── depfu_example.png
│ ├── filter_sketch.png
│ ├── hihat_sketch.png
│ ├── mixing_desk.jpg
│ ├── pattern_song.png
│ ├── snare_sketch.png
│ ├── beats_and_bars.png
│ ├── depfu-left-blue.png
│ ├── digital_analog.png
│ ├── hallgrimskirkja.jpg
│ ├── kickdrum_sketch.png
│ ├── reverb_diffused.png
│ ├── digital_2_analog.jpg
│ ├── loudspeaker_to_ear.jpg
│ ├── depfu_engine_update.png
│ ├── notes_patterns_songs.png
│ ├── david_von_michelangelo.jpg
│ ├── envelope-font-awesome.png
│ ├── sequencer_grid_sketch.png
│ ├── adsr.mp4
│ ├── chorus.mp4
│ ├── adsr.av1.mp4
│ ├── air-movie.mp4
│ ├── chorus.av1.mp4
│ ├── compressor.mp4
│ ├── full_song.mp4
│ ├── sonic_pi.mp4
│ ├── air-movie.av1.mp4
│ ├── compressor.av1.mp4
│ ├── full_song.av1.mp4
│ ├── sonic_pi.av1.mp4
│ ├── david_von_michelangelo.jpg:Zone.Identifier
│ ├── laptop.svg
│ ├── envelope-font-awesome.svg
│ └── audio_flow.svg
├── docs
│ ├── images
│ │ ├── add.png
│ │ ├── bug.png
│ │ ├── brick.png
│ │ ├── date.png
│ │ ├── find.png
│ │ ├── ruby.png
│ │ ├── zoom.png
│ │ ├── arrow_up.png
│ │ ├── delete.png
│ │ ├── package.png
│ │ ├── plugin.png
│ │ ├── tag_blue.png
│ │ ├── wrench.png
│ │ ├── brick_link.png
│ │ ├── page_green.png
│ │ ├── tag_green.png
│ │ ├── bullet_black.png
│ │ ├── macFFBgHack.png
│ │ ├── transparent.png
│ │ ├── wrench_orange.png
│ │ ├── page_white_text.png
│ │ ├── bullet_toggle_plus.png
│ │ ├── loadingAnimation.gif
│ │ ├── page_white_width.png
│ │ └── bullet_toggle_minus.png
│ ├── js
│ │ ├── navigation.js.gz
│ │ ├── searcher.js.gz
│ │ ├── search_index.js.gz
│ │ ├── search.js
│ │ ├── navigation.js
│ │ └── darkfish.js
│ ├── fonts
│ │ ├── Lato-Light.ttf
│ │ ├── Lato-Regular.ttf
│ │ ├── Lato-LightItalic.ttf
│ │ ├── Lato-RegularItalic.ttf
│ │ ├── SourceCodePro-Bold.ttf
│ │ └── SourceCodePro-Regular.ttf
│ ├── created.rid
│ ├── Limiter.html
│ ├── README_md.html
│ ├── Damper.html
│ ├── index.html
│ ├── OnePoleLP.html
│ ├── TunedDrum.html
│ └── Utils.html
├── samples
│ ├── bd.wav
│ ├── chord.wav
│ ├── clap.wav
│ ├── delay.wav
│ ├── drums.wav
│ ├── noise.wav
│ ├── square.wav
│ ├── acid_synth.wav
│ ├── amp_env.wav
│ ├── chorus.wav
│ ├── ducking.wav
│ ├── filter_env.wav
│ ├── filtered.wav
│ ├── full_song.ogg
│ ├── kick_drum.wav
│ ├── lfo_wub.wav
│ ├── main_chord.wav
│ ├── piano_long.wav
│ ├── pitch_env.wav
│ ├── real_snare.wav
│ ├── reverb.wav
│ ├── snare_drum.wav
│ ├── snare_only.wav
│ ├── waveshaper.wav
│ ├── lowpass_filtered.wav
│ ├── main_chord_maj.wav
│ ├── manual_snare.wav
│ ├── monosynth_demo.wav
│ ├── pitch_env_drum.wav
│ ├── simple_song.wav
│ ├── bandpass_filtered.wav
│ └── highpass_filtered.wav
├── presentations
│ ├── index.md
│ ├── 2019-06-22_euruko.html
│ ├── 2019-08-23_railsgrills.html
│ └── 2020-07-18_rubyconf_by.html
├── _includes
│ └── head-custom.html
├── glossary.md
├── test_opal.html
├── js
│ ├── live_ruby.js
│ └── player.js
├── index.md
├── _sass
│ └── custom
│ │ └── custom.scss
├── 04_drums.md
├── 01_introduction.md
└── 05_sequencer.md
├── examples
├── opal_loader.rb
├── noise.rb
├── hihat.rb
├── snare_drum.rb
├── reverb_demo.rb
├── kick_drum.rb
├── delay_demo.rb
├── monosynth_demo.rb
├── lowpass_filtered.rb
├── highpass_filtered.rb
├── square_wave.rb
├── snare_only.rb
├── chord.rb
├── bandpass_filtered.rb
├── chorus_demo.rb
├── amp_env.rb
├── waveshaper.rb
├── clap.rb
├── polysynth_demo.rb
├── filter_env.rb
├── lfo_wub.rb
├── drum_demo.rb
├── pitch_env.rb
├── pitch_env_drum.rb
├── manual_snare.rb
├── ducking_demo.rb
├── simple_song.rb
├── sequencer.rb
└── acid_synth.rb
├── drawings
├── adsr.png
├── chorus.png
├── sawtooth.png
├── compressor.png
├── reverb_bars.png
├── reverb_diffused.xcf
├── david_von_michelangelo.jpg
├── adsr.sifz
├── chorus.sifz
├── compressor.sifz
├── david_von_michelangelo.jpg:Zone.Identifier
├── highpass.svg
├── sawtooth.svg
├── waveshaper.svg
├── compressor.svg
├── lowpass.svg
├── eq.svg
├── delay.svg
├── bandpass.svg
└── notch.svg
├── meta
├── todos.md
└── outline.md
├── .gitignore
├── .gitattributes
├── Gemfile
├── Rakefile
├── README.md
├── _config.yml
└── Gemfile.lock
/.ruby-version:
--------------------------------------------------------------------------------
1 | 2.7.1
2 |
--------------------------------------------------------------------------------
/mise.toml:
--------------------------------------------------------------------------------
1 | [tools]
2 | ruby = "3.4.2"
3 |
--------------------------------------------------------------------------------
/website/_layouts/raw.html:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 | {{ content }}
4 |
--------------------------------------------------------------------------------
/website/.gitignore:
--------------------------------------------------------------------------------
1 | _site
2 | .sass-cache
3 | .jekyll-metadata
4 |
--------------------------------------------------------------------------------
/examples/opal_loader.rb:
--------------------------------------------------------------------------------
1 | require 'opal-parser'
2 | require 'synth_blocks'
3 |
--------------------------------------------------------------------------------
/website/images/.gitattributes:
--------------------------------------------------------------------------------
1 | *.ogv filter=lfs diff=lfs merge=lfs -text
2 |
--------------------------------------------------------------------------------
/drawings/adsr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/drawings/adsr.png
--------------------------------------------------------------------------------
/drawings/chorus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/drawings/chorus.png
--------------------------------------------------------------------------------
/drawings/sawtooth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/drawings/sawtooth.png
--------------------------------------------------------------------------------
/website/images/dac.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/dac.jpg
--------------------------------------------------------------------------------
/website/images/eq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/eq.png
--------------------------------------------------------------------------------
/drawings/compressor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/drawings/compressor.png
--------------------------------------------------------------------------------
/drawings/reverb_bars.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/drawings/reverb_bars.png
--------------------------------------------------------------------------------
/website/images/delay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/delay.png
--------------------------------------------------------------------------------
/website/images/hihat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/hihat.jpg
--------------------------------------------------------------------------------
/website/images/hihat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/hihat.png
--------------------------------------------------------------------------------
/website/images/mixer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/mixer.png
--------------------------------------------------------------------------------
/website/images/notch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/notch.png
--------------------------------------------------------------------------------
/website/images/notes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/notes.png
--------------------------------------------------------------------------------
/website/images/wave.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/wave.jpg
--------------------------------------------------------------------------------
/meta/todos.md:
--------------------------------------------------------------------------------
1 | # Todos
2 | - Exchange the Depfu example
3 | - Better SonicPi video fur sure
4 |
5 |
6 |
--------------------------------------------------------------------------------
/website/docs/images/add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/add.png
--------------------------------------------------------------------------------
/website/docs/images/bug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/bug.png
--------------------------------------------------------------------------------
/website/images/Envelope.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/Envelope.png
--------------------------------------------------------------------------------
/website/images/Filter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/Filter.png
--------------------------------------------------------------------------------
/website/images/airwaves.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/airwaves.jpg
--------------------------------------------------------------------------------
/website/images/audio_flow.svg:Zone.Identifier:
--------------------------------------------------------------------------------
1 | [ZoneTransfer]
2 | ZoneId=3
3 | HostUrl=about:internet
4 |
--------------------------------------------------------------------------------
/website/images/bandpass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/bandpass.png
--------------------------------------------------------------------------------
/website/images/highpass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/highpass.png
--------------------------------------------------------------------------------
/website/images/kickdrum.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/kickdrum.jpg
--------------------------------------------------------------------------------
/website/images/kickdrum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/kickdrum.png
--------------------------------------------------------------------------------
/website/images/lowpass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/lowpass.png
--------------------------------------------------------------------------------
/website/images/nyquist.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/nyquist.jpg
--------------------------------------------------------------------------------
/drawings/reverb_diffused.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/drawings/reverb_diffused.xcf
--------------------------------------------------------------------------------
/website/docs/images/brick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/brick.png
--------------------------------------------------------------------------------
/website/docs/images/date.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/date.png
--------------------------------------------------------------------------------
/website/docs/images/find.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/find.png
--------------------------------------------------------------------------------
/website/docs/images/ruby.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/ruby.png
--------------------------------------------------------------------------------
/website/docs/images/zoom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/zoom.png
--------------------------------------------------------------------------------
/website/images/SquareWave.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/SquareWave.png
--------------------------------------------------------------------------------
/website/images/depfu_mike.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/depfu_mike.png
--------------------------------------------------------------------------------
/website/images/reverb_raw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/reverb_raw.png
--------------------------------------------------------------------------------
/website/images/roland_808.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/roland_808.jpg
--------------------------------------------------------------------------------
/website/images/snare_drum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/snare_drum.png
--------------------------------------------------------------------------------
/website/images/snaredrum.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/snaredrum.png
--------------------------------------------------------------------------------
/website/images/waveshaper.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/waveshaper.png
--------------------------------------------------------------------------------
/website/docs/images/arrow_up.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/arrow_up.png
--------------------------------------------------------------------------------
/website/docs/images/delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/delete.png
--------------------------------------------------------------------------------
/website/docs/images/package.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/package.png
--------------------------------------------------------------------------------
/website/docs/images/plugin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/plugin.png
--------------------------------------------------------------------------------
/website/docs/images/tag_blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/tag_blue.png
--------------------------------------------------------------------------------
/website/docs/images/wrench.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/wrench.png
--------------------------------------------------------------------------------
/website/docs/js/navigation.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/js/navigation.js.gz
--------------------------------------------------------------------------------
/website/docs/js/searcher.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/js/searcher.js.gz
--------------------------------------------------------------------------------
/website/images/StateVarBlock.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/StateVarBlock.gif
--------------------------------------------------------------------------------
/website/images/depfu_example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/depfu_example.png
--------------------------------------------------------------------------------
/website/images/filter_sketch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/filter_sketch.png
--------------------------------------------------------------------------------
/website/images/hihat_sketch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/hihat_sketch.png
--------------------------------------------------------------------------------
/website/images/mixing_desk.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/mixing_desk.jpg
--------------------------------------------------------------------------------
/website/images/pattern_song.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/pattern_song.png
--------------------------------------------------------------------------------
/website/images/snare_sketch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/snare_sketch.png
--------------------------------------------------------------------------------
/website/docs/fonts/Lato-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/fonts/Lato-Light.ttf
--------------------------------------------------------------------------------
/website/docs/images/brick_link.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/brick_link.png
--------------------------------------------------------------------------------
/website/docs/images/page_green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/page_green.png
--------------------------------------------------------------------------------
/website/docs/images/tag_green.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/tag_green.png
--------------------------------------------------------------------------------
/website/docs/js/search_index.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/js/search_index.js.gz
--------------------------------------------------------------------------------
/website/images/beats_and_bars.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/beats_and_bars.png
--------------------------------------------------------------------------------
/website/images/depfu-left-blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/depfu-left-blue.png
--------------------------------------------------------------------------------
/website/images/digital_analog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/digital_analog.png
--------------------------------------------------------------------------------
/website/images/hallgrimskirkja.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/hallgrimskirkja.jpg
--------------------------------------------------------------------------------
/website/images/kickdrum_sketch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/kickdrum_sketch.png
--------------------------------------------------------------------------------
/website/images/reverb_diffused.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/reverb_diffused.png
--------------------------------------------------------------------------------
/drawings/david_von_michelangelo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/drawings/david_von_michelangelo.jpg
--------------------------------------------------------------------------------
/website/docs/fonts/Lato-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/fonts/Lato-Regular.ttf
--------------------------------------------------------------------------------
/website/docs/images/bullet_black.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/bullet_black.png
--------------------------------------------------------------------------------
/website/docs/images/macFFBgHack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/macFFBgHack.png
--------------------------------------------------------------------------------
/website/docs/images/transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/transparent.png
--------------------------------------------------------------------------------
/website/docs/images/wrench_orange.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/wrench_orange.png
--------------------------------------------------------------------------------
/website/images/digital_2_analog.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/digital_2_analog.jpg
--------------------------------------------------------------------------------
/website/images/loudspeaker_to_ear.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/loudspeaker_to_ear.jpg
--------------------------------------------------------------------------------
/website/docs/fonts/Lato-LightItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/fonts/Lato-LightItalic.ttf
--------------------------------------------------------------------------------
/website/docs/images/page_white_text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/page_white_text.png
--------------------------------------------------------------------------------
/website/images/depfu_engine_update.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/depfu_engine_update.png
--------------------------------------------------------------------------------
/website/images/notes_patterns_songs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/notes_patterns_songs.png
--------------------------------------------------------------------------------
/website/docs/fonts/Lato-RegularItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/fonts/Lato-RegularItalic.ttf
--------------------------------------------------------------------------------
/website/docs/fonts/SourceCodePro-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/fonts/SourceCodePro-Bold.ttf
--------------------------------------------------------------------------------
/website/docs/images/bullet_toggle_plus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/bullet_toggle_plus.png
--------------------------------------------------------------------------------
/website/docs/images/loadingAnimation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/loadingAnimation.gif
--------------------------------------------------------------------------------
/website/docs/images/page_white_width.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/page_white_width.png
--------------------------------------------------------------------------------
/website/images/david_von_michelangelo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/david_von_michelangelo.jpg
--------------------------------------------------------------------------------
/website/images/envelope-font-awesome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/envelope-font-awesome.png
--------------------------------------------------------------------------------
/website/images/sequencer_grid_sketch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/images/sequencer_grid_sketch.png
--------------------------------------------------------------------------------
/website/docs/fonts/SourceCodePro-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/fonts/SourceCodePro-Regular.ttf
--------------------------------------------------------------------------------
/website/docs/images/bullet_toggle_minus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/halfbyte/rubysynth/HEAD/website/docs/images/bullet_toggle_minus.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | test.wav
2 | debug.txt
3 | logs/*
4 | DEBUG.txt
5 |
6 | _site
7 | .sass-cache
8 | .jekyll-metadata
9 | /*.wav
10 | website/.jekyll-cache
11 |
--------------------------------------------------------------------------------
/drawings/adsr.sifz:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:f10a1a6884b245f33ea7ace0c730981d5aa0b10764ae4747d544a04dafe970c0
3 | size 1916
4 |
--------------------------------------------------------------------------------
/drawings/chorus.sifz:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:fc36f2cf3b9e0a10b54b5f12c0eb8043b0d8abb7786249dcd16e0bc91922979a
3 | size 1398
4 |
--------------------------------------------------------------------------------
/drawings/compressor.sifz:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:f11c613916b63526a503ced9f8d20747ed980f8ed281c804c6dec89ba44c6bb2
3 | size 1678
4 |
--------------------------------------------------------------------------------
/website/images/adsr.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:0200e3cedabcd42a6f6c18de698484999501261f6d4fc73de1baa5dfc9b35b47
3 | size 159600
4 |
--------------------------------------------------------------------------------
/website/images/chorus.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:d55673a0230d6f840cf8b3bca444929149d2913cb76e43eef43df3a2728acdd3
3 | size 230634
4 |
--------------------------------------------------------------------------------
/website/samples/bd.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:a458e8f3957ac1f24896a4e075c8d089a3edb78f66182ba66c9c32e3a7372abf
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/chord.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:431a24cc55cd5fbbac1ad5787b91b966d55b5738301309f21bfc94659f4d045c
3 | size 441048
4 |
--------------------------------------------------------------------------------
/website/samples/clap.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:4a6be8ff44c8b1c6c49cf20fe859e3b564d673b636d0844c2a0e178d98e616b8
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/delay.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:162d00a7d9311df4b8f9bf9886f36f67107e91463155f7033fc6b7fd70b766dc
3 | size 176444
4 |
--------------------------------------------------------------------------------
/website/samples/drums.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:db3127819d4da95d88088966683c45e2f09f80dd55d276d7875e6aac79e1c670
3 | size 529244
4 |
--------------------------------------------------------------------------------
/website/samples/noise.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:169a009a5122ad4125ef1151a99790161840ac761facafb64f4aa42e0e572737
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/square.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:5c1b82fd96982d62316eeb01484c956efb504523c1edac03b7402c8a247fdd39
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/images/adsr.av1.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:41ebe97cb1754ffcb5985d05eba78b4d82de69fb840100944663be89aec73282
3 | size 104316
4 |
--------------------------------------------------------------------------------
/website/images/air-movie.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:c9fea78f0ca09f34ca259c3974fcf0ac7c83ee549cfc8b15db13c15d3cc35b40
3 | size 2155921
4 |
--------------------------------------------------------------------------------
/website/images/chorus.av1.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:2096c70f861a074d8937c3a9790a5791ec977b5c4fbb58a15bf1e0c9e3a0c1db
3 | size 137287
4 |
--------------------------------------------------------------------------------
/website/images/compressor.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:6cef7de385f24a4dc25d2ca3fc6c3ddddd0ad2da89c7daf8c32e8b89e5de9651
3 | size 75854
4 |
--------------------------------------------------------------------------------
/website/images/full_song.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:6059f12f49fc47b507410984802ab7b8200ae91cd5f293b32bb708068f322180
3 | size 17593248
4 |
--------------------------------------------------------------------------------
/website/images/sonic_pi.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:34e993f8d05f0bca7755121798cb09b7c3cac4634664351de8edc93f445c551e
3 | size 83376251
4 |
--------------------------------------------------------------------------------
/website/samples/acid_synth.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:b2fda89830beb11a5d24c7f7eb2dc3bbb4ec679efae49bfefcc108a5b477d391
3 | size 352844
4 |
--------------------------------------------------------------------------------
/website/samples/amp_env.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:4aedd80cde09b09a60c365fa475badb1b88a4bdb760ada4fb0ab21d040f895af
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/chorus.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:120d165d3b1b95f8f30a8df8d3a4e5be041f28f205296c898fe9809a91be40e4
3 | size 352844
4 |
--------------------------------------------------------------------------------
/website/samples/ducking.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:7caeaf56e9de41dbd2f4d2abacc53eca504b71e4274f25d68e662b07d7ada7f9
3 | size 441044
4 |
--------------------------------------------------------------------------------
/website/samples/filter_env.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:42090754604887f58a209da8f43c62498e8098f09695b1a965e10c6735a94af1
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/filtered.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:2e1d09600ddda06184cc36a21cc9aeffa7f3677bce8e46a896e5d4c7da5575b5
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/full_song.ogg:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:2926c8bdb880a60a235b1fbe9b26a58641b007cc3fa3178e81aa448e8f851200
3 | size 594027
4 |
--------------------------------------------------------------------------------
/website/samples/kick_drum.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:ac37e381619444f9b4398b79b80324a7b0d89e3482cfc692967d9163d560320b
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/lfo_wub.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:32d3a16a1518db342238a03e2aa1a6cd1c8a5bc103b5ffb8061919789fd29462
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/main_chord.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:413bdb84546cba89bea7e180e4ab6dc04e9751f74f6c227b373d617d8625c514
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/piano_long.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:6361fa95711aba4df12c44c14dc67acf569d68a7031faa466657cec4697a8d9a
3 | size 376936
4 |
--------------------------------------------------------------------------------
/website/samples/pitch_env.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:ddab07cbd9357698fe171693ba962ba54179a21982c3cc3ae7ebb1787b7ed68d
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/real_snare.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:434f8c824e28da0d6423f4f7fd6eb56fb45e5cd061f870f5c7a2a3e4aa724ff2
3 | size 36908
4 |
--------------------------------------------------------------------------------
/website/samples/reverb.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:227763e10d375a7bb52682f888f23bf8064c638e7e8e0afdd21bab4b21ce15ab
3 | size 176444
4 |
--------------------------------------------------------------------------------
/website/samples/snare_drum.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:e5e9e3587fe52643655d4447d1700b075d979581d80eb1c7151467535adc5426
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/snare_only.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:886e7b732bf432670d9fc79f058852cc5f3454e0efdba880ca95d5d06c30d659
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/waveshaper.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:6ca329af9019a7897b4334341939bf9d77ecc5a34c53cfb5ef19ad95686096e4
3 | size 705644
4 |
--------------------------------------------------------------------------------
/website/images/air-movie.av1.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:37087a24fce969a759fcea88271064a3959decb05a877c15ff1eee09b08c4ffb
3 | size 1005608
4 |
--------------------------------------------------------------------------------
/website/images/compressor.av1.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:3233fb9135fc4bf0dd52b23dc4a3317c870b73303f61070a6f87e52512f1876e
3 | size 31990
4 |
--------------------------------------------------------------------------------
/website/images/full_song.av1.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:caa692826c2f2029151d0eec77b6d0b449ab353051d3ba17258a4dd21cacf5e2
3 | size 10645798
4 |
--------------------------------------------------------------------------------
/website/images/sonic_pi.av1.mp4:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:0d3ff211abb083e4d7fdc34e9182d04fc63b8272a5a7fcbbf23e505ae8a413dd
3 | size 7686792
4 |
--------------------------------------------------------------------------------
/website/samples/lowpass_filtered.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:b4313b391265dc2e77e0a34857d46e7ef8ccde34a667f34c446cd4d25f76a55a
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/main_chord_maj.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:f968f50158ed47ebef8cde6cf553ffbe4e5f71e238257c266c064410a89d425c
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/manual_snare.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:dc2be1ef10c2f788907d42b86bb502d0ae79a87a96b63554267a48e8d6186d12
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/monosynth_demo.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:f21182b0a347c34793462c5d4f60d9be4f726ad1b8eb35406a84cfdbe1c19287
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/pitch_env_drum.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:c6736cc9d3e2673f51733608220ff54058c1376f7c673e6b30fbd52c9fcc3198
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/simple_song.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:1af27ccac591b2cc64b04a460f23cb00d84bfe713551c5fc4707bf81bcb77424
3 | size 970244
4 |
--------------------------------------------------------------------------------
/website/samples/bandpass_filtered.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:049b858727082f2f016a991af4cd52ec1c8c6b0dc0e5af25eb0719209e5d8d8b
3 | size 88244
4 |
--------------------------------------------------------------------------------
/website/samples/highpass_filtered.wav:
--------------------------------------------------------------------------------
1 | version https://git-lfs.github.com/spec/v1
2 | oid sha256:e2d4edaee1862f1d0e0685ed962da3ee33de93c8b0db7c68b4d4ff0887e339d8
3 | size 88244
4 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.ogg filter=lfs diff=lfs merge=lfs -text
2 | *.wav filter=lfs diff=lfs merge=lfs -text
3 | *.sifz filter=lfs diff=lfs merge=lfs -text
4 | *.mp4 filter=lfs diff=lfs merge=lfs -text
5 |
--------------------------------------------------------------------------------
/drawings/david_von_michelangelo.jpg:Zone.Identifier:
--------------------------------------------------------------------------------
1 | [ZoneTransfer]
2 | ZoneId=3
3 | ReferrerUrl=https://upload.wikimedia.org/wikipedia/commons/d/d5/David_von_Michelangelo.jpg
4 | HostUrl=https://upload.wikimedia.org/wikipedia/commons/d/d5/David_von_Michelangelo.jpg
5 |
--------------------------------------------------------------------------------
/website/images/david_von_michelangelo.jpg:Zone.Identifier:
--------------------------------------------------------------------------------
1 | [ZoneTransfer]
2 | ZoneId=3
3 | ReferrerUrl=https://upload.wikimedia.org/wikipedia/commons/d/d5/David_von_Michelangelo.jpg
4 | HostUrl=https://upload.wikimedia.org/wikipedia/commons/d/d5/David_von_Michelangelo.jpg
5 |
--------------------------------------------------------------------------------
/examples/noise.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Almost white noise
5 | #
6 |
7 | SAMPLING_FREQUENCY=44100
8 |
9 | out = SAMPLING_FREQUENCY.times.map do
10 | output = rand() * 2 - 1
11 | output *= 0.2
12 | end
13 |
14 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
15 |
--------------------------------------------------------------------------------
/examples/hihat.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Demo of the High Hat drum sound
5 | #
6 |
7 | SRATE = 44100
8 | hat = SynthBlocks::Drum::Hihat.new(SRATE)
9 |
10 | hat.start(0.0)
11 |
12 | out = SRATE.times.map {|i| 0.5 * hat.run(i) }
13 |
14 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
--------------------------------------------------------------------------------
/examples/snare_drum.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Let's generate a snare drum sound
5 | #
6 |
7 | SRATE = 44100
8 | drum = SynthBlocks::Drum::SnareDrum.new(SRATE)
9 |
10 | drum.start(0.0)
11 |
12 | out = SRATE.times.map {|i| 0.5 * drum.run(i) }
13 |
14 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
15 |
--------------------------------------------------------------------------------
/website/presentations/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Presentations
3 | nav_order: 25
4 | has_children: true
5 | layout: default
6 | ---
7 | # Presentation files
8 |
9 | I've given this talk a couple of times and each time, tiny details change. In the interest of transparency, but also because I like to refer back to old versions, they are now here.
10 |
--------------------------------------------------------------------------------
/examples/reverb_demo.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 | SRATE = 44100
3 |
4 | snare = SynthBlocks::Drum::SnareDrum.new(SRATE)
5 | reverb = SynthBlocks::Fx::GVerb.new(SRATE)
6 | snare.start(0)
7 |
8 | out = (SRATE * 2).times.map do |i|
9 | reverb.run(snare.run(i))
10 | end
11 |
12 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
13 |
14 |
15 |
--------------------------------------------------------------------------------
/examples/kick_drum.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Demo of the kick drum
5 | #
6 |
7 | SRATE = 44100
8 |
9 | kick = SynthBlocks::Drum::KickDrum.new(SRATE)
10 | kick.start(0.0)
11 |
12 | ws = SynthBlocks::Fx::Waveshaper.new(5)
13 |
14 | out = SRATE.times.map {|i| 0.3 * ws.run(kick.run(i)) }
15 |
16 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
--------------------------------------------------------------------------------
/examples/delay_demo.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Demo of the Delay/Echo effect
5 | #
6 |
7 | SRATE = 44100
8 |
9 | snare = SynthBlocks::Drum::SnareDrum.new(SRATE)
10 | delay = SynthBlocks::Fx::Delay.new(SRATE, time: 0.3)
11 | snare.start(0)
12 |
13 | out = (SRATE * 2).times.map do |i|
14 | delay.run(snare.run(i))
15 | end
16 |
17 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
18 |
--------------------------------------------------------------------------------
/examples/monosynth_demo.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Simple Demo of the Monosyth
5 | #
6 |
7 | SFREQ = 44100
8 |
9 | synth = SynthBlocks::Synth::Monosynth.new(SFREQ, {
10 | flt_Q: 8,
11 | flt_frequency: 100
12 | })
13 |
14 | synth.start(0, 48)
15 | synth.stop(0.5, 48)
16 |
17 | out = (SFREQ).times.map { |i|
18 | synth.run(i) * 0.5
19 | }
20 |
21 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
--------------------------------------------------------------------------------
/examples/lowpass_filtered.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Lowpass Filter
5 | #
6 |
7 | SAMPLING_FREQUENCY=44100
8 |
9 | filter = SynthBlocks::Core::StateVariableFilter.new(SAMPLING_FREQUENCY)
10 |
11 | out = SAMPLING_FREQUENCY.times.map do
12 | output = rand() * 2 - 1
13 | output = filter.run(output, 2000.0, 2, type: :lowpass)
14 | output *= 0.3
15 | end
16 |
17 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
18 |
--------------------------------------------------------------------------------
/examples/highpass_filtered.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Highpass Filter
5 | #
6 |
7 | SAMPLING_FREQUENCY=44100
8 |
9 | filter = SynthBlocks::Core::StateVariableFilter.new(SAMPLING_FREQUENCY)
10 |
11 | out = SAMPLING_FREQUENCY.times.map do
12 | output = rand() * 2 - 1
13 | output = filter.run(output, 6000.0, 2, type: :highpass)
14 | output *= 0.1
15 | end
16 |
17 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
18 |
--------------------------------------------------------------------------------
/meta/outline.md:
--------------------------------------------------------------------------------
1 | # Talk Outline
2 |
3 | - [2] A quick demo of Sonic Pi
4 | - The first demo, explaining sox output
5 | - Synth
6 | - Squarewave
7 | - Filter
8 | - Envelopes
9 | - LFO
10 | - Notes -> Frequencies > Chords
11 | - Drums
12 | - Bassdrum
13 | - Snare
14 | - Hihat
15 |
16 | - Sequencing
17 | - Beats and Bars and Notes
18 | - Sequencing DSL
19 |
20 | - FX
21 | - Delay
22 | - Reverb
23 | - Waveshaper
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/website/images/laptop.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/website/_includes/head-custom.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/examples/square_wave.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks/core/wave_writer'
2 |
3 | #
4 | # Most simple example. Generates a square wave in 440 Hz for one second
5 | #
6 | SAMPLING_FREQUENCY=44100
7 | FREQUENCY=440
8 |
9 |
10 | in_cycle = 0
11 | samples = (SAMPLING_FREQUENCY).times.map do
12 | period = SAMPLING_FREQUENCY / FREQUENCY.to_f
13 | output = in_cycle > 0.5 ? -1.0 : 1.0
14 | in_cycle = (in_cycle + (1.0 / period)) % 1.0
15 | output * 0.5
16 | end
17 | SynthBlocks::Core::WaveWriter.write_if_name_given(samples)
--------------------------------------------------------------------------------
/examples/snare_only.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # A simple example of using amp, filter and pitch envelopes to shape a sound
5 | # But now as a draum sound
6 | #
7 |
8 | SAMPLING_FREQUENCY=44100
9 |
10 | amp_env = SynthBlocks::Mod::Adsr.new(0.001, 0.1, 0.5, 0.2)
11 | out = SAMPLING_FREQUENCY.times.map do |s|
12 | t = s.to_f / SAMPLING_FREQUENCY.to_f
13 | stopped = t >= 0.15 ? 0.15 : nil
14 | output = 0.3 * (rand() * 2) - 1
15 | output *= 0.3 * amp_env.run(t, stopped)
16 | end
17 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
--------------------------------------------------------------------------------
/examples/chord.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 | SRATE = 44100
3 | include SynthBlocks::Sequencer::SequencerDSL
4 | polysynth = SynthBlocks::Synth::Polysynth.new(SRATE)
5 |
6 | def_pattern(:chord, 16) do
7 | note_pattern polysynth, [
8 | P, P, ['C2,D#2,G2', 2], P,
9 | P, P, P, P,
10 | ['C#2,E2,G#2', 2], P, P, P,
11 | P, P, P, P
12 | ]
13 | end
14 |
15 | my_song = song(bpm: 135) do
16 | pattern(:chord, at: 0, repeat: 2)
17 | end
18 |
19 | out = my_song.render(SRATE) do |i|
20 | 0.8 * polysynth.run(i)
21 | end
22 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
--------------------------------------------------------------------------------
/examples/bandpass_filtered.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Bandpass Filter
5 | #
6 |
7 | SAMPLING_FREQUENCY=44100
8 | FREQUENCY=440
9 |
10 | filter = SynthBlocks::Core::StateVariableFilter.new(SAMPLING_FREQUENCY)
11 |
12 | in_cycle = 0
13 | out = SAMPLING_FREQUENCY.times.map do
14 | period = SAMPLING_FREQUENCY / FREQUENCY.to_f
15 | output = in_cycle > 0.5 ? -1.0 : 1.0
16 | in_cycle = (in_cycle + (1.0 / period)) % 1.0
17 | output = filter.run(output, 2000.0, 2, type: :bandpass)
18 | output *= 0.3
19 | end
20 |
21 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
22 |
--------------------------------------------------------------------------------
/examples/chorus_demo.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 | SRATE = 44100
3 |
4 | #
5 | # Example of the Chorus effect
6 | #
7 |
8 | mono = SynthBlocks::Synth::Monosynth.new(SRATE, {osc_waveform: :sawtooth})
9 | chorus = SynthBlocks::Fx::Chorus.new(SRATE, delay_time: 12)
10 |
11 | mono.start(0, 36)
12 | mono.stop(1, 36)
13 |
14 | mono.start(2, 36)
15 | mono.stop(3, 36)
16 |
17 | out = (SRATE * 4).times.map do |i|
18 | if (i >= SRATE * 2)
19 | chorus.run(mono.run(i)) * 0.8
20 | else
21 | mono.run(i) * 0.8
22 | end
23 | end
24 |
25 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
26 |
--------------------------------------------------------------------------------
/examples/amp_env.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Example for an amp envelope
5 | #
6 |
7 | SAMPLING_FREQUENCY=44100
8 | FREQUENCY=220
9 |
10 | env = SynthBlocks::Mod::Adsr.new(0.001, 0.2, 0.5, 0.2)
11 | in_cycle = 0
12 | out = SAMPLING_FREQUENCY.times.map do |s|
13 | t = s.to_f / SAMPLING_FREQUENCY.to_f
14 | stopped = t >= 0.4 ? 0.4 : nil
15 | period = SAMPLING_FREQUENCY / FREQUENCY.to_f
16 | output = in_cycle > 0.5 ? -1.0 : 1.0
17 | in_cycle = (in_cycle + (1.0 / period)) % 1.0
18 | output *= 0.3 * env.run(t, stopped)
19 | end
20 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
21 |
--------------------------------------------------------------------------------
/examples/waveshaper.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Example to show the effect of the waveshaper by increasingly distorting a kick drum
5 | #
6 |
7 | SRATE = 44100
8 |
9 | drum = SynthBlocks::Drum::KickDrum.new(SRATE)
10 | drum.start(0)
11 | drum.start(0.5)
12 | drum.start(1)
13 | drum.start(1.5)
14 |
15 | SHAPER_RATES = [1,2,4,8]
16 |
17 |
18 | out = []
19 | 4.times do |r|
20 | shaper = SynthBlocks::Fx::Waveshaper.new(SHAPER_RATES[r])
21 |
22 | (SRATE * 2).times do |i|
23 | out << shaper.run(drum.run(i))
24 | end
25 | end
26 |
27 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source "https://rubygems.org"
4 |
5 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
6 |
7 | gem "jekyll", "~> 4.0"
8 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
9 | gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby]
10 | # Performance-booster for watching directories on Windows
11 | gem "wdm", "~> 0.1.0" if Gem.win_platform?
12 | gem "just-the-docs", "~> 0.3"
13 | gem "synth_blocks", "~> 1.0"
14 | gem "rake", "~> 13.0"
15 | gem "opal"
16 | gem "irb"
17 | gem "logger"
18 | gem "csv"
19 | gem "base64"
20 | gem "bigdecimal"
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | SAMPLES = %w[pitch_env_drum waveshaper noise lowpass_filtered highpass_filtered amp_env filter_env pitch_env manual_snare snare_only]
2 |
3 | desc "update examples"
4 | task :update_examples => SAMPLES.map {|sample| "website/samples/#{sample}.wav"}
5 |
6 | SAMPLES.each do |sample|
7 | file "website/samples/#{sample}.wav" => ["examples/#{sample}.rb"] do |t|
8 | sh "bundle exec ruby #{t.prerequisites.first} #{t.name}"
9 | end
10 | end
11 |
12 | task :compile_opal => ['website/js/opal.js']
13 |
14 | file 'website/js/opal.js' => ['examples/opal_loader.rb'] do |t|
15 | sh "bundle exec opal -g synth_blocks --compile #{t.prerequisites.first} >#{t.name}"
16 | end
--------------------------------------------------------------------------------
/examples/clap.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Manual Clap
5 | #
6 |
7 | SFREQ = 44100
8 |
9 | filter = SynthBlocks::Core::StateVariableFilter.new(SFREQ)
10 | env = SynthBlocks::Mod::Envelope.new(0.001, 0.02)
11 | times = [[0, 1], [0.02, 0.8], [0.03, 0.6], [0.045, 0.4]]
12 | out = SFREQ.times.map do |i|
13 | t = i.to_f / SFREQ.to_f
14 | out = rand() * 2 - 1
15 | all_envs = 0
16 | times.each {|et| all_envs += env.run(t-et[0]) * et[1] if (t >= et[0]) }
17 | all_envs = [all_envs, 1].min
18 | ffreq = 100 + (2000 * all_envs)
19 | out = filter.run(out, ffreq, 4) * all_envs
20 | out *= 0.5
21 | end
22 |
23 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
--------------------------------------------------------------------------------
/website/glossary.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Glossary
3 | layout: page
4 | nav_order: 20
5 | ---
6 | Oscillator
7 | : A piece of electronics (or code) that produces a continuous waveform at a stable frequency, such as a sine wave, a sawtooth or a rectable.
8 |
9 | LFO (Low Frequency Oscillator)
10 | : An oscillator that runs a low frequencies, often way outside the audible range and is, instead of making sound directly, used to modulate parameters.
11 |
12 | Envelope
13 | : A signal genereator that, depending on events (usually: A keyboard key pressed down and then released again) generates a smooth curve to shape a sound in a more natural way than just switching in on and off. The ADSR (Attack, Decay, Sustain, Release) envelope is the most common one as it is a good compromise between control and ease of use
14 |
15 |
16 |
--------------------------------------------------------------------------------
/examples/polysynth_demo.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Simple Demo of the PolySynth
5 | #
6 |
7 | SRATE = 44100
8 |
9 | polysynth = SynthBlocks::Synth::Polysynth.new(SRATE, {
10 | amp_env_attack: 0.001,
11 | amp_env_release: 0.1,
12 | flt_env_attack: 0.001,
13 | flt_env_decay: 0.05,
14 | flt_env_sustain: 0.1,
15 | flt_frequency: 300,
16 | flt_envmod: 1000,
17 | flt_Q: 1,
18 | osc_waveform: :square
19 | })
20 |
21 | polysynth.start(0, 60)
22 | polysynth.start(0, 60 + 4)
23 | polysynth.start(0, 60 + 7)
24 | polysynth.start(0, 60 - 12)
25 |
26 | polysynth.stop(0.125, 60)
27 | polysynth.stop(0.125, 60 + 4)
28 | polysynth.stop(0.125, 60 + 7)
29 | polysynth.stop(0.125, 60 - 12)
30 |
31 | out = SRATE.times.map{ |i| 0.6 * polysynth.run(i) }
32 |
33 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
34 |
--------------------------------------------------------------------------------
/website/test_opal.html:
--------------------------------------------------------------------------------
1 | ---
2 | title: Testing Opal Integration
3 | layout: page
4 | nav_exclude: true
5 | ---
6 |
7 |
8 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | RUN
29 |
30 |
31 |
--------------------------------------------------------------------------------
/examples/filter_env.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # A filter envelope shapes the sound even more
5 | #
6 |
7 | SAMPLING_FREQUENCY=44100
8 | FREQUENCY=220
9 |
10 | filter = SynthBlocks::Core::StateVariableFilter.new(SAMPLING_FREQUENCY)
11 | amp_env = SynthBlocks::Mod::Adsr.new(0.001, 0.2, 0.5, 0.2)
12 | filter_env = SynthBlocks::Mod::Adsr.new(0.01, 0.1, 0.1, 0.1)
13 | in_cycle = 0
14 | out = SAMPLING_FREQUENCY.times.map do |s|
15 | t = s.to_f / SAMPLING_FREQUENCY.to_f
16 | stopped = t >= 0.4 ? 0.4 : nil
17 | period = SAMPLING_FREQUENCY / FREQUENCY.to_f
18 | output = in_cycle > 0.5 ? -1.0 : 1.0
19 | in_cycle = (in_cycle + (1.0 / period)) % 1.0
20 | output = filter.run(output, 500.0 + (8000.0 * filter_env.run(t, stopped)), 1)
21 | output *= 0.3 * amp_env.run(t, stopped)
22 | end
23 |
24 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
25 |
--------------------------------------------------------------------------------
/examples/lfo_wub.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Let's wobble!
5 | #
6 |
7 |
8 | SAMPLING_FREQUENCY=44100
9 | FREQUENCY=55
10 |
11 | filter = SynthBlocks::Core::StateVariableFilter.new(SAMPLING_FREQUENCY)
12 | lfo = SynthBlocks::Core::Oscillator.new(SAMPLING_FREQUENCY)
13 | lfo_freq = 4
14 | env = SynthBlocks::Mod::Adsr.new(0.001, 0.2, 0.5, 0.2)
15 |
16 | in_cycle = 0
17 | out = SAMPLING_FREQUENCY.times.map do |s|
18 | t = s.to_f / SAMPLING_FREQUENCY.to_f
19 | stopped = t >= 0.8 ? 0.8 : nil
20 | period = SAMPLING_FREQUENCY / FREQUENCY.to_f
21 | output = in_cycle > 0.5 ? -1.0 : 1.0
22 | in_cycle = (in_cycle + (1.0 / period)) % 1.0
23 | output = filter.run(output, 500.0 + ((lfo.run(lfo_freq, waveform: :sawtooth) + 1) * 2000.0), 2)
24 | output *= 0.3 * env.run(t, stopped)
25 | end
26 |
27 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
28 |
--------------------------------------------------------------------------------
/examples/drum_demo.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | include SynthBlocks::Sequencer::SequencerDSL
4 |
5 | SRATE = 44100
6 | TEMPO = 125
7 | P = nil # pause
8 |
9 | snare = SynthBlocks::Drum::SnareDrum.new(SRATE)
10 | kick = SynthBlocks::Drum::KickDrum.new(SRATE)
11 | hihat = SynthBlocks::Drum::Hihat.new(SRATE)
12 | open_hihat = SynthBlocks::Drum::Hihat.new(SRATE, amp_decay: 0.2)
13 | limiter = SynthBlocks::Fx::Limiter.new
14 | def_pattern(:drums_full, 16) do
15 | drum_pattern kick, '*---*---*---*---'
16 | drum_pattern snare, '----*-------*---'
17 | drum_pattern hihat, '--*---*---*---*-'
18 | drum_pattern open_hihat, '--*---*---*--*--'
19 | end
20 |
21 | my_song = song(bpm: TEMPO) do
22 | pattern(:drums_full, at: 0, repeat: 2)
23 | end
24 |
25 | out = my_song.render(SRATE) do |i|
26 | limiter.run(snare.run(i) + kick.run(i) + (0.3 * (hihat.run(i) + open_hihat.run(i))))
27 | end
28 |
29 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
30 |
31 |
32 |
--------------------------------------------------------------------------------
/examples/pitch_env.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # A simple example of using amp, filter and pitch envelopes to shape a sound
5 | #
6 |
7 | SAMPLING_FREQUENCY=44100
8 | FREQUENCY=220
9 |
10 | filter = SynthBlocks::Core::StateVariableFilter.new(SAMPLING_FREQUENCY)
11 | amp_env = SynthBlocks::Mod::Adsr.new(0.001, 0.2, 0.5, 0.2)
12 | filter_env = SynthBlocks::Mod::Adsr.new(0.01, 0.1, 0.1, 0.1)
13 | pitch_env = SynthBlocks::Mod::Adsr.new(0.01, 0.2, 0.0, 0.0)
14 | in_cycle = 0
15 | out = SAMPLING_FREQUENCY.times.map do |s|
16 | t = s.to_f / SAMPLING_FREQUENCY.to_f
17 | stopped = t >= 0.4 ? 0.4 : nil
18 | period = SAMPLING_FREQUENCY / (FREQUENCY.to_f * ((0.5 * pitch_env.run(t, stopped)) + 1))
19 | output = in_cycle > 0.5 ? -1.0 : 1.0
20 | in_cycle = (in_cycle + (1.0 / period)) % 1.0
21 | output = filter.run(output, 500.0 + (8000.0 * filter_env.run(t, stopped)), 1)
22 | output *= 0.3 * amp_env.run(t, stopped)
23 | end
24 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
--------------------------------------------------------------------------------
/examples/pitch_env_drum.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # A simple example of using amp, filter and pitch envelopes to shape a sound
5 | # But now as a draum sound
6 | #
7 |
8 | SAMPLING_FREQUENCY=44100
9 | FREQUENCY=110
10 |
11 | filter = SynthBlocks::Core::StateVariableFilter.new(SAMPLING_FREQUENCY)
12 | amp_env = SynthBlocks::Mod::Adsr.new(0.001, 0.1, 0.5, 0.2)
13 | filter_env = SynthBlocks::Mod::Adsr.new(0.01, 0.025, 0.1, 0.1)
14 | pitch_env = SynthBlocks::Mod::Adsr.new(0.01, 0.03, 0.0, 0.0)
15 | in_cycle = 0
16 | out = SAMPLING_FREQUENCY.times.map do |s|
17 | t = s.to_f / SAMPLING_FREQUENCY.to_f
18 | stopped = t >= 0.15 ? 0.15 : nil
19 | period = SAMPLING_FREQUENCY / (FREQUENCY.to_f * ((2 * pitch_env.run(t, stopped)) + 1))
20 | output = in_cycle > 0.5 ? -1.0 : 1.0
21 | in_cycle = (in_cycle + (1.0 / period)) % 1.0
22 | output = filter.run(output, 200.0 + (2000.0 * filter_env.run(t, stopped)), 1)
23 | output *= 0.3 * amp_env.run(t, stopped)
24 | end
25 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
--------------------------------------------------------------------------------
/examples/manual_snare.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # A simple example of using amp, filter and pitch envelopes to shape a sound
5 | # But now as a draum sound
6 | #
7 |
8 | SAMPLING_FREQUENCY=44100
9 | FREQUENCY=110
10 |
11 | filter = SynthBlocks::Core::StateVariableFilter.new(SAMPLING_FREQUENCY)
12 | amp_env = SynthBlocks::Mod::Adsr.new(0.001, 0.1, 0.5, 0.2)
13 | filter_env = SynthBlocks::Mod::Adsr.new(0.01, 0.025, 0.1, 0.1)
14 | pitch_env = SynthBlocks::Mod::Adsr.new(0.01, 0.03, 0.0, 0.0)
15 | in_cycle = 0
16 | out = SAMPLING_FREQUENCY.times.map do |s|
17 | t = s.to_f / SAMPLING_FREQUENCY.to_f
18 | stopped = t >= 0.15 ? 0.15 : nil
19 | period = SAMPLING_FREQUENCY / (FREQUENCY.to_f * ((2 * pitch_env.run(t, stopped)) + 1))
20 | output = in_cycle > 0.5 ? -1.0 : 1.0
21 | in_cycle = (in_cycle + (1.0 / period)) % 1.0
22 | output = filter.run(output, 200.0 + (2000.0 * filter_env.run(t, stopped)), 1)
23 | output += 0.3 * (rand() * 2) - 1
24 | output *= 0.3 * amp_env.run(t, stopped)
25 | end
26 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
--------------------------------------------------------------------------------
/drawings/highpass.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/examples/ducking_demo.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # Each mixer channel has a ducking function that allows to simulate sidechain compression
5 | #
6 |
7 | SFREQ = 44100
8 |
9 | poly = SynthBlocks::Synth::Polysynth.new(SFREQ, {amp_env_release: 0.2})
10 | channel = SynthBlocks::Mixer::MixerChannel.new(SFREQ, poly, insert_effects: [SynthBlocks::Fx::Chorus.new(SFREQ)], sends: [0.0], preset: {
11 | volume: 0.5, comp_threshold: 0.0,
12 | duck: 0.8
13 | })
14 |
15 | poly.start(0, 48)
16 | poly.start(0, 48 + 3)
17 | poly.start(0, 48 + 7)
18 |
19 | poly.stop(2, 48)
20 | poly.stop(2, 48 + 3)
21 | poly.stop(2, 48 + 7)
22 |
23 | poly.start(2, 48 + 5)
24 | poly.start(2, 48 + 3 + 5)
25 | poly.start(2, 48 + 7 + 5)
26 |
27 | poly.stop(4, 48 + 5)
28 | poly.stop(4, 48 + 3 + 5)
29 | poly.stop(4, 48 + 7 + 5)
30 | channel.duck(0)
31 | channel.duck(0.5)
32 | channel.duck(1)
33 | channel.duck(1.5)
34 | channel.duck(2)
35 | channel.duck(2.5)
36 | channel.duck(3)
37 | channel.duck(3.5)
38 | channel.duck(4.0)
39 | channel.duck(4.5)
40 |
41 | out = (5 * SFREQ).times.map { |i|
42 | SynthBlocks::Fx::Limiter.new.run(channel.run(i) * 0.6)
43 | }
44 |
45 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
--------------------------------------------------------------------------------
/website/js/live_ruby.js:
--------------------------------------------------------------------------------
1 | function drawInCanvas(selector, data) {
2 | const canvas = document.querySelector(selector)
3 | const ctx = canvas.getContext('2d')
4 | ctx.clearRect(0, 0, canvas.width, canvas.height)
5 | const perStep = canvas.width / data.length
6 | const height = canvas.height
7 | ctx.strokeStyle = "#000"
8 | ctx.strokeWidth = 2
9 | ctx.beginPath()
10 | ctx.moveTo(0, height / 2)
11 | data.forEach((d, x) => ctx.lineTo(perStep * x, ((d + 1) / 2 * height)))
12 | ctx.stroke()
13 | }
14 |
15 | document.getElementById('run-button').onclick = function(e) {
16 | e.preventDefault()
17 | const code = document.getElementById('code').value
18 | console.log(code)
19 | const evaluated = Opal.eval(code)
20 |
21 | const context = new AudioContext()
22 | const buffer = context.createBuffer(1, evaluated.length, 44100)
23 | const data = buffer.getChannelData(0)
24 | evaluated.forEach((w, i) => data[i] = w)
25 |
26 | const samplePlayer = context.createBufferSource()
27 | samplePlayer.connect(context.destination)
28 | samplePlayer.buffer = buffer
29 | samplePlayer.start()
30 | drawInCanvas('#canvas', evaluated)
31 |
32 | }
33 |
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RubySynth
2 |
3 | ```
4 | _______ __ ___t____ __ __
5 | | _ .--.--| |--.--.--| _ .--.--.-----| |_| |--.
6 | |. l | | | _ | | | 1___| | | | _| |
7 | |. _ |_____|_____|___ |____ |___ |__|__|____|__|__|
8 | |: | | |_____|: 1 |_____|
9 | |::.|:. | |::.. . |
10 | `--- ---' `-------'
11 |
12 | ```
13 |
14 | This Repo holds all the data for both [rubysynth.fun](https://rubysynth.fun) and the presentation about it I gave at Euruko 2019 and a couple of other places.
15 |
16 | The low level code now lives in it's own [project](https://github.com/halfbyte/ruby_synth_blocks) and [gem](https://rubygems.org/gems/synth_blocks).
17 |
18 | The sound examples used in the presentation and on the website are generated with the code in [examples/](examples/).
19 |
20 | ## Licenses
21 |
22 | All code here is licensed under the AGPL 3.0 license as documented at [LICENSE](LICENSE) unless stated otherwise.
23 |
24 | The entire contents of the "website" folder of the repo (and with that, this website you're just reading) is licensed under a [Creative Commons Attribution-ShareAlike Unported license](https://creativecommons.org/licenses/by-sa/3.0/deed.en). The full license is at [website/LICENSE](website/LICENSE)
25 |
26 |
--------------------------------------------------------------------------------
/website/docs/created.rid:
--------------------------------------------------------------------------------
1 | Mon, 24 Jun 2019 16:16:16 +0200
2 | README.md Mon, 24 Jun 2019 12:00:05 +0200
3 | lib/adsr.rb Mon, 24 Jun 2019 12:36:10 +0200
4 | lib/chorus.rb Mon, 24 Jun 2019 16:11:32 +0200
5 | lib/compressor.rb Mon, 24 Jun 2019 16:11:47 +0200
6 | lib/delay.rb Mon, 24 Jun 2019 13:06:32 +0200
7 | lib/envelope.rb Mon, 24 Jun 2019 12:40:02 +0200
8 | lib/eq.rb Mon, 24 Jun 2019 16:12:03 +0200
9 | lib/g_verb.rb Mon, 24 Jun 2019 13:18:43 +0200
10 | lib/hihat.rb Mon, 24 Jun 2019 13:28:27 +0200
11 | lib/kick_drum.rb Mon, 24 Jun 2019 13:42:33 +0200
12 | lib/limiter.rb Mon, 24 Jun 2019 16:12:37 +0200
13 | lib/mixer_channel.rb Mon, 24 Jun 2019 13:57:39 +0200
14 | lib/monosynth.rb Mon, 24 Jun 2019 14:59:35 +0200
15 | lib/moog_filter.rb Mon, 24 Jun 2019 16:12:57 +0200
16 | lib/oscillator.rb Mon, 24 Jun 2019 16:07:07 +0200
17 | lib/polysynth.rb Mon, 24 Jun 2019 16:13:22 +0200
18 | lib/ruby_synth.rb Sat, 22 Jun 2019 10:17:58 +0200
19 | lib/send_channel.rb Mon, 24 Jun 2019 16:14:00 +0200
20 | lib/sequencer_dsl.rb Mon, 24 Jun 2019 16:16:10 +0200
21 | lib/snare_drum.rb Mon, 24 Jun 2019 15:50:37 +0200
22 | lib/sound.rb Mon, 24 Jun 2019 16:00:16 +0200
23 | lib/state_variable_filter.rb Mon, 24 Jun 2019 16:01:14 +0200
24 | lib/tuned_drum.rb Mon, 24 Jun 2019 16:02:36 +0200
25 | lib/utils.rb Sat, 18 May 2019 22:50:18 +0200
26 | lib/waveshaper.rb Mon, 24 Jun 2019 16:04:35 +0200
27 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | # Welcome to Jekyll!
2 | #
3 | # This config file is meant for settings that affect your whole blog, values
4 | # which you are expected to set up once and rarely edit after that. If you find
5 | # yourself editing this file very often, consider using Jekyll's data files
6 | # feature for the data you need to update frequently.
7 | #
8 | # For technical reasons, this file is *NOT* reloaded automatically when you use
9 | # 'bundle exec jekyll serve'. If you change this file, please restart the server process.
10 |
11 | # Site settings
12 | # These are used to personalize your new site. If you look in the HTML files,
13 | # you will see them accessed via {{ site.title }}, {{ site.email }}, and so on.
14 | # You can create any custom variable you would like, and they will be accessible
15 | # in the templates via {{ site.myvariable }}.
16 | title: RubySynth
17 | email: jan@krutisch.de
18 | description: >- # this means to ignore newlines until "baseurl:"
19 | The documentation website for my Ruby Synth talk
20 | baseurl: "" # the subpath of your site, e.g. /blog
21 | url: "https://ruby-synth.fun" # the base hostname & protocol for your site, e.g. http://example.com
22 | github_username: halfbyte
23 |
24 | # Build settings
25 | markdown: kramdown
26 | theme: just-the-docs
27 |
28 | source: website
29 | timezone: Berlin
30 |
31 |
32 | # WHAT THE F
33 | compress_html:
34 | ignore:
35 | envs: all
--------------------------------------------------------------------------------
/examples/simple_song.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 | include SynthBlocks::Sequencer::SequencerDSL
3 |
4 | SRATE = 44100
5 | P = nil # pause
6 |
7 | kick_drum = SynthBlocks::Drum::KickDrum.new(SRATE)
8 | snare_drum = SynthBlocks::Drum::SnareDrum.new(SRATE)
9 | hihat = SynthBlocks::Drum::Hihat.new(SRATE)
10 | monosynth = SynthBlocks::Synth::Monosynth.new(SRATE)
11 | polysynth = SynthBlocks::Synth::Polysynth.new(SRATE)
12 |
13 | def_pattern(:drums_full, 16) do
14 | drum_pattern kick_drum, '*---*---*---*---'
15 | drum_pattern snare_drum, '----*-------*---'
16 | drum_pattern hihat, '--*---*---*---*-'
17 | end
18 |
19 | def_pattern(:bassline, 16) do
20 | note_pattern monosynth, [
21 | ['C1', 4], P, P, P,
22 | P, P, P, P,
23 | ['C#1', 6], P, P, P,
24 | P, P, P, P
25 | ]
26 | end
27 |
28 | def_pattern(:chord, 16) do
29 | note_pattern polysynth, [
30 | P, P, ['C2,D#2,G2', 2], P,
31 | P, P, P, P,
32 | ['C#2,E2,G#2', 2], P, P, P,
33 | P, P, P, P
34 | ]
35 | end
36 |
37 |
38 |
39 | my_song = song(bpm: 115) do
40 | pattern(:drums_full, at: 0, repeat: 1)
41 | pattern(:drums_full, at: 2, repeat: 2)
42 | pattern(:bassline, at: 0, repeat: 4)
43 | pattern(:chord, at: 0, repeat: 4)
44 | end
45 |
46 | out = my_song.render(SRATE) do |i|
47 | 0.3 * (kick_drum.run(i) + hihat.run(i) + snare_drum.run(i) + monosynth.run(i) + polysynth.run(i))
48 | end
49 |
50 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
51 |
--------------------------------------------------------------------------------
/examples/sequencer.rb:
--------------------------------------------------------------------------------
1 | require 'ruby-prof'
2 |
3 | require 'kick_drum'
4 | require 'monosynth'
5 | require 'polysynth'
6 | require 'snare_drum'
7 | require 'hihat'
8 | require 'sequencer_dsl'
9 | include SequencerDSL
10 |
11 | SRATE = 44100
12 | P = nil # pause
13 |
14 | kick_drum = KickDrum.new(SRATE)
15 | snare_drum = SnareDrum.new(SRATE)
16 | hihat = Hihat.new(SRATE)
17 | monosynth = Monosynth.new(SRATE)
18 | polysynth = Polysynth.new(SRATE)
19 |
20 | def_pattern(:drums_full, 16) do
21 | drum_pattern kick_drum, '*---*---*---*---'
22 | drum_pattern snare_drum, '----*-------*---'
23 | drum_pattern hihat, '--*---*---*---*-'
24 | end
25 |
26 | def_pattern(:bassline, 16) do
27 | note_pattern monosynth, [
28 | ['C1', 4], P, P, P,
29 | P, P, P, P,
30 | ['C#1', 6], P, P, P,
31 | P, P, P, P
32 | ]
33 | end
34 |
35 | def_pattern(:chord, 16) do
36 | note_pattern polysynth, [
37 | P, P, ['C2,D#2,G2', 2], P,
38 | P, P, P, P,
39 | ['C#2,E2,G#2', 2], P, P, P,
40 | P, P, P, P
41 | ]
42 | end
43 |
44 |
45 | length = song(bpm: 115) do
46 | pattern(:drums_full, at: 0, repeat: 1)
47 | pattern(:drums_full, at: 2, repeat: 2)
48 | pattern(:bassline, at: 0, repeat: 4)
49 | pattern(:chord, at: 0, repeat: 4)
50 | end
51 |
52 | RubyProf.start
53 | output = []
54 | (length * SRATE).times do |i|
55 | output << 0.3 * (kick_drum.run(i) + hihat.run(i) + snare_drum.run(i) + monosynth.run(i) + polysynth.run(i))
56 | end
57 | result = RubyProf.stop
58 | printer = RubyProf::FlatPrinter.new(result)
59 | File.open('prof.txt', 'wb') do |file|
60 | printer.print(file)
61 | end
62 | print output.pack('e*')
63 |
--------------------------------------------------------------------------------
/examples/acid_synth.rb:
--------------------------------------------------------------------------------
1 | require 'synth_blocks'
2 |
3 | #
4 | # A more complex example on how to compose synth blocks
5 | #
6 |
7 | include SynthBlocks::Utils
8 |
9 | SFREQ = 44100
10 | NOTES = [24, 24, 48, 37]
11 | OFFSETS = [0, 0, 3, 7]
12 | TEMPO = 120
13 |
14 | def n2f(n)
15 | (2.0 ** ((n - 69) / 12.0)) * 440.0
16 | end
17 |
18 | oscillator = SynthBlocks::Core::Oscillator.new(SFREQ)
19 | filter = SynthBlocks::Core::StateVariableFilter.new(SFREQ)
20 | vol_ar = SynthBlocks::Mod::Envelope.new(0.001,0.1)
21 | flt_ar = SynthBlocks::Mod::Envelope.new(0.02,0.04)
22 | verb = SynthBlocks::Fx::GVerb.new(SFREQ, max_room_size: 1200.0, room_size: 5.0, rev_time: 2.0, damping:0.3, spread: 15.0, input_bandwidth: 0.5, early_level:0.8, tail_level: 0.5)
23 | delay = SynthBlocks::Fx::Delay.new(SFREQ, time: 15.0 / TEMPO.to_f * 3)
24 | eq = SynthBlocks::Fx::Eq.new(SFREQ)
25 | eq.low_gain = 0.8
26 | eq.mid_gain = 0.5
27 | eq.high_gain = 1.0
28 |
29 | delay_eq = SynthBlocks::Fx::Eq.new(SFREQ)
30 | delay_eq.low_gain = 0.2
31 | delay_eq.mid_gain = 0.6
32 |
33 |
34 | out = (4 * SFREQ).times.map do |sample|
35 | t = sample.to_f / SFREQ.to_f # time in seconds
36 | s_per_b = 15.0 / TEMPO.to_f # seconds per quarternote
37 | b = t / s_per_b # quarternote
38 | t_in_b = t % s_per_b #time in quarternote
39 | l = (b / 4).floor # loop
40 | freq = n2f(24 + NOTES[b % NOTES.length] + OFFSETS[l % OFFSETS.length])
41 | v = oscillator.run(freq, waveform: :sawtooth)
42 | v = filter.run(v, 200 + flt_ar.run(t_in_b) * 1500, 4)
43 | v *= vol_ar.run(t_in_b)
44 | v = simple_waveshaper(v, 2)
45 | v = eq.run(v)
46 | v = delay.run(v) do |f|
47 | delay_eq.run(f)
48 | end
49 | v = v + (verb.run(v) * 0.2)
50 | v *= 0.33
51 | [1.0, [-1.0, v].max].min
52 | end
53 |
54 | SynthBlocks::Core::WaveWriter.write_if_name_given(out)
55 |
--------------------------------------------------------------------------------
/website/images/envelope-font-awesome.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | image/svg+xml
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/website/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Welcome to RubySynth
3 | layout: home
4 | nav_exclude: true
5 | ---
6 | # RubySynth
7 |
8 | RubySynth is a collection of DSP code snippets, held together with duct tape (as one does), to generate (electronic) music with pure Ruby.
9 |
10 | I've built this for my Talk at Euruko 2019 in Rotterdam called "The musical Ruby". This website primarily acts as additional reading material for people who have seen the talk, either online or at the conference. You probably want to [start here](01_introduction.html)
11 |
12 | You can find all source code, including the code for this website at [halfbyte/rubysynth](https://github.com/halfbyte/rubysynth) on GitHub.
13 |
14 | ## Credits
15 |
16 | Thank you to Sam Aaron for [SonicPi](https://sonic-pi.net/)
17 |
18 | Thank you to Lance Norskog for creating [SoX](sox.sourceforge.net/) and Chris Bagwell for maintaining it for more that 20 years now.
19 |
20 | Thank you to the amazing [MusicDSP mailing list](http://musicdsp.org) of where most of the more complicated DSP code has found it's way into this project.
21 |
22 | ## Image/Video Sources
23 |
24 | If not stated otherwise, the Images and Videos on this website are created by myself and subject to the content license mentioned below. All other images are taken from the Wikimedia Commons and are listed below:
25 |
26 | - [DAC chip](https://commons.wikimedia.org/wiki/File:CirrusLogicCS4282-AB.jpg)
27 | - [Loudspeaker](https://commons.wikimedia.org/wiki/File:Loudspeaker_side_en.svg)
28 | - Kick drum
29 | - Snare drum
30 | - [Hihat](https://commons.wikimedia.org/wiki/File:Hi-hat.jpg)
31 | - [Mixing Desk](https://commons.wikimedia.org/wiki/File:Image_of_a_mixing_desk_2014-02-16_00-50.jpg)
32 | - Roland 808
33 | - [Hallgrímskirkja](https://commons.wikimedia.org/wiki/File:Interior_of_Hallgr%C3%ADmskirkja_Church.jpg)
34 |
35 |
36 | ## Licenses
37 |
38 | All code here is licensed under the AGPL 3.0 license as documented at [LICENSE](https://github.com/halfbyte/rubysynth/blob/master/LICENSE) unless stated otherwise.
39 |
40 | The entire contents of the "website" folder of the repo (and with that, this website you're just reading) is licensed under a [Creative Commons Attribution-ShareAlike Unported license](https://creativecommons.org/licenses/by-sa/3.0/deed.en). The full license is at [website/LICENSE](https://github.com/halfbyte/rubysynth/blob/master/website/LICENSE)
41 |
42 |
--------------------------------------------------------------------------------
/drawings/sawtooth.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
21 |
41 |
46 |
51 |
52 |
54 |
55 |
57 | image/svg+xml
58 |
60 |
61 |
62 |
63 |
68 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/website/images/audio_flow.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/website/docs/js/search.js:
--------------------------------------------------------------------------------
1 | Search = function(data, input, result) {
2 | this.data = data;
3 | this.$input = $(input);
4 | this.$result = $(result);
5 |
6 | this.$current = null;
7 | this.$view = this.$result.parent();
8 | this.searcher = new Searcher(data.index);
9 | this.init();
10 | }
11 |
12 | Search.prototype = $.extend({}, Navigation, new function() {
13 | var suid = 1;
14 |
15 | this.init = function() {
16 | var _this = this;
17 | var observer = function(e) {
18 | switch(e.originalEvent.keyCode) {
19 | case 38: // Event.KEY_UP
20 | case 40: // Event.KEY_DOWN
21 | return;
22 | }
23 | _this.search(_this.$input[0].value);
24 | };
25 | this.$input.keyup(observer);
26 | this.$input.click(observer); // mac's clear field
27 |
28 | this.searcher.ready(function(results, isLast) {
29 | _this.addResults(results, isLast);
30 | })
31 |
32 | this.initNavigation();
33 | this.setNavigationActive(false);
34 | }
35 |
36 | this.search = function(value, selectFirstMatch) {
37 | value = jQuery.trim(value).toLowerCase();
38 | if (value) {
39 | this.setNavigationActive(true);
40 | } else {
41 | this.setNavigationActive(false);
42 | }
43 |
44 | if (value == '') {
45 | this.lastQuery = value;
46 | this.$result.empty();
47 | this.$result.attr('aria-expanded', 'false');
48 | this.setNavigationActive(false);
49 | } else if (value != this.lastQuery) {
50 | this.lastQuery = value;
51 | this.$result.attr('aria-busy', 'true');
52 | this.$result.attr('aria-expanded', 'true');
53 | this.firstRun = true;
54 | this.searcher.find(value);
55 | }
56 | }
57 |
58 | this.addResults = function(results, isLast) {
59 | var target = this.$result.get(0);
60 | if (this.firstRun && (results.length > 0 || isLast)) {
61 | this.$current = null;
62 | this.$result.empty();
63 | }
64 |
65 | for (var i=0, l = results.length; i < l; i++) {
66 | var item = this.renderItem.call(this, results[i]);
67 | item.setAttribute('id', 'search-result-' + target.childElementCount);
68 | target.appendChild(item);
69 | };
70 |
71 | if (this.firstRun && results.length > 0) {
72 | this.firstRun = false;
73 | this.$current = $(target.firstChild);
74 | this.$current.addClass('search-selected');
75 | }
76 | if (jQuery.browser.msie) this.$element[0].className += '';
77 |
78 | if (isLast) this.$result.attr('aria-busy', 'false');
79 | }
80 |
81 | this.move = function(isDown) {
82 | if (!this.$current) return;
83 | var $next = this.$current[isDown ? 'next' : 'prev']();
84 | if ($next.length) {
85 | this.$current.removeClass('search-selected');
86 | $next.addClass('search-selected');
87 | this.$input.attr('aria-activedescendant', $next.attr('id'));
88 | this.scrollIntoView($next[0], this.$view[0]);
89 | this.$current = $next;
90 | this.$input.val($next[0].firstChild.firstChild.text);
91 | this.$input.select();
92 | }
93 | return true;
94 | }
95 |
96 | this.hlt = function(html) {
97 | return this.escapeHTML(html).
98 | replace(/\u0001/g, '').
99 | replace(/\u0002/g, ' ');
100 | }
101 |
102 | this.escapeHTML = function(html) {
103 | return html.replace(/[&<>]/g, function(c) {
104 | return '' + c.charCodeAt(0) + ';';
105 | });
106 | }
107 |
108 | });
109 |
110 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | addressable (2.8.7)
5 | public_suffix (>= 2.0.2, < 7.0)
6 | ast (2.4.3)
7 | base64 (0.3.0)
8 | bigdecimal (3.2.1)
9 | colorator (1.1.0)
10 | concurrent-ruby (1.3.5)
11 | csv (3.3.4)
12 | date (3.4.1)
13 | em-websocket (0.5.3)
14 | eventmachine (>= 0.12.9)
15 | http_parser.rb (~> 0)
16 | erb (5.0.1)
17 | eventmachine (1.2.7)
18 | ffi (1.17.2)
19 | forwardable-extended (2.6.0)
20 | google-protobuf (4.31.1)
21 | bigdecimal
22 | rake (>= 13)
23 | http_parser.rb (0.8.0)
24 | i18n (1.14.7)
25 | concurrent-ruby (~> 1.0)
26 | io-console (0.8.0)
27 | irb (1.15.2)
28 | pp (>= 0.6.0)
29 | rdoc (>= 4.0.0)
30 | reline (>= 0.4.2)
31 | jekyll (4.4.1)
32 | addressable (~> 2.4)
33 | base64 (~> 0.2)
34 | colorator (~> 1.0)
35 | csv (~> 3.0)
36 | em-websocket (~> 0.5)
37 | i18n (~> 1.0)
38 | jekyll-sass-converter (>= 2.0, < 4.0)
39 | jekyll-watch (~> 2.0)
40 | json (~> 2.6)
41 | kramdown (~> 2.3, >= 2.3.1)
42 | kramdown-parser-gfm (~> 1.0)
43 | liquid (~> 4.0)
44 | mercenary (~> 0.3, >= 0.3.6)
45 | pathutil (~> 0.9)
46 | rouge (>= 3.0, < 5.0)
47 | safe_yaml (~> 1.0)
48 | terminal-table (>= 1.8, < 4.0)
49 | webrick (~> 1.7)
50 | jekyll-include-cache (0.2.1)
51 | jekyll (>= 3.7, < 5.0)
52 | jekyll-sass-converter (3.1.0)
53 | sass-embedded (~> 1.75)
54 | jekyll-seo-tag (2.8.0)
55 | jekyll (>= 3.8, < 5.0)
56 | jekyll-watch (2.2.1)
57 | listen (~> 3.0)
58 | json (2.12.2)
59 | just-the-docs (0.10.1)
60 | jekyll (>= 3.8.5)
61 | jekyll-include-cache
62 | jekyll-seo-tag (>= 2.0)
63 | rake (>= 12.3.1)
64 | kramdown (2.5.1)
65 | rexml (>= 3.3.9)
66 | kramdown-parser-gfm (1.1.0)
67 | kramdown (~> 2.0)
68 | liquid (4.0.4)
69 | listen (3.9.0)
70 | rb-fsevent (~> 0.10, >= 0.10.3)
71 | rb-inotify (~> 0.9, >= 0.9.10)
72 | logger (1.7.0)
73 | mercenary (0.4.0)
74 | opal (1.8.2)
75 | ast (>= 2.3.0)
76 | parser (~> 3.0, >= 3.0.3.2)
77 | parser (3.3.8.0)
78 | ast (~> 2.4.1)
79 | racc
80 | pathutil (0.16.2)
81 | forwardable-extended (~> 2.6)
82 | pp (0.6.2)
83 | prettyprint
84 | prettyprint (0.2.0)
85 | psych (5.2.6)
86 | date
87 | stringio
88 | public_suffix (6.0.2)
89 | racc (1.8.1)
90 | rake (13.3.0)
91 | rb-fsevent (0.11.2)
92 | rb-inotify (0.11.1)
93 | ffi (~> 1.0)
94 | rdoc (6.14.0)
95 | erb
96 | psych (>= 4.0.0)
97 | reline (0.6.1)
98 | io-console (~> 0.5)
99 | rexml (3.4.1)
100 | rouge (4.5.2)
101 | safe_yaml (1.0.5)
102 | sass-embedded (1.89.1)
103 | google-protobuf (~> 4.31)
104 | rake (>= 13)
105 | stringio (3.1.7)
106 | synth_blocks (1.0.3)
107 | wavefile (~> 1.1)
108 | terminal-table (3.0.2)
109 | unicode-display_width (>= 1.1.1, < 3)
110 | unicode-display_width (2.6.0)
111 | wavefile (1.1.2)
112 | webrick (1.9.1)
113 |
114 | PLATFORMS
115 | ruby
116 |
117 | DEPENDENCIES
118 | base64
119 | bigdecimal
120 | csv
121 | irb
122 | jekyll (~> 4.0)
123 | just-the-docs (~> 0.3)
124 | logger
125 | opal
126 | rake (~> 13.0)
127 | synth_blocks (~> 1.0)
128 | tzinfo-data
129 |
130 | BUNDLED WITH
131 | 2.6.9
132 |
--------------------------------------------------------------------------------
/website/_sass/custom/custom.scss:
--------------------------------------------------------------------------------
1 | // //
2 | // // Typography
3 | // //
4 | //
5 | // $body-font-family: -apple-system, BlinkMacSystemFont, "helvetica neue", helvetica, roboto, noto, "segoe ui", arial, sans-serif;
6 | // $mono-font-family: "SFMono-Regular", Menlo, Consolas, Monospace;
7 | // $root-font-size: 16px; // Base font-size for rems
8 | // $body-line-height: 1.4;
9 | // $body-heading-line-height: 1.15;
10 | //
11 | // //
12 | // // Colors
13 | // //
14 | //
15 | // $white: #fff;
16 | //
17 | // $grey-dk-000: #959396;
18 | // $grey-dk-100: #5c5962;
19 | // $grey-dk-200: #44434d;
20 | // $grey-dk-250: #302d36 !default;
21 | // $grey-dk-300: #27262b;
22 | //
23 | // $grey-lt-000: #f5f6fa;
24 | // $grey-lt-100: #eeebee;
25 | // $grey-lt-200: #ecebed;
26 | // $grey-lt-300: #e6e1e8;
27 | //
28 | // $purple-000: #7253ed;
29 | // $purple-100: #5e41d0;
30 | // $purple-200: #4e26af;
31 | // $purple-300: #381885;
32 | //
33 | // $blue-000: #2c84fa;
34 | // $blue-100: #2869e6;
35 | // $blue-200: #264caf;
36 | // $blue-300: #183385;
37 | //
38 | // $green-000: #41d693;
39 | // $green-100: #11b584;
40 | // $green-200: #009c7b;
41 | // $green-300: #026e57;
42 | //
43 | // $body-background-color: $white !default;
44 | // $sidebar-color: $grey-lt-000 !default;
45 | // $code-background-color: $grey-lt-000 !default;
46 |
47 | // $body-text-color: $grey-dk-100 !default;
48 | // $body-heading-color: $grey-dk-300 !default;
49 | // $nav-child-link-color: $grey-dk-100 !default;
50 | // $link-color: $purple-000 !default;
51 | // $btn-primary-color: $purple-100 !default;
52 | // $base-button-color: #f7f7f7 !default;
53 | //
54 | // //
55 | // // Media queries in pixels
56 | // //
57 | //
58 | // $media-queries: (
59 | // xs: 320px,
60 | // sm: 500px,
61 | // md: 740px,
62 | // lg: 1120px,
63 | // xl: 1400px
64 | // );
65 | //
66 | // //
67 | // // Spacing
68 | // //
69 | //
70 | // $spacing-unit: 1rem; // 1rem == 16px
71 | //
72 | // $spacers: (
73 | // sp-0: 0,
74 | // sp-1: $spacing-unit * 0.25,
75 | // sp-2: $spacing-unit * 0.5,
76 | // sp-3: $spacing-unit * 0.75,
77 | // sp-4: $spacing-unit,
78 | // sp-5: $spacing-unit * 1.5,
79 | // sp-6: $spacing-unit * 2,
80 | // sp-7: $spacing-unit * 2.5,
81 | // sp-8: $spacing-unit * 3,
82 | // sp-9: $spacing-unit * 3.5,
83 | // sp-10: $spacing-unit * 4
84 | // );
85 | //
86 | // $sp-1: map-get($spacers, sp-1); // 0.25 rem == 4px
87 | // $sp-2: map-get($spacers, sp-2); // 0.5 rem == 8px
88 | // $sp-3: map-get($spacers, sp-3); // 0.75 rem == 12px
89 | // $sp-4: map-get($spacers, sp-4); // 1 rem == 16px
90 | // $sp-5: map-get($spacers, sp-5); // 1.5 rem == 24px
91 | // $sp-6: map-get($spacers, sp-6); // 2 rem == 32px
92 | // $sp-7: map-get($spacers, sp-7); // 2.5 rem == 40px
93 | // $sp-8: map-get($spacers, sp-8); // 3 rem == 48px
94 | // $sp-9: map-get($spacers, sp-9); // 4 rem == 48px
95 | // $sp-10: map-get($spacers, sp-10); // 4.5 rem == 48px
96 | //
97 | // //
98 | // // Borders
99 | // //
100 | //
101 | // $border: 1px solid;
102 | // $border-radius: 4px;
103 | // $border-color: $grey-lt-100;
104 | //
105 | // //
106 | // // Grid system
107 | // //
108 | //
109 | // $gutter-spacing: $sp-6;
110 | // $gutter-spacing-sm: $sp-4;
111 | // $nav-width: 232px;
112 | // $content-width: 800px;
113 | //
114 | // $media-queries: (
115 | // xs: 320px,
116 | // sm: 500px,
117 | // md: 740px,
118 | // lg: 800px,
119 | // xl: 1316px
120 | // );
121 |
122 | .main-content video {
123 | width: 100%;
124 | }
125 |
126 | .main-content img {
127 | display: block;
128 | margin: 0 auto 1em auto;
129 | max-width: 100%;
130 | }
131 |
132 | canvas.scope {
133 | background: #000;
134 | width: 600px;
135 | }
136 | .player {
137 | width: 600px;
138 | display: inline-block;
139 | margin-bottom: 1em;
140 | }
141 | .player-fft {
142 | width: 600px;
143 | display: inline-block;
144 | }
145 | .player button {
146 | display: block;
147 | width: 100%;
148 | background: green;
149 | border: 1px solid black;
150 | box-shadow: 2px 2px 3px rgba(0,0,0,0.2);
151 | border-radius: 5px;
152 | padding: 5px;
153 | color: #fff;
154 | }
155 |
--------------------------------------------------------------------------------
/drawings/waveshaper.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
21 |
41 |
46 |
51 |
52 |
54 |
55 |
57 | image/svg+xml
58 |
60 |
61 |
62 |
63 |
64 |
68 |
75 |
81 |
86 |
91 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/website/04_drums.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Drum sounds
3 | layout: page
4 | nav_order: 4
5 | ---
6 | # Drum Sounds
7 |
8 | We're now perfectly equipped to create some lush or harsh synthesizer sounds, so we should be able to make some good ambient music. But while I do like me some good ambient, I'm more of a dance music kind of guy and for that we're missing an important part. Now, I could cheat here and just use sampling - That's what most dance music producers nowadays do, but that would be cheating, right?
9 |
10 | Additionally, if you look at how music styles like House and Techno came about, they were literally based on the sounds of two drum machines, both from Roland, the TR-808 and the TR-909 - The 808 is using analog synthesis for everything while the 909 uses a limited amount of samples - So generating drums with the sythesizing technologies we've explored so far would give us a good understanding of how these machines worked.
11 |
12 | # Kick drum
13 |
14 | 
15 |
16 | Let's start with the foundation of every house or techno groove, the bassdrum or kickdrum. If you analyze the sound of an accoustic kick drum (or basically any drum with a similar design with a drum head and a drum corpus), as if you were a Roland engineer in the 80's, you'll notice two very distinct parts of a drum sound. The sharp attack, when the drum stick hits the skin of the drum head, which is really more like a shark click and then the sound of the drum body, where the full body including the two skins (and the air trapped in them) vibrates.
17 |
18 | To simulate these two parts, We can use a sine wave (or a filtered down squarewave) and quickly modulate it's pitch from a relatively high value to a relatively low value. By varying the speed and the two frequencies, we can get a surprising amout of different percussion sounds and some of them do sound like a bassdrum.
19 |
20 | 
21 |
22 | In this example, I've also modulated the filter in a way so that it is a bit more open at the very beginning, adding to that sharpness of the first attack.
23 |
24 | # Snare drum
25 |
26 | 
27 | .png)
28 | A snare drum is, together with the kick drum, the backbone of every rock groove. What a snare drum is, esentially, is a tom, so a midsized drum, that has a so called snare carpet that lies on the bottom drum skin. This leads to the characteristic noisy sound of a snare that is much more than just the sound of the drum, which would sound like this.
29 |
30 | To construct a snare sound, we pretty much need two components - A version of our kick drum sound that is just slightly pitched up (as a smaller drum usually creates a higher pitche sounds), like this, and then something to emulate the snares. To me, this actually sounds a lot like white noise and so that's what we're going to use. White noise is surprisingly easy to create:
31 |
32 | ```ruby
33 | noise_out = rand * 2.0 - 1.0
34 | ```
35 |
36 | On top of that, we're going to emulate the snare wires being a bit more bright in the beginning and then dampening down while they settle by putting a lowpass filter on top with an envelope shaping the sound a little it. Of course I aso put another envelope on the volume.
37 |
38 | 
39 |
40 |
41 | # Hihat
42 |
43 | 
44 |
45 | This is our last drum sound. The hihat, in a traditional drum kit, looks like this - It's essentially two cymbals on top of each other and you can move them together with a foot pedal, resulting in either very short or longer sounds.
46 |
47 | Our hihat emulation will be somewhat crude, but it will actually work quite well within the groove we want to build with this.
48 |
49 | Again, we'll start with white noise. Having a shorter or longer decay on our volume envelope gives us the chance to emulate an open or a closed hihat. By adding a static filter, a bandpass in this case, we can sort of tune the noise into something that at least starts to sound like a real hihat. To be honest, in my own music, I often favour these clean sounding hihats to accoustic ones.
50 |
51 | 
52 |
--------------------------------------------------------------------------------
/website/docs/js/navigation.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Navigation allows movement using the arrow keys through the search results.
3 | *
4 | * When using this library you will need to set scrollIntoView to the
5 | * appropriate function for your layout. Use scrollInWindow if the container
6 | * is not scrollable and scrollInElement if the container is a separate
7 | * scrolling region.
8 | */
9 | Navigation = new function() {
10 | this.initNavigation = function() {
11 | var _this = this;
12 |
13 | $(document).keydown(function(e) {
14 | _this.onkeydown(e);
15 | }).keyup(function(e) {
16 | _this.onkeyup(e);
17 | });
18 |
19 | this.navigationActive = true;
20 | }
21 |
22 | this.setNavigationActive = function(state) {
23 | this.navigationActive = state;
24 | this.clearMoveTimeout();
25 | }
26 |
27 | this.onkeyup = function(e) {
28 | if (!this.navigationActive) return;
29 |
30 | switch(e.keyCode) {
31 | case 37: //Event.KEY_LEFT:
32 | case 38: //Event.KEY_UP:
33 | case 39: //Event.KEY_RIGHT:
34 | case 40: //Event.KEY_DOWN:
35 | this.clearMoveTimeout();
36 | break;
37 | }
38 | }
39 |
40 | this.onkeydown = function(e) {
41 | if (!this.navigationActive) return;
42 | switch(e.keyCode) {
43 | case 37: //Event.KEY_LEFT:
44 | if (this.moveLeft()) e.preventDefault();
45 | break;
46 | case 38: //Event.KEY_UP:
47 | if (e.keyCode == 38 || e.ctrlKey) {
48 | if (this.moveUp()) e.preventDefault();
49 | this.startMoveTimeout(false);
50 | }
51 | break;
52 | case 39: //Event.KEY_RIGHT:
53 | if (this.moveRight()) e.preventDefault();
54 | break;
55 | case 40: //Event.KEY_DOWN:
56 | if (e.keyCode == 40 || e.ctrlKey) {
57 | if (this.moveDown()) e.preventDefault();
58 | this.startMoveTimeout(true);
59 | }
60 | break;
61 | case 13: //Event.KEY_RETURN:
62 | if (this.$current) e.preventDefault();
63 | this.select(this.$current);
64 | break;
65 | }
66 | if (e.ctrlKey && e.shiftKey) this.select(this.$current);
67 | }
68 |
69 | this.clearMoveTimeout = function() {
70 | clearTimeout(this.moveTimeout);
71 | this.moveTimeout = null;
72 | }
73 |
74 | this.startMoveTimeout = function(isDown) {
75 | if (!$.browser.mozilla && !$.browser.opera) return;
76 | if (this.moveTimeout) this.clearMoveTimeout();
77 | var _this = this;
78 |
79 | var go = function() {
80 | if (!_this.moveTimeout) return;
81 | _this[isDown ? 'moveDown' : 'moveUp']();
82 | _this.moveTimeout = setTimeout(go, 100);
83 | }
84 | this.moveTimeout = setTimeout(go, 200);
85 | }
86 |
87 | this.moveRight = function() {
88 | }
89 |
90 | this.moveLeft = function() {
91 | }
92 |
93 | this.move = function(isDown) {
94 | }
95 |
96 | this.moveUp = function() {
97 | return this.move(false);
98 | }
99 |
100 | this.moveDown = function() {
101 | return this.move(true);
102 | }
103 |
104 | /*
105 | * Scrolls to the given element in the scrollable element view.
106 | */
107 | this.scrollInElement = function(element, view) {
108 | var offset, viewHeight, viewScroll, height;
109 | offset = element.offsetTop;
110 | height = element.offsetHeight;
111 | viewHeight = view.offsetHeight;
112 | viewScroll = view.scrollTop;
113 |
114 | if (offset - viewScroll + height > viewHeight) {
115 | view.scrollTop = offset - viewHeight + height;
116 | }
117 | if (offset < viewScroll) {
118 | view.scrollTop = offset;
119 | }
120 | }
121 |
122 | /*
123 | * Scrolls to the given element in the window. The second argument is
124 | * ignored
125 | */
126 | this.scrollInWindow = function(element, ignored) {
127 | var offset, viewHeight, viewScroll, height;
128 | offset = element.offsetTop;
129 | height = element.offsetHeight;
130 | viewHeight = window.innerHeight;
131 | viewScroll = window.scrollY;
132 |
133 | if (offset - viewScroll + height > viewHeight) {
134 | window.scrollTo(window.scrollX, offset - viewHeight + height);
135 | }
136 | if (offset < viewScroll) {
137 | window.scrollTo(window.scrollX, offset);
138 | }
139 | }
140 | }
141 |
142 |
--------------------------------------------------------------------------------
/website/presentations/2019-06-22_euruko.html:
--------------------------------------------------------------------------------
1 | ---
2 | title: Euruko 2019
3 | parent: Presentations
4 | ---
5 |
6 |
7 |
8 | The musical Ruby - A presentation by Jan Krutisch for Euruko 2019
9 |
10 |
119 |
120 |
121 |
124 |
125 |
127 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/website/01_introduction.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Introduction
3 | layout: page
4 | nav_order: 1
5 | ---
6 | # Introduction
7 |
8 | We'll start this off with a short demonstration of a software called SonicPi, which allows you to live code music:
9 |
10 |
11 |
12 |
13 |
14 |
15 | Sonic Pi is a wonderful piece of software. It can teach both the basics of programming and the basics of music making while sounding quite professional. That's due to the great foundation Sonic Pi is based on: Supercollider is a system specifically built for live coding and has been under continuous development since 1996!
16 |
17 | But today we're going to leave those comfortable foundations behind and going to try to recreate at least parts of it with pure ruby. The idea here is that we can use an expressive and easy to read language like ruby and show how to implement stuff that is usually written in C or C++, with lots of performance optimizations, which doesn't necessarily makes for the most readable code.
18 |
19 | We're going to do this in three parts. At first we're going to take a look at how to generate typical synthesizer sounds, including some drum sounds. Next, we're going to figure out how to turn these into music by looking at sequencing (or, in old school terms, arranging). Last but not least we'll add some effects that will bring the sound to the pro level.
20 |
21 | I'll show a lot of code in this talk, but don't concentrate too much on it, though, it's all available for you to study afterwards. And, unfortunately, since we have a very full todo list for the rest of this talk, I need to glance over a couple of things I would have loved to talk about in detail - But fear not, the content is all there, if only in written form. If you go to ruby-synth.fun, you'll find a lot of additional material there, including, of course, all the code examples.
22 |
23 | ## Making noise with Ruby
24 |
25 | Ruby doesn't have a simple, integrated way of outputting sound directly to your computer's soundcard. While there may be libraries, I opted to use the power of Unix and leverage a tool called SoX, (short for "Sound eXchange"), which is essentially the swiss army knife of audio file conversion. It's been around for ages, I even used it back when I still had my AMIGA computer at the end of the 90's. Originally conceived by Lance Norskog, and then maintained by Chris Bagwell, it has thousands of contributors and is a great example for a long running open source project that does one thing and does it well. By playing around with Ruby's quirky `Array#pack` method and SoX's command line switches, I came up with the following snippet to make ruby output a binary stream of 32 bit, little endian float values:
26 |
27 | ```ruby
28 | SAMPLING_FREQUENCY=44100
29 | FREQUENCY=440
30 |
31 | in_cycle = 0
32 | samples = SAMPLING_FREQUENCY.times.map do
33 | period = SAMPLING_FREQUENCY / FREQUENCY.to_f
34 | output = in_cycle > 0.5 ? -1.0 : 1.0
35 | in_cycle = (in_cycle + (1.0 / period)) % 1.0
36 | output * 0.5
37 | end
38 | print samples.pack('e*')
39 | ```
40 | we then can use the following bash script that utilizes SoX's `play` command to pipe the output of the ruby script to your soundcard:
41 |
42 | ```bash
43 | #!/bin/bash
44 | # play.sh
45 | ruby -Ilib $1 | play -t raw -b 32 -r 44100 -c 1 \
46 | -e floating-point --endian little -
47 | ```
48 |
49 | ```bash
50 | $ ./play.sh examples/square_wave.rb
51 | ```
52 |
53 | If, instead of sending the data to our soundcard, we want to save it to a soundfile, to, for example, play the file from a webpage (how very self referential of me, right?), we can use the following snippet and invocation:
54 |
55 | ```bash
56 | #!/bin/bash
57 | # save.sh
58 | ruby -Ilib $1 | sox -t raw -b 32 -r 44100 -c 1 \
59 | -e floating-point --endian little - -t wav -b 16 $2
60 | ```
61 |
62 | ```bash
63 | $ ./save.sh examples/square_wave.rb square_wave.wav
64 | ```
65 |
66 | ## Try it yourself
67 |
68 | 1. Check out the repo [halfbyte/rubysynth](https://github.com/halfbyte/rubysynth)
69 | 1. Install SoX (Available on Homebrew, all linux package managers and Chocolatey)
70 | 1. `./bin/play.sh examples/square_wave.rb` or `./bin/play.sh examples/square_wave.rb square_wave.wav`
71 |
72 | I've developed and tested all of this on Linux, it should run fine on MacOS.
73 |
74 | I'll try to provide Windows .bat files as well later on.
75 |
76 |
--------------------------------------------------------------------------------
/website/presentations/2019-08-23_railsgrills.html:
--------------------------------------------------------------------------------
1 | ---
2 | title: Railsgrills 3.1 Praha
3 | parent: Presentations
4 | ---
5 |
6 |
7 |
8 | The musical Ruby - A presentation by Jan Krutisch for Railsgrills 3.1
9 |
10 |
119 |
120 |
121 |
124 |
125 |
127 |
151 |
152 |
153 |
154 |
--------------------------------------------------------------------------------
/website/05_sequencer.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Building a sequencer
3 | layout: page
4 | nav_order: 5
5 | ---
6 | # Sequencing basics
7 |
8 | Now that we have our sound repertoire, we can start to think about how to turn these single sounds into actual music.
9 |
10 | For that, we need to learn a little about sequencing and rhythm.
11 |
12 | ## A bar and a beat
13 |
14 | Most modern dance music (as is most music you would hear on the radio) is writting in a straight 4/4 metric. But what does that mean?
15 |
16 | It means that a measure (or bar) of our music is comprised of four quarter notes. A quarter note in in this measure represents a beat.
17 |
18 | I'm not going to go into more detail about rhythm, because the 4/4 is so easy to work with and this can get complicated very quickly - just one quick example of a different beat, here's a 6/8 walz.
19 |
20 | Tempo in music is often measured in beats per minute or short BPM. For 4/4, this very conveniently means that we can simply count the quarter notes. To make things even more simpler, we can stick to a very typical (for, say, slow house music) 120 BPM and thus we can determine that we'll need 2 beats per second, meaning that each beat is half a second long.
21 |
22 | Each 16th note will thus be 1/8 of a second long. This is relevant because a 16th note is a very common unit used in so calles step sequencers, made popular by drum machines like the legendary Roland 808, pictured below, which used 16 buttons to make it easy to program these 16 steps in a bar in a very convenient manner.
23 |
24 | 
25 |
26 | Here's how you would do the math in code:
27 |
28 | ``` ruby
29 | BPM = 120
30 | beat_length_in_seconds = 60 / BPM # = 0.5s
31 | bar_length = beat_length_in_seconds * 4 # = 2s
32 | sixteenth_note_length = beat_length_in_seconds / 4 # = 0.125s
33 |
34 | ```
35 |
36 | ## Patterns
37 |
38 | Most modern dance music is developed on a basis of so called patterns. patterns, in this case mean small chunks of music, often a bar for example or multiples thereof, that can then be assembled into full songs. A pattern could be a drum pattern for example.
39 |
40 | Here's a screenshot of how that looks in a modern music production software, in this case Ableton Live, which I also use to produce music if I'm not programming it in Ruby:
41 |
42 | 
43 |
44 | In a way, you can think of patterns as abstractions that can be reused. Which brings us back to the question of how we could best represent this in code.
45 |
46 | ## Let's make a DSL for that.
47 |
48 | Here's some "dream code" to define a drum pattern:
49 |
50 | ``` ruby
51 | def_pattern(:drums_full, 16) do
52 | drum_pattern kick_drum, '*---*---*---*---'
53 | drum_pattern snare_drum, '----*-------*---'
54 | drum_pattern hihat, '--*---*---*---*-'
55 | end
56 | ```
57 |
58 | The following example is a first crude idea on how melody pattern definitions could look like:
59 |
60 | ``` ruby
61 | def_pattern(:bassline, 16) do
62 | note_pattern monosynth, [
63 | ['C1', 4], P, P, P,
64 | P, P, P, P,
65 | ['C#1', 6], P, P, P,
66 | P, P, P, P
67 | ]
68 | end
69 | ```
70 |
71 | The P in there is just a constant set to nil, and stands for "Pause". The array contains a note (note and octave) and a length in steps (or 1/16 notes).
72 |
73 | Now, let's take these pattern definitions and then turn them into a song:
74 |
75 | ``` ruby
76 | length = song(bpm: 115) do
77 | pattern(:drums_full, at: 0, repeat: 1)
78 | pattern(:drums_full, at: 2, repeat: 2)
79 | pattern(:bassline, at: 0, repeat: 4)
80 | pattern(:chord, at: 0, repeat: 4)
81 | end
82 | ```
83 |
84 | So, you can start a pattern at a certain position (specified in bars this time) and you can repeat them as many times as you want. Together with setting the tempo, this code can now schdule all notes to all the instruments.
85 |
86 | The code to make this all work is a bit too long to list it all here, so please, by all means take a look at [lib/sequencer_dsl.rb](https://github.com/halfbyte/rubysynth/blob/master/lib/sequencer_dsl.rb).
87 |
88 | Additonally, take a look at [lib/sound.rb](https://github.com/halfbyte/rubysynth/blob/master/lib/sound.rb) which is the base class for every sound generator and among other things completely handles interpreting the scheduled events into a coherent view usable by the generator to render the actual sounds.
89 |
90 |
91 |
--------------------------------------------------------------------------------
/website/presentations/2020-07-18_rubyconf_by.html:
--------------------------------------------------------------------------------
1 | ---
2 | title: RubyConfOnline.by 2020
3 | parent: Presentations
4 | ---
5 |
6 |
7 |
8 | Ruby Patterns for contempory dance music - A presentation by Jan Krutisch for RubyConfOnline.by 2020
9 |
10 |
138 |
139 |
140 |
143 |
144 |
146 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/website/docs/Limiter.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | class Limiter - RDoc Documentation
8 |
9 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
54 |
55 |
56 |
57 |
81 |
82 |
83 |
84 |
85 | class Limiter
86 |
87 |
88 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | Public Instance Methods
108 |
109 |
110 |
111 |
112 |
113 |
114 | run (x)
116 |
117 | click to toggle source
118 |
119 |
120 |
121 |
122 |
123 |
124 |
run limiter
125 |
126 |
127 |
128 |
129 |
130 |
131 | def run (x )
132 | x * (27.0 + x * x ) / (27.0 + 9.0 * x * x )
133 | end
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
156 |
157 |
--------------------------------------------------------------------------------
/website/docs/README_md.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | README - RDoc Documentation
8 |
9 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
54 |
55 |
56 |
57 |
Table of Contents
58 |
59 |
64 |
65 |
66 |
67 |
79 |
80 |
81 |
82 |
83 | RubySynth¶ ↑
84 |
85 | _______ __ ___t____ __ __
86 | | _ .--.--| |--.--.--| _ .--.--.-----| |_| |--.
87 | |. l | | | _ | | | 1___| | | | _| |
88 | |. _ |_____|_____|___ |____ |___ |__|__|____|__|__|
89 | |: | | |_____|: 1 |_____|
90 | |::.|:. | |::.. . |
91 | `--- ---' `-------'
92 |
93 | Ruby Synth is a collection of primitives to make electronic music with pure ruby.
94 |
95 | Ruby Synth is the backing project for my EuRuKo 2019 talk “The musical Ruby”.
96 |
97 | Ruby Synth also contains a ton of additional writing to supplement the very dense 30 minute talk. You can read that additional material at ruby-synth.fun .
98 |
99 |
100 | Eventually I'll try to turn the primitives into a proper gem and better tests, but that will depend on your interest and if I can give this talk a couple of more times.
101 |
102 | Contributing or just playing around¶ ↑
103 |
104 | You'll need to install SoX
105 |
106 | You'll need Ruby 2.6.3 (it's an arbitrary choice and you could modify .ruby-version to make it run on older rubies, I don't use any 2.6 specific code)
107 |
108 | Most code is somewhat documented but I haven't yet built proper docs for it.
109 |
110 |
111 | Licenses¶ ↑
112 |
113 | All code here is licensed under the AGPL 3.0 license as documented at LICENSE unless stated otherwise.
114 |
115 | The entire contents of the “website” folder of the repo (and with that, this website you're just reading) is licensed under a Creative Commons Attribution-ShareAlike Unported license . The full license is at website/LICENSE
116 |
117 |
118 |
119 |
120 |
121 |
126 |
127 |
--------------------------------------------------------------------------------
/website/js/player.js:
--------------------------------------------------------------------------------
1 | const context = new AudioContext()
2 |
3 | class DemoPlayer {
4 | constructor(slideshow, context, element) {
5 | this.active = false
6 | this.slideshow = slideshow
7 | this.context = context
8 | this.element = element
9 | this.sourceNode = new MediaElementAudioSourceNode(this.context, {mediaElement: element})
10 | this.analyzer = context.createAnalyser()
11 | this.analyzer.fftSize = 4096
12 | console.log(this.analyzer.frequencyBinCount)
13 | this.sourceNode.connect(this.analyzer)
14 | this.sourceNode.connect(this.context.destination)
15 | const player = element.getAttribute('data-player')
16 | const [playerType, playerVariant] = player.split('-')
17 | this.playerType = playerType
18 | this.playerVariant = playerVariant
19 | this.slideParent = this.element.closest('.remark-slide-content')
20 | this.insertUI()
21 | if (this.slideshow != null) {
22 | this.slideshow.on('hideSlide', () => { this.active = false})
23 | }
24 | this.element.addEventListener('play', this.play.bind(this))
25 | this.element.addEventListener('ended', this.ended.bind(this))
26 | }
27 | insertUI() {
28 | const wrapper = document.createElement('div')
29 | wrapper.className = `player player-${this.playerType}`
30 | const playButton = document.createElement('button')
31 | const buttonText = document.createTextNode("Play ▶")
32 | playButton.appendChild(buttonText)
33 | this.element.parentNode.insertBefore(wrapper, this.element.nextSibling)
34 | playButton.addEventListener('click', (e) => this.element.play())
35 |
36 | this.scope = document.createElement('canvas')
37 | this.scopeContext = this.scope.getContext('2d')
38 | this.scope.width = 2048
39 | this.scope.height = 1152
40 |
41 | if (this.playerType !== 'simple') {
42 | if (this.playerVariant === 'full' && this.slideParent != null) {
43 | this.scope.className = "scope-full"
44 | this.slideParent.appendChild(this.scope)
45 | } else {
46 | this.scope.className = "scope"
47 | wrapper.appendChild(this.scope)
48 | }
49 | }
50 |
51 | if (this.playerType === 'scope') {
52 | this.updateScope = this.updateScope.bind(this)
53 | }
54 | if (this.playerType === 'fft') {
55 | this.updateFFT = this.updateFFT.bind(this)
56 | }
57 | wrapper.appendChild(playButton)
58 | }
59 | updateScope() {
60 | const dataArray = new Float32Array(this.analyzer.fftSize)
61 | const halfHeight = this.scope.height / 2
62 | this.analyzer.getFloatTimeDomainData(dataArray)
63 | this.scopeContext.clearRect(0, 0, this.scope.width, this.scope.height)
64 | if (this.playerVariant === 'full') {
65 | this.scopeContext.strokeStyle = "rgba(0,128,0,0.5)"
66 | } else {
67 | this.scopeContext.strokeStyle = "#0f0"
68 | }
69 | this.scopeContext.lineWidth = 4
70 | this.scopeContext.beginPath()
71 | this.scopeContext.moveTo(0, halfHeight)
72 | dataArray.forEach(function(v, i) {
73 | const x = i / this.analyzer.fftSize * this.scope.width
74 | const y = v * halfHeight + halfHeight
75 | this.scopeContext.lineTo(x,y)
76 | }, this)
77 | this.scopeContext.stroke()
78 | if (this.active) {
79 | requestAnimationFrame(this.updateScope)
80 | } else {
81 | this.scopeContext.clearRect(0, 0, this.scope.width, this.scope.height)
82 | }
83 | }
84 | updateFFT() {
85 | const dataArray = new Uint8Array(this.analyzer.frequencyBinCount)
86 | this.analyzer.getByteFrequencyData(dataArray)
87 | // console.log(dataArray)
88 | this.scopeContext.clearRect(0, 0, this.scope.width, this.scope.height)
89 | if (this.playerVariant === 'full') {
90 | this.scopeContext.strokeStyle = "rgba(0,128,0,0.5)"
91 | } else {
92 | this.scopeContext.strokeStyle = "#0f0"
93 | }
94 | this.scopeContext.lineWidth = 4
95 | this.scopeContext.beginPath()
96 | dataArray.forEach(function(v, i) {
97 | const x = i / this.analyzer.frequencyBinCount * this.scope.width
98 | const halfHeight = this.scope.height / 2
99 | const y = this.scope.height - (this.scope.height * (v / 255))
100 | if (i == 0) { this.scopeContext.moveTo(x, y) }
101 | this.scopeContext.lineTo(x,y)
102 | }, this)
103 | this.scopeContext.stroke()
104 | if (this.active) {
105 | requestAnimationFrame(this.updateFFT)
106 | } else {
107 | this.scopeContext.clearRect(0, 0, this.scope.width, this.scope.height)
108 | }
109 | }
110 | play() {
111 | this.context.resume()
112 | if (!this.active) {
113 | this.active = true
114 | if (this.playerType === 'scope') {
115 | this.updateScope()
116 | }
117 | if (this.playerType === 'fft') {
118 | this.updateFFT()
119 | }
120 | }
121 | }
122 | ended() {
123 | this.active = false
124 | }
125 |
126 | }
127 |
128 | function initPlayer() {
129 | document.querySelectorAll('audio[data-player]').forEach(function(element) {
130 | let sl = null
131 | if (typeof slideshow !== 'undefined') {
132 | sl = slideshow
133 | }
134 | new DemoPlayer(sl, context, element)
135 | })
136 | }
137 |
--------------------------------------------------------------------------------
/drawings/compressor.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
21 |
29 |
35 |
36 |
44 |
50 |
51 |
52 |
72 |
77 |
82 |
87 |
92 |
93 |
95 |
96 |
98 | image/svg+xml
99 |
101 |
102 |
103 |
104 |
105 |
110 |
117 |
125 |
133 |
134 |
135 |
--------------------------------------------------------------------------------
/website/docs/js/darkfish.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Darkfish Page Functions
4 | * $Id: darkfish.js 53 2009-01-07 02:52:03Z deveiant $
5 | *
6 | * Author: Michael Granger
7 | *
8 | */
9 |
10 | /* Provide console simulation for firebug-less environments */
11 | if (!("console" in window) || !("firebug" in console)) {
12 | var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml",
13 | "group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"];
14 |
15 | window.console = {};
16 | for (var i = 0; i < names.length; ++i)
17 | window.console[names[i]] = function() {};
18 | };
19 |
20 |
21 | /**
22 | * Unwrap the first element that matches the given @expr@ from the targets and return them.
23 | */
24 | $.fn.unwrap = function( expr ) {
25 | return this.each( function() {
26 | $(this).parents( expr ).eq( 0 ).after( this ).remove();
27 | });
28 | };
29 |
30 |
31 | function showSource( e ) {
32 | var target = e.target;
33 | var codeSections = $(target).
34 | parents('.method-detail').
35 | find('.method-source-code');
36 |
37 | $(target).
38 | parents('.method-detail').
39 | find('.method-source-code').
40 | slideToggle();
41 | };
42 |
43 | function hookSourceViews() {
44 | $('.method-heading').click( showSource );
45 | };
46 |
47 | function hookSearch() {
48 | var input = $('#search-field').eq(0);
49 | var result = $('#search-results').eq(0);
50 | $(result).show();
51 |
52 | var search_section = $('#search-section').get(0);
53 | $(search_section).show();
54 |
55 | var search = new Search(search_data, input, result);
56 |
57 | search.renderItem = function(result) {
58 | var li = document.createElement('li');
59 | var html = '';
60 |
61 | // TODO add relative path to
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
54 |
55 |
56 |
57 |
83 |
84 |
85 |
86 |
87 | class Damper
88 |
89 |
90 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | Public Class Methods
108 |
109 |
110 |
111 |
112 |
113 |
114 | new (damping)
116 |
117 | click to toggle source
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | def initialize (damping )
132 | @damping = damping
133 | @delay = 0.0
134 | end
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 | Public Instance Methods
150 |
151 |
152 |
153 |
154 |
155 |
156 | run (x)
158 |
159 | click to toggle source
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 | def run (x )
174 | y = x * (1.0 - @damping ) + @delay * @damping ;
175 | @delay = y
176 | y
177 | end
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
200 |
201 |
--------------------------------------------------------------------------------
/drawings/eq.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
21 |
29 |
35 |
36 |
44 |
50 |
51 |
52 |
73 |
78 |
83 |
88 |
93 |
94 |
96 |
97 |
99 | image/svg+xml
100 |
102 |
103 |
104 |
105 |
106 |
111 |
119 |
128 |
137 |
145 |
146 |
147 |
--------------------------------------------------------------------------------
/drawings/delay.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
21 |
29 |
34 |
35 |
43 |
48 |
49 |
50 |
70 |
75 |
80 |
85 |
90 |
91 |
93 |
94 |
96 | image/svg+xml
97 |
99 |
100 |
101 |
102 |
103 |
107 |
112 |
114 |
119 |
124 |
129 |
134 |
139 |
144 |
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/drawings/bandpass.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
22 |
24 |
32 |
37 |
38 |
46 |
51 |
52 |
53 |
73 |
78 |
83 |
88 |
93 |
98 |
103 |
108 |
113 |
114 |
116 |
117 |
119 | image/svg+xml
120 |
122 |
123 |
124 |
125 |
126 |
130 |
138 |
147 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/website/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | RDoc Documentation
8 |
9 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
37 |
38 |
39 |
53 |
54 |
55 |
56 |
126 |
127 |
128 |
129 |
130 |
131 | RubySynth¶ ↑
132 |
133 | _______ __ ___t____ __ __
134 | | _ .--.--| |--.--.--| _ .--.--.-----| |_| |--.
135 | |. l | | | _ | | | 1___| | | | _| |
136 | |. _ |_____|_____|___ |____ |___ |__|__|____|__|__|
137 | |: | | |_____|: 1 |_____|
138 | |::.|:. | |::.. . |
139 | `--- ---' `-------'
140 |
141 | Ruby Synth is a collection of primitives to make electronic music with pure ruby.
142 |
143 | Ruby Synth is the backing project for my EuRuKo 2019 talk “The musical Ruby”.
144 |
145 | Ruby Synth also contains a ton of additional writing to supplement the very dense 30 minute talk. You can read that additional material at ruby-synth.fun .
146 |
147 |
148 | Eventually I'll try to turn the primitives into a proper gem and better tests, but that will depend on your interest and if I can give this talk a couple of more times.
149 |
150 | Contributing or just playing around¶ ↑
151 |
152 | You'll need to install SoX
153 |
154 | You'll need Ruby 2.6.3 (it's an arbitrary choice and you could modify .ruby-version to make it run on older rubies, I don't use any 2.6 specific code)
155 |
156 | Most code is somewhat documented but I haven't yet built proper docs for it.
157 |
158 |
159 | Licenses¶ ↑
160 |
161 | All code here is licensed under the AGPL 3.0 license as documented at LICENSE unless stated otherwise.
162 |
163 | The entire contents of the “website” folder of the repo (and with that, this website you're just reading) is licensed under a Creative Commons Attribution-ShareAlike Unported license . The full license is at website/LICENSE
164 |
165 |
166 |
167 |
168 |
169 |
170 |
175 |
176 |
--------------------------------------------------------------------------------
/drawings/notch.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
22 |
24 |
32 |
37 |
38 |
46 |
51 |
52 |
53 |
73 |
78 |
83 |
88 |
93 |
98 |
103 |
108 |
113 |
114 |
116 |
117 |
119 | image/svg+xml
120 |
122 |
123 |
124 |
125 |
126 |
130 |
138 |
147 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/website/docs/OnePoleLP.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | class OnePoleLP - RDoc Documentation
8 |
9 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
54 |
55 |
56 |
57 |
83 |
84 |
85 |
86 |
87 | class OnePoleLP
88 |
89 |
90 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | Public Class Methods
108 |
109 |
110 |
111 |
112 |
113 |
114 | new ()
116 |
117 | click to toggle source
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | def initialize
132 | @outputs = 0.0
133 | end
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 | Public Instance Methods
149 |
150 |
151 |
152 |
153 |
154 |
155 | run (input, cutoff)
157 |
158 | click to toggle source
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 | def run (input , cutoff )
173 | p = (cutoff * 0.98 ) * (cutoff * 0.98 ) * (cutoff * 0.98 ) * (cutoff * 0.98 );
174 | @outputs = (1.0 - p ) * input + p * @outputs
175 | end
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
198 |
199 |
--------------------------------------------------------------------------------
/website/docs/TunedDrum.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | class TunedDrum - RDoc Documentation
8 |
9 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
54 |
55 |
56 |
57 |
81 |
82 |
83 |
84 |
85 | class TunedDrum
86 |
87 |
88 |
89 |
90 | Special case of the kick drum that allows to run it from a note pattern to create percussive sounds
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | Public Instance Methods
108 |
109 |
110 |
111 |
112 |
113 |
114 | run (offset)
116 |
117 | click to toggle source
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | def run (offset )
132 | t = time (offset )
133 | events = active_events (t )
134 | if events .empty?
135 | 0.0
136 | else
137 | event = events [events .keys .last ]
138 | note = events .keys .last
139 | base_freq = frequency (note )
140 | local_started = t - event [:started ]
141 | osc_out = @oscillator .run (base_freq + @pitch_env .run (local_started ) * @preset [:pitch_mod ].to_f , waveform: :sine )
142 | osc_out = osc_out * 1.0 * @amp_env .run (local_started )
143 | end
144 | end
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
167 |
168 |
--------------------------------------------------------------------------------
/website/docs/Utils.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | module Utils - RDoc Documentation
8 |
9 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
54 |
55 |
56 |
57 |
76 |
77 |
78 |
79 |
80 | module Utils
81 |
82 |
83 |
84 |
85 | Some simple utils
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | Public Instance Methods
103 |
104 |
105 |
106 |
107 |
108 |
109 | bitreduce (input, bits=8)
111 |
112 | click to toggle source
113 |
114 |
115 |
116 |
117 |
118 |
119 |
a simple bitreducer using rounding bits is the number of bits you want to reduce to
120 |
121 |
122 |
123 |
124 |
125 |
126 | def bitreduce (input , bits =8 )
127 | (input * bits .to_f ).round .to_f / bits .to_f
128 | end
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 | simple_waveshaper (input, a)
144 |
145 | click to toggle source
146 |
147 |
148 |
149 |
150 |
151 |
152 |
waveshaper, source www.musicdsp.org/en/latest/Effects/41-waveshaper.html a can go from 1 to … oo the higher a the stronger is the distortion
153 |
154 |
155 |
156 |
157 |
158 |
159 | def simple_waveshaper (input , a )
160 | input * (input .abs + a ) / (input ** 2 + (a - 1 ) * input .abs + 1 )
161 | end
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
184 |
185 |
--------------------------------------------------------------------------------