• Better sounding guitar distortion ... beyond \[clip~\] and \[tanh~\]

Hi there,

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]?

• Hmm...you could try using two [filterplot.mmb]s and associate them with

• I'll try it as soon as possible, thanks !

• Tonite I don't have much time.
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

• It's in iem_tab. You have to import it or use the prefix, i.e. [iem_tab/tab_add].

• Hi there,

sorry for being so stupid sometimes...

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

• Sorry, nau. The problem with summing two [fliterplot.mmb]s is totally my fault. I forgot that I wrote it so that it would plot to an array with the default y-range of -1 to 1 no matter what you may have set the range of [filterplot.mmb] to. So, all of the amp values are scaled, and you have to take that into account. Also, when summing the plots, you have to make sure you are in raw-amp mode (i.e. [units 1( ) when you add the values, then convert them back to dB.

I've attached a patch to illustrate how to do it correctly with the quirks of [filterplot.mmb]. It's a bit of a headache, though. I may go into [filterplot.mmb] and change it so that it changes the arrays using [donecanvasdialog( instead of scaling the values to make this a little easier...

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

• Ok, thanks Maelstorm. Of course summing two transfer functions is not equal to summing the magnitudes only, I understand this is why the summing wasn't working (even with the same db scaling set to every array using the right inputs of the [filterplot_mmb] objects). Phase matters, isn't it

I'll check your solution tonite, of course I already knew that summing the two raw signals was a good idea, but I was still dreaming that the "magnitude db sum" could work.

Anyway, I still can't figure out why my simple 'two parallel allpass' case remains an apparent paradox ! When I say 'allpass', I mean a very simple 'unitary gain- unchanged phases' case, in such a way it could be seen as a biquad with [0 0 1 0 0] coefficients. That's weird, and still makes me unconfortable.

thanks anyway !

Nau

P.S. : I found this interresting (I'm talking to the others newbies around ) http://www.dspguide.com/CH33.PDF

• @nau said:

Anyway, I still can't figure out why my simple 'two parallel allpass' case remains an apparent paradox ! When I say 'allpass', I mean a very simple 'unitary gain- unchanged phases' case, in such a way it could be seen as a biquad with [0 0 1 0 0] coefficients. That's weird, and still makes me unconfortable.

It's because you were adding two arrays that were at zero. That's what I meant about making up for the scaling. The y-range of the arrays are -1 to 1, so I wrote [filterplot.mmb] so that y=-1 represents an amplitude of zero, and y=0 represents an amplitude of 1. The allpass filters, which have an amplitude of 1 for all frequencies, would plot y=0 throughout. So adding them just gave zero. If you first add 1 to the tables before summing them, you'd get the correct values.

• Thank you Maelstorm.
The patch you designed to make db additions spared me a lot of hassle, and works very well. Thank to you, I am now able to try to visually match my filter with the one depicted in the article. As I display the leftmost and rightmost db values and the minimum as well, that's a nice workbench to work on !

To be continued ...

Thanx,

Nau

• Hi there,

here it is... a handy workbench to emulate a distorsion pedal following the article https://ccrma.stanford.edu/~dtyeh/papers/yeh07_dafx_distortion.pdf and Maelstorm's best support and advices.

A free of rights soundfile is joined, in such a way that if we want to interact everyone has the same workbench basis.
The file to be opened is DS1-workbench.pd. Some abstractions (several made by Maelstorm) are joined. It should work on extended.

The BJT gains are bound to my 'signal amplitude policy' : input file or audio source and output should never clip. These gains can be seen as follows : the first one (before the clipper) adjust 'how early' distortion occurs, and the second one gives the distorted signal a boost in order to give similar subjective level than dry signal.
The values were found empirically.

I have several interrogations:

• when switching between upsampled or not upsampled processing, the difference is barely noticeable (maybe the upsampled one has more highs, but that is the exact contrary of what I would expect). Does someone see what I am doing wrong, if this is the cause of this perceptual draw ?

• the transfer curves can be seen in the patches, but are always slightly different than the one showed in the article. But I have been very careful when calculating coefficients and I don't really think they are wrong. Would there persist a difference between [filterplot.mmb] and traditional Matlab-like graphs ?

• The DS1-tone_stage helpfile has been written by Maelstorm, and the response curve shows no gain value above 0db. Nevertheless the tone knob, when pushed, can lead to signal amplitude beyond [-1 1]... I can't figure out how a signal can have all its discretised frequencies pulled down and still exhibit peaking. Should I read more about the subject (is there a name for this symptom ?), or is there an error in my patch ?

• is my 'signal policy' perfectible ? I want the output signal never to clip, so I multiply the output by 0.4 in such a way that when Tone and Dist are full right but Level is medium the signal never clips. Pushing further Level will cause 'unwanted output distortion'. Of course I'm thinking about modifying this final output gain in such a way that it is bound to Level or anything else. This is away from the original circuit, but is legitimated by numerical audio considerations.

Thank you,

Nau

• wow, nice to finally see this!

had a play here and all sounding pretty good.

>>

• when switching between upsampled or not upsampled processing, the difference is barely noticeable (maybe the upsampled one has more highs, but that is the exact contrary of what I would expect). Does someone see what I am doing wrong, if this is the cause of this perceptual draw ? <<

why are highs contrary to what you'd expect? at a low sample rate, the highs are folded back into low frequencies, but when you upsample, the highs are preserved as true highs. i think it works just how it should. The upsampled version is certainly much clearer and brighter to my ears. Particularly with a high distortion level.

actually, this patch really demonstrates the effect of aliasing. if you turn the tone knob down as far as it will go, and also turn the distortion down to zero, and turn aliasing off, you can clearly hear the rustling noise caused caused by those wrapping frequencies.
turn aliasing back on again, and the noise is gone.

lovely work. will have a more thorough look soon.

• Also quite glad to see this! This has become one of my favorite threads of the forum. It covers a lot of ground, and it's great to see your hard work and perseverance payoff here. Cheers too you, nau!

@nau said:

The BJT gains are bound to my 'signal amplitude policy' : input file or audio source and output should never clip. These gains can be seen as follows : the first one (before the clipper) adjust 'how early' distortion occurs, and the second one gives the distorted signal a boost in order to give similar subjective level than dry signal.
The values were found empirically.

This might be where I have the biggest issue, though the article doesn't make it so clear, either. In the article, it shows the frequency response of the BJT stage as having about a 36 dB boost in the pass band. That amounts to multiplying the signal by about 63. And, if you want to get really technical, the waveshaper in the article clips at +/- .6, so you'd have to add about another 4.5 dB to make up for that. You're using much lower values. This is what I was talking about earlier when I said you should really crank the input to [tanh~] to get some serious distortion, and the DS-1 isn't a baby's distortion pedal.

Now, the article also says that the second BJT stage is really to boost the signal back up for the subsequent load. Since we're not sending this into other circuits here, I think the dB boost of the second BJT should be ignored. Also, you don't need to calculate the boost into the filter coefficients. That's only useful for plotting. You can just use [*~] before or after the filter do accomplish it.

So basically what I'm saying is, there should be a boost of about 40 dB ([*~ 100]) as part of the first BJT stage, and no boost for the last one. Then you can really break some teeth with this distortion.

• when switching between upsampled or not upsampled processing, the difference is barely noticeable (maybe the upsampled one has more highs, but that is the exact contrary of what I would expect). Does someone see what I am doing wrong, if this is the cause of this perceptual draw ?

As mod said, it's not so much more highs as less lows, and those lows are a result of aliasing. To my ears, the upsampled version sounds less muddy. (By the way, in your upsampled portion, you have a different argument for the second [DS1-bjt_stage~]. Making them equal makes the difference even less noticeable, and draws more attention to the mud than the highs.)

• the transfer curves can be seen in the patches, but are always slightly different than the one showed in the article. But I have been very careful when calculating coefficients and I don't really think they are wrong. Would there persist a difference between [filterplot.mmb] and traditional Matlab-like graphs ?

Yes, there is a difference, but it's not a Matlab thing. It's the choice of the logarithmic scaling in the x-axis. The article uses powers-of-ten as equal distances. Mine uses [mtof] for the scaling, so that a semitone, octave, or whatever musical interval is the same distance. Also, I made an adjustment so that everything between 0 and about 20 Hz (at 44.1k) gets squashed in the leftmost 10% of the graph. If I didn't to that, then about half the plot would be taken up with frequencies below the audible range.

• The DS1-tone_stage helpfile has been written by Maelstorm, and the response curve shows no gain value above 0db. Nevertheless the tone knob, when pushed, can lead to signal amplitude beyond [-1 1]... I can't figure out how a signal can have all its discretised frequencies pulled down and still exhibit peaking. Should I read more about the subject (is there a name for this symptom ?), or is there an error in my patch ?

This has nothing to do with your tone stage. It's because of the passband ripple in the Chebychev filters. The IEM Chebychev filters have a 1 dB ripple, though I don't actually know if that means +/- 1 dB or +/- .5 dB. Either way, it's creating a boost at some frequencies, and pushing the output down by 1 dB should keep it below [-1, 1]. This could also be contributing to the highs, as the ripple is typically more pronounced near the cutoff frequency.

• is my 'signal policy' perfectible ? I want the output signal never to clip, so I multiply the output by 0.4 in such a way that when Tone and Dist are full right but Level is medium the signal never clips.

The output from [tanh~] will never clip, so as long as you make up for the ripple and don't boost the second BJT stage, you should be fine.

Just one more thing to add for now, and that is you're doing too much in the upsampled portion. The only thing that needs to be in there is the non-linear function ([tanh~]) and the anti-aliasing filters. Everything else is linear and doesn't benefit from upsampling, so it's just creating more computational load. So it should look more like this:

[*~ 100]
|
[DS1-bjt_stage~ 1]
|
[DS1-opamp_gain~]
|
[*~ 8]
|
[pd upsample]
|
[DS1-tone_stage~]
|
[DS1-bjt_stage~ 1]
|
[*~ .891] <-- 1 dB cut

And [pd upsample] should look like this:

[inlet~]
|
[lp10_cheb~ 18000] [block~ 64 1 8]
|
[tanh~]
|
[lp10_cheb~ 18000]
|
[outlet~]

Okay, that turned out to be more words than I expected. But we're getting into DETAILS here! Again, nice work, nau.

• Hi there,

thank you for your feedback !

@mod said:

wow, nice to finally see this!
why are highs contrary to what you'd expect? at a low sample rate, the highs are folded back into low frequencies, but when you upsample, the highs are preserved as true highs. i think it works just how it should. The upsampled version is certainly much clearer and brighter to my ears. Particularly with a high distortion level.

That makes sense. The upsampling workaround officially wins (I'll try x16)! I think I focus too much on highs, as I tend to find this disto patch rather 'acid'; the original sample sounds much darker than the distorted sound. I don't owe the actual pedal so I only rely on my 'feeling', which is far from reliable Of course it's logical to add highs with such a nonlinearity, and lows are filtered several times.
Anyway I still find the heavily distorted sounds have a strong 'schh schh schh component' in the highs, and I can't remember having heard that as strong in actual analogic effects. Would you agree with that? Of course I know this is a rather basic 'physically-informed' design, and that analog will always sound better

@mod said:

actually, this patch really demonstrates the effect of aliasing. if you turn the tone knob down as far as it will go, and also turn the distortion down to zero, and turn aliasing off, you can clearly hear the rustling noise caused caused by those wrapping frequencies.
turn aliasing back on again, and the noise is gone.

Very strange, when I do what you say, the upsampled version sounds like the 'not upsampled one', with a 'sch sch' noise added !

@Maelstorm said:

@nau said:

The BJT gains are bound to my 'signal amplitude policy' : input file or audio source and output should never clip. These gains can be seen as follows : the first one (before the clipper) adjust 'how early' distortion occurs, and the second one gives the distorted signal a boost in order to give similar subjective level than dry signal.
The values were found empirically.

This might be where I have the biggest issue, though the article doesn't make it so clear, either. [...] the DS-1 isn't a baby's distortion pedal.
[...] Also, you don't need to calculate the boost into the filter coefficients. That's only useful for plotting. You can just use [*~] before or after the filter do accomplish it.

I understand all these arguments. I'll modify the patch. At the beginning I was using this kind of reasoning, but as the 'nominal input level' is -20dbu (http://www.bossus.com/gear/productdetails.php?ProductId=127&ParentId=254#), and the dbu definition I found seemed difficult to bind to 'our' db, I just dared to make the basic (36db-20db=16db~6.3 times in amplitude) operation... not far from the 6 in my patch Not very scientific, though.
Anyway I understood another reason why my 'subjective hearing' failed: feedind my patch with a 0db normalised sample maximizes input level, and the result will always be 'over the top' compared to non-active guitar pickups with a volume knob not always pushed to max. In other words, if I look at demos on youtube the result heard will be less distorted than my patch's. Anyway this can always be seen as an additional parameter for a 'parametric DS1 deluxe edition patch'

@Maelstorm said:

As mod said, it's not so much more highs as less lows, and those lows are a result of aliasing. To my ears, the upsampled version sounds less muddy. (By the way, in your upsampled portion, you have a different argument for the second [DS1-bjt_stage~]. Making them equal makes the difference even less noticeable, and draws more attention to the mud than the highs.)

Ok, upsampling wins !

@Maelstorm said:

Yes, there is a difference, but it's not a Matlab thing. It's the choice of the logarithmic scaling in the x-axis. The article uses powers-of-ten as equal distances. Mine uses [mtof] for the scaling, so that a semitone, octave, or whatever musical interval is the same distance. Also, I made an adjustment so that everything between 0 and about 20 Hz (at 44.1k) gets squashed in the leftmost 10% of the graph. If I didn't to that, then about half the plot would be taken up with frequencies below the audible range.

Ok, perfect ! Everything's cool now.

@Maelstorm said:

(commenting peaking after ToneStage)
This has nothing to do with your tone stage. It's because of the passband ripple in the Chebychev filters. The IEM Chebychev filters have a 1 dB ripple, though I don't actually know if that means +/- 1 dB or +/- .5 dB. Either way, it's creating a boost at some frequencies, and pushing the output down by 1 dB should keep it below [-1, 1]. This could also be contributing to the highs, as the ripple is typically more pronounced near the cutoff frequency.

Mmh, I thought the same, but then I decided to check the plots taken out of the 'not upsampling' part, and the peaking is still there ! The Chebyshev filters can be the source, then ...

@Maelstorm said:

The output from [tanh~] will never clip, so as long as you make up for the ripple and don't boost the second BJT stage, you should be fine.
[...]
Just one more thing to add for now, and that is you're doing too much in the upsampled portion. The only thing that needs to be in there is the non-linear function ([tanh~]) and the anti-aliasing filters. Everything else is linear and doesn't benefit from upsampling, so it's just creating more computational load.

Of course I precisely want to get rid of this peaking to be able to fully rely on [tanh~] to 'master' my output gain. I'll try the FIR instead of cheby (as proposed by acreil) some day. (I don't even know yet how they work and how I'll have to implement it).

I left the 'full upsampled chain' in this patch only to see if someone would have commented it, and we totally agree. But this 'playing the noob' attitude of mine is a rather raw 'fishing method' for getting stimulating information ... sorry this lead you to lay down the whole picture BUT nothing wasted, as your final 'delicate' -1db cut surprises me and I'll use it (when I'll get rid of peaking) and moreover, as you are reminding me that you use a 18000 cutoff freq, I'll give a look again at it, just trying to find a good criterion to pick one

Thank you everybody,
See you,

Nau

P.S. : sorry for those very long sentences ... not very clear

• @nau said:

I'll try the FIR instead of cheby (as proposed by acreil) some day. (I don't even know yet how they work and how I'll have to implement it).

Well, I only mentioned it because I was wondering if there was some automated and optimized way to make an "Fs/16" (or whatever) brickwall FIR filter. I'd like to see it, anyway. It would make it pretty convenient to do integer ratio sample rate conversions with high quality. There would still be some overshoot, but it wouldn't have the Chebyshev filter's passband ripple or phase response. But I think a lot of the Chebyshev filter's relative shortcomings are reduced if you use a slightly higher sample rate- maybe 48 kHz rather than 44.1.

• Well, since you bring it up.

But it's probably worth mentioning that Chebychev filters have almost (though not perfectly) linear phase in the passband and stopband. It's the transition band that gets pretty wonky, but since this is a distortion patch and the transition band is out of most people's audible range, I still think the effect is negligible.

http://www.pdpatchrepo.info/hurleur/FIR.mmb.zip

• Yop,

thank you Maelstorm for the last post.

Tonite I fixed the gains, upsampled 16 times etc.
Anyway, among others, the peaking tone stage is still a problem to me. This would be so nice to find a solution to keep output away from clipping in another way than removing 10dB !
As mentioned before, the problem isn't really chebyshev filters, as the problem remains when no upsampling is performed. The joined patch underlines it.

My feeling would be that as this is a parallel filter I 'simply' add the signals coming from the two filters (weighed sum) and this sum is in the [-2 2] interval (in fact less, but how one can predict that ?).
If I'm right there's no other way than multiply the output signal by 0.5, end of the story.
Anyway there is a set of formulas that allow to calculate the biquad coefficients of a parallel scheme, as I have a small doubt that it could give a different result (I mean : I don't believe it, but as I am here to learn things it could be interesting to push forward, scientific curiosity). But if someone confirms me it won't change anything, I will save time

See you,
Thanks,

Nau

http://www.pdpatchrepo.info/hurleur/DS1-tone_stage_mystery~.pd

• You're right, it wasn't simply the Chebychev filters. I played around and did some tests. I ran [noise~] through [env~] and found that the highest RMS level came out to be about 95.7 dB (or -4.3 dBfs). Pure white noise will give produce every frequency as loud as possible without clipping. I then ran [noise~] through [*~ 63] -> [tanh~] -> [env~] and found that the highest RMS level was 99.98 dB. All of those added partials were driving the overall amplitude too high! That explains why the article showed the waveshaping curve limiting at +/- .6. Otherwise, the output is too loud. So I then tried multiplying the output of [tanh~] by .6...still a little bit of clipping, but much less. After some trial and error, I found that multiplying by .56 seemed to be about the threshold. So .5 might really be the safe answer.

• Well, shit, no. There still seems to be some boost caused by the filters as well. This is a head-scratcher. Running a sinewave sweep through the filters seems to show no clipping and a correct frequency response. I think there might be a DC issue, possibly caused by phase interference from summing the two filters. I just stuck a [hip~ 5] after the filter stage, and that seemed to make a difference.

• @Maelstorm said:

I think there might be a DC issue, possibly caused by phase interference from summing the two filters. I just stuck a [hip~ 5] after the filter stage, and that seemed to make a difference.

Thanks, I think I'll try the 'parallel combination into a single biquad" option tonight (here, in Belgium), or dissect Katjav's material proposed in http://puredata.hurleur.com/sujet-5678-blending-blending-filter-graph ... or anything

Nau

Posts 76 | Views 71184
Internal error.

Oops! Looks like something went wrong!