I've been toying with the idea of writing a synth lately. I bought a copy of Musical Applications for Microprocessors many years ago with the intention of writing one for the PS2, but never got round to it. So it's probably time to actually attempt it :)
One of the major shortcomings with 4Klang and V2 seems to be the lack of easy pitch bending functionality. NeriakX seems to miss pitch bends a lot too.
My current idea is a half way house between a true synth and something similar to XM. Using XM for the pattern data and commands but generating the sounds in realtime and feeding them into the playback routing instead of predefined samples. Ideally I'd like to offer the option to precalc sounds or generate in realtime, but that's something to worry about later.
Do you think this approach is workable? I know writing the VST instrument is probably going to be tricky due to the two sources of data (XM for notes, synth for actual sounds) and it's not suitable for Midi, but I think it would be quite nice if I manage it. Not to mention, hopefully fairly easy to jazz up existing XM files.
Any thoughts?
Thanks
Very interesting project/idea - unfortunately I cannot suggest if and how it would work. Would be definately interesting to see how this would turn out - on the other hand - it might be a pretty large project? What amount of time do you plan to invest ?
Are there any tracker code available as open source you could maybe reuse?
Best,
benny!
I'm hoping to use something like renoise for the actual composition as that handles XM and supports VSTI plugins (the synth instruments). I'm hoping someone like Ferris who has created synths before can point out if this is a no go from the outset due to something or other that I may have overlooked or am not aware of.
As for time, I'm not sure how long it would take. I'm willing to invest a fair chunk of time working on it as I think it will be useful if I can pull it off. It seems like a logical and fairly straightforward concept, so there's bound to be some limiting factor or other that I'm not aware of that's stopped others doing something like this before. I can't see it taking a massive amount of time as there are already good resources out there relating to DSP sound generation, and also KBs excellent articles regarding the V2 synth.
I'm trying to get some crazy shader stuff sorted at the moment, but once that's working (or abandoned - eek), this will be my next project.
Sounds definately cool. Sorry that I cannot help - would be cool if some other ppl here could share some information with you.
Good luck, mate!
Thanks Benny! Will keep you posted on progress :)
Sorry I can't help either, but I did want to mention I've got a huge interest in writing a softsynth as well, my housemate (who's into music, and about to start a really interesting music education) keeps telling me I should look into that. I've been reading a lot about the physics of sound and psychoacoustical compression techniques lately, as well as having a lot of interesting discussions about virtual VS analogue synths.
I'll defenatly keep my eyes on this thread as well, hopefully a few more helpfull people will get in here! :)
Cool stuff Kirl. I will probably pick your brains for some theory at some point! :)
Do you do any coding in other languages than action-script? I intend to use C# to start this off (as I'm very familiar with it and find it nice and quick for prototyping) and then port everything over to C/C++ when I'm happy with it. I'd be more than happy for you to have a play around with it once I've got something rough and ready going.
Quote from: Raizor on January 16, 2012One of the major shortcomings with 4Klang and V2 seems to be the lack of easy pitch bending functionality.
I haven't really used any of the two but I don't see why the pitch shouldn't be controlable.
On the other hand you wouldn't do it to save pattern size and use a lfo to control the pitch.
Quote from: Raizor on January 16, 2012My current idea is a half way house between a true synth and something similar to XM. Using XM for the pattern data and commands but generating the sounds in realtime and feeding them into the playback routing instead of predefined samples.
So you're sacrificing to control any other parameter in realtime in favour of pitch.
Quote from: Raizor on January 17, 2012I'm hoping to use something like renoise for the actual composition as that handles XM and supports VSTI plugins (the synth instruments).
Renoise handles XM just as far as loading it.
It uses completely different scales for replay which makes any XM sound very broken.
There is a relatively easy to handle xml interface, though.
QuoteDo you think this approach is workable?
It's basically what they did in Stash (http://www.pouet.net/prod.php?which=3), for example.
The main problem back in the dos days was to switch between different applications (sample-generator and tracker) which is not particularly nice workflow.
Generally I like the idea of combining synthesized and sampled sounds as it gives some interesting possibilities like granular synthesis (http://en.wikipedia.org/wiki/Granular_synthesis).
The difficult thing is to make it usable within a proper user interface.
Thanks Hellfire.
Quote from: hellfire on January 18, 2012
So you're sacrificing to control any other parameter in realtime in favour of pitch.
Hopefully not. If I can feed the sounds generated from the synth straight into the replayer in realtime, I should be able to have the best of both worlds.
Maybe using something like OpenMPT as a base would be a good start for an interface. I'll try and get some nice sounds and then have a look at interface stuff.
I don't see how generating waveforms on the fly gives you the ability to pitch bend. Since static xm files with fixed samples are able to do this, it seems to me that pitch bending is a function of the playback routines and not a function of the samples themselves.
Am I missing an ambition? :)
Jim
A waveform generator is usually just made up of a few oscilators which can easily be tuned up or down, so there's no need to generate a sample.
I don't think tuning the vsti is possible using the typical xm-like effects-column as it just affects the sample player of the tracker.
But you can modify all vsti parameters using the automation panel - have a look here (http://www.youtube.com/watch?v=YxhijSDOo_E).
Quote from: Jim on January 18, 2012
I don't see how generating waveforms on the fly gives you the ability to pitch bend. Since static xm files with fixed samples are able to do this, it seems to me that pitch bending is a function of the playback routines and not a function of the samples themselves.
Am I missing an ambition? :)
Jim
I was planning to feed the samples into the replayer as they're generated and let the replayer take care of pitch bending. Maybe I'm missing something??
Quote from: Raizor on January 17, 2012
Do you do any coding in other languages than action-script? ... I'd be more than happy for you to have a play around with it once I've got something rough and ready going.
I do not have a lot of experience outside of scripting, except for a little bit of J2ME for phones. I've been planning to move to more powerfull languages for a long time as I keep running into limmiting factors. Sound generation is defenatly one of the main things that makes me want to learn other languages. Reading up on the terms and bits of synth theory mentioned here will be interesting to get a better understanding of it all.
Looking forward to play with whatever you'll come up with, good luck! :)
Maybe I can help, too. I've already successfully failed to finish two promising synth designs! ;)
Kirl and Hellfire :)
@Raizor, I also tried to do a synth that way and guess what... I have failed completely :), things like importing a .xm file turned into a nightmare for me. And if you are trying to make small intros (<64k) the xm format isn't good for that.
I did make a synth for 4k intros, and I choose to make my own interface, it was "less painfully" for me than working with existing interfaces, it works like Ferris "sonant", where a song is precalc before playing, not really good for musicians but it's possible to make some "music" with it. ;)
Not forgetting to mention that Hellfire helped me a lot on how to develop a useful interface/features for a musician.
Not knowing anything about music and synth, this thing takes me a lot of time to make it usable. So, a help from a musician will make your life better.
Today I know some people are successfully using a combination of VSTi pluggins + editors like Renoise, like for example Loonies synth, made by BlueBerry (http://www.pouet.net/groups.php?which=442&order=release).
Still I think having your own interface and format is less painfully than having to deal with features not existing/provided on your synth. But of course, either way, it's a hard task.
Ok, to do a synth is *really* hard, but man, when you hear it's first song done, it's one of the most awesome feeling you could have, it's was really great for me, which was really worth all the pain.
Good luck with your project and never give up :)
I have no idea what the state of the art is.
Sounds like people have a tune pattern and use the note values in there to drive oscillators in real time to get the music, whereas I was thinking that you'd use some meta-data to describe some samples (by adding oscillators, noise, etc) and have that generated beforehand, then use a pattern player with as many or as few xm features as you can fit playing like a standard player.
Jim
@RBZ, Thanks for sharing that. I'm still going to give my idea a try and if it fails, I'll rethink a little :) Did Ferris ever release source for his synth? I've seem a javascript conversion of Sonat, so I assume the source is available somewhere. I'd really prefer to avoid making my own interface, but maybe that's going to end up being the only viable option.
@Jim, I'm not 100% sure what's state of the art these days either. It seems most synths for 4k precalc the sounds, whereas V2 generates them on the fly as it plays. I guess the precalc method yields smaller code.
Quote from: Raizor on January 19, 2012
...
@Jim, I'm not 100% sure what's state of the art these days either. It seems most synths for 4k precalc the sounds, whereas V2 generates them on the fly as it plays. I guess the precalc method yields smaller code.
As far as I remember it - I precalculated the sound in Znax3D (http://pouet.net/prod.php?which=30495) and Shameless Plug (http://pouet.net/prod.php?which=30450), rendered it as wav to disk and played it using WinApi. This way I do not had to care about having additional replay routines and it saves CPU power.
Guess this way it works in most of the 4Ks out there - but I am not into that topic any more.
Quote from: Raizor on January 19, 2012It seems most synths for 4k precalc the sounds, whereas V2 generates them on the fly as it plays. I guess the precalc method yields smaller code.
Your musician will be very happy if your stuff is usable without pre-rendering and low-latency, otherwise it's just pain to use it.
Later on you can still do a slower size-optimized version.
If you're heading for 64k it's just annoying to have a minute of sound-precalc just to save a few hundred bytes of code.
Quote from: hellfire on January 19, 2012
...
If you're heading for 64k it's just annoying to have a minute of sound-precalc just to save a few hundred bytes of code.
trve!
I've started working on something along these lines now. Rather than trying to make a soft-synth from the ground up, I'm putting together a tool that will let you load an XM file and replace the samples with synth sounds. The replayer will generate the sounds in realtime and feed them into the replayer. Hopefully, this will provide the flexibility of XM with some nice sounding synth voices. It's early days, so this may well come crashing down around my ears soon ;)
I'm putting together the GUI in managed C++ / C++ .Net; so I can then call the standard C/C++ replayer and synth code easily. Getting managed and unmanaged code to play nicely together has given me quite a headache but I've finally got the two playing reasonably nicely together! I have a Winforms app that lets you load an XM with a file-browser and play it, so I'm getting somewhere...
Not sure how useful the finished product will be but I'm sure to learn a lot during its development. My primary goal at the moment is being able to easily jazz up old XM tunes for use in intros and make them smaller at the same time (due to having no stored samples anymore). Hopefully I'll be able to come up with a friendly GUI that makes it easy to replace the samples with synth sounds (side by side comparison etc). I'm using MiniFmod as a base and will modify that as I go along to fit in the synth stuff.
Ideally I'd like to be able to detect (roughly) the type of sample (drum, hi-hat, lead etc) and auto-generate something similar automatically. This may be a pipe dream though. Hopefully I can at least detect the pitch of the source sample in most cases and match that with the generated synth voice.
I came across Protrekkr earlier which seems to do exactly what my eventual grand plan was (fasttracker style app with in-built synth), which looks very nice if a little confusing.
Anyway, enough rambling for now :)
raizor
Sounds awesome, looking forward to it!
You're a brave man. :)
Quote from: Raizor on February 05, 2012
I'm putting together a tool that will let you load an XM file and replace the samples with synth sounds.
I seriously doubt that's a good workflow.
If you want to keep it simple, just export the generated sounds to wav.
So your muisican can import them into his favourite tracker and work with them.
Quote from: hellfire on February 06, 2012
Quote from: Raizor on February 05, 2012
I'm putting together a tool that will let you load an XM file and replace the samples with synth sounds.
I seriously doubt that's a good workflow.
If you want to keep it simple, just export the generated sounds to wav.
So your muisican can import them into his favourite tracker and work with them.
It would be a pretty horrible workflow for a musician to compose with for sure. This is just for me to play with using existing XM files, rather than for composing new ones.
OK, I concede that the XM idea is a bit crazy, especially as a first project in this area.
I've started putting together my first synth, which is going ok so far. I've got oscillators in place, generating all the basic waveforms (and noise).
I plan to have a voice pool (initially 32 voices) and a 16 channels. Oscillators and effects willbe available in a fixed stack (3 oscillators with optional ring mod and master/slave setup). I think making a flexible stack system is probably asking for trouble at the moment, but that can always be added later. I'm writing the synth in c# initially and will write a replayer in c++ eventually. This makes knocking up the GUI fairly straightforward and it should be possible to wrap it up in a VSTI eventually...
I'm not overly concerned with size as I doubt this will compact enough for 4k use.
I have a few questions that hopefully someone with some experience or musical knowledge might know the answer to:
For handling polyphony, is this normally done per channel? I.e. instrument X can only play 2 instances per channel, or is it a free for all until the voice pool is full?
For detuning, how granular should the detune amount be? Is a semitone enough? I've seen some synth patches mentioning detuning by cents (1/100 of an octave). Kb's synth allows detuning from -64 to 63, which to me seems a little weird as I have no idea of the size of these steps (maybe a semitone??)
Are channel effects the norm? I'd like to have effects per channel as well as per patch or globally. This would allow some nice mod/xm style effects (hopefully). For triggering these effects I'm hoping to use unused midi channel commands (or existing ones if they fit). I've not had a chance to read up on midi commands yet, so I don't know if this is a bad idea yet.
Any comments or tips would be great :)
Quote from: Raizor on February 20, 2012
For handling polyphony, is this normally done per channel? I.e. instrument X can only play 2 instances per channel, or is it a free for all until the voice pool is full?
What you call "channels" are probably multi-timbral instances of the same synth?
In that case you'd limit polyphony per instance, it's sometimes desirable to run one voice monophonic and another one polyphonic.
QuoteFor detuning, how granular should the detune amount be? Is a semitone enough?
You'd usual split this into fine-tune (eg +/- 1 semitone) and pitch (eg to run one osci an octave lower than the other).
QuoteKb's synth allows detuning from -64 to 63, which to me seems a little weird
That's because midi allows values between 0 and 127.
QuoteI'd like to have effects per channel as well as per patch or globally.
There're usually effects per voice and global (for mastering track volume).
Thanks Hellfire. I'm thinking of channels in the tracker sense. Maybe that mindset isn't the right one here. In a VSTI, each channel being an instance of the synth makes perfect sense. My desire for channels is really just to group effects such as pitch bend or distortion. Having the lead playing in channel #1 with a phase effect for example. Maybe I'm missing something or overcooking this?
I've been making some reasonable progress on this but I'm a bit confused about AUX buffers. A lot of synths seem to use them but I can't find any real details on their purpose or how they work. Does anyone have any info please?
This should help you out :) (http://www.mediacollege.com/audio/mixer/auxiliary-channels.html)
Great Ferris, thanks :)
K++
Before I head too far down the wrong path. I just wanted to get some ideas/thoughts on layout and structure for the components within a patch/instrument.
Currently, I have a single stack system, that allows you do drop components (oscillator, envelope etc) on top of each other. The signal passes down the stack, through the components and is then mixed with the global output at the end like so:
[OSC 1]
|
[OSC 2]
|
[ENV 1]
|
[ OUT ]
I'm wondering if this is going to be flexible enough. I plan to allow LFO's and other modulators to be dropped in set to control parameters for other components that will be linked to the LFO (i.e. link LFO to Oscillator 1 volume or panning). Do you think I should allow different processing streams within a patch and allow the outputs to be mixed? for example:
[OSC 1] [OSC 2]
| |
[DELAY] [DISTORTION]
\ /
\ /
\___/
|
[ENV 1]
|
[ OUT ]
I think this will make the synth much more flexible, I'm just wondering if the pain is worth the gain. Coming up with a nice GUI for example 2 is going to more work :)
I'm also wondering if patches should take the output of another patch as input. So I could have a patch called "Synth 1" that is a nice clean synth voice and then have a patch called "Synth 2" which takes the output from "Synth 1" and adds delay or some other effects to it. Is this worth investigating/implementing?
Thanks
In my later 4k synth I had a basic stack scheme you showed in your first diagram, but one crucial addition was a mixer device that would mix the output of two stacks together. This made it MUCH more flexible, but again, this was in a 4k synth and there are much smarter ways to do this for a full-sized thing :) . One idea that's used in Reason is the Spider Audio Merger/Splitter; it's literally exactly what it sounds like (the highlighted device in this pic):
(http://d3vvl31cy8gagb.cloudfront.net/326_combinator/1c.jpg)
There's also a variant in Reason for CV signals. In more standard DAW's, however, you often have the concept of sends/busses. A bus is basically a signal path and a send is a routing assignment to direct signal to that path. I would make a better screenshot for you in Reaper if I had it installed on this machine, but since I don't, here's an old screenshot:
(http://dl.dropbox.com/u/4646373/saturday.png)
here each mixer channel you see represents either an original audio signal or a bus (in Reaper both are just tracks). There's a small I/O box on each as you can see; the ones with "snd" highlighted means they have output going to a bus other than the "master" which is their usual output (which either goes to the actual master or their parent track; another feature in Reaper), and the ones with "rcv" means that they're receiving one or more input signals from another track.
Implementation-wise, this would be pretty straightforward; each signal or bus could just be a Channel (or Track in Reaper terms) object with a Parent field. If the Parent is null, the output goes to the main mixing bus; else the main output goes to the channel's parent (this sort of routing is something I often use for drums so you would have volume/fx control per percussion sound and another volume/fx control for the ensemble). There would also be a global list of Send objects, where a Send object could simply contain two Channel references (representing the source and destination respectively) and the volume for this send. So, each sample/synth buffer iteration all of the Channels would take input from all of the other Channels that are sending them input, mix them together, and produce their own output. To reduce inter-Channel latency, a simple pass could be performed whenever routing is changed to figure out the order in which devices should be calculated. This could be a recursive algorithm where you simply visit each bus sending output to the main bus, and for each of these you then visit the Channels they're receiving input from. The visitation order is then the reverse of the order the machines should be calculated in (note that if a device has already been visited, it is ignored upon revisitation). If you have loops in the send/receive routing, this would still incur some latency, but that's a rare special case that should be avoided by the user anyways.
As far as the patches goes; I would recommend each Channel to simply have a linear list of devices to work from, just as you showed in your first diagram. Then, you could serialize the devices and their parameters as patches per channel; this is also how it's done in Reaper and how it could work in your system. Not exactly the same functionality as you mentioned, but it could be a nice alternative :)
This post kinda turned into a rant about how my next synth will work, haha :P Man, I love this stuff... anyways, hope my blabbering helps; please let me know if some of this doesn't make sense :)
Thanks for the in-depth response Ferris. I should probably study Reason and Reaper a bit to get some more ideas.
"There's also a variant in Reason for CV signals"
What's a CV signal btw?
I'll need to read that a couple more times to get my head around it properly. I'm still a bit confused by the last part.
CV stands for Control Voltage; a pretty "vintage" term for parameter signals that's still in use :) Things like parameter automation and LFO's would be CV signals.
perhaps a point of interrest:
http://www.dbfinteractive.com/forum/index.php?topic=5623.0
Thanks Energy. Will have a read through the source and see if I can make any sense of it.
I'm still making steady progress (which is kinda nice). I've just finished implementing resonant filters (high pass, low pass, band pass and notch) which seems to work quite well (after a good few hours chasing my tail due to silly coding mistake).
I'm still using a linear stack for patch components and still mulling over the best way to handle mixing within a patch. My current thinking is to have an AuxA and AuX buffer per voice (as well as a standard output buffer for voice that gets mixed into the main mix with all the other voices as the final buffer is prepared).
My idea is to allow a mixer component in the stack to take inputs from the main voice buffer and also the Aux A and Aux B buffers for the voice. This way, if your doing some chorus effect (or whatever) you can chuck a mixer into the stack before the chorus and then have the mixer spit out the signal to the main voice buffer and an Aux buffer to. The chorus component can then dirty up the main voice buffer. I'd then have another mixer in the stack below the chorus that takes the dirty chorus signal (from the main buffer) and the cleaner (pre-chorus) signal from Aux and then mix them and output them back to the main voice buffer. This would allow me to do a nice dry/wet mix of the chorus output and the clean signal before it hit the chorus. I'm not sure if that makes sense, but it seems logical to me. My only concern would be processing overhead with the additional steps for the mixing...
The spider route might be better, but the above approach keeps all signals linear (no backwards processing up the stack, which it seems a spider approach would do).
Any comments or suggestions gratefully received :)
@Raizor: here some synths that might interest you:
Quiver (VSTi):
http://straightarrow.dk/quiver/
Sunvox (Full tracker):
http://www.warmplace.ru/
It's useful to see which features they use, might help you designing your own.
For me, I'm going to re-code my little synth attempt, while trying to fix some (lots of) design mistakes and keeping some few good ones. :)
@rbz
Thanks for the links! K++
SunVox looks pretty damn swish! Lovely looking interface. I'd need to delve into WPF to get something looking anywhere near as nice as that.
I'd be interested in seeing your old synth, if you don't mind or maybe just a screenshot for curiousity's sake :)
Quiver led me to a link that's very interesting. The PadSynth oscillator (http://zynaddsubfx.sourceforge.net/doc/PADsynth/PADsynth.htm). Looks like a great wavetable generator and sounds really lovely. Something to investigate for sure.
Also, I grabbed a copy of this book (http://www.amazon.co.uk/BasicSynth-Daniel-Mitchell/dp/0557022126/ref=pd_sim_b_13) from Amazon today. Hopefully it will arrive tomorrow. It looks very useful.
Great to hear you're making good progress, keep it up! Looks like a really interesting book as well!
Bunch of cool links in this thread too! :cheers:
On the subject of cool links, here's a list (http://www.soundonsound.com/sos/allsynthsecrets.htm) of all Synth Secrets articles from Sound on Sound. Not really related to coding but they cover loads of synth theory and explain how lots of components work. I've leaned a ton reading through them.
Quote from: Raizor on March 06, 2012
On the subject of cool links, here's a list (http://www.soundonsound.com/sos/allsynthsecrets.htm) of all Synth Secrets articles from Sound on Sound. Not really related to coding but they cover loads of synth theory and explain how lots of components work.
Although the series doesn't address coders in the first place, it conveys a very good understanding of creating sounds that are musically useful.
This is absolutely essential and especially useful for coders who never touched an actual synth or even instrument before.
That's why I already linked it 3 years ago (http://www.dbfinteractive.com/forum/index.php?topic=3861.msg52071#msg52071) :)
Do you have an approach for anti-aliasing yet?
Quote from: hellfire on March 06, 2012
Do you have an approach for anti-aliasing yet?
Not touched on that at all yet Hellfire. Any tips? I take it that it's not as simple as working at a higher sample-rate and downsampling during mixing?
Quote from: Raizor on March 06, 2012Not touched on that at all yet Hellfire. Any tips?
I take it that it's not as simple as working at a higher sample-rate and downsampling during mixing?
Proper anti-aliasing is essential for a synth, otherwise it will just sound like crap when playing higher notes.
There are several possible approaches, each has its pro and cons.
Probably the easiest way is a global oversampling factor with a lowpass filter.
Since the harmonics of your source-waveforms are falling off rather slowly (and you want to keep most of the audible spectrum), you'd need quite a large oversampling factor to cover the worst cases.
But other parts of your signal route might need no oversampling at all.
So another option is to oversample each generator as much as it requires.
If you're generating a sawtooth at 50hz, at 20khz it's fallen to 1/400 and you don't have to care much.
With the low-pass included into the oscilator you have an additional option to control its' timbre.
On the other hand you will usually put some kind of lowpass after the oscilator section anyway.
But all the oversampling is just trying to compensate errors which are already present.
So it makes perfectly sense to generate wave-forms which don't contain frequency beyond the audible range in the first place.
It's computationally a little bit heavy to run hundreds of sine oscilators to generate a saw, though.
So you'd need a bit of precalc, eg generate a wavetable for every note and interpolate for the frequencies in between.
This solves some problems but involves new ones, for example syncing oscilators or changing pitch quickly (frequency modulation).
Of course that can be solved, too. Since the band-limited and non-limited waveforms only differ significantly at level-jumps, you can just store the difference between the two wave-forms (commonly called minbleps) and mix that piece of sound into your non-bandlimited waveform.
Although this sounds nice and simple it's quite some trouble to fade the blep before the next phase-jump happens.
So after all there's no approach which works particularly well in all scenarios.
Great info Hellfire, thanks very much. K++
Which of the methods would you most likely use, or would that depend on the specific scenario?
As I'm progressing, pre-calc for at least some things is seeming more and more likely. Especially after hearing the lovely sounds that come with using pre-calculated wave tables. I'll do some info hunting and reading on the approaches you mentioned.
In regard to a low-pass filter inside the oscillator, is this the norm? Looking at V2 the other day, I could see no other obvious way of implementing the "color" slider for an oscillator, so this definitely seems like something to add.
Reading through example for wave table generation, they seem to FFT (or IFFT) a lot. Is this a good idea or would it add too much overhead (in terms of code size for the replayer). Just wondering if there's a cheaper alternative that sounds comparable.
Quote from: Raizor on March 06, 2012
In regard to a low-pass filter inside the oscillator, is this the norm? Looking at V2 the other day, I could see no other obvious way of implementing the "color" slider for an oscillator, so this definitely seems like something to add.
I think in v2 the color attribute morphs between saw- and triangle-wave (and something comparable for the other wave-forms).
For sine waves you can morph to sin^2 or something like that.
QuoteReading through example for wave table generation, they seem to FFT (or IFFT) a lot. Is this a good idea or would it add too much overhead.
If you use a naive radix-2 fft the code is very simple.
To precalc a wave-table for every note using additive synthesis, you can simply upsample the note from one octave above and just add the missing harmonic.
Thanks Hellfire.
Quote from: Kirl on March 06, 2012
Great to hear you're making good progress, keep it up! Looks like a really interesting book as well!
Bunch of cool links in this thread too! :cheers:
Book just arrived. Had a quick scan and it looks fantastic. Loads of great info in there.
I started rolling everything up into a managed C# VSTI last night. So far, so good :)
I've got myself into a bit of a confused pickle in terms of voices and patch instances and could do with a little advice if possible.
At present I have a separate instance of each patch per voice. For example, if I have 10 voices and 2 patches, each of the 10 voices will have its own copy of each of the 2 patches. This seemed to make sense initially as a lot of the patch components need per-instance settings for internal time and setting values. The only logical way I could overcome this was to have a unique instance of each patch per voice. Otherwise, if I just use a reference to a single global patch within the voice, the voices screw up the patch settings as each voice is played (voice 1 increments patch time when played, then voice 2 starts to play the patch time and further increments the patch time etc).
When i edit a patch in the GUI, I update the associated patch instance for each of the voices to keep everything in sync.
As I'm coming to implement LFOs and other items that modulate other parameters for patch components, things are starting to get quite messy. I wondering if there's a more elegant solution? I considered the idea of having a patch and its variable parameters stored separately, with a unique instance of a set of patch parameters per voice and a single instance of the actual patch which the voice would provide its parameter set to when using the patch.
Hopefully this makes sense, sorry if it's a bit unclear.
Any suggestions would be great. Thank you.
EDIT: It's ok, I figured it out. I decided to have a separate param object that each patch component can contain instances of. Each param instance has an array of values (one value per voice) so I can track the state of each voice individually while still only needing one global instance of a patch object. So far, this is working well. As an aside, the Basic Synth book I mentioned before is excellent. It covers loads of stuff including the wavetable interpolation that Hellfire mentioned before. A great book for anyone attempting a synth :)
Still making progress with this but it's a little slow due to having what seems like a never ending head cold :|
I'm still trying to get my LFOs working properly. In case anyone is reading this and is not sure what an LFO (low frequency oscillator) is, I'll try and briefly explain.
Imagine you have a stack of various controls to make up a synth patch (instrument). Let's take a wave oscillator as an example. The wave oscillator generates a constant tone (sine, saw wave etc) and when its output is played, results in a continuous tone (beeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee etc). The wave oscillator takes a note (midi note number corresponding to a particular pitch/frequency) or frequency as input and this controls pitch of the sound that comes out of the wave oscillator. It's common to have some sliders or knobs on the wave oscillator control to control things such as output volume or modify the frequency by a certain amount. This is all well and good and allows you to twiddle the knobs or slide the sliders to change the sound. However, to make things more interesting, we'd like these knobs to twiddle themselves by a certain amount over time and for this we need an LFO.
An LFO is similar to the wave oscillators we use to generate the wave sounds, except that it operates at a much lower frequency (typically below 10hz and rarely above 20hz). The lower the frequency, the slower the output values change over time. So an LFO with its frequency set low generates a slowly undulating wave. If we go back to our wave oscillator and imagine the volume knob has a float parameter to represent volume in the range 0 to 1, we can use the output from the LFO to modify the volume parameter and have the same effect as manually twiddling the volume knob. As the LFO output wave drops, the volume drops down and increases back up as the LFO wave rises again. This gives us a nice means of controlling parameters automatically. We can even use one LFO to modify the parameters of another for all sorts of crazy sounds.
Anyway, my implementation uses a buffer to store the output from the LFO. If an item parameter (such as wave oscillator volume) is linked to the LFO, it reads values from the LFO output buffer to modify the volume. This works nicely apart from the fact that the LFO output buffer can be shared by multiple parameters. When a voice plays, the values in the LFO buffer will not be the same for each voice, which sounds a bit crappy. For example, if I have an LFO and a wave oscillator that uses the LFO values to control frequency change, when voice 1 starts the values in the LFO are such that the pitch increases. Now if another voice starts playing shortly after, the LFO wave could be on a down slope resulting in this voice starting with its pitch decreasing. I'm trying to get round the issue without having to store more than one output buffer for the LFO if possible. If anyone has any advice or if I've approached this the wrong way, I'd appreciate some tips.
Apologies for typos, using my iPad, which is awful for typing (is it too much to ask for virtual cursor keys instead of a crazy magnifying glass?!? :)
Thanks
Raizor
EDIT: I think I'm going to give wavewables for LFO samples a go. Seems to make the most sense, and I need to get that sorted for other stuff (wavetables for sound generation etc).
You need to separate the data in the buffer from the playback. Effectively each playback item needs its own pointer into the data.
Or, is the problem that the buffer data has changed due to time elapsing?
Jim
@Jim
Thanks for the response. The buffer data isn't changing, it's the different time index per voice that was the problem.
I seem to have a solution though. I'm pre-generating a wave buffer at 1hz and then using the current sample index for the oscillator buffer to index into the pre-generated buffer. If I multiply the sample index from the oscillator buffer by the desired frequency and then modulus against the pre-generated buffer length, I get the correct sine (or whatever) value from the pre-generated buffer - almost for free :) It seems to work surprisingly well and with a little bit of interpolation, should solve a lot of my problems.
As an aside, what's the correct term when you use modulus? Above I said "modulus against" but I'm not sure of the correct terminology.
A keypress event usually triggers a reset the lfo's phase (just as it resets the oscilators and volume envolpe).
There's usually an option to enable/disable such triggers.
Thanks Hellfire, that's handy info.
One nice thing about LFOs is that you don't have to evaluate them per sample.
You're probably mixing at some granularity, let's say 64 or 128 samples at each time.
So you can fetch your lfo output at the start and end of your block and interpolate them linearly.
The interpolation of all parameters is essential to avoid discontinuities.
Quote from: hellfire on March 26, 2012
One nice thing about LFOs is that you don't have to evaluate them per sample.
You're probably mixing at some granularity, let's say 64 or 128 samples at each time.
So you can fetch your lfo output at the start and end of your block and interpolate them linearly.
The interpolation of all parameters is essential to avoid discontinuities.
Thanks Hellfire. I am sort of evaluating my LFOs per sample at present (using a wavetable). It seems to work quite well, but your approach might give me a performance boost. I hit a few snags with the wavetables, which I seem to have overcome now. Once I've got it broken down even further (separate tables per octave/semitone), I'll write some notes here as they may be useful to someone else in the future.
One thing that's been causing me problems is ring modulation. From what I understand, I should multiply the samples of two oscillators together to ring modulate them. Is that correct? I seemed to end up with just really weak and quiet output when trying that.
I've also been looking at other vst synths for some inspiration (especially for GUI design). Cakewalk Z3ta really blew my socks off. Some lovely features in there, especially the mini pattern editor allowing little patterns within the patch :)
Make sure to look at how Massive does its modulation routing GUI. It's s00per simple and intuitive :)
Quote from: Raizor on March 26, 2012
One thing that's been causing me problems is ring modulation. From what I understand, I should multiply the samples of two oscillators together to ring modulate them. Is that correct? I seemed to end up with just really weak and quiet output when trying that.
The output of ring modulation contains sum and difference of the original frequencies (thus making your signal wider).
So your oscillators need proper tuning to produce harmonic output or you'll just hear noise (which can still be useful for percussions).
To make the sound more interesting you should try to apply the ring-modulation after (resonant) filtering (there's a sound example over here (http://sequencer.de/synth/images/c/c6/PostfilterRM.mp3)).
Quote from: Ferris on March 26, 2012
Make sure to look at how Massive does its modulation routing GUI. It's s00per simple and intuitive :)
Will do Ferris, thanks.
Quote from: hellfire on March 26, 2012
Quote from: Raizor on March 26, 2012
One thing that's been causing me problems is ring modulation. From what I understand, I should multiply the samples of two oscillators together to ring modulate them. Is that correct? I seemed to end up with just really weak and quiet output when trying that.
The output of ring modulation contains sum and difference of the original frequencies (thus making your signal wider).
So your oscillators need proper tuning to produce harmonic output or you'll just hear noise (which can still be useful for percussions).
To make the sound more interesting you should try to apply the ring-modulation after (resonant) filtering (there's a sound example over here (http://sequencer.de/synth/images/c/c6/PostfilterRM.mp3)).
Sorry Hellfire, I'm still lost. What do you mean by "proper tuning" please?
QuoteWhat do you mean by "proper tuning" please?
Let's assume you have two oscillators and each is able to generate some frequency.
But you can only specify a single base frequency by pressing a note on your keyboard.
So each oscillator must have some kind of detuning parameter to specify it's actual frequency.
If your oscis produce sines at the frequencies m and c, the modulated output will contain the frequencies m-c and m+c.
So you have to pick m and c carefully to make this sound musically useful, especially if you're using waveform with rich harmonics like saw or pulse.
Quote from: hellfire on March 26, 2012
QuoteWhat do you mean by "proper tuning" please?
Let's assume you have two oscillators and each is able to generate some frequency.
But you can only specify a single base frequency by pressing a note on your keyboard.
So each oscillator must have some kind of detuning parameter to specify it's actual frequency.
If your oscis produce sines at the frequencies m and c, the modulated output will contain the frequencies m-c and m+c.
So you have to pick m and c carefully to make this sound musically useful, especially if you're using waveform with rich harmonics like saw or pulse.
Ah, that makes sense now. Thanks Hellfire.
On the subject of GUIs, what do these big companies use to make their nice interfaces? I mean in terms of graphics libraries, I assume it's not all done by hand. I've never done any GUI work in C++ before, save for a few Win32 dialogs.
I'd actually be willing to bet it IS done by hand; I think each of the big guys use an internal library maintained in house.
GUI systems are a bitch to make mainly because they're tedious (simply a lot they need to do to be properly functional) but their actual design is pretty straightforward, given you use a typical event-driven system (if this event happens in this widget's area, call widget's event handler where widget gets focused and captures input etc etc).
Quote from: Ferris on March 26, 2012
I'd actually be willing to bet it IS done by hand; I think each of the big guys use an internal library maintained in house.
GUI systems are a bitch to make mainly because they're tedious (simply a lot they need to do to be properly functional) but their actual design is pretty straightforward, given you use a typical event-driven system (if this event happens in this widget's area, call widget's event handler where widget gets focused and captures input etc etc).
Ouch. Sounds like a real time sink.
I'm now putting together my modulation matrix design, which I've based on the modulation matrix in Z3TA (I love Z3TA).
I just wanted to check that my idea of how modulations should affect parameters are along the right lines. I couldn't find any relevant info, so I've made a lot of assumptions, which could well be very wrong.
When my LFO is modulating the frequency of an oscillator, I use the LFO value to alter the input frequency of the oscillator. My LFO produces values in the -1 to +1 range and I use this value to alter frequency like so:
Freq = Freq + (Freq * LFO_VALUE)
As the LFO value is in the range -1 to +1, this seems to work quite well.
If I'm using a depth/strength setting on the LFO, this becomes:
Freq = Freq + (Freq * LFO_VALUE * DEPTH)
Is this a sensible way to handle things?
I haven't yet got envelopes modulating anything except oscillator volume/amplitude, but I'd like them to be able to modulate pretty much anything an LFO can. To this effect, I was thinking of approaching this in a similar way to the LFO method above, and having ENV_VALUE replace LFO_VALUE in the above equation. Would that also be sensible?
I also plan to have both unipolar (0 to +1) as well as bipolar (-1 to +1) modes for the modulators.
Many thanks,
Raizor
Seems like you're on the right track. The only important things I've really noticed when working with LFO's in synths is that 1. You're adding the lfo's value to the preexisting parameter value (as you're doing here; even though the range is modified by the preexisting value), and 2. If you at all have high and low bounds for the parameter, these are enforced AFTER the lfo has been applied.
Thanks Ferris
Quote from: Raizor on April 01, 2012Freq = Freq + (Freq * LFO_VALUE)
I don't think this will work really well.
If your lfo is oscillating between -0.5..+0.5 your frequency will change between 0.5..1.5 - which is one octave down but only 7 semitones up...
Quote from: hellfire on April 02, 2012
Quote from: Raizor on April 01, 2012Freq = Freq + (Freq * LFO_VALUE)
I don't think this will work really well.
If your lfo is oscillating between -0.5..+0.5 your frequency will change between 0.5..1.5 - which is one octave down but only 7 semitones up...
Hmm, any suggestions on a better way Hellfire?
Simply apply the modulation on the "note":
frequency = note2freq( note + tune + modulations );
I'll give that a try, thanks Hellfire.
I've decided to do everything in C++ now.
Initially I had the synth in a C# DLL wrapped up in a C# VST and planned to rewrite the synth in C++ for the replayer. This was crazy...
I then decided to write the core synth in C++ and have it referenced as a lib by a managed C++ DLL that the C# VST referenced. This was also crazy...
Now I've bitten the bullet and am using VSTGUI from the VST SDK (2.4 atm) to create a single DLL VST. The synth core is still in a C++ lib in a separate project. It's going to be a bit more fiddly this way, but cleaner. Setting up the VST SDK project was a bit of a nightmare. Thankfully, after a bit of hunting I came across this nice Vibrato plugin (http://samharman.com/2010/11/c-vst-vibrato-plugin/), which I've used as a template. Bear in mind that this plugin is an Effect plugin, rather than an Instrument plugin. The VST SDK does come with a Synth plugin template that you can use to see how an Instrument plugin is put together. I studied this and modified the vibrato template to come up with a working solution. You can find the Synth sample in the SDK: vstsdk2.4\public.sdk\samples\vst2.x\vstxsynth\
You need to register on the Steinberg site to download the SDK. However, it's included (v2.4) in the Vibrato plugin download link above.
The default stuff in VSTGUI looks a bit crap. I found something that looks very promising called KnobMan (http://www.g200kg.com/en/software/knobman.html) (hehe). This looks really useful for making nice controls for your synth. There are some great sample knobs on the site too.
Once I've got something halfway decent up and running, I'll post my project here as it might be useful for others getting started with this stuff.
I'm using v2.4 of the VST SDK as opposed to v3.x as it sounds like there are a number of changes in architecture, that while very neat make compatibility with old VST hosts a problem. I may have the wrong end of the stick here, but that's the impression I've got from reading so far...
Excellent, I love this thread as you do a great job explaining your decisions throughout the process. I enjoyed following your progress and it should be a really usefull source of info if I'll ever venture this far into it.
Good luck! :)
Meanwhile I've rephrased my own wild plans from "writing a simple synth" to a somewhat more realistic "fiddling with pitch and distortions and such"... ;D
Thanks Kirl :)
Quote from: Kirl on April 14, 2012
Meanwhile I've rephrased my own wild plans from "writing a simple synth" to a somewhat more realistic "fiddling with pitch and distortions and such"... ;D
That sounds like a synth to me, just need to fiddle with the pitch according to note input :) What language are you using?
After some time playing with VstGUI, I've canned that idea and taken a few steps back. Making nice, usable GUI controls with it proved to be quite a pain, so I've gone back to using a C# front-end for the GUI of the VST plugin with a simple managed C++ layer that lets the GUI talk to the underlying synth (which still lives in an unmanaged C/C++ lib).
A quck question for you C/C++ gurus, if you don't mind. I started converting the core synth from C++ to C with the thinking that it would likely produce smaller code that I would have more control over. The C++ version uses some template classes, which I feel (from reading) may introduce some bloat in terms of eventual filesize. Is this likely to be the case? I also figured that with things in C, it would be easier to optimize at a later date if I choose to convert part of all of the underlying code to ASM. Coding it in C is certainly slower in terms of development, so if the advantages to this approach are minimal (or non-existent), I'll stick with C++.
I've also given up on the idea of making the synth stack based and have changed to having a fixed set of components per patch (which can be turned on or off). Seeing as this is my first attempt at a soft synth, this should make the project a lot less complex in terms of development and keep the interface simple for any musicians.
In terms of new functionality, there hasn't been a lot of progress due to all the chopping and changing. I've got some ideas for features that should make the synth unique though. I'm going to add the ability to use samples from GM.DLS, which should provide some half decent percussion sounds that can be jazzed up by the synth.
That's about it for now :)
Quote from: Raizor on May 11, 2012I started converting the core synth from C++ to C with the thinking that it would likely produce smaller code that I would have more control over. The C++ version uses some template classes, which I feel (from reading) may introduce some bloat in terms of eventual filesize.
Every instance of a new template type leads to duplicated code.
It doesn't make sense to avoid all C++ features, though.
Actually you can avoid most templating by using a clever class hierarchy.
Eg. you can use a common interface for all generators and filters.
Recreating such structures in plain C is pretty annoying.
QuoteI'm going to add the ability to use samples from GM.DLS, which should provide some half decent percussion sounds that can be jazzed up by the synth.
You can also use the loopable part of each sample as an oscilator waveform.
Thanks for the input Hellfire, much appreciated.
I've been deep in the land of annoying structure recreation, so I probably will go with a mix of C++ and C. All my components and parameters contain an instance of a base parameter or component structure, which should keep things a little smaller. I've written out all the template stuff too, so most of the painful refactoring is out of the way for now.
The loopable gm.dls sample portion as a waveform sounds like a great idea. I still need to dig into the gm.dls format to get up to speed. Do you know if the loopable sections are marked in the file? Hopefully I can parse that information if so.
Thanks again.
Quote from: Raizor on May 11, 2012
Do you know if the loopable sections are marked in the file?
Sure. Parsing dls is very simple:
for each sample
find "fmt "
find "wsmp"
- 5th dword tells if the instrument has looping
- 8th dword tells how many samples the loop range has (from the end of the sample data)
find "data"
- sample data starts here
I also have a question about vsti's. How are non-automatable param's set up, and how does midi-interaction work? What sort of methods do you implement for these? (sure this stuff is probably easy to find but it's even easier to ask :) )
I'm using VST.Net (http://vstnet.codeplex.com/) to take care of all that for me :)
I didn't dig too far into the VST SDK from Steinberg, but it looked pretty similar. In my case, VST.Net provides me with midi events (note on, note off etc) which I pass on to my synth. As far for automatable params, that's just a flag in VST.Net to expose params externally.
I'm having some trouble getting my head around using one wavetable oscillator to act as a frequency modulator for another oscillator and wonder if anyone can share some insight please? I've been hunting around and reading various things but I'm still not clear on the concept. My oscillators fill a float buffer with values in the -1 to +1 range. How would I go about using the output of one oscillator to FM another? Maybe I'm getting a bit lost and thinking about this in the wrong way. I've been stuck with this for a number of days now so any advice would be great.
In terms of progress, things are still plodding along with my synth. I'm able to save banks or instruments and record and playback a tune now. It still sounds pretty nasty to be honest, but hopefully that will improve soon :)
Many thanks,
Raizor
Think of the frequency as a phase increment.
phaseInc= PI*2.0*frequency/SampleRate
phase= 0
for each sample
{
amplitude= sin( phase )
phase += phaseInc
}
So modulating the frequency is nothing else than modulating the phase:
// modulator:
modulatorAmp= sin( modulatorPhase )
modulatorPhase += modulatorPhaseInc
// carrier:
carrierAmp= sin( carrierPhase + modIntensity*modAmp );
carrierPhase += carrierPhaseInc
Thanks Hellfire. I will give that a whirl.
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:
(http://www.0xdeadface.com/dump/zynth1.jpg)
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.
(http://www.0xdeadface.com/dump/oscSync.png)
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 (http://zynaddsubfx.sourceforge.net/doc/PADsynth/PADsynth.htm) 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 :)
Yeah, GUI looks fantastic!
Looks pretty good there Raizor, and nice explanation about of what you are doing.
Does all those controls (sliders/buttons) are working?
Thanks Benny and Rbz.
Quote from: rbz on July 20, 2012
Looks pretty good there Raizor, and nice explanation about of what you are doing.
Does all those controls (sliders/buttons) are working?
Most work, or will hopefully work eventually. The waveshaping stuff on the right hand side of the oscillator panel will be dropped and I may stick with a single waveform for the LFO instead of allowing 2 waveforms. Getting close to size limit already, so need to scale things back and bit :)
Trying to get the processing order for various things sorted out atm as there are lots of options for modulating one thing with another and I'm trying to process things to buffers in order for the output to be used for modulation. Giving me quite a headache this evening :|
Quote from: Raizor on July 20, 2012
Trying to get the processing order for various things sorted out atm as there are lots of options for modulating one thing with another and I'm trying to process things to buffers in order for the output to be used for modulation. Giving me quite a headache this evening :|
I've never did anything like that myself, but my first try would be something like this:
[pseudo code]
//instrument setup
int instrument_comb[MAX_COMB] = {
3, //execute function 3 = (delay)
1, //highpass
2, //reverb
0 //Lowpass
};
//loop
switch(instrument_comb[loop])
{
case 0:
function0(buffer); //(Lowpass)
case 1:
function1(buffer); //(highpass)
case 2:
function2(buffer); //(reverb)
case 3:
function3(buffer); //(delay)
}
//loop
This looks epic, lots of parameters to tweak already and more to come by the sound of it.
Have you given it to any musicians to play with yet?
Not yet Shockwave, it's still far too broken for that at the moment :)
rbz, thank you.
Woot, that really does look epic! Haven't really commented yet because I still haven't read through the post in detail. Some day I will but for now the pics look really impressive!
Really interesting to play around with the building blocks of sound, have you encountered some weird/beautifull or interesting errors during the process?
Quote from: Kirl on July 25, 2012
Woot, that really does look epic! Haven't really commented yet because I still haven't read through the post in detail. Some day I will but for now the pics look really impressive!
Really interesting to play around with the building blocks of sound, have you encountered some weird/beautifull or interesting errors during the process?
Thanks Kirl. I've had quite a few weird errors but I can't say any of them have sounded beautiful unfortunately, most have me frantically reaching for the volume knob to turn it down ;)
I must say, it's taking much more time to get things going that I would have hoped. Coming into this field with hardly any knowledge of sound/signal processing is probably why, but it's mostly fun and I'm learning a lot. Getting the PadSynth stuff working has been the nicest thing sound-wise so far. Hopefully I'll be able to show you something soon-ish.
Progress
Still plugging away in most of my free time, which isn't massive at the moment, due to me having to repoint the brickwork for most of the outside of the house this Summer :|
I've got most of the features in place now. This last week has been very productive, leading to the inclusion of Delay, Reverb, Distortion and Filters (high pass, low pass etc). I've still got to get Compression in place as well as a few misc effects such as Flanging, Phasing and hopefully some kind of funky glitch machine functionality for Dubstep style craziness. In terms of functionality, I seem to be getting close to exceeding what V2 can do, which is a bit shock to me, but kinda nice at the same time.
One of the areas that caused me some headaches has been the MIDI side of things in regard to the VST plugin. Trying to come up with a nice workflow for handling patch assignments to MIDI channels has been quite frustrating due to this being a mutli-timbral synth. Both V2 and 4KLang are also multi-timbral, but handle instrument/patch assignment differently. This probably needs some explaining, as I didn't understand this properly until quite recently:
In order to use the synth (or V2, 4KL), you must have a composition program (sequencer/tracker) to write your music. In my case, I've been using Renoise for this purpose, but you could use Cubase, Fruity Loops or whatever. When you create a new song in renoise, you have a bank of instruments for the song. These instrumnts can be plain old samples or VST instruments. VST instruments can be monophonic or multi-timbral. Say for example, you're making a dance music track. You may have a particular VST instrument to do the drum sounds, another different instrument for the lead lines and yet another for pad style effects. In this case, each of these VST instruments would probably be monophonic. They are effectively standalone instruments that are assigned to a single MIDI channel. When the song is playing, it may fire a note-on event on MIDI channel 1, which is assigned to the drum VST, therefore the drum VST would be responsible for making a drum sound for the note. Another totally separate VST may be assigned to channel 3 for lead sounds, so when a MIDI note-on event for channel 3 is fired, the lead sound VST would receive the event and be responsible to generating the sound. In a scenario like this, these VST instruments are totally independent and have no concept of each other or awareness that other VST instruments exist or are assigned to the track.
A multi-timbral synth (such as V2, 4KL or Zynth) shares a single VST plugin instance for all channels for a music track (renoise song). The way V2 handles having different patches (intruments/sounds) for different channels works by inserting MIDI program change commands into the track. As a track plays, various note-on and note-off commands are fired to simulate keys on a keyboard being pressed and released. In addition to these note-on/off commands, there are other special MIDI commands that can be fired for a particular MIDI channel to do various things. One of these commands in the 'program change' command. When using V2, you must send a program change command for a particular MIDI channel to change the V2 patch that is assigned to that channel. While this works, it can feel a little clunky from a user's perspective (imho). 4Klang on the other hand defaults to assigning patches sequentially to channels. So if a note is played on channel 1, it will use patch/insturment 1, for channel 2, patch/instrument 2 is used (etc etc). I'm not sure if 4KLang support program change commands, but I think not.
At the moment, my synth (Zynth) uses the 4KLang method, so by default patch 1 is associated with channel 1, patch 2 with channel 2 etc. You can also send program change commands to change this. Not ideal, but usable for now at least...
As my synth is primarily a wavetable based synth, I'm building a little PadSynth wavetable designer, that lets you create various types of PadSynth wavetables. These will be recreated prior to playback by the replayer in the demo/intro. I'm also working on a wavetable designer that lets you combine various existing wavetables in weird ways to create new ones. This works by having a stack of wavetables and various operators (add, subtract, multiply etc) to control how the values from the warious source wavetables are summed to produce the final wavetable. I'm hoping this will allow creation of some crazy sounds but may turn out to be totally useless :)
Question
One thing I am confused about is sync-to-tempo functionality. I've seen this in a lot of commercial synths (especially LFO sync) but I can't seem to find a description of what it actually does. My guess would be that the LFO (or whatever is being synched) repeats for each beat. So a 120 BMP song has an LFO that repeats a single cycle/period 120 times per minute. I've seen a denominator value used in these instances too, I guess that acts as a multiplier/divisor to make the LFO repeat 240 (*2) or 60(/2) times per minute. If anyone can shed any light on this, I'd appreciate it very much.
Well, that's it for now. Still nothing to show/demo yet :)
Quote from: Raizor on August 21, 2012
[At the moment, my synth (Zynth) uses the 4KLang method, so by default patch 1 is associated with channel 1, patch 2 with channel 2 etc.
I'm really happy you went this way. I hate the programm change method in V2 - sometimes it was very buggy when replaying the tune. That might be an issue with v2 but I love the fixed instrument per midi channel more. Also I'm used to it when composing in Cubase.
I've read the whole thread now in the last hour and have to admit, I'm glad you're still working on Zynth. Let me know when you need some testing! The GUI looks kickass. the z3ta is and always was my favourite soft-synth.
In answer to your question about the beat-synced LFO's: I think you're right with what you're saying. I'm totally bad in music-theory .. I just hit keys and have a sense for timing and harmonies, but your explanation makes completely sense. Beat-synced LFOs are petty awesome for gate effects, can be nicely used for filters, sound-ducking and stuff like that. therfore it make sense to have a multiplier/divisor for it. it's very popular using this for eg. in dubstep tunes - for fast wicked filtering .. you mostly think in 1,2,4,8,16,32 and 64th steps plus the triplets (8. , 16. , ...)
Thanks neriakX, very useful info!
Still on Skype, yep. Haven't signed in for a while again though. Tried pinging you last night :)
Hey mate, found a cool workshop from farbrausch - might be of interest!
Revision 2012 - The possible next generation of demoscene 64k softsynths (http://www.youtube.com/watch?v=HV3S_H28s2E)
Quote from: neriakX on September 09, 2012
Hey mate, found a cool workshop from farbrausch - might be of interest!
Revision 2012 - The possible next generation of demoscene 64k softsynths (http://www.youtube.com/watch?v=HV3S_H28s2E)
Cool! Looks very interesting. I think I had a quick look at it before but will watch it through this time. Thanks for the link matey :)