Wavetable synthesis. theory, practice, fear?

DSP, Plugin and Host development discussion.
RELATED
PRODUCTS

Post

Hello,
I'm creating my first synthesizer from scratch in c++, fun time mixed with extreme terror.

Mostly fun, but the terror part often comes in relation to some artifacts I'm experiencing with the sound. At lower frequencies my sine wave turns in to a square-saw hybrid(i think) - but not always! sometimes this also spread up trough the range, then to be heard at the higher frequencies as well. its a loud sound, much bigger in amplitude than my other waveforms - so as you could imagine the terror is real - playing the synth now is down right frightening (but the square/saw wave is almost like a distorted guiar-lead so maybe feature ? 8) no.. )

I think this might be happening because the values exceed the bit-memory - double wraps around and becomes signed. maybe. Or maybe the general amplitude is above the 22000 limit, and that causes insane aliasing. Interestingly it's also more prominent in debug mode - leading me to suspect performance to be involved, but the synth only takes 1 % of my cpu at the moment and 7 mb of ram, so its not like I'm running out of power.

I apologies for my long winded explanation, but the context is - I'm naked(unskilled) and afraid(deaf). The question as for now is - could this also be due to me only using one generated table? I made one huge table(16392 units) - and only change the phase - getting accuracy with resolution. This feels wrong to me, and I've read that there its possible to get the same clear tone with a table of only 1024 units- or maybe i misunderstood and they use multiple tables with a tone generated at different wavelengths like one would do when sampling a piano or the likes. I.e. record some of the range and interpolate the rest.

Thanks in advance for advice you can give.

Edit:
Needed to get past spam filter for some reason, I removed the word " h - e - l -p " seems to have done the trick.

Post

As the history repeats itself, it's amusing to look back : viewtopic.php?p=6641483
BTW, there is an implementation of the filters mentioned in the thread by xoxos in the intel ipp library.
~stratum~

Post

Hmmmm, aliasing in a sine wave... Could you elaborate on that, stratum?
I'd like to see the raw produced waves at low medium and high frequencies before drawing any conclusions yet.
We are the KVR collective. Resistance is futile. You will be assimilated. Image
My MusicCalc is served over https!!

Post

BertKoor wrote:Hmmmm, aliasing in a sine wave... Could you elaborate on that, stratum?
I'd like to see the raw produced waves at low medium and high frequencies before drawing any conclusions yet.
It wasn't a directly related reply, that thread contains various related information. It's obvious that there is something basic wrong with what the OP is doing, and there are many things that can go wrong. When you start questioning that, that usually results a 10 page thread until it is found.
~stratum~

Post

I appreciate you guys taking the time to reply. There is most likely something basic wrong, but at this stage it's not a very complex engine. I'm using port audio callback, and a single wavetable - frequency controlled by mididata. Simple math convert the midi range to frequencies and this is multiplied by table size divided by sample rate : Phase_Increment = (Osc_freq * tablesize/ Samplerate). The table is then sent to the audio buffer and incremented by the calculated Phase Increment. Each note is an oscillator and has a simple ADSR envelope. No filters, just simple table to audio buffer setup. If its hard to pinpoint this issue i understand - I'll figure it out my self eventually, just hoping to save time here believing it to be a common but (hard to google) issue.

Maybe you could instead tell me if multiple tables for the same waveform is common practice : same wave developed with different fundamental frequencies? or something like this. or am i right to have a single table for waveforms - seems to be working well for all notes above F1/C1.

And maybe quickly illuminate me on the issue regarding what is common as to wavetable size - what is common practice?

Post

Conceptually a wave table is just a medium you sample, somewhat like sampling an analog signal. But the samples taken need to result a properly bandlimited signal because you are sampling a digital signal instead of sampling an analog signal, for that reason you cannot attach an antialiasing filter before the sampling process and still have a simple lookup table. The table already needs to be properly bandlimited for the frequency range you use it. The answers you seek are just a consequence of this fact, but it's somewhat hard to debug that process through a forum. One consequence is that yes multiple tables are the norm unless the wave table contains a sine wave, because that's the only way you can use that 'antialiasing filter' that cannot be added to the sampling process, you keep already filtered waves in separate tables, instead.

p.s. there is a tutorial here http://www.earlevel.com/main/category/d ... cillators/
~stratum~

Post

I see, thanks for answering. I'll read the earlevel tutorial more carefully, even though his naming conventions give me nightmares. I also realized that there are soundcard scopes available, and you can see my waveform wrapping around - going from signed to unsigned. Oddly enough the error is inconsistent, the more time i give each keystroke the less likely it is to create distortion. Removing some cout comands, lets me go way below C0. - even though cpu is at 0%. I'll keep reading i guess ;) thanks again
You do not have the required permissions to view the files attached to this post.

Post

Are you using integers for that table or for the interpolator that estimates values between samples?
~stratum~

Post

Phase value and increment/accumulation is unsigned Int that wraps around to zero at table length. My output is in double. the interpolator doesn't change the outcome, have tried taking that out completely. - Removing it results in longer jumps between notes, but at the low frequencies it still flips out - and this can some times trip up the entire card setup, giving me artifacting and distortion on the normal sound output(not generated by me - youtube etc). I would blame the audiocard but i have several other synths and vst's working in perfect harmony and order. Maybe I'm generating the wave wrong - not using 20hz , or maybe portAudio doesn't jive with my setup.

Simple sine generation I'm using, outputting double - Table = sin( (i/TABLE_SIZE) * PI * 2. )

At work now, but i threw together a rough tone generator with RTaudio, no filter, no interpolation. There seems to be no distortion- even at the limit of my earplugs. This is a linux machine.

Post

Port audio has a flag about clipping of out of range signals, have you tried it to see if it changes anything?
~stratum~

Post

portaudio is set to paClipOff - tried both ways :/

Post

This looks like a simple bug and it apparently has nothing to do with "wave table synthesis, theory or practice". You just have to debug it.
~stratum~

Post

Yes, so it seems. I'm gonna try to switch to RTaudio on this computer aswell - and see if my soundcard likes this setup better. thanks for your help :)

Post

I guess it's not the cause of your problem but I noticed that you wrote that your table has a size of 16392. This is not a power of 2 and the nearest one would be 2^14=16384. So if it is not just a typo here in the forum then you might want to fix this.

If I was you I would try to test the individual components in isolation. For example if you want to test your phase accumulator do not read from the wavetable. Instead use the phase and put it into the sin() function and output the results of that. Also try to attenuate the signal to ensure that no clipping effect can occur. You might also want to hard code the frequency that's outputted at each MIDI event, etc.

I also find it helpful to have some code to simply write samples into a file, e.g. as raw audio. That way you can examine the output of the oscillator in an audio editor. To do so it can be helpful to write unit tests so that you have more control over the code that you want to test and that you do not need to fire up the DAW for each test.

Good luck! :)
Passed 303 posts. Next stop: 808.

Post

LiteX2 wrote:Yes, so it seems. I'm gonna try to switch to RTaudio on this computer aswell - and see if my soundcard likes this setup better. thanks for your help :)
You're almost certainly trying to search for the problem from the wrong place, since it's quite unlikely that any of the common APIs is going to turn a nice-looking signal into junk. That suggests your signal is probably borked by the time it reaches the API.

First, clip your signals manually, using something like:

double clipped = (std::min)(.999, (std::max)(-.999, value));

If it's still showing the folding-weirdness then it's certainly not the API but something earlier in your signal chain and if that fixes the problem, then you just solved the problem.

Post Reply

Return to “DSP and Plugin Development”