Upgrade to Pro — share decks privately, control downloads, hide ads and more …

106js

 106js

Highlighting the features of 106.js, a browser-based emulation of the Roland Juno 106 analog synth.

http://github.com/stevengoldberg/juno106

Steve Goldberg

July 14, 2015
Tweet

More Decks by Steve Goldberg

Other Decks in Technology

Transcript

  1. 106.js Browser-based emulation of the Roland Juno-106 polyphonic analog synthesizer

    Using WebAudio and WebMIDI http://github.com/stevengoldberg/juno106
  2. Juno 106 • Produced 1984–1988 by Roland • Successor to

    Juno 6 and Juno 60, first with MIDI • 6-note polyphony • 1 DCO ft. pulse, saw, square sub, and noise, LFO, ADSR envelope, and 24 dB/oct resonant LPF per voice • HPF and chorus effect
  3. Notable features of 106.js • Authentic voice-stealing • Analog-like dynamic

    envelope behavior • Playable by mouse, keyboard, or MIDI • Patch sharing via URL • Arbitrary mapping of 7- and 14-bit MIDI CCs
  4. Voice stealing • Analog synths have limited polyphony • Digital

    synths are limited only by CPU power • Voice stealing can be musical • Track an array of active voices • Remove a note if the same pitch is triggered • Remove the oldest note when MAX_POLYPHONY is reached • Manage oscillator lifespan with OscillatorNode.onended
  5. Voice Stealing cont'd On a noteOff event, we trigger the

    voice's noteOff() method and listen for the voice to be killed, at which point we remove it from the activeVoices array.
  6. Voice Stealing cont'd The voice's noteOff() method propagates itself down

    to the ENV and DCO, which it keeps synced. The voice triggers an event after all the oscillatorNodes have been stopped.
  7. Voice Stealing cont'd The oscillator.onended callback sends an event when

    the oscillators are stopped. The DCO's noteOff() method takes an optional releaseLength param, so it can kill a note immediately (for stealing), or after a delay (for an envelope release).
  8. Realistic envelopes • Analog synth envelopes respond to changes in

    real-time • Most websynths don't – changes only heard on next note • We can keep track of envelope stage by caching currentTime on note events:
  9. Working with MIDI • The WebMIDI API is super simple

    • Read the spec, it's short and straightforward: www.w3.org/TR/webmidi/ • Use requestMIDIAccess to build an array of MIDI inputs
  10. Handling MIDI messages • Define an onMIDIMessage callback to fire

    whenever a message is received • Now you just need to understand the anatomy of a MIDI message to deal with it appropriately • MIDI manufacturer's assoc. summary: midi.org/techspecs/midimessages.php • Another good resource: indiana.edu/~emusic/etext/MIDI/chapter3_MIDI4.shtml
  11. Notes on MIDI messages • MIDI messages are contained in

    the MIDIMessageEvent.data array and consist of 3 bytes • Status byte, data byte 1, data byte 2 • Status byte tells us which channel and what kind of message • MIDI channels are a way of namespacing MIDI events – 106.js ignores MIDI channel, a.k.a. “Omni mode” • MIDI message types include Note On, Note Off, Control Change (CC), Pitch Bend, Aftertouch, Program Change, Sysex
  12. MIDI Messages cont'd • Sometimes it's easier to deal with

    MIDI message data as binary, sometimes as decimal • A “Note on” message with velocity 0 should be interpreted as a “Note Off” message • 106.js ignores velocity because the Juno 106 wasn't velocity-sensitive
  13. MIDI-mum Maximum • Note messages are easy to deal with:

    First 4 bits of the status byte = Note On or Note off, Data Byte 1 = Note Number, Data Byte 2 = Velocity
  14. L'après-MIDI d'un faune • CCs are a little more complex

    • Some MIDI CCs are defined in the spec, but with modern devices they're essentially arbitrary • A single MIDI message uses 7-bits to represent 0 – 127, but 2 messages can be combined for increased resolution (14-bit MIDI) • Many modern controllers transmit 14-bit MIDI from their knobs or faders • 14-bit MIDI consists of an MSB and an LSB, offset by 32 • To handle 14-bit CCs, we fill a buffer with 2 consecutive messages to determine if it's 7- or 14-bit
  15. Cut out the MIDI-man • “length” data-param is defined on

    UI elements with discrete positions (switches, buttons) so that CCs can properly translate
  16. Everything I need to know about MIDI I learned in

    Kindergarten • When we create a new MIDI assignment, clear the old assignment for that CC, then update localStorage
  17. Patch sharing • To share a patch, we create a

    URL from the serialized synth model
  18. Sharing === Caring • On loading a patch URL, the

    router fires an event with the decoded synth model, then the UI gets updated