As said before, my aim was to recreate the Minimoog using webaudio nodes, as close as possible to the original hardware configuration. As a consequence, I needed to make some concessions to the resulting sound. I could have used a few ADSR objects in parallel to overcome annoying glitches and plopping noises, espessialy noticeable on slower systems. But I did'nt because the Minimoog only has a single Adsr. Nor did I use additional filtering to remove the glitches. So no tricks to hide webaudio imperfections. I wil now describe the webaudio components for each subsystem of the simulation.
Just as the original keyboard, the simulation generates a 'voltage' for each key, 1 volts per octave. The key voltage is amplified by a power of 2, added to the value for F0 and applied to the offset of a ConstantSourceNode who is connected to the pitch amplifier. 2 additional CSNodes, one for tune and one for the pitchwheel, are connected to the gain of the pitch amplifier. The pitch amplifier output goes to the oscillator bank and the keyboard voltage follower of the filter. The keyboard has 'low note priority' just as the original.
The oscillator bank contains 3 oscillators, each with a gainnode acting as octave amplifier connected to the frequency input. The input of each octave amplifier is connected to pitch-out. The 3 oscillators are connected to the mixer inputs. PeriodicWaves are used for the special Moog waveforms; reversed sawtooth, sharktooth and narrow pulses.
The Modulation module controls 4 modulation sources; the LFO oscillator, the Noise generator, the output of oscillator 3 and the output of the filter ADSR. According to the Moog specs, the type of noise is not white/pink but pink/red. I used an algorithm for the noise generator that I found on this website, but instead of a ScriptProcessorNode it uses a 2 seconds constant-loop AudioBufferSourceNode. The output of oscillator 3 is fed back to the modulation input trough a delay line. This is neccesary because a direct feedback from the output to it's own frequency input would otherwise disable all the audionodes in the feedbackpath. The 4 modulation sources are then switched to 2 GainNodes, one with normal, the other one with inverted gain, controlled by the modulation mix knob. The final GainNode is controlled by the modulation wheel. The modulaton output is fed to the modulation inputs of the oscillator bank and the pitch circuit.
The mixer has 5 switchable GainNodes for the 5 input sources; 3 oscillators, noise and the external input. The external input is a feedback signal from the final output trough a short delay. Amplifier clipping is simulated by a waveshaper node. Overload indication is accomplished by repeatedly reading the reduction property of a DynamicsCompresssorNode. The final output of the mixer is connected to the filter input. There is an additional noise source allways connected to the mixer output. This produces a tiny bit of noise to replicate the noise produced by analog components. Without it the filter will not start self-generating when the emphasis knob is turned fully clockwise with all sources switched off.
The 24dB/octave filter is made of two lowpass BiquadFilterNodes in series. The Frequency, Q and Detune parameters are interconnected by 3 ConstantSource Nodes. In the diagram the 5 nodes are drawn as 1 block. The ADSR and modulation signals are connected to the filter detune parameter. Modulation of the filter generates unwanted noises, popping sounds, especially on slow systems and with steep adsr curves. This seemed to be less when the modulation was connected to detune than when it was to the frequency parameter. The Filter Adsr is, in contrary to the Contour Adsr, of the retriggerable type, meaning that it is retriggered at every keypress, and not only when a key is released, that does'nt sound very musically. For the sake of glitch-avoiding, the attack is slightly delayed by about 20 milliseconds. I did not use setTargetAtTime for the Adsr transitions but instead used linearRampToValueAtTime with interpolation between values when the ramp curve is interrupted by a retrigger.
The Contour Adsr is a GainNode with a LinearRamp object connected to its gain parameter. The ramp object takes care of a smooth transition between the attack, decay and release stages. It does automatic interpolation of the start and end values when a transition is interrupted. The Contour Adrs is only fully retriggered when a key is released, but not when a new key is pressed before one is released. First of all I dont' think this is necessary, and second, this avoids excessive glitches on slower systems.The final output stage contains a single GainNode for main volume adjustment, a DynamicsCompressorNode necessary to prevent overdriving of the audio destination, and a DelayNode for the feedback signal to the Mixer External Input.