I thought it was about time I posted a little update on the progess of my soft synth (which I'm currently calling "Zynth"). Those of you who've been following my previous posts will know that I've based my synth (the GUI at least) on Cakewalk's Z3TA VST Synth. As you can see from the image below, I'm currently using gfx based (ripped) on Z3TA, until I get a chance to make my own:
The shot above shows my VST Test App, which is how I test my Synth without having to load up a VST host (such as Renoise) repeatedly. It's a simple C# app that has the main VST control for my synth embedded in the form (C# WinForm). The keyboard and buttons at the bottom are part of the Test app and don't appear on when the VST is running in a host. I'll probably change that though as the mini keyboard is quite useful when designing patches (instruments). I've ended up writing a few C# components for the GUI for handling this like visualizing wavetables and envelopes and changing the modulation matrix, oh and for the knobs and sliders too. The VST core is written in C# and uses VST.Net. The VST core loads a C# DLL that contains a static synth lib, which is the only bit that'll be included in demos/intros, essentially the repalyer.
Oscillators are forever a work in progress, but I'm getting to where I want to be, albeit slowly. Support for standard waveforms (Sine, Saw, Triangle, Square) works pretty well and I've got a white noise generator available too. Each of these uses a single wavetable (which contains a single period [cycle of the wave] at 0.1hz). To play a specific pitched note, I increase the step size when sampling the wavetable in order to increase pitch. If I wanted to play a note at 0.1hz, I'd play every sample in turn. To increase the pitch, I sample every other sample or every 4th sample etc, which results in higher pitched output. I've also added support for oscillator sync. Oscilator Sync (and Oscillator modes)Oscillator (Hard) Sync
Oscillator Sync allows you to sync the output of one oscillator with another. What this does is cause the slave oscillator to reset when the master oscillator restarts. If both oscillators are tuned the same, you'll hear no effect as both oscillators produce a wave with the same frequency so the wave period for both oscillators starts and stops at the same point. If we were to increase the frequency of the master oscillator however, the period length for the master oscilator would then be shorter than that of the slave oscillator. If you look at the below image and imagine the top wave is the wave from the master oscillator and the bottom wave is the wave from the slave oscillator, this should help you visualize what I mean. As you can see, both oscillators start at full amplitude (let's call this +1.0) and then drop down to min amplitude (let's call this -1.0), and then rise back up to full ampltiude (+1.0 again) before dropping again. This dropping rising is a single period of the wave. With oscillator sync enabled, when the higher frequency master oscillator completes a cycle/period, the lower frequency slave oscillator is only halfway through a cycle because it is half the frequency of the master oscillator (slave has dropped from +1 to -1 while master has dropped from +1 to -1 and risen back up to +1). What happens now is the master oscillator signals to the slave oscillator to reset and the slave oscillator restarts a new cycle/period, regardless of how far through a cycle it was. By changing the frequencies of the master and slave oscillators (by detuning or modulation with an LFO etc), we can produce some very different sounds.Other modes
There are other oscillator modes that are still in progress, such as 'fixed' and 'free'. 'Fixed' mode essentially produces an unpitched waveform, so regardless of which key is pressed on a keyboard, the note played is always the same pitch. This is useful for things such as drum sounds. 'Free' mode effectively makes the oscillator cycle free-running. Usually, when a oscillator is started due to a note-on command (keyboard key pressed), the oscillor will start to generate from the start of a cycle. In 'free' mode, the cycle isn't reset and the waveform cycle just loops up and down constantly in the background regardless of whether the oscillator is actually outputting sound.
Each of the oscillator modes also has an 'inverted' setting, which just inverts the oscillator output. So a value of +1 would become -1 if the oscillator was inverted.PadSynth
One of my initial goals when I started creating the synth was to implement support for PadSynth sounds. If you're not familiar with PadSynth, have a look here
and listen to some of the samples sounds on the page and I'm sure you'll instantly understand the appeal. What the PadSynth algorithm does is produce loopable wavetables that be used for Wavetable Oscillators to produce a wide range of sounds such as choirs, ensembles and organs. Probably the biggest hurdle I had when working on implementing PadSynth was due to the fact that PadSynth requires an IFFT (Inverse Fast Fourier Transform) in order to produce the Wavetables. I won't go into what the PadSynth algorithm does as that's already covered on the website. The demonstration code that comes with the PadSynth algorithm uses the FFTW library to perform the IFFT transforms. The FFTW library weighs in at around 2.5mb, so that wasn't at all practical for a synth that needs to fit nicely inside a 64k intro. After some hacking about I managed to get a small and acceptably fast IFFT implemented that adds ~1.5kb to the compiled output, which is fine in terms of size for now.Implementation
For my PadSynth implementation, I have a constant defined that controls how many PadSynth wavetables there are per octave. Initially, I tried using one large wavetable at a very low frequency played back at different frequencies (for different keyboard notes) by changing the sampling step. If I need to play at twice the frequency, I sample every other value when reading from the wavetable, which produces a higher pitched output. The handle step sizes that aren't integers, I do some interpolation too. While this works fairly well for the standard simple waveforms such as Sine and Square, it sounds ghastly when this technique is used with a PadSynth wavetable. I'm not totally sure why it sounds quite so bad, but I would guess that a lot of the lower harmonics are removed by the resampling and the higher harmonics end up exceeding the Nysquist limit and head off into screechy alias hell. If you're not familiar with the Nyquist frequency, it's the frequency that equals half your sample rate (44100 sample rate has a Nyquist frequency 22050). Any frequencies that fall above the Nyquist frequency will end up folding back to a lower frequency once they hit the Nyquist frequency. So to try and overcome this problem, I generate multiple PadSynth wavtables and sample from the one which has the base frequency closest to the frequency of the note I want to play. This improves things a lot but there is a noticable audiable difference when the wavetable that's being sampled switched as you play notes in sequence (running up or down the keyboard for example). Allowing yet more wavetables so we have several wavetable per octave and less difference in frequency, which goes further to help the problem. I'm still left with the earlier problem of the noticable jumps, but it's better than before. Modulation
One of the cool things you can do with a synth is modulation. This essentially allows you to use the output from something (envelope generator, LFO etc) to alter something else (pitch of oscillator, volume/amplitude of oscillator). For instance, an LFO (low frequency oscillator) produces a wave at a very low frequency (speed) and this output could be used to change the frequency of an oscillator to give it a wobble sound. Another use of modulators and LFOs in particular is to vary something very slowly by having the LFO frequency set very low. This could then slowly change the cut-off for a low pass filter which sounds like someone slowly turning the treble knob on a hi-fi. If you listen to most modern tunes made with a soft-syth such as V2, you can often hear an LFO or evnvelope gate being used to change the cut-off frequncy of a low pass filter. Modulations in Zynth are working quite nicely for the simple waveforms and the only problem I currently have is the modulator output can push the frequency of an Oscillator above the Nyquist limit sometimes. I'm not sure if this is really a problem or something that should be left to the musician so they can tune the modulation by increasing the strength. The real problems start when trying to modulate the PadSynth wavetable oscillators. Those wavetable switches/jumps that I mentioned earlier are really noticable in this instance. I'm still not sure of the best solution, but I'm going to try cross-fading between the wavetable below and the wavetable above the frequency of the note I wish to play. This should either fix the problem or throw another load of awful into the mix.
That's it for now. I've got filters partially implemented (from studying the V2 code), but they're quite buggy and sound nasty at times. I've still not got reverb, echo, delay, chorus or distortion implemented but those should be underway soon. As always, any tips, comment or suggestions most gratefully received :)