├── LICENSE ├── README.md ├── assets ├── audio │ └── BasketCaseGreendayriffDI.mp3 └── midi │ └── lame.mid ├── examples ├── dynamicHostExamples │ ├── chainFaustWAPsExample.html │ ├── chainJSWAPsExample.html │ ├── dynamicLoadingHost.html │ └── styles.css ├── examplePluginRepository │ └── repository.json ├── midi │ ├── JZZ │ │ ├── JZZ.gui.Player.js │ │ ├── JZZ.input.Kbd.js │ │ ├── JZZ.js │ │ ├── JZZ.midi.GM.js │ │ ├── JZZ.midi.SMF.js │ │ ├── JZZ.synth.OSC.js │ │ └── JZZ.synth.Tiny.js │ ├── MidiIn │ │ ├── main.html │ │ ├── main.js │ │ ├── main.json │ │ └── testMidiIn.html │ ├── MidiKeyboard │ │ ├── assets │ │ │ └── MidiKeyboard.png │ │ ├── main.html │ │ ├── main.js │ │ ├── main.json │ │ └── testMidiKeyboard.html │ ├── MidiMonitor │ │ ├── main.html │ │ ├── main.js │ │ ├── main.json │ │ └── testMidiMonitor.html │ ├── MidiOut │ │ ├── main.html │ │ ├── main.js │ │ ├── main.json │ │ └── testMidiOut.html │ ├── MidiPlayer │ │ ├── main.html │ │ ├── main.js │ │ ├── main.json │ │ └── testMidiPlayer.html │ ├── README.md │ ├── testMidi.html │ └── testMidi2.html └── plugins │ ├── Faust │ ├── DeadGate │ │ ├── Original Faust Code │ │ │ ├── Readme.txt │ │ │ └── kpp_deadgate.dsp │ │ ├── assets │ │ │ ├── Vintage_Knob.png │ │ │ └── deadgate.png │ │ ├── deadgate-processor.js │ │ ├── main.html │ │ ├── main.js │ │ ├── main.json │ │ └── testDeadgate.html │ ├── Oliver-Larkin │ │ ├── Blipper │ │ │ ├── Blipper-processor.js │ │ │ ├── FaustBlipper.png │ │ │ ├── Original Faust Code │ │ │ │ └── Blipper.dsp │ │ │ ├── main.html │ │ │ ├── main.js │ │ │ ├── main.json │ │ │ └── testBlipper.html │ │ ├── DualPitchShifter │ │ │ ├── DualPitchShifter-processor.js │ │ │ ├── FaustDualPitchShifter.png │ │ │ ├── Original Faust Code │ │ │ │ ├── DualPitchShifter.dsp │ │ │ │ ├── FrequencyShifter.lib │ │ │ │ └── IIRHilbert.lib │ │ │ ├── main.html │ │ │ ├── main.js │ │ │ ├── main.json │ │ │ └── testDualPitchShifter.html │ │ ├── StereoFrequencyShifter │ │ │ ├── FaustStereoFreqShifter.png │ │ │ ├── Original Faust Code │ │ │ │ ├── FrequencyShifter.lib │ │ │ │ ├── IIRHilbert.lib │ │ │ │ └── StereoFreqShifter.dsp │ │ │ ├── StereoFreqShifter-processor.js │ │ │ ├── main.html │ │ │ ├── main.js │ │ │ ├── main.json │ │ │ └── testStereoFrequencyShifter.html │ │ ├── ThruZeroFlanger │ │ │ ├── FaustThruZeroFlanger.png │ │ │ ├── Original Faust Code │ │ │ │ └── ThruZeroFlanger_withoutBypass.dsp │ │ │ ├── ThruZeroFlanger-processor.js │ │ │ ├── main.html │ │ │ ├── main.js │ │ │ ├── main.json │ │ │ └── testThruZeroFlanger.html │ │ └── WeirdPhaser │ │ │ ├── FaustWeirdPhaser.png │ │ │ ├── Original Faust Code │ │ │ └── WeirdPhaser.dsp │ │ │ ├── WeirdPhaser-processor.js │ │ │ ├── main.html │ │ │ ├── main.js │ │ │ ├── main.json │ │ │ └── testWeirdPhaser.html │ └── ZitaRevV3 │ │ ├── FaustZitaRev.png │ │ ├── Original Faust Code │ │ └── zitaRev.dsp │ │ ├── main.html │ │ ├── main.js │ │ ├── main.json │ │ ├── main2.html │ │ ├── testZitaRev.html │ │ └── zitaRev_bypass2-processor.js │ └── PureJS │ ├── GuitarTuner │ ├── WasabiTuner.png │ ├── assets │ │ └── clock.ttf │ ├── main.html │ ├── main.js │ ├── main.json │ ├── testTunerWithGuitar.html │ └── testTunerWithSample.html │ ├── Minilogue │ ├── Minilogue.png │ ├── assets │ │ ├── Res.png │ │ ├── grey.png │ │ └── modechooser.png │ ├── lib │ │ └── querty-hancock.js │ ├── main.html │ ├── main.js │ ├── main.json │ └── testMinilogue.html │ ├── PingPongDelay │ ├── WasabiPingPongDelay.png │ ├── main.html │ ├── main.js │ ├── main.json │ └── testPingPongDelay.html │ ├── QuadraFuzz │ ├── assets │ │ ├── MiniMoog_Main.png │ │ ├── WasabiQuadraFuzz.png │ │ ├── background.png │ │ └── switch_1.png │ ├── main.html │ ├── main.js │ ├── main.json │ └── testQuadrafuzz.html │ ├── StereoFlanger │ ├── WasabiStereoFlanger.png │ ├── main.html │ ├── main.js │ ├── main.json │ └── testStereoFlanger.html │ └── WahVox │ ├── WasabiWahVox.png │ ├── image │ ├── vsliderbody.png │ └── vsliderknob.png │ ├── main.html │ ├── main.js │ ├── main.json │ ├── testWahWithGuitarAsInput.html │ └── testWahWithSamples.html ├── imgs ├── PluginWithGUI.png ├── RepoTester2.png ├── pluginTester.png └── worldDominationPlan4.png ├── polyfills └── webcomponents-lite.js ├── sdk └── WebAudioSDK.js ├── testers ├── exploreRemoteRepoAndTest.html ├── styles.css ├── testPluginMetadata.html └── testPluginWithMocha.html └── tutorial ├── createyourwap.md └── lowfilter ├── assets └── myknob.png ├── main.html ├── main.js ├── main.json └── testLowfilter.html /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 micbuffa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /assets/audio/BasketCaseGreendayriffDI.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/assets/audio/BasketCaseGreendayriffDI.mp3 -------------------------------------------------------------------------------- /assets/midi/lame.mid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/assets/midi/lame.mid -------------------------------------------------------------------------------- /examples/dynamicHostExamples/chainFaustWAPsExample.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | Host that loads a plugin with its GUI 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |

CHAINED FAUST WAP

20 | 21 | 22 |
23 | 24 | 51 | 52 | -------------------------------------------------------------------------------- /examples/dynamicHostExamples/chainJSWAPsExample.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | Host that loads a plugin with its GUI 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |

CHAINED WAP

21 |
22 | 23 | 48 | 49 | -------------------------------------------------------------------------------- /examples/dynamicHostExamples/dynamicLoadingHost.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Plugin tester 10 | 11 | 12 | 13 |
14 |

Plugin Tester

15 |
16 |
17 |
18 | 19 |

Paste here the link to your webaudio plugin

20 |
21 | Plugin URL (repository where your main.json file is) 22 | 23 | GUI 24 | 25 |
26 |
27 | 28 |
29 |
30 |
31 | 32 | you can try : 33 |

34 | for 35 | wasabi delay

36 | for 37 | Faust ZitaRev

38 | for 39 | Oliver Larkin Blipper

40 | 41 | for Oliver Larkin Flanger

42 |
43 |
44 |
45 |
46 |
47 |
48 | 49 | 159 | -------------------------------------------------------------------------------- /examples/dynamicHostExamples/styles.css: -------------------------------------------------------------------------------- 1 | #WAP { 2 | float: left; 3 | width: 50%; 4 | padding-top: 5%; 5 | padding-left: 15%; 6 | } 7 | 8 | .urlRepo { 9 | color: blue; 10 | } 11 | 12 | #mocha { 13 | float: right; 14 | width: 50%; 15 | height: 400px; 16 | overflow: scroll; 17 | padding: 0%; 18 | } 19 | 20 | #onetest { 21 | display: flex; 22 | } 23 | 24 | #inputs { 25 | display: grid; 26 | } 27 | 28 | #urlPlugin { 29 | width: 300px; 30 | } 31 | 32 | #main { 33 | float: left; 34 | width: 50% 35 | } 36 | 37 | #layout { 38 | display: flex; 39 | } 40 | 41 | #helper { 42 | float: left; 43 | border: 3px; 44 | border-style: solid; 45 | padding: 10px; 46 | width: 50% 47 | } -------------------------------------------------------------------------------- /examples/examplePluginRepository/repository.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "WAP repo number 1", 3 | "root": "optional_abs_url", 4 | "plugs": { 5 | "zitaRev": "https://wasabi.i3s.unice.fr/WebAudioPluginBank/Faust/ZitaRevV3", 6 | "quadrafuzz":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/WASABI/QuadraFuzz3", 7 | "blipper":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/Oliver-Larkin2/Blipper", 8 | "dualpitchshifter":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/Oliver-Larkin2/DualPitchShifter", 9 | "stereofreqshifter":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/Oliver-Larkin2/StereoFrequencyShifter", 10 | "weirdphaser":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/Oliver-Larkin2/WeirdPhaser", 11 | "thruzeroflanger":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/Oliver-Larkin2/ThruZeroFlanger", 12 | "pingpongdelay":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/WASABI/PingPongDelay3", 13 | "stereoflanger":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/Mike-AUBENAS/StereoFlanger", 14 | "channelmixeur":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/Mike-AUBENAS/MixingConsole/ChannelMixer", 15 | "mixer":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/Mike-AUBENAS/MixingConsole/Mixer", 16 | "minilogue":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/Etev/Minilogue", 17 | "wah":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/jordan-SINTES/wah_effect/WahVox", 18 | "CleanMachine":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/Buffa/CleanMachine", 19 | "DrumMachine":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/jordan-SINTES/drum_machine/drumMachine", 20 | "DistoMachine": "https://wasabi.i3s.unice.fr/WebAudioPluginBank/jordan-SINTES/disto_machine/disto", 21 | "Metalachine": "https://wasabi.i3s.unice.fr/WebAudioPluginBank/Buffa/MetalMachine/metal", 22 | "TunerMachine": "https://wasabi.i3s.unice.fr/WebAudioPluginBank/jordan-SINTES/tuner_machine/tuner", 23 | "DeadGate":"https://wasabi.i3s.unice.fr/WebAudioPluginBank/Faust/DeadGate" 24 | } 25 | } -------------------------------------------------------------------------------- /examples/midi/JZZ/JZZ.midi.GM.js: -------------------------------------------------------------------------------- 1 | (function(global, factory) { 2 | if (typeof exports === 'object' && typeof module !== 'undefined') { 3 | module.exports = factory; 4 | } 5 | else if (typeof define === 'function' && define.amd) { 6 | define('JZZ.midi.GM', ['JZZ'], factory); 7 | } 8 | else { 9 | factory(JZZ); 10 | } 11 | })(this, function(JZZ) { 12 | 13 | var i; 14 | 15 | var _group = ['Piano', 'Chromatic Percussion', 'Organ', 'Guitar', 'Bass', 'Strings', 'Ensemble', 'Brass', 'Reed', 'Pipe', 'Synth Lead', 'Synth Pad', 'Synth Effects', 'Ethnic', 'Percussive', 'Sound Effects']; 16 | 17 | var _instr = [ 18 | 'Acoustic Grand Piano', 'Bright Acoustic Piano', 'Electric Grand Piano', 'Honky-tonk Piano', 'Electric Piano 1', 'Electric Piano 2', 'Harpsichord', 'Clavinet', 19 | 'Celesta', 'Glockenspiel', 'Music Box', 'Vibraphone', 'Marimba', 'Xylophone', 'Tubular Bells', 'Dulcimer', 20 | 'Drawbar Organ', 'Percussive Organ', 'Rock Organ', 'Church Organ', 'Reed Organ', 'Accordion', 'Harmonica', 'Tango Accordion', 21 | 'Acoustic Guitar (nylon)', 'Acoustic Guitar (steel)', 'Electric Guitar (jazz)', 'Electric Guitar (clean)', 'Electric Guitar (muted)', 'Overdriven Guitar', 'Distortion Guitar', 'Guitar Harmonics', 22 | 'Acoustic Bass', 'Electric Bass (finger)', 'Electric Bass (pick)', 'Fretless Bass', 'Slap Bass 1', 'Slap Bass 2', 'Synth Bass 1', 'Synth Bass 2', 23 | 'Violin', 'Viola', 'Cello', 'Contrabass', 'Tremolo Strings', 'Pizzicato Strings', 'Orchestral Harp', 'Timpani', 24 | 'String Ensemble 1', 'String Ensemble 2', 'Synth Strings 1', 'Synth Strings 2', 'Choir Aahs', 'Voice Oohs', 'Synth Choir', 'Orchestra Hit', 25 | 'Trumpet', 'Trombone', 'Tuba', 'Muted Trumpet', 'French Horn', 'Brass Section', 'Synth Brass 1', 'Synth Brass 2', 26 | 'Soprano Sax', 'Alto Sax', 'Tenor Sax', 'Baritone Sax', 'Oboe', 'English Horn', 'Bassoon', 'Clarinet', 27 | 'Piccolo', 'Flute', 'Recorder', 'Pan Flute', 'Blown Bottle', 'Shakuhachi', 'Whistle', 'Ocarina', 28 | 'Lead 1 (square)', 'Lead 2 (sawtooth)', 'Lead 3 (calliope)', 'Lead 4 (chiff)', 'Lead 5 (charang)', 'Lead 6 (voice)', 'Lead 7 (fifths)', 'Lead 8 (bass + lead)', 29 | 'Pad 1 (new age)', 'Pad 2 (warm)', 'Pad 3 (polysynth)', 'Pad 4 (choir)', 'Pad 5 (bowed)', 'Pad 6 (metallic)', 'Pad 7 (halo)', 'Pad 8 (sweep)', 30 | 'FX 1 (rain)', 'FX 2 (soundtrack)', 'FX 3 (crystal)', 'FX 4 (atmosphere)', 'FX 5 (brightness)', 'FX 6 (goblins)', 'FX 7 (echoes)', 'FX 8 (sci-fi)', 31 | 'Sitar', 'Banjo', 'Shamisen', 'Koto', 'Kalimba', 'Bagpipe', 'Fiddle', 'Shanai', 32 | 'Tinkle Bell', 'Agogo', 'Steel Drums', 'Woodblock', 'Taiko Drum', 'Melodic Tom', 'Synth Drum', 'Reverse Cymbal', 33 | 'Guitar Fret Noise', 'Breath Noise', 'Seashore', 'Bird Tweet', 'Telephone Ring', 'Helicopter', 'Applause', 'Gunshot' 34 | ]; 35 | 36 | var _perc = [ 37 | 'High-Q', 'Slap', 'Scratch Push', 'Scratch Pull', 'Sticks', 'Square Click', 'Metronome Click', 'Metronome Bell', 38 | 'Acoustic Bass Drum', 'Bass Drum 1', 'Side Stick', 'Acoustic Snare', 'Hand Clap', 'Electric Snare', 'Low Floor Tom', 'Closed Hi Hat', 39 | 'High Floor Tom', 'Pedal Hi-Hat', 'Low Tom', 'Open Hi-Hat', 'Low-Mid Tom', 'Hi-Mid Tom', 'Crash Cymbal 1', 'High Tom', 40 | 'Ride Cymbal 1', 'Chinese Cymbal', 'Ride Bell', 'Tambourine', 'Splash Cymbal', 'Cowbell', 'Crash Cymbal 2', 'Vibraslap', 41 | 'Ride Cymbal 2', 'Hi Bongo', 'Low Bongo', 'Mute Hi Conga', 'Open Hi Conga', 'Low Conga', 'High Timbale', 'Low Timbale', 42 | 'High Agogo', 'Low Agogo', 'Cabasa', 'Maracas', 'Short Whistle', 'Long Whistle', 'Short Guiro', 'Long Guiro', 43 | 'Claves', 'Hi Wood Block', 'Low Wood Block', 'Mute Cuica', 'Open Cuica', 'Mute Triangle', 'Open Triangle', 'Shaker', 44 | 'Jingle Bell', 'Bell Tree', 'Castanets', 'Mute Surdo', 'Open Surdo' 45 | ]; 46 | 47 | var _more = { 48 | 'Hammond': 17, 'Keyboard': 18, 'Uke': 24, 'Ukulele': 24, 'Fuzz': 30, 'Sax': 66, 'Saxophone': 66, 49 | 'Soprano Saxophone': 64, 'Alto Saxophone': 65, 'Tenor Saxophone': 66, 'Baritone Saxophone': 67 50 | }; 51 | 52 | function _strip(s) { 53 | if (typeof s == 'undefined') s = ''; 54 | return ' ' + s.toString().toLowerCase().replace(/\W+/g, ' ').trim() + ' '; 55 | } 56 | 57 | var _program = {}; 58 | for (i = 0; i < _instr.length; i++) _program[_strip(_instr[i])] = i; 59 | for (i = 0; i < _group.length; i++) _program[_strip(_group[i])] = i * 8; 60 | for (i in _more) if (_more.hasOwnProperty(i)) _program[_strip(i)] = _more[i]; 61 | 62 | var _percussion = {}; 63 | for (i = 0; i < _perc.length; i++) _percussion[_strip(_perc[i])] = i + 27; 64 | 65 | function _score(a, b) { 66 | var c, i, j, x, y, z; 67 | if (a.length > b.length) { c = a; a = b; b = c; } 68 | var m = []; 69 | for (i = 0; i < a.length; i++) { 70 | m[i] = []; 71 | if (!i) { 72 | for (j = 0; j < b.length; j++) { 73 | m[i][j] = a[i] == b[j] ? 2 : 0; 74 | } 75 | } 76 | else { 77 | m[i][0] = a[i] == b[0] ? 2 : 0; 78 | for (j = 1; j < b.length; j++) { 79 | x = m[i - 1][j] - (a[i] == ' ' ? 1 : 2); 80 | y = m[i][j - 1] - (b[j] == ' ' ? 1 : 2); 81 | z = m[i - 1][j - 1] + (a[i] == b[j] ? 2 : -2); 82 | if (x < 0) x = 0; 83 | if (x < y) x = y; 84 | if (x < z) x = z; 85 | m[i][j] = x; 86 | } 87 | } 88 | } 89 | for (i = 0; i < a.length; i++) for (j = 0; j < b.length; j++) m[i][j] = m[i][j] > 2 ? m[i][j] - 2 : 0; 90 | c = 0; 91 | while (m.length) { 92 | x = 0; y = 0; z = 0; 93 | for (i = 0; i < m.length; i++) for (j = 0; j < m[0].length; j++) { 94 | if (z < m[i][j]) { 95 | x = i; y = j; z = m[i][j]; 96 | } 97 | } 98 | if (!z) break; 99 | c += z; 100 | m.splice(x, 1); 101 | for (i = 0; i < m.length; i++) m[i].splice(y); 102 | } 103 | return c; 104 | } 105 | 106 | function _search(h, s) { 107 | var k, l, m, n, q; 108 | l = 0; m = 0; n = 0; 109 | for (k in h) if (h.hasOwnProperty(k)) { 110 | q = _score(s, k); 111 | if (q > n || q == n && k.length < l) { 112 | l = k.length; m = h[k]; n = q; 113 | } 114 | } 115 | return [n, m]; 116 | } 117 | 118 | var _noteValue = JZZ.MIDI.noteValue; 119 | 120 | JZZ.MIDI.programName = function(n) { if (n >= 0 && n <= 127) return _instr[n]; }; 121 | JZZ.MIDI.groupName = function(n) { if (n >= 0 && n <= 127) return _group[n >> 3]; }; 122 | JZZ.MIDI.percussionName = function(n) { if (n >= 27 && n <= 87) return _perc[n - 27]; }; 123 | 124 | JZZ.MIDI.programValue = function(x) { 125 | if (x == parseInt(x)) return x; 126 | var s = _strip(x); 127 | var n = _program[s]; 128 | if (typeof n != 'undefined') return n; 129 | var guess = _search(_program, s); 130 | return guess[1]; 131 | }; 132 | 133 | JZZ.MIDI.noteValue = function(x) { 134 | var n = _noteValue(x); 135 | if (typeof n != 'undefined') return n; 136 | var s = _strip(x); 137 | n = _percussion[s]; 138 | if (typeof n != 'undefined') return n; 139 | var guess = _search(_percussion, s); 140 | return guess[1]; 141 | }; 142 | 143 | JZZ.MIDI.guessValue = function(x) { 144 | if (x == parseInt(x) && x >= 0 && x <= 127) return x; 145 | var n = _noteValue(x); 146 | if (typeof n != 'undefined') return -n; 147 | var s = _strip(x); 148 | n = _program[s]; 149 | if (typeof n != 'undefined') return n; 150 | n = _percussion[s]; 151 | if (typeof n != 'undefined') return -n; 152 | var a = _search(_program, s); 153 | var b = _search(_percussion, s); 154 | return b[0] > a[0] ? -b[1] : a[1]; 155 | }; 156 | 157 | }); -------------------------------------------------------------------------------- /examples/midi/JZZ/JZZ.synth.OSC.js: -------------------------------------------------------------------------------- 1 | (function(global, factory) { 2 | if (typeof exports === 'object' && typeof module !== 'undefined') { 3 | module.exports = factory; 4 | } 5 | else if (typeof define === 'function' && define.amd) { 6 | define('JZZ.synth.OSC', ['JZZ'], factory); 7 | } 8 | else { 9 | factory(JZZ); 10 | } 11 | })(this, function(JZZ) { 12 | 13 | if (!JZZ) return; 14 | if (!JZZ.synth) JZZ.synth = {}; 15 | if (JZZ.synth.OSC) return; 16 | 17 | var _version = '1.1.1'; 18 | 19 | var _ac = JZZ.lib.getAudioContext(); 20 | 21 | function Synth() { 22 | this.ac = _ac; 23 | this.dest = this.ac.destination; 24 | this.channels = []; 25 | this.channel = function(c) { 26 | if (!this.channels[c]) { 27 | this.channels[c] = new Channel(this); 28 | if (c == 9) this.channels[c].note = function(n) { 29 | if (!this.notes[n]) this.notes[n] = new Perc(n, this); 30 | return this.notes[n]; 31 | }; 32 | } 33 | return this.channels[c]; 34 | }; 35 | this.play = function(arr) { 36 | var b = arr[0]; 37 | var n = arr[1]; 38 | var v = arr[2]; 39 | if (b < 0 || b > 255) return; 40 | var c = b & 15; 41 | var s = b >> 4; 42 | if (s == 9) this.channel(c).play(n, v); 43 | else if (s == 8) this.channel(c).play(n, 0); 44 | else if (s == 0xb) { 45 | if (n == 0x78 || n == 0x7b) this.channel(c).allSoundOff(); 46 | else if (n == 0x40) this.channel(c).damper(!!v); 47 | } 48 | }; 49 | this.plug = function(dest) { 50 | try { 51 | this.ac = undefined; 52 | if (dest.context instanceof AudioContext || dest.context instanceof webkitAudioContext) { 53 | this.ac = dest.context; 54 | this.dest = dest; 55 | } 56 | } 57 | catch (e) { 58 | this.ac = undefined; 59 | } 60 | if (!this.ac) { 61 | this.ac = _ac; 62 | this.dest = this.ac.destination; 63 | } 64 | }; 65 | } 66 | 67 | function Channel(synth) { 68 | this.synth = synth; 69 | this.notes = []; 70 | this.sustain = false; 71 | this.note = function(n) { 72 | if (!this.notes[n]) this.notes[n] = new Note(n, this); 73 | return this.notes[n]; 74 | }; 75 | this.play = function(n, v) { 76 | this.note(n).play(v); 77 | }; 78 | this.allSoundOff = function() { 79 | for (var n = 0; n < this.notes.length; n++) if (this.notes[n]) this.notes[n].stop(); 80 | }; 81 | this.damper = function(x) { 82 | if (!x && this.sustain != x) { 83 | for (var n = 0; n < this.notes.length; n++) if (this.notes[n] && this.notes[n].sustain) this.notes[n].stop(); 84 | } 85 | this.sustain = x; 86 | }; 87 | } 88 | 89 | function Note(n, c) { 90 | this.note = n; 91 | this.channel = c; 92 | this.freq = 440 * Math.pow(2,(n-69)/12); 93 | this.stop = function() { 94 | try { 95 | if (this.oscillator) this.oscillator.stop(0); 96 | this.oscillator = undefined; 97 | this.sustain = false; 98 | } 99 | catch (e) {} 100 | }; 101 | this.play = function(v) { 102 | if (v || !this.channel.sustain) this.stop(); 103 | if (!v) { 104 | this.sustain = this.channel.sustain; 105 | return; 106 | } 107 | var ampl = v/127; 108 | this.oscillator = this.channel.synth.ac.createOscillator(); 109 | this.oscillator.type = 'sawtooth'; 110 | this.oscillator.frequency.setTargetAtTime(this.freq, this.channel.synth.ac.currentTime, 0.005); 111 | if (!this.oscillator.start) this.oscillator.start = this.oscillator.noteOn; 112 | if (!this.oscillator.stop) this.oscillator.stop = this.oscillator.noteOff; 113 | 114 | this.gain = this.channel.synth.ac.createGain(); 115 | var releaseTime = 2; 116 | var now = this.channel.synth.ac.currentTime; 117 | this.gain.gain.setValueAtTime(ampl, now); 118 | this.gain.gain.exponentialRampToValueAtTime(0.01*ampl, now + releaseTime); 119 | 120 | this.oscillator.connect(this.gain); 121 | this.gain.connect(this.channel.synth.dest); 122 | 123 | this.oscillator.start(0); 124 | }; 125 | } 126 | 127 | function Perc(n, c) { 128 | this.note = n; 129 | this.channel = c; 130 | this.freq = 200; 131 | this.stop = function() {}; 132 | this.play = function(v) { 133 | if (!v) return; 134 | 135 | var ampl = v/127; 136 | this.oscillator = this.channel.synth.ac.createOscillator(); 137 | this.oscillator.type = 'sine'; 138 | this.oscillator.frequency.setTargetAtTime(this.freq, this.channel.synth.ac.currentTime, 0.005); 139 | if (!this.oscillator.start) this.oscillator.start = this.oscillator.noteOn; 140 | if (!this.oscillator.stop) this.oscillator.stop = this.oscillator.noteOff; 141 | 142 | this.gain = this.channel.synth.ac.createGain(); 143 | var releaseTime = 2; 144 | var now = this.channel.synth.ac.currentTime; 145 | this.gain.gain.setValueAtTime(ampl, now); 146 | 147 | this.oscillator.connect(this.gain); 148 | this.gain.connect(this.channel.synth.dest); 149 | 150 | this.oscillator.start(0); 151 | this.oscillator.stop(this.channel.synth.ac.currentTime + 0.04); 152 | }; 153 | } 154 | 155 | var _synth = {}; 156 | var _noname = []; 157 | var _engine = {}; 158 | 159 | _engine._info = function(name) { 160 | if (!name) name = 'JZZ.synth.OSC'; 161 | return { 162 | type: 'Web Audo', 163 | name: name, 164 | manufacturer: 'virtual', 165 | version: _version 166 | }; 167 | }; 168 | 169 | _engine._openOut = function(port, name) { 170 | if (!_ac) { port._crash('AudioContext not supported'); return; } 171 | var synth; 172 | if (typeof name !== 'undefined') { 173 | name = '' + name; 174 | if (!_synth[name]) _synth[name] = new Synth(); 175 | synth = _synth[name]; 176 | } 177 | else { 178 | synth = new Synth(); 179 | _noname.push(synth); 180 | } 181 | port.plug = function(dest) { synth.plug(dest); }; 182 | port._info = _engine._info(name); 183 | port._receive = function(msg) { synth.play(msg); }; 184 | port._resume(); 185 | }; 186 | 187 | JZZ.synth.OSC = function(name) { 188 | return JZZ.lib.openMidiOut(name, _engine); 189 | }; 190 | 191 | JZZ.synth.OSC.register = function(name) { 192 | return _ac ? JZZ.lib.registerMidiOut(name, _engine) : false; 193 | }; 194 | 195 | JZZ.synth.OSC.version = function() { return _version; }; 196 | 197 | }); -------------------------------------------------------------------------------- /examples/midi/MidiIn/main.html: -------------------------------------------------------------------------------- 1 | 22 | 23 | 61 | -------------------------------------------------------------------------------- /examples/midi/MidiIn/main.js: -------------------------------------------------------------------------------- 1 | window.MidiIn = class MidiIn extends WebAudioPluginCompositeNode { 2 | 3 | constructor(ctx, URL, options) { 4 | super(ctx, URL, options) 5 | super.setup(); 6 | } 7 | 8 | createNodes() { 9 | var self = this; 10 | this.ports = []; 11 | this.current = ''; 12 | this.currentPort = undefined; 13 | this.outputsMidi[0] = JZZ.Widget(); 14 | this.inputsMidi[0] = this.outputsMidi[0]; 15 | var update = function() { 16 | const info = self.engine.info(); 17 | self.ports = []; 18 | for (var i = 0; i < info.inputs.length; i++) self.ports.push(info.inputs[i].name); 19 | self.updateGui(); 20 | } 21 | this.updateGui = function() {}; 22 | this.open = function(arg) { 23 | if (arg == '') { // disconnect 24 | if (self.currentPort) { 25 | self.currentPort.disconnect(self.outputsMidi[0]); 26 | self.currentPort.close(); 27 | self.currentPort = undefined; 28 | self.current = ''; 29 | } 30 | self.updateGui(); 31 | return; 32 | } 33 | this.engine.openMidiIn(arg).or(function() { self.updateGui(); }).and(function() { 34 | if (self.currentPort) { 35 | self.currentPort.disconnect(self.outputsMidi[0]); 36 | self.currentPort.close(); 37 | } 38 | self.currentPort = this; 39 | self.currentPort.connect(self.outputsMidi[0]); 40 | self.current = this.info().name; 41 | self.updateGui(); 42 | }); 43 | } 44 | this.engine = JZZ(); // if required SysEx, call JZZ({ sysex: true, degrade: true }); 45 | this.engine.and(update); 46 | this.open(); 47 | }; 48 | 49 | connectNodes() { 50 | }; 51 | 52 | setParam(key, value) { 53 | try { 54 | this[key] = value; 55 | } catch (error) { 56 | console.warn("this plugin does not implement this param") 57 | } 58 | } 59 | } 60 | 61 | window.JazzSoftMidiIn = class JazzSoftMidiIn extends WebAudioPluginFactory { 62 | constructor(context, baseUrl) { 63 | super(context, baseUrl); 64 | } 65 | } -------------------------------------------------------------------------------- /examples/midi/MidiIn/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "", 3 | "name": "MidiIn", 4 | "thumbnail": "", 5 | "vendor": "JazzSoft", 6 | "category":"MIDI", 7 | "version": "1.0" 8 | } -------------------------------------------------------------------------------- /examples/midi/MidiIn/testMidiIn.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MIDI In test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |

MIDI input goes to the console.log ...

15 | 16 | 17 | 25 | 26 | -------------------------------------------------------------------------------- /examples/midi/MidiKeyboard/assets/MidiKeyboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/midi/MidiKeyboard/assets/MidiKeyboard.png -------------------------------------------------------------------------------- /examples/midi/MidiKeyboard/main.html: -------------------------------------------------------------------------------- 1 | 38 | 39 | 124 | -------------------------------------------------------------------------------- /examples/midi/MidiKeyboard/main.js: -------------------------------------------------------------------------------- 1 | window.MidiKeyboard = class MidiKeyboard extends WebAudioPluginCompositeNode { 2 | constructor(ctx, URL, options) { 3 | super(ctx, URL, options) 4 | super.setup(); 5 | } 6 | 7 | createNodes() { 8 | this.synth = JZZ.synth.Tiny(); 9 | this.inputsMidi[0] = JZZ.Widget(); 10 | this.outputsMidi[0] = JZZ.Widget(); 11 | this.inputsMidi[0].connect(this.outputsMidi[0]); 12 | this.outputsMidi[0].connect(this.synth); 13 | }; 14 | connectNodes() { 15 | this.synth.plug(this._output); 16 | }; 17 | 18 | setParam(key, value) { 19 | try { 20 | this[key] = value; 21 | } catch (error) { 22 | console.warn("this plugin does not implement this param") 23 | } 24 | } 25 | } 26 | 27 | window.JazzSoftMidiKeyboard = class JazzSoftMidiKeyboard extends WebAudioPluginFactory { 28 | constructor(context, baseUrl) { 29 | super(context, baseUrl); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/midi/MidiKeyboard/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "...", 3 | "name": "MidiKeyboard", 4 | "thumbnail": "assets/MidiKeyboard.png", 5 | "vendor": "JazzSoft", 6 | "category":"Test", 7 | "version": "1.0" 8 | } -------------------------------------------------------------------------------- /examples/midi/MidiKeyboard/testMidiKeyboard.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MIDI Keyboard test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 37 | 38 | -------------------------------------------------------------------------------- /examples/midi/MidiMonitor/main.html: -------------------------------------------------------------------------------- 1 | 20 | 21 | 59 | -------------------------------------------------------------------------------- /examples/midi/MidiMonitor/main.js: -------------------------------------------------------------------------------- 1 | window.MidiMonitor = class MidiMonitor extends WebAudioPluginCompositeNode { 2 | 3 | constructor(ctx, URL, options) { 4 | super(ctx, URL, options) 5 | super.setup(); 6 | } 7 | 8 | createNodes() { 9 | var self = this; 10 | var widget = JZZ.Widget(); 11 | this.inputsMidi[0] = widget; 12 | this.outputsMidi[0] = widget; 13 | widget._receive = function(msg) { 14 | console.log(msg.toString()); 15 | this._emit(msg); 16 | self.log(msg); 17 | }; 18 | this.log = function(msg) {}; 19 | }; 20 | connectNodes() { 21 | }; 22 | 23 | setParam(key, value) { 24 | try { 25 | this[key] = value; 26 | } catch (error) { 27 | console.warn("this plugin does not implement this param") 28 | } 29 | } 30 | } 31 | 32 | window.JazzSoftMidiMonitor = class JazzSoftMidiMonitor extends WebAudioPluginFactory { 33 | constructor(context, baseUrl) { 34 | super(context, baseUrl); 35 | } 36 | } -------------------------------------------------------------------------------- /examples/midi/MidiMonitor/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "", 3 | "name": "MidiMonitor", 4 | "thumbnail": "", 5 | "vendor": "JazzSoft", 6 | "category":"MIDI", 7 | "version": "1.0" 8 | } -------------------------------------------------------------------------------- /examples/midi/MidiMonitor/testMidiMonitor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MIDI Monitor test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 30 | 31 | -------------------------------------------------------------------------------- /examples/midi/MidiOut/main.html: -------------------------------------------------------------------------------- 1 | 22 | 23 | 61 | -------------------------------------------------------------------------------- /examples/midi/MidiOut/main.js: -------------------------------------------------------------------------------- 1 | window.MidiOut = class MidiOut extends WebAudioPluginCompositeNode { 2 | 3 | constructor(ctx, URL, options) { 4 | super(ctx, URL, options) 5 | super.setup(); 6 | } 7 | 8 | createNodes() { 9 | var self = this; 10 | this.ports = []; 11 | this.current = ''; 12 | this.currentPort = undefined; 13 | this.inputsMidi[0] = JZZ.Widget(); 14 | this.outputsMidi[0] = this.inputsMidi[0]; 15 | var update = function() { 16 | const info = self.engine.info(); 17 | self.ports = []; 18 | for (var i = 0; i < info.outputs.length; i++) self.ports.push(info.outputs[i].name); 19 | self.updateGui(); 20 | } 21 | this.updateGui = function() {}; 22 | this.open = function(arg) { 23 | if (arg == '') { // disconnect 24 | if (self.currentPort) { 25 | self.inputsMidi[0].disconnect(self.currentPort); 26 | self.currentPort.close(); 27 | self.currentPort = undefined; 28 | self.current = ''; 29 | } 30 | self.updateGui(); 31 | return; 32 | } 33 | this.engine.openMidiOut(arg).or(function() { self.updateGui(); }).and(function() { 34 | if (self.currentPort) { 35 | self.inputsMidi[0].disconnect(self.currentPort); 36 | self.currentPort.close(); 37 | } 38 | self.currentPort = this; 39 | self.inputsMidi[0].connect(self.currentPort); 40 | self.current = this.info().name; 41 | self.updateGui(); 42 | }); 43 | } 44 | this.engine = JZZ(); // if required SysEx, call JZZ({ sysex: true, degrade: true }); 45 | this.engine.and(update); 46 | this.open(); 47 | }; 48 | 49 | connectNodes() { 50 | }; 51 | 52 | setParam(key, value) { 53 | try { 54 | this[key] = value; 55 | } catch (error) { 56 | console.warn("this plugin does not implement this param") 57 | } 58 | } 59 | } 60 | 61 | window.JazzSoftMidiOut = class JazzSoftMidiOut extends WebAudioPluginFactory { 62 | constructor(context, baseUrl) { 63 | super(context, baseUrl); 64 | } 65 | } -------------------------------------------------------------------------------- /examples/midi/MidiOut/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "", 3 | "name": "MidiOut", 4 | "thumbnail": "", 5 | "vendor": "JazzSoft", 6 | "category":"MIDI", 7 | "version": "1.0" 8 | } -------------------------------------------------------------------------------- /examples/midi/MidiOut/testMidiOut.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MIDI Out test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 29 | 30 | -------------------------------------------------------------------------------- /examples/midi/MidiPlayer/main.html: -------------------------------------------------------------------------------- 1 | 12 | 13 | 49 | -------------------------------------------------------------------------------- /examples/midi/MidiPlayer/main.js: -------------------------------------------------------------------------------- 1 | window.MidiPlayer = class MidiPlayer extends WebAudioPluginCompositeNode { 2 | 3 | constructor(ctx, URL, options) { 4 | super(ctx, URL, options) 5 | super.setup(); 6 | } 7 | 8 | createNodes() { 9 | var self = this; 10 | var player; 11 | this.inputsMidi[0] = JZZ.Widget(); 12 | this.outputsMidi[0] = this.inputsMidi[0]; 13 | this.load = function(data) { 14 | if (player) { 15 | player.stop(); 16 | player.disconnect(this.outputsMidi[0]); 17 | } 18 | var smf = new JZZ.MIDI.SMF(data); 19 | player = smf.player(); 20 | player.connect(this.outputsMidi[0]); 21 | }; 22 | this.loop = function(x) { if (player) player.loop(x); } 23 | this.play = function() { if (player) player.play(); } 24 | this.pause = function() { if (player) player.pause(); } 25 | this.resume = function() { if (player) player.resume(); } 26 | this.stop = function() { if (player) player.stop(); } 27 | }; 28 | 29 | connectNodes() { 30 | }; 31 | 32 | setParam(key, value) { 33 | try { 34 | this[key] = value; 35 | } catch (error) { 36 | console.warn("this plugin does not implement this param") 37 | } 38 | } 39 | } 40 | 41 | window.JazzSoftMidiPlayer = class JazzSoftMidiPlayer extends WebAudioPluginFactory { 42 | constructor(context, baseUrl) { 43 | super(context, baseUrl); 44 | } 45 | } -------------------------------------------------------------------------------- /examples/midi/MidiPlayer/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "", 3 | "name": "MidiPlayer", 4 | "thumbnail": "", 5 | "vendor": "JazzSoft", 6 | "category":"MIDI", 7 | "version": "1.0" 8 | } -------------------------------------------------------------------------------- /examples/midi/MidiPlayer/testMidiPlayer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MIDI Player test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |

MIDI output goes to the console.log ...

17 | 18 | 19 | 32 | 33 | -------------------------------------------------------------------------------- /examples/midi/README.md: -------------------------------------------------------------------------------- 1 | # WebAudioPlugins MIDI 2 | 3 | experimenting with MIDI... 4 | -------------------------------------------------------------------------------- /examples/midi/testMidi.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MIDI test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 33 | 34 | 35 | 36 |
37 |
38 |
39 |
40 | 41 | 42 | 96 | 97 | -------------------------------------------------------------------------------- /examples/midi/testMidi2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MIDI test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 40 | 41 | 42 | 43 |
44 |
45 |
46 |
47 | 48 | 49 | 119 | 120 | -------------------------------------------------------------------------------- /examples/plugins/Faust/DeadGate/Original Faust Code/Readme.txt: -------------------------------------------------------------------------------- 1 | Original code by Oleg Kapitonov. See https://github.com/olegkapitonov/Kapitonov-Plugins-Pack -------------------------------------------------------------------------------- /examples/plugins/Faust/DeadGate/Original Faust Code/kpp_deadgate.dsp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Oleg Kapitonov 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | * -------------------------------------------------------------------------- 18 | */ 19 | /* 20 | * This pugin is effective noise gate. 21 | * 22 | * Process chain: 23 | * 24 | * input->deadzone->multigate->output 25 | * 26 | * deadzone - INSTANTLY eliminates the signal below the threshold level. 27 | * This kills noise in pauses but distorts the signal around zero level. 28 | * 29 | * multigate - 7-band noise gate. The input signal is divided into 7 frequency bands. 30 | * In each band, the signal is eliminated when falling below the 31 | * threshold level with attack time 10 ms, hold time 100 ms, release 32 | * time 20 ms. 33 | * 34 | */ 35 | 36 | declare name "kpp_deadgate"; 37 | declare author "Oleg Kapitonov"; 38 | declare license "GPLv3"; 39 | declare version "0.1b"; 40 | 41 | import("stdfaust.lib"); 42 | 43 | process = output with { 44 | 45 | deadzone_knob = ba.db2linear(vslider("Dead Zone", -120, -120, 0, 0.001)); 46 | noizegate_knob = vslider("Noise Gate", -120, -120, 0, 0.001); 47 | 48 | deadzone = _ <: (max(deadzone_knob) : -(deadzone_knob)), 49 | (min(-deadzone_knob) : +(deadzone_knob)) : + ; 50 | 51 | multigate = _ : fi.filterbank(3, (65, 150, 300, 600, 1200, 2400)) : 52 | ef.gate_mono(noizegate_knob, 0.01, 0.1, 0.02), 53 | ef.gate_mono(noizegate_knob, 0.01, 0.1, 0.02), 54 | ef.gate_mono(noizegate_knob, 0.01, 0.1, 0.02), 55 | ef.gate_mono(noizegate_knob, 0.01, 0.1, 0.02), 56 | ef.gate_mono(noizegate_knob, 0.01, 0.1, 0.02), 57 | ef.gate_mono(noizegate_knob, 0.01, 0.1, 0.02), 58 | ef.gate_mono(noizegate_knob, 0.01, 0.1, 0.02) :> _; 59 | 60 | output = _,_ :> fi.highpass(1,10) : deadzone : multigate <: _,_ ; 61 | }; 62 | 63 | 64 | -------------------------------------------------------------------------------- /examples/plugins/Faust/DeadGate/assets/Vintage_Knob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/Faust/DeadGate/assets/Vintage_Knob.png -------------------------------------------------------------------------------- /examples/plugins/Faust/DeadGate/assets/deadgate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/Faust/DeadGate/assets/deadgate.png -------------------------------------------------------------------------------- /examples/plugins/Faust/DeadGate/main.html: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 160 | -------------------------------------------------------------------------------- /examples/plugins/Faust/DeadGate/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DeadGate", 3 | "vendor": "Faust", 4 | "version": "1.0", 5 | "homepage": "https://faust.grame.fr", 6 | "thumbnail": "./assets/deadgate.png", 7 | "category":"Gate" 8 | } 9 | 10 | -------------------------------------------------------------------------------- /examples/plugins/Faust/DeadGate/testDeadgate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Host that loads a plugin with its GUI 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 53 | 54 | -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/Blipper/FaustBlipper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/Faust/Oliver-Larkin/Blipper/FaustBlipper.png -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/Blipper/Original Faust Code/Blipper.dsp: -------------------------------------------------------------------------------- 1 | declare name "Blipper"; 2 | declare description "Envelope Follower controlling pitch of a triangle oscillator, good with percussive input"; 3 | declare author "Oli Larkin (contact@olilarkin.co.uk)"; 4 | declare copyright "Oliver Larkin"; 5 | declare version "0.2"; 6 | declare licence "GPL"; 7 | 8 | import("stdfaust.lib"); 9 | 10 | // Generic bypass mecanism 11 | bypass = checkbox("bypass"); 12 | 13 | block_on(fx) = par(i, inputs(fx), _*(1-bypass)); 14 | block_off(fx) = par(i, inputs(fx), _*bypass); 15 | 16 | bypass_fx(fx) = par(i, inputs(fx), _) <: ((block_on(fx):fx), block_off(fx)):> par(i, outputs(fx), _); 17 | 18 | basepitch = hslider("BasePitch [unit:semitones] [OWL:PARAMETER_A]", 60, 24, 96, 0.1) : si.smooth(ba.tau2pole(0.01)); 19 | pitchmod = hslider("PitchMod [unit:semitones] [OWL:PARAMETER_B]", 24, -64, 64, 1) : si.smooth(ba.tau2pole(0.005)); 20 | //attack = hslider("Attack [unit:ms] [OWL:PARAMETER_C]", 2, 2, 1000, 1) : *(0.001) : max(1.0/float(ma.SR)); 21 | release = hslider("Release [unit:ms] [OWL:PARAMETER_C]", 20, 2, 100, 1) : *(0.001) : max(1.0/float(ma.SR)); 22 | attack = 0.005; 23 | mix = hslider("Mix[OWL:PARAMETER_D]", 0.5, 0, 1, 0.01) : si.smooth(ba.tau2pole(0.005)); 24 | 25 | blipper(l, r) = l, r <: *(1-mix), *(1-mix), mono2stereo :> _,_ 26 | 27 | with { 28 | mono2stereo = + : pc2 * mix <: _,_; 29 | pc2 = an.amp_follower_ud(attack, release) <: (ba.midikey2hz(basepitch + (pitchmod * _)): os.triangle), _ : *; 30 | }; 31 | process = bypass_fx(blipper); 32 | -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/Blipper/main.html: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 143 | -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/Blipper/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "...", 3 | "name": "Blipper", 4 | "thumbnail": "FaustBlipper.png", 5 | "vendor": "Larkin", 6 | "category":"Modulation", 7 | "version": "1.0" 8 | } 9 | -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/Blipper/testBlipper.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Host that loads a plugin with its GUI 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 54 | 55 | -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/DualPitchShifter/FaustDualPitchShifter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/Faust/Oliver-Larkin/DualPitchShifter/FaustDualPitchShifter.png -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/DualPitchShifter/Original Faust Code/DualPitchShifter.dsp: -------------------------------------------------------------------------------- 1 | declare name "Dual Pitch Shifter"; 2 | declare description "Dual Channel pitch shifter, based on Faust pitch_shifter.dsp by Grame"; 3 | declare author "Oli Larkin (contact@olilarkin.co.uk)"; 4 | declare copyright "Oliver Larkin"; 5 | declare version "0.1"; 6 | declare licence "GPL"; 7 | 8 | import("stdfaust.lib"); 9 | 10 | bypass = checkbox("bypass"); 11 | 12 | block_on(fx) = par(i, inputs(fx), _*(1-bypass)); 13 | block_off(fx) = par(i, inputs(fx), _*bypass); 14 | 15 | bypass_fx(fx) = par(i, inputs(fx), _) <: ((block_on(fx):fx), block_off(fx)):> par(i, outputs(fx), _); 16 | 17 | msec = ma.SR/1000.0; 18 | shiftl = hslider("Shift L [unit:semitones] [OWL:PARAMETER_A]", 0, -12, +12, 0.1); 19 | shiftr = hslider("Shift R [unit:semitones] [OWL:PARAMETER_B]", 0, -12, +12, 0.1); 20 | ws = hslider("Window Size [unit:ms] [OWL:PARAMETER_C]", 50, 20, 1000, 1) * msec : si.smooth(ba.tau2pole(0.005)); 21 | mix = hslider("Mix[OWL:PARAMETER_D]", 0.5, 0, 1, 0.01) : si.smooth(ba.tau2pole(0.005)); 22 | 23 | xf = 20 * msec; 24 | 25 | transpose (w, x, s, sig) = de.fdelay(65536, d,sig)*ma.fmin(d/x,1) + de.fdelay(65536,d+w,sig)*(1-ma.fmin(d/x,1)) 26 | with { 27 | i = 1 - pow(2, s/12); 28 | d = i : (+ : +(w) : fmod(_,w)) ~ _; 29 | }; 30 | 31 | pitchshifter(l,r) = l,r <: *(1-mix), *(1-mix), transpose(ws, xf, shiftl, l)*mix, transpose(ws, xf, shiftr, r)*mix :> _,_; 32 | 33 | 34 | process = bypass_fx(pitchshifter); 35 | -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/DualPitchShifter/Original Faust Code/FrequencyShifter.lib: -------------------------------------------------------------------------------- 1 | import("IIRHilbert.lib"); 2 | 3 | freqshift(x, shift) = negative(x), positive(x) 4 | with { 5 | negative(x) = real(x)*cosv - imag(x)*sinv; 6 | positive(x) = real(x)*cosv + imag(x)*sinv; 7 | real(x) = hilbert(x) : _ , !; 8 | imag(x) = hilbert(x) : ! , _; 9 | 10 | phasor(x) = fmod((x/float(ma.SR) : (+ : ma.decimal) ~ _), 1.) * (ma.PI * 2); 11 | 12 | sinv = sin(phasor(shift)); 13 | cosv = cos(phasor(shift)); 14 | 15 | hilbert = hilbertef; 16 | }; 17 | 18 | ssb(shift, x) = freqshift(x, shift) : _ , !; // only take one sideband -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/DualPitchShifter/Original Faust Code/IIRHilbert.lib: -------------------------------------------------------------------------------- 1 | import("stdfaust.lib"); 2 | 3 | // IIR hilbert transform Emmanuel Favreau (via Miller Puckette) 4 | // fastest 5 | hilbertef(x) = real(x), imag(x) 6 | with { 7 | biquad(a1,a2,b0,b1,b2) = + ~ conv2(a1,a2) : conv3(b0,b1,b2) 8 | with { 9 | conv3(k0,k1,k2,x) = k0*x + k1*x' + k2*x''; 10 | conv2(k0,k1,x) = k0*x + k1*x'; 11 | }; 12 | real = biquad(-0.02569, 0.260502, -0.260502, 0.02569, 1) 13 | : biquad(1.8685, -0.870686, 0.870686, -1.8685, 1) ; 14 | imag = biquad(1.94632, -0.94657, 0.94657, -1.94632, 1) 15 | : biquad(0.83774, -0.06338, 0.06338, -0.83774, 1) ; 16 | }; -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/DualPitchShifter/main.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "documentation": "...", 4 | "name": "DualPitchShifter", 5 | "thumbnail": "FaustDualPitchShifter.png", 6 | "vendor": "Larkin", 7 | "category":"Modulation", 8 | "version": "1.0" 9 | } 10 | -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/DualPitchShifter/testDualPitchShifter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Host that loads a plugin with its GUI 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 53 | 54 | -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/StereoFrequencyShifter/FaustStereoFreqShifter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/Faust/Oliver-Larkin/StereoFrequencyShifter/FaustStereoFreqShifter.png -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/StereoFrequencyShifter/Original Faust Code/FrequencyShifter.lib: -------------------------------------------------------------------------------- 1 | import("IIRHilbert.lib"); 2 | 3 | freqshift(x, shift) = negative(x), positive(x) 4 | with { 5 | negative(x) = real(x)*cosv - imag(x)*sinv; 6 | positive(x) = real(x)*cosv + imag(x)*sinv; 7 | real(x) = hilbert(x) : _ , !; 8 | imag(x) = hilbert(x) : ! , _; 9 | 10 | phasor(x) = fmod((x/float(ma.SR) : (+ : ma.decimal) ~ _), 1.) * (ma.PI * 2); 11 | 12 | sinv = sin(phasor(shift)); 13 | cosv = cos(phasor(shift)); 14 | 15 | hilbert = hilbertef; 16 | }; 17 | 18 | ssb(shift, x) = freqshift(x, shift) : _ , !; // only take one sideband -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/StereoFrequencyShifter/Original Faust Code/IIRHilbert.lib: -------------------------------------------------------------------------------- 1 | import("stdfaust.lib"); 2 | 3 | // IIR hilbert transform Emmanuel Favreau (via Miller Puckette) 4 | // fastest 5 | hilbertef(x) = real(x), imag(x) 6 | with { 7 | biquad(a1,a2,b0,b1,b2) = + ~ conv2(a1,a2) : conv3(b0,b1,b2) 8 | with { 9 | conv3(k0,k1,k2,x) = k0*x + k1*x' + k2*x''; 10 | conv2(k0,k1,x) = k0*x + k1*x'; 11 | }; 12 | real = biquad(-0.02569, 0.260502, -0.260502, 0.02569, 1) 13 | : biquad(1.8685, -0.870686, 0.870686, -1.8685, 1) ; 14 | imag = biquad(1.94632, -0.94657, 0.94657, -1.94632, 1) 15 | : biquad(0.83774, -0.06338, 0.06338, -0.83774, 1) ; 16 | }; -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/StereoFrequencyShifter/Original Faust Code/StereoFreqShifter.dsp: -------------------------------------------------------------------------------- 1 | declare name "Stereo Frequency Shifter"; 2 | declare description "Stereo Frequency Shifting"; 3 | declare author "Oli Larkin (contact@olilarkin.co.uk)"; 4 | declare copyright "Oliver Larkin"; 5 | declare version "0.1"; 6 | declare licence "GPL"; 7 | 8 | import("stdfaust.lib"); 9 | import("FrequencyShifter.lib"); 10 | 11 | // Generic bypass mecanism 12 | bypass = checkbox("bypass"); 13 | 14 | block_on(fx) = par(i, inputs(fx), _*(1-bypass)); 15 | block_off(fx) = par(i, inputs(fx), _*bypass); 16 | 17 | bypass_fx(fx) = par(i, inputs(fx), _) <: ((block_on(fx):fx), block_off(fx)):> par(i, outputs(fx), _); 18 | 19 | shift = hslider("Shift [unit:hz] [OWL:PARAMETER_A]", 0.0, -1., 1, 0.001); 20 | shift_scalar = hslider("Shift Scalar [OWL:PARAMETER_B]", 1., 1., 100, 0.1); 21 | lr_offset = hslider("L-R Offset [OWL:PARAMETER_C]", 0., 0., 1., 0.00001); 22 | mix = hslider("Mix [OWL:PARAMETER_D]",0.5,0,1,0.01) : si.smooth(ba.tau2pole(0.005)); 23 | 24 | shift_amount = shift*shift_scalar; 25 | stereofreqshifter(l, r) = l, r <: *(1-mix), *(1-mix), ssb(shift_amount,l)*mix, ssb(shift_amount+lr_offset,r)*mix :> _,_; 26 | process = bypass_fx(stereofreqshifter); -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/StereoFrequencyShifter/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "...", 3 | "name": "StereoFreqShifter", 4 | "thumbnail": "FaustStereoFreqShifter.png", 5 | "vendor": "Larkin", 6 | "category":"Modulation", 7 | "version": "1.0" 8 | } 9 | -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/StereoFrequencyShifter/testStereoFrequencyShifter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Host that loads a plugin with its GUI 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 68 | 69 | -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/ThruZeroFlanger/FaustThruZeroFlanger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/Faust/Oliver-Larkin/ThruZeroFlanger/FaustThruZeroFlanger.png -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/ThruZeroFlanger/Original Faust Code/ThruZeroFlanger_withoutBypass.dsp: -------------------------------------------------------------------------------- 1 | declare name "Thru Zero Flanger"; 2 | declare description "Stereo Thru Zero Flanger - warning can ZERO the sound!"; 3 | declare author "Oli Larkin (contact@olilarkin.co.uk)"; 4 | declare copyright "Oliver Larkin"; 5 | declare version "0.1"; 6 | declare licence "GPL"; 7 | 8 | import("stdfaust.lib"); 9 | 10 | lutsize = 1 << 9; 11 | maxdtms = 20; 12 | smooth_time = 0.005; 13 | 14 | rate = hslider("Rate [unit:hz] [OWL:PARAMETER_A]", 0.1, 0., 1, 0.001); 15 | dt = hslider("Delay [unit:ms] [OWL:PARAMETER_B]", 10., 0.5, maxdtms, 0.01) : si.smooth(ba.tau2pole(smooth_time)); 16 | lr_offset = hslider("L-R Offset [OWL:PARAMETER_C]", 0, 0., 1, 0.001) *(0.5) : si.smooth(ba.tau2pole(smooth_time)); 17 | depth = hslider("Depth [unit:%] [OWL:PARAMETER_D]", 20., 3., 100., 1) *(0.01): si.smooth(ba.tau2pole(smooth_time)); 18 | 19 | tbllookup(phase) = s1+d*(s2-s1) 20 | with { 21 | i = int(phase * lutsize); 22 | d = ma.decimal(phase * lutsize); 23 | triangle_table = triangle_phasor(float(ba.time)/float(lutsize)); 24 | triangle_phasor(t) = ((0<=t) & (t<=0.5))*((2*t-0.5)/0.5) + ((0.5 2 | 7 | 8 | 142 | -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/ThruZeroFlanger/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "...", 3 | "name":"ThruZeroFlanger", 4 | "thumbnail": "FaustThruZeroFlanger.png", 5 | "vendor": "Larkin", 6 | "category":"Modulation", 7 | "version": "1.0" 8 | } 9 | -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/ThruZeroFlanger/testThruZeroFlanger.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Host that loads a plugin with its GUI 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 54 | 55 | -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/WeirdPhaser/FaustWeirdPhaser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/Faust/Oliver-Larkin/WeirdPhaser/FaustWeirdPhaser.png -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/WeirdPhaser/Original Faust Code/WeirdPhaser.dsp: -------------------------------------------------------------------------------- 1 | declare name "Weird Phaser"; 2 | declare description "Stereo Phaser based on SSB Modulation"; 3 | declare author "Oli Larkin (contact@olilarkin.co.uk)"; 4 | declare copyright "Oliver Larkin"; 5 | declare version "0.1"; 6 | declare licence "GPL"; 7 | 8 | import("IIRHilbert.lib"); 9 | import("stdfaust.lib"); 10 | 11 | // Generic bypass mecanism 12 | bypass = checkbox("bypass"); 13 | 14 | block_on(fx) = par(i, inputs(fx), _*(1-bypass)); 15 | block_off(fx) = par(i, inputs(fx), _*bypass); 16 | 17 | bypass_fx(fx) = par(i, inputs(fx), _) <: ((block_on(fx):fx), block_off(fx)):> par(i, outputs(fx), _); 18 | 19 | mix = 0.5; 20 | maxfeedback = 0.7; 21 | 22 | rate = hslider("Rate [unit:hz] [OWL:PARAMETER_A]", 0, 0., 1, 0.001); 23 | rateScalar = hslider("Rate Scalar [OWL:PARAMETER_B]", 1., 1., 40., 0.001); 24 | offset = hslider("L-R Offset [OWL:PARAMETER_C]", 0., 0., 1., 0.001) * 0.5; 25 | fbk = hslider("Feedback [OWL:PARAMETER_D]", 0., 0, 1., 0.01) : *(maxfeedback) : si.smooth(ba.tau2pole(0.005)); 26 | 27 | ssbfreqshift(x, offset) = (+ : negative) ~ (*(fbk) : clip(-1, 1)) 28 | with { 29 | negative(x) = real(x)*cosv - imag(x)*sinv; 30 | positive(x) = real(x)*cosv + imag(x)*sinv; 31 | real(x) = hilbert(x) : _ , !; 32 | imag(x) = hilbert(x) : ! , _; 33 | phasor = fmod(((rate*rateScalar)/float(ma.SR) : (+ : ma.decimal) ~ _)+offset, 1.) * (2*ma.PI); 34 | sinv = sin(phasor); 35 | cosv = cos(phasor); 36 | hilbert = hilbertef; 37 | clip(lo,hi) = min(hi) : max(lo); 38 | }; 39 | 40 | weirdphaser(l,r) = l,r <: *(1-mix), *(1-mix), ssbfreqshift(l, 0.)*mix, ssbfreqshift(r, offset)*mix :> _,_; 41 | process = bypass_fx(weirdphaser); -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/WeirdPhaser/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "...", 3 | "name": "WeirdPhaser", 4 | "thumbnail": "FaustWeirdPhaser.png", 5 | "vendor": "Larkin", 6 | "category":"Modulation", 7 | "version": "1.0" 8 | } 9 | -------------------------------------------------------------------------------- /examples/plugins/Faust/Oliver-Larkin/WeirdPhaser/testWeirdPhaser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Host that loads a plugin with its GUI 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 67 | 68 | -------------------------------------------------------------------------------- /examples/plugins/Faust/ZitaRevV3/FaustZitaRev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/Faust/ZitaRevV3/FaustZitaRev.png -------------------------------------------------------------------------------- /examples/plugins/Faust/ZitaRevV3/Original Faust Code/zitaRev.dsp: -------------------------------------------------------------------------------- 1 | declare name "zitaRev"; 2 | declare version "0.0"; 3 | declare author "JOS, Revised by RM"; 4 | declare description "Example GUI for zita_rev1_stereo (mostly following the Linux zita-rev1 GUI)."; 5 | 6 | import("stdfaust.lib"); 7 | import("bypass.lib"); 8 | 9 | // Bypass 'brutal' 10 | //process = bypass_fx(checkbox("bypass"), dm.zita_rev1); 11 | 12 | // Bypass avec un fade exprimé en 'samples', ici 1/10 de sec (calculé avec la SR utilisée) 13 | 14 | process = bypass_fx_fade(checkbox("bypass"), ma.SR/10, dm.zita_rev1); 15 | -------------------------------------------------------------------------------- /examples/plugins/Faust/ZitaRevV3/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "comming soon", 3 | "name":"ZitaRev2", 4 | "thumbnail": "FaustZitaRev.png", 5 | "vendor": "Faust", 6 | "category": "Reverb", 7 | "version": "1.0" 8 | } -------------------------------------------------------------------------------- /examples/plugins/Faust/ZitaRevV3/testZitaRev.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Host that loads a plugin with its GUI 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 67 | 68 | -------------------------------------------------------------------------------- /examples/plugins/PureJS/GuitarTuner/WasabiTuner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/GuitarTuner/WasabiTuner.png -------------------------------------------------------------------------------- /examples/plugins/PureJS/GuitarTuner/assets/clock.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/GuitarTuner/assets/clock.ttf -------------------------------------------------------------------------------- /examples/plugins/PureJS/GuitarTuner/main.html: -------------------------------------------------------------------------------- 1 | 2 | 7 | 16 | 17 | 184 | -------------------------------------------------------------------------------- /examples/plugins/PureJS/GuitarTuner/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "TODO", 3 | "name": "TunerMachine", 4 | "thumbnail": "WasabiTuner.png", 5 | "vendor": "Wasabi", 6 | "category":"Tuner", 7 | "version": "1.0" 8 | } -------------------------------------------------------------------------------- /examples/plugins/PureJS/GuitarTuner/testTunerWithGuitar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test Tuner 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 16 | 17 | 18 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /examples/plugins/PureJS/GuitarTuner/testTunerWithSample.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test Tuner 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 40 | 41 | -------------------------------------------------------------------------------- /examples/plugins/PureJS/Minilogue/Minilogue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/Minilogue/Minilogue.png -------------------------------------------------------------------------------- /examples/plugins/PureJS/Minilogue/assets/Res.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/Minilogue/assets/Res.png -------------------------------------------------------------------------------- /examples/plugins/PureJS/Minilogue/assets/grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/Minilogue/assets/grey.png -------------------------------------------------------------------------------- /examples/plugins/PureJS/Minilogue/assets/modechooser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/Minilogue/assets/modechooser.png -------------------------------------------------------------------------------- /examples/plugins/PureJS/Minilogue/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "...", 3 | "name": "Minilogue", 4 | "thumbnail": "Minilogue.png", 5 | "vendor": "Wasabi", 6 | "type": "Audio", 7 | "description": "Poly synth with filter, delay, lfo, white noise", 8 | "authorInformation": "Guillaume Etevenard, i3s trainee in Nice - Sophia-Antipolis, France", 9 | "category":"synth", 10 | "version": "1.2" 11 | } -------------------------------------------------------------------------------- /examples/plugins/PureJS/Minilogue/testMinilogue.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Host that loads a plugin with its GUI 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 30 | 31 | -------------------------------------------------------------------------------- /examples/plugins/PureJS/PingPongDelay/WasabiPingPongDelay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/PingPongDelay/WasabiPingPongDelay.png -------------------------------------------------------------------------------- /examples/plugins/PureJS/PingPongDelay/main.html: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 129 | -------------------------------------------------------------------------------- /examples/plugins/PureJS/PingPongDelay/main.js: -------------------------------------------------------------------------------- 1 | /* ################################## PingPongDelay ######################################## */ 2 | 3 | /* ES6 web audio class following the API standard 4 | * Author : Guillaume Etevenard 5 | */ 6 | window.PingPongDelay = class PingPongDelay extends WebAudioPluginCompositeNode { 7 | 8 | constructor(ctx,URL ,options) { 9 | /* ################ API PROPERTIES ############### */ 10 | super(ctx,URL, options) 11 | 12 | this.addParam({name:'feedback', defaultValue: 0.5, minValue: 0, maxValue: 1 }); 13 | this.addParam({name: 'time',defaultValue: 0.5, minValue: 0, maxValue: 1 }); 14 | this.addParam({name: 'mix',defaultValue: 0.5, minValue: 0, maxValue: 1 }); 15 | 16 | // Bypass feature. Useful for swithing the plugin on and off 17 | Object.assign({"status": "disable"},this.params); 18 | super.setup(); 19 | } 20 | 21 | /* ################ API METHODS Overriding ############### */ 22 | getPatch(index) { 23 | console.warn("this module does not implements patches use getState / setState to get an array of current params values "); 24 | } 25 | setPatch(data, index) { 26 | console.warn("this module does not implements patches use getState / setState to get an array of current params values "); 27 | } 28 | setParam(key, value) { 29 | //console.log(key, value); 30 | try { 31 | this[key] = (value); 32 | } catch (error) { 33 | 34 | console.warn("this plugin does not implement this param") 35 | } 36 | } 37 | 38 | /* ######### Personnal code for the web audio graph ######### */ 39 | 40 | createNodes() { 41 | this.delayNodeLeft = this.context.createDelay(); 42 | this.delayNodeRight = this.context.createDelay(); 43 | this.dryGainNode = this.context.createGain(); 44 | this.wetGainNode = this.context.createGain(); 45 | this.feedbackGainNode = this.context.createGain(); 46 | this.channelMerger = this.context.createChannelMerger(2); 47 | } 48 | 49 | connectNodes() { 50 | // dry mix 51 | this._input.connect(this.dryGainNode); 52 | // dry mix out 53 | this.dryGainNode.connect(this._output); 54 | 55 | // the feedback loop 56 | this.delayNodeLeft.connect(this.channelMerger, 0, 0); 57 | this.delayNodeRight.connect(this.channelMerger, 0, 1); 58 | 59 | this.feedbackGainNode.connect(this.delayNodeLeft); 60 | this.delayNodeRight.connect(this.feedbackGainNode); 61 | 62 | this.delayNodeLeft.connect(this.delayNodeRight); 63 | 64 | // wet mix 65 | this._input.connect(this.feedbackGainNode); 66 | 67 | // wet out 68 | this.channelMerger.connect(this.wetGainNode); 69 | this.wetGainNode.connect(this._output); 70 | } 71 | 72 | // Setter part, it is here that you define the link between the params and the nodes values. 73 | set time(_time) { 74 | if (_time < this._descriptor.time.maxValue && _time > this._descriptor.time.minValue) this.params.time = _time; 75 | this.delayNodeLeft.delayTime.setValueAtTime(_time, this.context.currentTime); 76 | this.delayNodeRight.delayTime.setValueAtTime(_time, this.context.currentTime); 77 | } 78 | 79 | set feedback(_feedback) { 80 | if (_feedback < this._descriptor.feedback.maxValue && _feedback > this._descriptor.feedback.minValue) this.params.feedback = _feedback; 81 | this.feedbackGainNode.gain.setValueAtTime(parseFloat(_feedback, 10), this.context.currentTime); 82 | } 83 | 84 | set mix(_mix) { 85 | if (_mix < this._descriptor.mix.maxValue && _mix > this._descriptor.mix.minValue)this.params.mix = _mix; 86 | this.dryGainNode.gain.setValueAtTime(this.getDryLevel(this.params.mix), this.context.currentTime); 87 | this.wetGainNode.gain.setValueAtTime(this.getWetLevel(this.params.mix), this.context.currentTime); 88 | } 89 | 90 | set status(_sig) { 91 | if (_sig === "enable") { 92 | this.params.status = "enable"; 93 | this._input.disconnect(this._output); 94 | this._input.connect(this.feedbackGainNode); 95 | this._input.connect(this.dryGainNode); 96 | } 97 | else if (_sig === "disable") { 98 | this.params.status = "disable"; 99 | this._input.disconnect(this.feedbackGainNode); 100 | this._input.disconnect(this.dryGainNode); 101 | this._input.connect(this._output); 102 | } 103 | } 104 | 105 | 106 | 107 | // delay tools 108 | /* 109 | * 110 | *Tools to build sounds 111 | */ 112 | 113 | isNumber(arg) { 114 | return toString.call(arg) === '[object Number]' && arg === +arg; 115 | } 116 | 117 | getDryLevel(mix) { 118 | if (!this.isNumber(mix) || mix > 1 || mix < 0) 119 | return 0; 120 | 121 | if (mix <= 0.5) 122 | return 1; 123 | 124 | return 1 - ((mix - 0.5) * 2); 125 | } 126 | 127 | getWetLevel(mix) { 128 | if (!this.isNumber(mix) || mix > 1 || mix < 0) 129 | return 0; 130 | 131 | if (mix >= 0.5) 132 | return 1; 133 | 134 | return 1 - ((0.5 - mix) * 2); 135 | } 136 | 137 | } 138 | 139 | 140 | window.WasabiPingPongDelay = class WasabiPingPongDelay extends WebAudioPluginFactory { 141 | 142 | constructor(context, baseUrl, options) { 143 | super(context, baseUrl,options); 144 | } 145 | 146 | } 147 | 148 | AudioContext.prototype.createWasabiDelayCompositeNode = 149 | OfflineAudioContext.prototype.createWasabiDelayCompositeNode = function (options) { 150 | return new PingPongDelay(this, options); 151 | }; -------------------------------------------------------------------------------- /examples/plugins/PureJS/PingPongDelay/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "...", 3 | "name": "PingPongDelay", 4 | "thumbnail": "WasabiPingPongDelay.png", 5 | "vendor": "Wasabi", 6 | "category":"Delay", 7 | "version": "1.0" 8 | } -------------------------------------------------------------------------------- /examples/plugins/PureJS/PingPongDelay/testPingPongDelay.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Host that loads a plugin with its GUI 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 55 | 56 | -------------------------------------------------------------------------------- /examples/plugins/PureJS/QuadraFuzz/assets/MiniMoog_Main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/QuadraFuzz/assets/MiniMoog_Main.png -------------------------------------------------------------------------------- /examples/plugins/PureJS/QuadraFuzz/assets/WasabiQuadraFuzz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/QuadraFuzz/assets/WasabiQuadraFuzz.png -------------------------------------------------------------------------------- /examples/plugins/PureJS/QuadraFuzz/assets/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/QuadraFuzz/assets/background.png -------------------------------------------------------------------------------- /examples/plugins/PureJS/QuadraFuzz/assets/switch_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/QuadraFuzz/assets/switch_1.png -------------------------------------------------------------------------------- /examples/plugins/PureJS/QuadraFuzz/main.html: -------------------------------------------------------------------------------- 1 | 6 | 7 | 168 | -------------------------------------------------------------------------------- /examples/plugins/PureJS/QuadraFuzz/main.js: -------------------------------------------------------------------------------- 1 | /* ################################## Quadrafuzz ######################################## */ 2 | 3 | /* ES6 web audio class following the API standard 4 | * Author : Guillaume Etevenard 5 | */ 6 | window.QuadraFuzz = class QuadraFuzz extends WebAudioPluginCompositeNode { 7 | 8 | 9 | constructor(ctx, URL, options) { 10 | super(ctx, URL, options) 11 | /* ################ API PROPERTIES ############### */ 12 | 13 | this.addParam({ name: 'lowgain', defaultValue: 0.6, minValue: 0, maxValue: 1 }); 14 | this.addParam({ name: 'midlowgain', defaultValue: 0.8, minValue: 0, maxValue: 1 }); 15 | this.addParam({ name: 'midhighgain', defaultValue: 0.5, minValue: 0, maxValue: 1 }); 16 | this.addParam({ name: 'highgain', defaultValue: 0.5, minValue: 0, maxValue: 1 }); 17 | 18 | // To have a on/off management 19 | Object.assign({ "status": "disable" }, this.params) 20 | // Call the SDK protocol to build the WAP 21 | super.setup(); 22 | 23 | } 24 | 25 | /* ################ API METHODS Overriding ############### */ 26 | 27 | getPatch(index) { 28 | console.warn("this module does not implements patches use getState / setState to get an array of current params values "); 29 | } 30 | setPatch(data, index) { 31 | console.warn("this module does not implements patches use getState / setState to get an array of current params values "); 32 | } 33 | 34 | setParam(key, value) { 35 | try { 36 | this[key] = value; 37 | } catch (error) { 38 | console.warn("this plugin does not implement this param") 39 | } 40 | } 41 | 42 | /* ######### Personnal code for the web audio graph ######### */ 43 | createNodes() { 44 | 45 | this.dryGainNode = this.context.createGain(); 46 | this.wetGainNode = this.context.createGain(); 47 | 48 | this.lowpassLeft = this.context.createBiquadFilter(); 49 | this.lowpassLeft.type = 'lowpass'; 50 | this.lowpassLeft.frequency.value = 147; 51 | this.lowpassLeft.Q.value = 0.7071; 52 | 53 | this.bandpass1Left = this.context.createBiquadFilter(); 54 | this.bandpass1Left.type = 'bandpass'; 55 | this.bandpass1Left.frequency.value = 587; 56 | this.bandpass1Left.Q.value = 0.7071; 57 | 58 | this.bandpass2Left = this.context.createBiquadFilter(); 59 | this.bandpass2Left.type = 'bandpass'; 60 | this.bandpass2Left.frequency.value = 2490; 61 | this.bandpass2Left.Q.value = 0.7071; 62 | 63 | this.highpassLeft = this.context.createBiquadFilter(); 64 | this.highpassLeft.type = 'highpass'; 65 | this.highpassLeft.frequency.value = 4980; 66 | this.highpassLeft.Q.value = 0.7071; 67 | 68 | this.overdrives = []; 69 | for (var i = 0; i < 4; i++) { 70 | this.overdrives[i] = this.context.createWaveShaper(); 71 | this.overdrives[i].curve = this.getDistortionCurve(); 72 | } 73 | 74 | } 75 | 76 | connectNodes() { 77 | this._input.connect(this.wetGainNode); 78 | this._input.connect(this.dryGainNode); 79 | this.dryGainNode.connect(this._output); 80 | 81 | var filters = [this.lowpassLeft, this.bandpass1Left, this.bandpass2Left, this.highpassLeft]; 82 | for (var i = 0; i < filters.length; i++) { 83 | this.wetGainNode.connect(filters[i]); 84 | filters[i].connect(this.overdrives[i]); 85 | this.overdrives[i].connect(this._output); 86 | } 87 | 88 | } 89 | /* 90 | * 91 | *Tools to build sounds 92 | */ 93 | getDistortionCurve(gain) { 94 | var sampleRate = this.context.sampleRate; 95 | var curve = new Float32Array(sampleRate); 96 | var deg = Math.PI / 180; 97 | 98 | for (var i = 0; i < sampleRate; i++) { 99 | var x = i * 2 / sampleRate - 1; 100 | curve[i] = (3 + gain) * x * 20 * deg / (Math.PI + gain * Math.abs(x)); 101 | } 102 | return curve; 103 | } 104 | 105 | isNumber(arg) { 106 | return toString.call(arg) === '[object Number]' && arg === +arg; 107 | } 108 | 109 | isInRange(arg, min, max) { 110 | if (!this.isNumber(arg) || !this.isNumber(min) || !this.isNumber(max)) 111 | return false; 112 | 113 | return arg >= min && arg <= max; 114 | } 115 | 116 | 117 | // Takes a number from 0 to 1 and normalizes it to fit within range floor to ceiling 118 | normalize(num, floor, ceil) { 119 | if (!this.isNumber(num) || !this.isNumber(floor) || !this.isNumber(ceil)) 120 | return; 121 | 122 | return ((ceil - floor) * num) / 1 + floor; 123 | } 124 | 125 | // Setter part, it is here that you define the link between the params and the nodes values. 126 | set lowgain(_lowGain) { 127 | if (!this.isInRange(_lowGain, 0, 1)) 128 | return; 129 | this.params.lowgain = _lowGain; 130 | this.overdrives[0].curve = this.getDistortionCurve(this.normalize(_lowGain, 0, 150)); 131 | } 132 | 133 | set midlowgain(_midLowGain) { 134 | if (!this.isInRange(_midLowGain, 0, 1)) 135 | return; 136 | this.params.midlowgain = _midLowGain; 137 | this.overdrives[1].curve = this.getDistortionCurve(this.normalize(_midLowGain, 0, 150)); 138 | 139 | } 140 | 141 | set midhighgain(_midHighGain) { 142 | if (!this.isInRange(_midHighGain, 0, 1)) 143 | return; 144 | this.params.midhighgain = _midHighGain; 145 | this.overdrives[2].curve = this.getDistortionCurve(this.normalize(_midHighGain, 0, 150)); 146 | } 147 | set highgain(_highGain) { 148 | if (!this.isInRange(_highGain, 0, 1)) 149 | return; 150 | this.params.highgain = _highGain; 151 | this.overdrives[3].curve = this.getDistortionCurve(this.normalize(_highGain, 0, 150)); 152 | } 153 | 154 | set status(_sig) { 155 | if (_sig === "enable") { 156 | this.params.status = "enable"; 157 | this._input.disconnect(this._output); 158 | this.connectNodes(); 159 | 160 | } 161 | else if (_sig === "disable") { 162 | this.params.status = "disable"; 163 | this._input.disconnect(this.dryGainNode); 164 | this._input.disconnect(this.wetGainNode); 165 | this._input.connect(this._output); 166 | } 167 | } 168 | 169 | } 170 | 171 | 172 | window.WasabiQuadraFuzz = class WasabiQuadraFuzz extends WebAudioPluginFactory { 173 | 174 | constructor(context, baseUrl) { 175 | super(context, baseUrl); 176 | } 177 | 178 | } 179 | AudioContext.prototype.createWasabiQuadraFuzzCompositeNode = 180 | OfflineAudioContext.prototype.createWasabiQuadraFuzzCompositeNode = function (options) { 181 | return new QuadraFuzz(this, options); 182 | }; -------------------------------------------------------------------------------- /examples/plugins/PureJS/QuadraFuzz/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "...", 3 | "name": "QuadraFuzz", 4 | "thumbnail": "./assets/WasabiQuadraFuzz.png", 5 | "vendor": "Wasabi", 6 | "category":"Distortion", 7 | "version": "1.2" 8 | } -------------------------------------------------------------------------------- /examples/plugins/PureJS/QuadraFuzz/testQuadrafuzz.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Quadrafuzz state setter 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 63 | 64 | -------------------------------------------------------------------------------- /examples/plugins/PureJS/StereoFlanger/WasabiStereoFlanger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/StereoFlanger/WasabiStereoFlanger.png -------------------------------------------------------------------------------- /examples/plugins/PureJS/StereoFlanger/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 162 | 163 | -------------------------------------------------------------------------------- /examples/plugins/PureJS/StereoFlanger/main.js: -------------------------------------------------------------------------------- 1 | window.StereoFlanger = class StereoFlanger extends WebAudioPluginCompositeNode { 2 | constructor(ctx,URL ,options) { 3 | super(ctx,URL, options) 4 | 5 | 6 | this.addParam({ name: 'feedback', defaultValue: 0.5, minValue: 0, maxValue: 1 }); 7 | this.addParam({ name: 'delay', defaultValue: 0.003, minValue: 0.001, maxValue: 0.02 }); 8 | this.addParam({ name: 'depth', defaultValue: 0.005, minValue: 0.0005, maxValue: 0.02 }); 9 | this.addParam({ name: 'frequency', defaultValue: 0.15, minValue: 0.05, maxValue: 2 }); 10 | Object.assign({ "status": "disable" }, this.params) 11 | 12 | super.setup(); 13 | } 14 | 15 | 16 | setParam(key, value) { 17 | console.log(key, value); 18 | try { 19 | this[key] = (value); 20 | } catch (error) { 21 | 22 | console.warn("this plugin does not implement this param") 23 | } 24 | } 25 | 26 | 27 | createNodes() { 28 | /* @see : https://github.com/cwilso/Audio-Input-Effects/blob/master/js/effects.js */ 29 | 30 | this.splitter = this.context.createChannelSplitter(2); 31 | this.merger = this.context.createChannelMerger(2); 32 | this.feedbackLeft = this.context.createGain(); 33 | this.feedbackRight = this.context.createGain(); 34 | this.oscillator = this.context.createOscillator(); 35 | this.depthLeft = this.context.createGain(); 36 | this.depthRight = this.context.createGain(); 37 | this.delayLeft = this.context.createDelay(); 38 | this.delayRight = this.context.createDelay(); 39 | this.wetGain = this.context.createGain(); 40 | } 41 | 42 | connectNodes() { 43 | /* @see : https://github.com/cwilso/Audio-Input-Effects/blob/master/js/effects.js */ 44 | 45 | this._input.connect(this.splitter); 46 | this._input.connect(this.wetGain); 47 | 48 | this.splitter.connect(this.delayLeft, 0); 49 | this.splitter.connect(this.delayRight, 1); 50 | 51 | this.delayLeft.connect(this.feedbackLeft); 52 | this.delayRight.connect(this.feedbackRight); 53 | 54 | this.feedbackLeft.connect(this.delayRight); 55 | this.feedbackRight.connect(this.delayLeft); 56 | 57 | this.oscillator.type = 'triangle'; 58 | this.oscillator.connect(this.depthLeft); 59 | this.oscillator.connect(this.depthRight); 60 | 61 | this.depthLeft.connect(this.delayLeft.delayTime); 62 | this.depthRight.connect(this.delayRight.delayTime); 63 | 64 | this.delayLeft.connect(this.merger, 0, 0); 65 | this.delayRight.connect(this.merger, 0, 1); 66 | 67 | this.merger.connect(this.wetGain); 68 | 69 | this.wetGain.connect(this._output); 70 | this.oscillator.start(); 71 | 72 | } 73 | 74 | set feedback(_feedback) { 75 | if ((_feedback < this._descriptor.feedback.maxValue) && (_feedback > this._descriptor.feedback.minValue)) 76 | this.params.feedback = _feedback; 77 | 78 | this.feedbackLeft.gain.setValueAtTime(parseFloat(this.params.feedback, 10), this.context.currentTime); 79 | this.feedbackRight.gain.setValueAtTime(parseFloat(this.params.feedback, 10), this.context.currentTime); 80 | } 81 | 82 | set delay(_delay) { 83 | if ((_delay < this._descriptor.delay.maxValue) && (_delay > this._descriptor.delay.minValue)) 84 | this.params.delay = _delay; 85 | 86 | this.delayLeft.delayTime.setValueAtTime(parseFloat(this.params.delay, 10), this.context.currentTime); 87 | this.delayRight.delayTime.setValueAtTime(parseFloat(this.params.delay, 10), this.context.currentTime); 88 | } 89 | 90 | set depth(_depth) { 91 | if ((_depth < this._descriptor.depth.maxValue) && (_depth > this._descriptor.depth.minValue)) 92 | this.params.depth = _depth; 93 | 94 | this.depthLeft.gain.setValueAtTime(parseFloat(this.params.depth, 10), this.context.currentTime); 95 | this.depthRight.gain.setValueAtTime(- parseFloat(this.params.depth, 10), this.context.currentTime); 96 | } 97 | 98 | set frequency(_frequency) { 99 | if ((_frequency < this._descriptor.frequency.maxValue) && (_frequency > this._descriptor.frequency.minValue)) 100 | this.params.frequency = _frequency; 101 | 102 | this.oscillator.frequency.setValueAtTime(parseFloat(this.params.frequency, 10), this.context.currentTime); 103 | } 104 | set status(_sig) { 105 | if (_sig === "enable") { 106 | this.params.status = "enable"; 107 | this._input.connect(this.splitter); 108 | this._input.connect(this.wetGain); 109 | this._input.disconnect(this._output); 110 | 111 | } 112 | else if (_sig === "disable") { 113 | this.params.status = "disable"; 114 | this._input.connect(this._output); 115 | this._input.disconnect(this.splitter); 116 | this._input.disconnect(this.wetGain); 117 | } 118 | } 119 | } 120 | 121 | 122 | 123 | ////////////////////////////////////////////////////////////////////////////////////////// 124 | 125 | window.WasabiStereoFlanger = class WasabiStereoFlanger extends WebAudioPluginFactory { 126 | constructor(context, baseUrl, options) { super(context, baseUrl, options); } 127 | } 128 | 129 | ////////////////////////////////////////////////////////////////////////////////////////// 130 | 131 | AudioContext.prototype.createWasabiDelayCompositeNode = OfflineAudioContext.prototype.createWasabiDelayCompositeNode = function (options) { return new StereoFlanger(this, baseUrl, options); }; -------------------------------------------------------------------------------- /examples/plugins/PureJS/StereoFlanger/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "TODO", 3 | "name": "StereoFlanger", 4 | "thumbnail": "WasabiStereoFlanger.png", 5 | "vendor": "Wasabi", 6 | "category":"Modulation", 7 | "version": "1.0" 8 | } -------------------------------------------------------------------------------- /examples/plugins/PureJS/StereoFlanger/testStereoFlanger.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Host that loads a plugin with its GUI 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 46 | 47 | -------------------------------------------------------------------------------- /examples/plugins/PureJS/WahVox/WasabiWahVox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/WahVox/WasabiWahVox.png -------------------------------------------------------------------------------- /examples/plugins/PureJS/WahVox/image/vsliderbody.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/WahVox/image/vsliderbody.png -------------------------------------------------------------------------------- /examples/plugins/PureJS/WahVox/image/vsliderknob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/examples/plugins/PureJS/WahVox/image/vsliderknob.png -------------------------------------------------------------------------------- /examples/plugins/PureJS/WahVox/main.js: -------------------------------------------------------------------------------- 1 | /* ################################## WAH ######################################## */ 2 | 3 | /* ES6 web audio class following the API standard 4 | * Author : Jordan Sintes 5 | * Comment: Based on the structure of Pedal Wah Vox V847, more information: https://www.electrosmash.com/vox-v847-analysis 6 | */ 7 | window.WahVox = class WahVox extends WebAudioPluginCompositeNode { 8 | constructor(ctx, URL, options) { 9 | super(ctx, URL, options) 10 | /* ################ API PROPERTIES ############### */ 11 | 12 | this.state; 13 | this.params = { 14 | "status": "disable", 15 | "boost": "disable", 16 | } 17 | 18 | this.addParam({ name: 'effect', defaultValue: 50, minValue: 0, maxValue: 100 }); 19 | this.addParam({ name: 'mode', defaultValue: 1, minValue: 1, maxValue: 3 }); 20 | this.addParam({ name: 'frequency', defaultValue: 3, minValue: 1, maxValue: 5 }); 21 | this.addParam({ name: 'qfactor', defaultValue: 3, minValue: 1, maxValue: 5 }); 22 | 23 | this.qMin = 7; 24 | this.qMax = 2; 25 | this.freqMin = 450; 26 | this.freqMax = 1600; 27 | this.gainnotboosted = Math.pow(10, (18 / 20)); // refers to: https://stackoverflow.com/questions/22604500/web-audio-api-working-with-decibels 28 | this.gainboosted = Math.pow(10, (24 / 20)); 29 | 30 | super.setup(); 31 | } 32 | 33 | /* ################ API METHODS ############### */ 34 | 35 | getPatch(index) { 36 | console.warn("this module does not implements patches use getState / setState to get an array of current params values "); 37 | } 38 | setPatch(data, index) { 39 | console.warn("this module does not implements patches use getState / setState to get an array of current params values "); 40 | } 41 | 42 | setParam(key, value) { 43 | console.log(key, value); 44 | try { 45 | this[key] = (value); 46 | } catch (error) { 47 | console.log(key, error) 48 | console.warn("this plugin does not implement this param") 49 | } 50 | } 51 | 52 | createNodes() { 53 | this.dryGainNode = this.context.createGain(); 54 | this.wetGainNode = this.context.createGain(); 55 | this.bandPass = this.context.createBiquadFilter(); 56 | 57 | this.bandPass.type = "bandpass"; 58 | this.bandPass.frequency.value = 750; 59 | this.bandPass.Q.value = this.map(this.bandPass.frequency.value, this.freqMin, this.freqMax, this.qMax, this.qMin); 60 | this.bandPass.gain.value = 1; 61 | } 62 | 63 | connectNodes() { 64 | this._input.connect(this.dryGainNode); 65 | this.dryGainNode.connect(this.bandPass); 66 | this.bandPass.connect(this.wetGainNode); 67 | this.wetGainNode.connect(this._output); 68 | } 69 | 70 | /* ######### Personnal code for the web audio graph ######### */ 71 | 72 | //To change the amplitude depends on parameter 73 | map(value, istart, istop, ostart, ostop) { 74 | return ostart + (ostop - ostart) * ((value - istart) / (istop - istart)); 75 | } 76 | 77 | set mode(_mode) { 78 | this.params.mode = _mode; 79 | } 80 | 81 | set effect(_effect) { 82 | //Using map function until the knob has logarithmic/exponential/linear increase 83 | this.params.effect = _effect; 84 | if (this.params.mode === 1) { 85 | //Logarithmic Mode 86 | if (_effect === 0) _effect = 1; 87 | // conversion manuelle en log 88 | _effect = Math.log(_effect); 89 | // normalisation entre freq min et freqmax 90 | let freq = this.map(_effect, Math.log(1), Math.log(100), this.params.freqMin, this.params.freqMax); 91 | // _effect entre 0 et 1, plus simple à gérer 92 | this.bandPass.frequency.setValueAtTime(freq, this.context.currentTime); 93 | var qparam = this.map(freq, this.params.freqMin, this.params.freqMax, this.params.qMax, this.params.qMin); 94 | this.bandPass.Q.setValueAtTime(qparam, this.context.currentTime); 95 | console.log("f=" + freq + " q =" + qparam); 96 | } 97 | 98 | else if (this.params.mode === 2) { 99 | //Exponential mode 100 | _effect = _effect / 100; 101 | // conversion manuelle en log 102 | _effect = Math.exp(_effect); 103 | // normalisation entre freq min et freqmax 104 | let freq = this.map(_effect, Math.exp(0), Math.exp(1), this.params.freqMin, this.params.freqMax); 105 | 106 | // _effect entre 0 et 1, plus simple à gérer 107 | this.bandPass.frequency.setValueAtTime(freq, this.context.currentTime); 108 | var qparam = this.map(freq, this.params.freqMin, this.params.freqMax, this.params.qMax, this.params.qMin); 109 | this.bandPass.Q.setValueAtTime(qparam, this.context.currentTime); 110 | console.log("f=" + freq + " q =" + qparam); 111 | } 112 | 113 | else if (this.params.mode === 3) { 114 | //Linear mode 115 | if (_effect === 0) _effect = 1; 116 | let freq = this.map(_effect, 1, 100, this.params.freqMin, this.params.freqMax); 117 | this.bandPass.frequency.setValueAtTime(freq, this.context.currentTime); 118 | var qparam = this.map(freq, this.params.freqMin, this.params.freqMax, this.params.qMax, this.params.qMin); 119 | this.bandPass.Q.setValueAtTime(qparam, this.context.currentTime); 120 | console.log("f=" + freq + " q =" + qparam); 121 | } 122 | } 123 | 124 | set status(_sig) { 125 | if (_sig === "enable") { 126 | this.params.status = "enable"; 127 | this._input.disconnect(this._output); 128 | this._input.connect(this.dryGainNode); 129 | if (this.params.boost === "enable") { 130 | this._input.gain.setValueAtTime(this.gainboosted, this.context.currentTime); 131 | } 132 | else if (this.params.boost === "disable") { 133 | console.log(this.gainnotboosted); 134 | this._input.gain.setValueAtTime(this.gainnotboosted, this.context.currentTime); 135 | } 136 | } 137 | else if (_sig === "disable") { 138 | this.params.status = "disable"; 139 | this._input.disconnect(this.dryGainNode); 140 | this._input.connect(this._output); 141 | this._input.gain.setValueAtTime(1, this.context.currentTime); 142 | } 143 | } 144 | 145 | set boost(_sig) { 146 | if (this.params.status === "enable") { 147 | if (_sig === "enable") { 148 | this.params.boost = "enable"; 149 | this._input.gain.setValueAtTime(this.gainboosted, this.context.currentTime); 150 | } 151 | else if (_sig === "disable") { 152 | this.params.boost = "disable"; 153 | this._input.gain.setValueAtTime(this.gainnotboosted, this.context.currentTime); 154 | } 155 | } 156 | 157 | else if (this.params.status === "disable") { 158 | console.log("Boost aren't avaiable"); 159 | this._input.gain.setValueAtTime(1, this.context.currentTime); 160 | } 161 | } 162 | 163 | set frequency(_sig) { 164 | this.params.frequency = _sig; 165 | if (_sig === 1) { 166 | this.params.freqMin = 250; 167 | this.params.freqMax = 1400; 168 | } 169 | 170 | else if (_sig === 2) { 171 | this.params.freqMin = 350; 172 | this.params.freqMax = 1500; 173 | } 174 | 175 | else if (_sig === 3) { 176 | this.params.freqMin = 450; 177 | this.params.freqMax = 1600; 178 | } 179 | 180 | else if (_sig === 4) { 181 | this.params.freqMin = 550; 182 | this.params.freqMax = 1700; 183 | } 184 | 185 | else if (_sig === 5) { 186 | this.params.freqMin = 650; 187 | this.params.freqMax = 1800; 188 | } 189 | } 190 | 191 | set qfactor(_sig) { 192 | this.params.qfactor = _sig; 193 | if (_sig === 1) { 194 | this.params.qMin = 1; 195 | this.params.qMax = 8.5; 196 | } 197 | 198 | else if (_sig === 2) { 199 | this.params.qMin = 1; 200 | this.params.qMax = 8; 201 | } 202 | 203 | else if (_sig === 3) { 204 | this.params.qMin = 2; 205 | this.params.qMax = 7; 206 | } 207 | 208 | else if (_sig === 4) { 209 | this.params.qMin = 3; 210 | this.params.qMax = 6; 211 | } 212 | 213 | else if (_sig === 5) { 214 | this.params.qMin = 4; 215 | this.params.qMax = 5; 216 | } 217 | } 218 | } 219 | 220 | 221 | ////////////////////////////////////////////////////////////////////////////////////////// 222 | 223 | window.WasabiWahVox = class WasabiWahVox extends WebAudioPluginFactory { 224 | constructor(context, baseUrl) { super(context, baseUrl); } 225 | } 226 | 227 | ////////////////////////////////////////////////////////////////////////////////////////// 228 | 229 | AudioContext.prototype.createWasabiDelayCompositeNode = OfflineAudioContext.prototype.createWasabiDelayCompositeNode = function (options) { return new WahVox(this, options); }; 230 | 231 | -------------------------------------------------------------------------------- /examples/plugins/PureJS/WahVox/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "TODO", 3 | "name": "WahVox", 4 | "thumbnail": "WasabiWahVox.png", 5 | "vendor": "Wasabi", 6 | "category":"Expression", 7 | "version": "1.0" 8 | } -------------------------------------------------------------------------------- /examples/plugins/PureJS/WahVox/testWahWithGuitarAsInput.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test Wah Effect 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | 79 | 80 | -------------------------------------------------------------------------------- /examples/plugins/PureJS/WahVox/testWahWithSamples.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test Wah Vox V847 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 57 | 58 | -------------------------------------------------------------------------------- /imgs/PluginWithGUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/imgs/PluginWithGUI.png -------------------------------------------------------------------------------- /imgs/RepoTester2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/imgs/RepoTester2.png -------------------------------------------------------------------------------- /imgs/pluginTester.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/imgs/pluginTester.png -------------------------------------------------------------------------------- /imgs/worldDominationPlan4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/imgs/worldDominationPlan4.png -------------------------------------------------------------------------------- /testers/styles.css: -------------------------------------------------------------------------------- 1 | #WAP { 2 | float: left; 3 | width: 50%; 4 | padding-top: 5%; 5 | padding-left: 15%; 6 | } 7 | 8 | .urlRepo { 9 | color: blue; 10 | } 11 | 12 | #mocha { 13 | float: right; 14 | width: 50%; 15 | height: 400px; 16 | overflow: scroll; 17 | padding: 0%; 18 | } 19 | 20 | #onetest { 21 | display: flex; 22 | } 23 | 24 | #inputs { 25 | display: grid; 26 | } 27 | 28 | #urlPlugin { 29 | width: 300px; 30 | } 31 | 32 | #main { 33 | float: left; 34 | width: 50% 35 | } 36 | 37 | #layout { 38 | display: flex; 39 | } 40 | 41 | #helper { 42 | float: left; 43 | border: 3px; 44 | border-style: solid; 45 | padding: 10px; 46 | width: 50% 47 | } -------------------------------------------------------------------------------- /tutorial/createyourwap.md: -------------------------------------------------------------------------------- 1 | # Create your own WAP : 2 | 3 | In this tutorial you'll learn how to create your own WAP, with its GUI, and make it available. 4 | 5 | ### Architecture 6 | ``` 7 | wapName 8 | ├──main.js 9 | ├──main.html 10 | ├──main.json 11 | └──assets 12 | ├──thumbnail.png 13 | └──js 14 | └──externalScript.js 15 | 16 | 17 | ``` 18 | 19 | ### *Metadata* main.json 20 | 21 | Must contain at least name, category, vendor name & thumbnail to interact correctly with other WAP tools. 22 | 23 | ```json 24 | { 25 | "documentation": "https://github.com/you/thisproject", 26 | "name": "wapName", 27 | "thumbnail": "./assets/thumbnail.png", 28 | "vendor": "you", 29 | "category":"Filter", 30 | "version": "1.0" 31 | } 32 | ``` 33 | Some of our applications fetch this file first and use those fields to prepare the WAP launch. 34 | 35 | 36 | ### *Audio Node(s)* main.js 37 | 38 | Define and build the audio graph of your WAP. 39 | 40 | **First** you have to create 2 classes inherited from the webaudioSDK: 41 | 42 | The first class is the actual Audio Node 43 | ```js 44 | window.PluginName = class PluginName extends WebAudioPluginCompositeNode { 45 | 46 | constructor(ctx, URL, options) { 47 | super(ctx, URL, options) 48 | /* ################ API PROPERTIES ############### */ 49 | 50 | this.addParam({ name: 'cutoff', defaultValue: 1500, minValue: 30, maxValue: 22000 }); 51 | super.setup(); 52 | } 53 | } 54 | ``` 55 | It's inherited from a CompositeNode which manages inputs, outputs & params. 56 | Here you just have to add your params as you can see in the snippet and the SDK will build a key-value _**`descriptor`**_ and a _**`params`**_ object which will be useful later. Basically we add a param when the value of an audioparam is made to change (ex : type of an oscillator, frequency of a filter). 57 | 58 | If some of yours params don't fit the descriptor you can add it like `Object.assign({ "status": "disable" }, this.params)` in the constructor. 59 | 60 | The SDK has some tools like : **descriptor** getter, **numberOfOutputs** getter that you can override if you have features to add. It also makes available default I/O called respectively `this._input` and `this._output` that are by default on `this.inputs[Ø]` and `this.outputs[0]` tabs that you can fill with additionnal I/O's. 61 | 62 | Let's jump to the audio graph : you need to implements 2 methods : 63 | ```js 64 | createNodes(){}; 65 | connectNodes(){}; 66 | ``` 67 | You are free to have your own workflow but those method are called by default in the super.setup(); It's also quite clear if your code is shared. 68 | 69 | ### Example 70 | ```js 71 | createNodes(){ 72 | this.lpfilter = this.context.createBiquadFilter(); 73 | this.lpfilter.type = "lowpass"; 74 | }; 75 | connectNodes(){ 76 | this._input.connect(this.lpfilter); 77 | this.lpfilter.connect(this._output); 78 | }; 79 | ``` 80 | Now the params are created and the audio nodes too, you just have to bind it. We recommend something like that : 81 | 82 | ```js 83 | setParam(key, value) { 84 | try { 85 | this[key] = value; 86 | } catch (error) { 87 | console.warn("this plugin does not implement this param") 88 | } 89 | } 90 | 91 | set myparam(_value){ 92 | // to store the new value 93 | this.params.myparam = _value; 94 | // if your param is linked to the filter frequency you can : 95 | this.lpfilter.frequency.setValueAtTime(_value,this.context.currentTime); 96 | 97 | } 98 | ``` 99 | 100 | We are done with audio processing. Let's create the factory wich will make available our audio node : 101 | 102 | ```js 103 | window.VendorNamePluginName = class VendorNamePluginName extends WebAudioPluginFactory { 104 | 105 | constructor(context, baseUrl) { 106 | super(context, baseUrl); 107 | } 108 | 109 | } 110 | ``` 111 | 112 | The class **WebAudioPluginFactory** contains methods to fetch and load your WAP. We encourage you to read it in the webaudioSDK.js file. 113 | 114 | 115 | ### *GUI* main.html 116 | 117 | The SDK contains a **loadGUI()** method that link the **main.html** file. 118 | 119 | GUI is optionnal for a WAP, but here is how we build our own : 120 | 121 | **First** define an html/css template 122 | 123 | ```html 124 | 134 | ``` 135 | We also recommend to use the [g200k webaudio controls](https://github.com/g200kg/webaudio-controls/tree/master/2.0) library in its Web component version to have more custom options. For this you have to add this link on your `main.html` file : 136 | ```html 137 | 138 | ``` 139 | and enable the midi control : 140 | 141 | ```html 142 | 143 | ``` 144 | After that, go to the [knobgalery](https://www.g200kg.com/en/webknobman/gallery.php), choose your knobs and render it with 99 sprites. Put the png file in the WAP assets and add the webaudio element to your template. 145 | 146 | ```html 147 | 148 | ``` 149 | 150 | **When your template is done**, clone it in a webcomponent shadowroot. 151 | 152 | ```js 153 | let lowfiltertemp = document.currentScript.ownerDocument.querySelector('#template-lowpass'); 154 | class PluginNameGui extends HTMLElement { 155 | constructor(plug) { 156 | super(); 157 | // The audio processor is a field of this GUI 158 | this._plug = plug; 159 | // The link is bidirectionnal to be catched by the processor if needed once the module is loaded (for features like presets) 160 | this._plug.gui = this; 161 | // bind shadow to the class and clone the template into it 162 | this._root = this.attachShadow({ mode: 'open' }); 163 | this._root.appendChild(lowfiltertemp.content.cloneNode(true)); 164 | 165 | this.setUp(); 166 | } 167 | ... 168 | } 169 | ``` 170 | **&** bind the GUI with your Audio node setter : 171 | 172 | ```js 173 | setUp(){ 174 | this._root.querySelector("#cutoff").querySelector("input").addEventListener("input", (e)=>{this._plug.setParam("cutoff", e.target.value)}) 175 | } 176 | ``` 177 | **if you choose to use webaudio-knobs**, set the src : 178 | 179 | ```js 180 | this._root.querySelector("#cutoff").querySelector("webaudio-knob").setAttribute('src', this._plug.URL + '/assets/knobFile.png'); 181 | ``` 182 | 183 | **Last** step is to create a function that builds this GUI and registers it (out of the class) : 184 | 185 | ```js 186 | try { 187 | // Define the custom element to the browser 188 | customElements.define('wasabi-myplugin', MyPluginGui); 189 | console.log("Element defined"); 190 | } catch (error) { 191 | console.log(error); 192 | console.log("Element already defined"); 193 | } 194 | /** 195 | * Gui factory, called from the SDK. 196 | * The name must be create+MyModule 197 | */ 198 | createMyPlugin = (plug) => { 199 | let elem = new MyPluginGui(plug); 200 | return elem; 201 | } 202 | ``` 203 | 204 | Now the WAP is ready to be tested. Lets create a HTML file and test this minimal code : 205 | ```html 206 | 207 | 208 | 209 | 210 | Host that loads a plugin with its GUI 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 243 | 244 | 245 | ``` 246 | 247 | You can now affect the audioplayer with your WAP! Congrats! 248 | 249 | ### If you want to submit your WAP, publish it on npm and let us know its name : 250 | 251 | * Create an account on [npmjs](https://www.npmjs.com/signup) 252 | * open a terminal at your WAP root, bind the session by typing `npm login https://www.npmjs.com/~usrname` 253 | * `npm init` and specify your entry point as `main.js` 254 | * `npm publish` 255 | * for the versionning : `npm version patch` 256 | 257 | 258 | -------------------------------------------------------------------------------- /tutorial/lowfilter/assets/myknob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/micbuffa/WebAudioPlugins/2fab2ee55d131aa5de753dc2dd3b3723fbd5b274/tutorial/lowfilter/assets/myknob.png -------------------------------------------------------------------------------- /tutorial/lowfilter/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 59 | -------------------------------------------------------------------------------- /tutorial/lowfilter/main.js: -------------------------------------------------------------------------------- 1 | window.Lowfilter = class Lowfilter extends WebAudioPluginCompositeNode { 2 | 3 | constructor(ctx, URL, options) { 4 | super(ctx, URL, options) 5 | /* ################ API PROPERTIES ############### */ 6 | 7 | this.addParam({ name: 'cutoff', defaultValue: 1500, minValue: 30, maxValue: 2800 }); 8 | this.addParam({name:'resonance',defaultValue: 0.1, minValue: 0, maxValue: 30 }) 9 | super.setup(); 10 | } 11 | 12 | createNodes(){ 13 | this.lpfilter = this.context.createBiquadFilter(); 14 | this.lpfilter.type = "lowpass"; 15 | }; 16 | connectNodes(){ 17 | this._input.connect(this.lpfilter); 18 | this.lpfilter.connect(this._output); 19 | }; 20 | 21 | setParam(key, value) { 22 | try { 23 | this[key] = value; 24 | } catch (error) { 25 | console.warn("this plugin does not implement this param") 26 | } 27 | } 28 | 29 | set cutoff(_value){ 30 | // to store the new value 31 | this.params.cutoff = _value; 32 | // if your param is linked to the filter frequency you can : 33 | this.lpfilter.frequency.setValueAtTime(_value,this.context.currentTime); 34 | 35 | } 36 | 37 | set resonance(_value){ 38 | // to store the new value 39 | this.params.resonance = _value; 40 | // if your param is linked to the filter Q you can : 41 | this.lpfilter.Q.setValueAtTime(_value,this.context.currentTime); 42 | 43 | } 44 | } 45 | 46 | window.WasabiLowfilter = class WasabiLowfilter extends WebAudioPluginFactory { 47 | 48 | constructor(context, baseUrl) { 49 | super(context, baseUrl); 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /tutorial/lowfilter/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "documentation": "...", 3 | "name": "Lowfilter", 4 | "thumbnail": "assets/Lowfilter.png", 5 | "vendor": "Wasabi", 6 | "category":"Filters", 7 | "version": "1.0" 8 | } -------------------------------------------------------------------------------- /tutorial/lowfilter/testLowfilter.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Host that loads a plugin with its GUI 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 38 | 39 | --------------------------------------------------------------------------------