Skip to content

Instantly share code, notes, and snippets.

@charlieroberts
Created March 22, 2018 13:27
Show Gist options
  • Select an option

  • Save charlieroberts/4888ecfb2c7f754ec75d3124a1a0ad55 to your computer and use it in GitHub Desktop.

Select an option

Save charlieroberts/4888ecfb2c7f754ec75d3124a1a0ad55 to your computer and use it in GitHub Desktop.
Notes/code from subtractive synthesis lecturer

Show SDF stuff

https://www.youtube.com/watch?v=s8nFqwOho-s http://mercury.sexy/hg_sdf/

1902 Thaddeus Cahill - Teleharmonium

  • first synthetic instrument

    • additive synthesis, like the Hammond organ (b3)
    • transmitted music over phone lines
      • early Musak
    • Mark I: 7 Tons
    • Mark II: 200 Tons
    • $200,000 in 1906 (close to 5 million today)
    • 36 note per octave keyboard (Cahill liked just intonation)
  • Other important digital musical instruments

    • Theremin
    • Buchla vs. Moog

Moog vs. Buchla

  • West Coast vs East Coast
  • Wendy Carlos
    • Switched on Bach
    • Scores for Tron, A Clockwork Orange, The Shining

Subtractive Synthesis

  • Start from waveform rich in overtones / harmonics
  • Emphasize / De-emphasize various frequencies
    • We do this via "filters"
      • Filters are typically high-pass, low-pass, bandpass, or notch
      • Filters also have a Q, or "quality" control, that can emphasize the cutoff frequency
        • On some synthesizers this was called resonance.

Review

An enveloped oscillator with frequency assigned to mouse control:

<!doctype html>
<html lang='en'>
  <body></body>
  <script src='./tonal.min.js'></script>
  <script>
    window.onload = function() {
      const scale = Tonal.Scale.notes( 'c4', 'minor' )
      
      const ctx = new AudioContext()
    
      const playNote = function( frequency, amp, attack, decay ) {
        const osc = ctx.createOscillator()
        osc.type = 'sawtooth'  
        osc.frequency.value = frequency
      
        const gainNode = ctx.createGain()
        gainNode.gain.setValueAtTime( 0, ctx.currentTime )
        gainNode.gain.linearRampToValueAtTime( amp, ctx.currentTime + attack )
        gainNode.gain.linearRampToValueAtTime( 0, ctx.currentTime + attack + decay )        
      
        osc.connect( gainNode )
        gainNode.connect( ctx.destination )
      
        osc.start()
        osc.stop( ctx.currentTime + attack + decay )
      }
      
      window.onclick = evt => {
        //const freq = 100 + (evt.clientY / window.innerHeight) * 1000
        const idx = Math.floor( evt.clientY / window.innerHeight * scale.length )
        const freq = Tonal.freq( scale[ idx ] )
        playNote( freq, evt.clientX / window.innerWidth, .001, .15 )
      }
      
    }
  </script>
</html>

Add a biquad filter

ctx = new AudioContext()

playNote = function( frequency, amp, attack, decay, cutoff, Q ) {
  var osc = ctx.createOscillator()
  osc.type = 'sawtooth'
  osc.frequency.value = frequency
  
  // create gain node to control amplitude
  var gainNode = ctx.createGain()
  gainNode.gain.setValueAtTime( 0, ctx.currentTime )
  gainNode.gain.linearRampToValueAtTime( amp, ctx.currentTime + attack )
  gainNode.gain.linearRampToValueAtTime( 0,   ctx.currentTime + attack + decay )
  
  var filter = ctx.createBiquadFilter()
  filter.type = 'lowpass'
  filter.frequency.value = cutoff
  filter.Q.value = Q
  
  osc.connect( gainNode )
  gainNode.connect( filter )
  filter.connect( ctx.destination )
 
  osc.start()
  osc.stop( ctx.currentTime + attack + decay ) 
}
 
// 220 Hz, .5 amplitude
// 1 second attack, 1 second decay
playNote( 220, .5, 1, 1, 800, 10 )
ctx = new AudioContext()

playNote = function( frequency, amp, attack, decay, cutoff, Q ) {
  var osc = ctx.createOscillator()
  osc.type = 'sawtooth'
  osc.frequency.value = frequency
  
  // create gain node to control amplitude
  var gainNode = ctx.createGain()
  gainNode.gain.setValueAtTime( 0, ctx.currentTime )
  gainNode.gain.linearRampToValueAtTime( amp, ctx.currentTime + attack )
  gainNode.gain.linearRampToValueAtTime( 0,   ctx.currentTime + attack + decay )
  
  var filter = ctx.createBiquadFilter()
  filter.type = 'lowpass'
  filter.frequency.value = 50
  filter.frequency.linearRampToValueAtTime( cutoff, ctx.currentTime + attack )
  filter.frequency.linearRampToValueAtTime( 50, ctx.currentTime + attack + decay )
  filter.Q.value = Q
  
  osc.connect( gainNode )
  gainNode.connect( filter )
  filter.connect( ctx.destination )
 
  osc.start()
  osc.stop( ctx.currentTime + attack + decay ) 
}
 
playNote( 220, .5, .001, .5, 1500, 10 )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment