Inspired by this thread -- but also because I like messing around with DSP stuff from time to time .... I wrote two programs that let you design and apply noise shaping filters. Check out my little homepage (screenshot and ZIP to downlad).

I'm kind of proud of the way poles and zeros are controlled. Havn't seen this approach before. Also, you get to hear the result instantly. Try altering the response while audio is on

Cheers!Sebastian

PS: I should probably mention that the noise you hear (program "iiirdsgn") is TPDF dithered silence.

PPS: It's likely that you can design better noise shaping filters than those that are supplied. I didn't have accurate equal loudness data available. Filter design tips:- Try to keep the number of red and blue strings minimal- Keep the response below ... say +30 dB- Don't try to approximate equal loudness curves below, say, 1 kHz. If you do, the filters only get more complicated. There's hardly a gain due to the small bandwidth of that region. I intentionally use a linear frequency axis, so don't bother approximation the curves for a very small region.

You may link to *.sos files you created if you think you've designed a really good one.

It seems to have clicking noises while typing or changing to another window. Anything you can do about that?These dithering tests have made me realize that being a bit sensitive to HF content may not be such a good thing 48KHz sounds a lot less objectionable than 44KKz to me, so I think I might use 48KHz as my target samplerate. Out of the built-in filters, I like strong-ath48 best.

Inspired by this thread -- but also because I like messing around with DSP stuff from time to time .... I wrote two programs that let you design and apply noise shaping filters. Check out my little homepage (screenshot and ZIP to downlad).

Very very nice, certainly easier than positioning the poles and zeros in the z-plane to obtain the freq. response!

Thanks!

QUOTE (Firon @ Sep 4 2006, 22:43)

It seems to have clicking noises while typing or changing to another window. Anything you can do about that?

I developed it under Ubuntu Linux using Sun's Java 1.5 SDK. I was surprised that I could drop the buffer down to 40 ms. But I know what you mean. I tried it yesterday on a WinXP machine and I noticed dropouts. I guess I'll make the buffer size configurable for the next version and/or do something about the thread's priorities. What I can't change is the JRE's sound API implementation or how your OS handles threads.

QUOTE (Firon @ Sep 4 2006, 22:43)

These dithering tests have made me realize that being a bit sensitive to HF content may not be such a good thing 48KHz sounds a lot less objectionable than 44KKz to me, so I think I might use 48KHz as my target samplerate. Out of the built-in filters, I like strong-ath48 best.

I think it's important to note that some soundcards have "issues" playing 44 kHz content. I for one have a Soundblaster Live Value! which is known to resample badly from 44 to 48 kHz internally. So, it might be possible that you push noise to high frequencies which are mirrored down to the audible range due to the bad resampling.

I think it's important to note that some soundcards have "issues" playing 44 kHz content. I for one have a Soundblaster Live Value! which is known to resample badly from 44 to 48 kHz internally. So, it might be possible that you push noise to high frequencies which are mirrored down to the audible range due to the bad resampling.

I've got the nForce2 onboard, and I remember reading on HA that the resampling it did was pretty decent. Still could very well be the case though.

Dummy question:In the transfert function, is z^{x} representing the signal or the quantization error.I'd think that it should be the quantization error, as noise shaping is supposed to be a filter on quantization error, however the presence of z^{0} is then puzzling me.

Those questions could be stupid, but..What does the moving bar actually show?

It indicates the maximum sample value you got for the last second. Dithering and noise shaping especially at low resolutions may lead to large fluctuations of samples even in case you might not hear it (because it may be mainly high frequency noise).

QUOTE (Hollunder @ Sep 5 2006, 11:59)

Does it make sense to make a filter at 8 bit to use it at a higher bitrate? (well at least it works..)

Yes. In fact this is what I did to design the filters 'cause the noise is easily noticable at lower resolutions. If you use the same filter with a higher resolution the noise floor just gets lowered -- it still has the same "colour" to you (if you can hear it).

QUOTE (Hollunder @ Sep 5 2006, 11:59)

How to understand this Z-plane-thing? A pointer to some ressources would be nice.

Sorry, I'm no good at giving pointers on this subject. Maybe someone can comment on some good DSP books. IIRC there was a "good DSP/digital audio books" thread in the R&D sub forum (or something like that).<technical mumbo jumbo>A point in the Z-Plane basically corresponds to an oscillating signal with either decreasing amplitude (inside the circle), constant amplitude (on the circle) or increasing amplitude (outside the circle) and of a certain frequency that's given by the argument of the point (as complex number). The filter transfer function just tells you what the filter is doing to said oscillating signals. If you care about what it does to constant amplitude sinusoids you just evaluate this function on the circle (which is how the green curve is derived). The zeros (blue circles) and poles (red crosses) are defining that transfer function as a rational polynomial with the zeros as roots of the nominator and poles as roots of the denominator. This should also explain why those things have the greatest impact on the response if they're close to the unit circle. The number that gets showed for each root in the frequency response plot is the distance of the root from the origin. I'm afraid I possibly havn't achieved anything by saying it with my own words in such a compact way. You better grab a good DSP book to look at.</technical mumbo jumbo>

QUOTE (Gabriel @ Sep 5 2006, 12:49)

In the transfer function, is z^{x} representing the signal or the quantization error.I'd think that it should be the quantization error, as noise shaping is supposed to be a filter on quantization error, however the presence of z^{0} is then puzzling me.

It's just a transfer function corresponding to an IIR filter. This IIR filter is applied to the unshaped noise. The presence of z^0 is not a problem really, z^0 = 1 -- although it takes a while to understand how filtering can be applied to the noise only. (Well, at least it took me quite a while to realize).

<technical info>Recall the "difference IIR" formula:y_{n} = b_0 * x_{n} + b_1 * x_{n-1} + b_2 * x_{n-2} + ... - a_1 * y_{n-1} - a_2 * y_{n-2} - a_3 * y_{n-3}where y is the filter's output, x is the filter's input, the index n refers to the current sample, n-1 refers to the previous sample a.s.o. and b's and a's are the filter's coefficients. In case of noise shaping filters b_0 needs to be equal to ONE so that output and input are related in the following way:y_{n} = x_{n} + OutputInputDifference(n)where OutputInputDifference(n) ist just an abbreviation of the sum given above and depends on the filter's coefficients and past (un)filtered samples.

The funny thing about noise shaping is: You're computing the current sample without knowing x_{n} before because x_{n} will be the quantization error. Suppose s_{n} are the samples of the actual signal you want to transport and x,y are the samples of the (un)filtered noise. What actually happens in the inner loop over n is:1) wanted_{n} = s_{n} + OutputInputDifference(n)2) quantized_{n} = quantize( wanted_{n} + dither() )3) y_{n} = quantized_{n} - s_{n}4) x_{n} = y_{n} - OutputInputDifference(n) // == quantized_{n} - wanted_{n}, the actual error

I recently checked Why 1-Bit Delta Conversion is Unsuitable for High-Quality Applications again. Their noise shaper's transfer function is given by 1-H(z) which also corresponds to a rational polynomial of the form (1+b1*z^{-1}+b2*z^{-2}+...)/(1+a1*z^{-1}+a2*z^{-2}+...) like printed by IIIRDSGN. And any such rational polynomial can be represented as 1+polynomial_division_residual. In the end it's all the same.</technical info>

Save the above text to "lameath44.sos" and the filter is ready to be used by REQUANT.

Note: This filter is NOT compatible to IIIRDSGN. It has a pair of distinct real poles and IIIRDSGN only supports complex conjugate roots. IIIRDSGN will simply ignore 2nd order polynomials with distinct real roots, print out a warning and show you a different magnitude response.

edit:In case your noise shaping implementation follows this popular signal flow graph and you require the coefficients b_h & a_h for H(z) then you need to derive these from the noise shaper's transfer function G(z) (given by b & a) like this:b_h = remove_leading_zero(a-b);a_h = a;due to the relationship G(z) = 1 - z^-1 H(z). So, for the above example b_h would beb_h = [2.20610 -0.47070 -0.25340 -0.62130];For FIR filters this boils down to removing the leading one and negating the remaining coefficients.

For those who are interested in using these filters on their own I'm sharing some demo code written for Matlab/Octave. The main file nsqdemo.m is a script that also contains some documentation and should be self-explanatory.

The algorithm is the same as the one used in IIIRDSGN and REQUANT internally: It uses chained 2nd-order sections in direct form II. The parameters needed to initialize the filter's state is a SOS-matrix that describes the noise shaper's transfer function G(z) directly -- not H(z) for G(z)=1 - z^-1 H(z). This is the SOS-matrix that's stored in the *.sos files (sometimes without 1st and 4th column which always contain ones).

edit:Here's a 48 kHz version derived simply by frequency warping the 44kHz-filter from above:

This package is FREEWARE. You are allowed to copy/distribute it in its original unmodified form and use it for private non-commercial purposes. For intendet commercial use please contact the author via EMail

I have written my own quantizer because I have to go all the way down to 1 bit because, well, the Aquarius can only send an on or an off to the speaker. I have also distributed the quantization error and incorporated a random dither (although not on all of the reduced bits because that destroys ANY audio fidelity.)

Anyway, I do not really know what I am doing. I know I am distributing the quantization error and I know I am adding some random dither, I also know that this results in some type of noise/distortion shaping. All I did was modify my coefficients until it "sounded good."

My sampling rate is 50,700 Hz so the Nyquist Frequency is 25,350. I'd like to move the noise from 3,000 Hz and 12,000 Hz up to 25,000 Hz - but I have no idea how. I realize that at 1 bit it won't ever sound "great" but I know it can sound better. Any ideas?

My sampling rate is 50,700 Hz so the Nyquist Frequency is 25,350. I'd like to move the noise from 3,000 Hz and 12,000 Hz up to 25,000 Hz - but I have no idea how. I realize that at 1 bit it won't ever sound "great" but I know it can sound better. Any ideas?

While the matter is a bit too complicated for me, there are a few things to note: These filters seem to be designed for multi-bit output. There are probably better approaches for the 1-bit case. In the examples you produced, I noticed that your most recent output appears to be completely devoid of high-frequency content past 16kHz or so.

I know you want to do the processing on your device, but it would seem to me you'd be better served processing the data on your PC and then storing only the encoded data on the device. That way you can perform more complicated processing.

I invite you to make a separate post in our Scientific Discussion forum describing your problem and what you hope to achieve. I think some people who may be otherwise interested in the topic may miss out otherwise.

For those who are interested in using these filters on their own I'm sharing some demo code written for Matlab/Octave. The main file nsqdemo.m is a script that also contains some documentation and should be self-explanatory.

The algorithm is the same as the one used in IIIRDSGN and REQUANT internally: It uses chained 2nd-order sections in direct form II. The parameters needed to initialize the filter's state is a SOS-matrix that describes the noise shaper's transfer function G(z) directly -- not H(z) for G(z)=1 - z^-1 H(z). This is the SOS-matrix that's stored in the *.sos files (sometimes without 1st and 4th column which always contain ones).

edit:Here's a 48 kHz version derived simply by frequency warping the 44kHz-filter from above: