I am trying to reasonably emulate a bitcrushing/downsampling/waveshaping guitar pedal. After having put together those three functions, I realised (looking at videos on the net - I don't actually owe the pedal) that when bit depth/samplerate are set to maximum (best sound 'quality') and a 'unitary' wavetable is used (doesn't modify anything in the sound), the actual pedal still provides a broad "distortion/fuzz" sound. (of course the video provides clean and effected sound, ensuring comprehension)

As the sound I actually get with my patch is deceiving yet logical, I came to the conclusion that the clipping stage has to be 'upgraded'. I replaced the previous [clip~ -1 1] with a [tanh~], and I found it interesting but still far from satisfactory.

Googling about analog fuzz/distortion/overdrive gave some hints, but I'm still far from being able to put together a 'simplified physical model' of such a fuzz/distortion.

So I will try to start with a good transistor electronics book, to see what is the difference between germanium and silicium devices, and see if I could use some caracteristic curves to build a [diode~] and a [transitor_amplifier~] objects.

Any help appreciated !

Thanks,

Nau

]]>I am trying to reasonably emulate a bitcrushing/downsampling/waveshaping guitar pedal. After having put together those three functions, I realised (looking at videos on the net - I don't actually owe the pedal) that when bit depth/samplerate are set to maximum (best sound 'quality') and a 'unitary' wavetable is used (doesn't modify anything in the sound), the actual pedal still provides a broad "distortion/fuzz" sound. (of course the video provides clean and effected sound, ensuring comprehension)

As the sound I actually get with my patch is deceiving yet logical, I came to the conclusion that the clipping stage has to be 'upgraded'. I replaced the previous [clip~ -1 1] with a [tanh~], and I found it interesting but still far from satisfactory.

Googling about analog fuzz/distortion/overdrive gave some hints, but I'm still far from being able to put together a 'simplified physical model' of such a fuzz/distortion.

So I will try to start with a good transistor electronics book, to see what is the difference between germanium and silicium devices, and see if I could use some caracteristic curves to build a [diode~] and a [transitor_amplifier~] objects.

Any help appreciated !

Thanks,

Nau

]]>Also, distortion is highly nonlinear, meaning it will produce many more partials than what is already present in the signal. These partials will alias, which can alter the sound of the distortion in a way that you might not want. So it's a good idea to have the distortion in an upsampled patch. Filter the input at below the parent's Nyquist frequency (because upsampling causes the spectrum to repeat), apply the distortion, and filter again before the output to minimize aliasing. I should also mention that upsampling causes the energy of the original signal to be spread out, and the filter will get rid of most of it. So you will need to make up for the lost energy by multiplying the input by the upsampling factor.

I highly recommend this paper:

https://ccrma.stanford.edu/~dtyeh/papers/yeh07_dafx_distortion.pdf

It dissects and explains models for the Boss DS-1 and Ibanez Tube Screamer. Even if you don't understand all the math (I don't), there are some nice block diagrams to ease the pain. I've made an emulation of the DS-1 in Pd based on this paper (though I need to clean it up as it's doing more work in the upsampled part than it needs to), and it sounds pretty close to the Distortion unit in Guitar Rig, which has the same parameters. There's also a unit in Guitar Rig called Screamer, also with the same controls. I'm interested in how similar that turns out to be, too.

]]>Thank you so much !

Nau

]]>I am trying to use [rpole~] and [rzero~] objects to make a (not pre-warped thus with foldover) approaching filter for the transfer function H(s) numbered 15 page 3 of the article previously mentionned by Maelstorm.

Using the technique explained in http://en.wikipedia.org/wiki/Bilinear_transform , I'm trying to calculate the coefficient values for those [rpole~] and [rzero~] objects.

The first try lead me to coeffs that give me a plot (using the Miller Puckette's filter_graph2 subpatches) which is far from the one expected.

Tomorrow I'll give another shot, but advises would be appreciated !

Thanks,

Nau

]]>But if I were to try and design it in Pd, I wouldn't get into [rpole~] and friends for that one. It's a second-order filter, so it would be easier--and more computationally efficient--to just calculate the coefficients and plug them into [biquad~].

(15) can be re-written as:

s^2 + (ω1 + ω2)*s + ω1*ω2

So now you have the s-domain coefficients needed for mapping to the z-domain using equations (4)-(9). One thing to remember is that [biquad~] assumes A0==1, so once you calculate the coefficients using (4)-(9), you'll need to factor out A0 from all of them (i.e. divide them all by A0). And then, there you go, biquad coefficients for a BJT frequency response.

]]>I'm on the way ... made a patch with all the calculations, but I have to debug it.

We'll see that tomorrow in the evening !

Thank you for the input.

Nau

]]>I figured out what was wrong in my patch. The calculations were good except that I had to multiply either fb1 and fb2 by (-1) to make it work.

I retreived this information from some objects Maelstorm's posted here : http://puredata.hurleur.com/sujet-5678-blending-blending-filter-graph.

I never found info about which H(z) equation does the [biquad~] object rely on. Now I see that the denominator is written as a substraction rather than an addition, just a matter of convention. Maelstorm, can I ask you where you picked this peculiar info?

I post here a 'didactic' patch that implements the BJT stage and draws a graph of it. This shows that the 'prescribed implementation' is very similar to the 'two [hip~]' implementation used by Maelstorm.

I'm glad I learned a bit about all that stuff, now I'm going furher with the opamp gain stage ... Maelstorm, did you use the method described 'in (9)', which is explained in an american patent document, or just the 'classic' one with upsampling ? I'm gonna try the 'classic' first

Thanks,

Nau

]]>Glad to hear you got it working! I don't have time to look at it right now, but I'll try and answer some of your questions.

@nau said:

I never found info about which H(z) equation does the [biquad~] object rely on. Now I see that the denominator is written as a substraction rather than an addition, just a matter of convention. Maelstorm, can I ask you where you picked this peculiar info?

Typically, a biquad filter is defined as subtracting the feedback part in the difference equation, and I don't really know why that is. But, you don't always see it defined that way, so you have to look out for it. Also, the conversion from the difference equation (y[n] = ...) to the transfer function (H(z) = ...) causes the signs of the feedback coefficients to be reversed, so subtraction in the difference equation becomes addition in the transfer function. More confusion. In fact, it caused quite a bit of frustration when I was making those filters. I'm not sure if the comments in those patches are 100% correct.

Anyway, it turns out, [biquad~] is one of the filters that doesn't follow that convention. The help file gives the difference equation in the more confusing Direct Form II. I'm guessing it's because Miller wanted to illustrate how it's implemented, since Direct Form II can be done using only two delays instead of four. But the results are exactly the same, so I don't see why that matters from the user's end. Anyway, in Direct Form I (as it's more commonly seen), [biquad~]'s difference equation is this:

y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] + a1*y[n-1] + a2*y[n-2]

Which, in the z-domain, becomes:

b0 + b1*z^-1 + b2*z^-2

H(z) = -----------------------------

1 - a1*z^-1 - a2*z^-2

So, in order to make that line up with convention, the signs in front of a1 and a2 should be reversed.

The Wikipedia page on digital biquad filters mostly talks about the difference between Direct Forms I and II, and also gives the more conventional form:

http://en.wikipedia.org/wiki/Digital_biquad_filter

Maelstorm, did you use the method described 'in (9)', which is explained in an american patent document, or just the 'classic' one with upsampling ?

I just upsampled. I haven't taken a look at that patent. But my impression from the wording of the paper is that (9) uses upsampling, too.

]]>So if I want to do good work, I should 'encapsulate' these operations in a subpatch and upsample, I gess.

I read on wikipedia that I should upsample (a lot), distort, low-pass, and then downsample.

Could anyone give me good 'values' for those operations ?

Thanks,

Nau

]]>Now, when you upsample, the parts of the spectrum above the original Nyquist will fall below the new Nyquist. And when you send it through [tanh~], those frequencies will produce new frequencies, some of which will alias in the new sample rate, and some of which will fall below Nyquist when you downsample back to the original sample rate. You probably don't want that. So, you'll need to filter after you upsample to remove the repeated spectrum. And the [tanh~] will produce so many partials that you'll need to filter again before you downsample.

I would recommend upsampling by a factor of at least 8. You'll still get some aliasing, but what gets aliased will probably get masked. I think Pd only lets you upsample by powers-of-two, so the next one would be a factor of 16. That should be high enough, though it could be cpu intensive. As for the filters, they should just be far enough below the original Nyquist so most or all of what is above it is filtered out. I would recommend using [lp10_cheb~] for this as it has a very steep roll-off. You could probably set it to about 18kHz without aliasing.

]]>I am testing the upsampling method.

I got an upsampled version of my processing working, but as I like seeing things in addition to hearing them, I made a filter graphing patch using Miller's H12 patch.

And back to very basic testing ...

The first test here is with a [hip~ 2000], and I graph it with or without upsampling (8 times). The response curves are very different ! (no cheb filtering yet here, just a basic test) !

Why is this ?

Thanks,

Nau

http://www.pdpatchrepo.info/hurleur/upsample_filtering_test.pd

]]>Also, if you just change the sample rate in the original (non-upsampled) part and plot the response, you'll again see what you'd expect since the generated signal is already at the high sample rate. You'll have to save and reopen the patch for it, though, because the butterworth abstraction only check for the sample rate on load.

http://www.pdpatchrepo.info/hurleur/upsample_filtering_test.mmb.pd

]]>it's interresting ... by now I'm using article https://ccrma.stanford.edu/~dtyeh/papers/yeh07_dafx_distortion.pdf as a thread to follow and learn more about filters, and the 'upsampling method' is just one of the two strategies proposed in order to "fight" hi-freq foldover. I am interrested in any input about 'best low-pass filter to use' (I was wondering wether elliptic was not another good choice), but I think I won't spend many evenings in trying to figure it out, as I had already planned to study (and experiment?) http://www.freepatentsonline.com/5789689.pdf .

In the prev. cited article, they propose "better design methods" that can be found in http://eceweb1.rutgers.edu/~orfanidi/ece348/peq.pdf . This will be my next step in my learning journey ...

Thank you acreil,

Thank you Maelstorm,

Nau

]]>If I remember well (can't find back the topic where I first read it), it's difficult (impossible) to render an 'horizontal axis logarithmic scale', so the best would be vectors loaded in Matlab or so. As I work under linux, I'll try scilab. A brand new world to discover !

Nau

]]>I remember now that you said in another post that you were to post it in the 'patch section' ... which I follow much less than this one. Sorry and thank you Maelstorm !

Nau

]]>Maelstorm, your filter [filterplot.mmb] is a real jewel. Thank you again.

As the tone stage I'm trying to implement is documented in https://ccrma.stanford.edu/~dtyeh/papers/yeh07_dafx_distortion.pdf as "involving a fade between high pass filter and low pass filter blocks", I searched for the smarter way to take account for fading.

I found that I could multiplicate the b0 b1 b2 coefficients getting out from [filtercoeff.mmb] by a number between 0 and 1 to achieve this (as any digital filter geek should know, I guess ). Factors greater than 1 lead to unwanted results (for stability reasons, maybe).

Now I have to find correct weights to visually match my filter with the one I see in the article, it's just up to me !

Thank you again for this high quality input that allows me to learn a bit everyday.

Nau

edit : 30' playing with it and ... aargh ! Now I guess I see ... no cascade here but parallel ! Will it be possible to workaround this fundamental incompatibility with [filterplot.mmb]?

]]>Later I will implement a simple loop reading and adding values, as I can't find any [tab_add] object. Which library is it from ?

Thanks,

Nau

]]>sorry for being so stupid sometimes...

... but I'm banging my head against a apparent paradox.

I'm dealing with graphing parallel filters. As proposed by Maelstorm, the amplitude of the transfer function in such a case is the sum of the ones being paralleled.

Let's imagine two unit gain allpass filters in parallel. The sum of the resulting signal is twice the input signal, and the final overall gain should be +6db. But the transfer functions in parallel are "straight lines" at 0db (unit gain), so that the resulting final transfer function would remain a 0db "straight line" (0+0)? Where am I doing a stupid mistake ?

The idea is to draw the response of a fade between two filters, using two [filterplot.mmb] objects, as you could imagine Gain of each filter would be between 0 and 1.

This apparent paradox is the simplest way I found to explain the problems I have when trying to combine filters in parallel. When I put a [lop~ 320] and a [hip~ 1160] in parallel and draw the response with Miller Puckette's [filter_graph1] and [filter_graph1] found in H12.peaking.pd (soundtesting method), I get something with a valley in it. When I sum the arrays outputted by two [filterplot.mmb] feeded with two correctly calculeted coefficients, it gives me a hill.

I am lost. What makes me mad is that I am feeling like this is a very very stupid mistake I am doing here ... but after four hours I decided to surrender and to ask for some advice.

Thank you,

Nau

]]>