Last active
August 28, 2024 18:57
-
-
Save charlieroberts/4efc0ab599f88a5561d63bc3bc49f882 to your computer and use it in GitHub Desktop.
2-op FM synthesis, beginning with low-frequency oscillation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* ****** low-frequency modulation (vibrato) ****** | |
| This example shows how to use a second oscillator to | |
| modulate the frequency of a oscillator over time. */ | |
| ctx = new AudioContext() | |
| // create our primary oscillator, called the "carrier" | |
| // in frequency modulation terminology (from radio) | |
| carrier = ctx.createOscillator() | |
| carrier.type = 'square' | |
| // create an oscillator for modulation | |
| mod = ctx.createOscillator() | |
| mod.type = 'sine' | |
| // slow oscillation... | |
| mod.frequency.value = .5 | |
| // by default, oscillators output values in the range of {-1,1}. | |
| // To create a wider range we use a gainNode | |
| gainNode = ctx.createGain() | |
| // scale input by 20... {-1,1} becomes {-20,20} | |
| gainNode.gain.value = 20 | |
| // route modulating oscillator into gain node | |
| mod.connect( gainNode ) | |
| // plug the gain node into the frequency of | |
| // our carrier | |
| gainNode.connect( carrier.frequency ) | |
| // connect carrier to master output | |
| carrier.connect( ctx.destination ) | |
| // start both oscillators | |
| mod.start( ctx.currentTime ) | |
| carrier.start( ctx.currentTime ) | |
| /************* classic 2-op FM Synthesis *****************/ | |
| ctx = new AudioContext() | |
| // gong | |
| // const index = .95 | |
| // const cmRatio = 1.4 | |
| // const attack .01 | |
| // const decay = 5 | |
| // bass | |
| // const index = 1 | |
| // const cmRatio = 3 | |
| // const attack = .001 | |
| // const decay = .25 | |
| // glockenspiel | |
| const index = 1 | |
| const cmRatio = 3.5307 | |
| const attack = .01 | |
| const decay = .5 | |
| playNote = function( frequency, duration ) { | |
| // create our primary oscillator | |
| let osc = ctx.createOscillator() | |
| osc.type = 'sine' | |
| osc.frequency.value = frequency | |
| // create an oscillator for modulation | |
| let mod = ctx.createOscillator() | |
| mod.type = 'sine' | |
| // change oscillation speed... | |
| mod.frequency.value = frequency * cmRatio | |
| // this will amplify our modulator | |
| // and control the range of modulation | |
| let modGainNode = ctx.createGain() | |
| modGainNode.gain.value = frequency * index | |
| mod.connect( modGainNode ) | |
| // plug the gain node into the frequency of | |
| // our oscillator | |
| modGainNode.connect( osc.frequency ) | |
| let envelope = ctx.createGain() | |
| envelope.gain.linearRampToValueAtTime( 1, ctx.currentTime + attack ) | |
| envelope.gain.linearRampToValueAtTime( 0, ctx.currentTime + attack + decay ) | |
| osc.connect( envelope ) | |
| envelope.connect( ctx.destination ) | |
| mod.start( ctx.currentTime ) | |
| osc.start( ctx.currentTime ) | |
| // remove the node two seconds from | |
| // the current audio time | |
| osc.stop( ctx.currentTime + duration ) | |
| } | |
| // 220 Hz, 2 seconds | |
| playNote( 880, 2 ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment