Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: Triangular Probability Density Function Dither (Read 51523 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Triangular Probability Density Function Dither

Hello everybody,

THis is my first post on this site. NIce to find a forum for this field which I am interested in and studying.

So here is the problem...

I need to write in C, a program that will dither and truncate a 16 bit stereo file to a 14 bit stereo file. It is for an assignment for university basically. I more or less have the idea of how it works after having read several books and websites.

However here is the problem/question.

To go from 16 bit to 14 bit and add dither before truncating it is necessary to add 3 bits of noise to the 16 bit original signal.

3 bits can have the maximum value of 8. In audio Terms -4 to +4. Correct so far?

Now if i generate a random number between 0 and 8, I can't just add that number to the 16 bit stream right? Becuase I need to add a +4 to -4 range number. It that correct? and if it is, how can I generate a random number between +4 and -4 in C?

int a = rand() % 8;

this would give a random value between 0 and 8. BUt how do i set a lower and upper limit for the random number to be generated?

Well, at this point this is all i will ask. I have a feeling this is somehting really simple and for some reason I have been stuck on it for some time now. 

Thank you in advance for reading it and hopefully replying.

In the meantime, Happy New Year everybody! 


PS: Oops..i just realised it was moved from general audio to Scientific..Sorry..i am new ..i thought this was a simple question and thats why i put it in General audio.

Triangular Probability Density Function Dither

Reply #1
Hi,

I'm quite a newbie, so I can't offer you real help, but I just want to point out something small.

3 bits give you 8 choices, yes, but with unsigned integers you'll probably get from 0 to 7, and with signed integers you'll probably get from -4 to 3.

-4, -3, -2, -1, 0, 1, 2, 3. Which makes 8 choices.

If you use % 8, you'll get numbers ranging from 0 to 7. Subtract 4, and you can get -4 to 3.

Triangular Probability Density Function Dither

Reply #2
AFAIK rectangular dither is equal to random noise (= same probability for every value, in your case between -4 and 3). Triangular dither means adding independant random noise (values 0-7) 2 times and substracting 7 resulting in a triangular distribution of values:
7 = 1 / 64
6 = 2 / 64
5 = 3 / 64
...
0 = 8 / 63
...
-6= 2 / 64
-7= 1 / 64

BTW: There might be something wrong with this as Cool Edit Pro behaves not exactly the same: The values are in [-8;7] range instead, I guess because it uses higher resolution to generate and apply dither noise before truncation to final resolution.

I hope someone more knowledgable can help here soon. Maybe having a look at SSRC source (avail. here will be helpful for you.
Let's suppose that rain washes out a picnic. Who is feeling negative? The rain? Or YOU? What's causing the negative feeling? The rain or your reaction? - Anthony De Mello

Triangular Probability Density Function Dither

Reply #3
Hey..thanks for your replies.

I have come up with this code so far for Triangular Probability Density Function Dither from 16 bit to 14 bit. I declare two intigers and b. Two random numbers will be assigned to these intigers before they are added.

Since i need to add 3 bits of noice and as you already have explained that gives values between 0 to 7 unsigned or -4 to 3 for signed. In Rectangular Probability Densisty Function I would only use one random number generator for values 0 to 7 or -4 to 3 and add them to the signal as noise.

In Triangular Probability Function in order to achieve a highier number of values towards centre of the value range, I need to use two random number generators and add the sum for those two numbers to the signal as noise.

However, while the number generated for Rectangular Probability can be:

int a = rand() % 8;  and add the value to the signal,

In Triangular Probability I would be:

int a = rand() % 4;
int b = rand() % 4;

a = a + b; and add this sum to the signal.

QUESTION: Is this logic so far correct?

Bellow is the code I have so far. I haven't tried to compile it cause the system at the labs in the University is down and the administrator obviosuly is not working due to New Years Holiday. But for those who are more familiar with this type of work, does the code below make sense in theory?


Once again, thanx in advance and Happy New Year

PS:Sorry for the long post.

//Triangular Probability Density Function Dither

int a, b;                                                        //Declare two integer

while( (numberOfReadFrames = afReadFrames(afInputFileHandle, trackId, (void*) sampleBuffer, numberOfFramesPerBuffer) ) > 0 )
{

    for(j = 0; j < numberOfReadFrames; j++)
    {
        //Generate random noise between 0 and 3
        a = rand() % 4;
        //Generate random noise between 0 and 3
        b = rand() % 4;   

        a = a + b;                                          //Add random numbers
       
        //Add noise to Left Channel
        sampleBuffer[2*j] = (short) (sampleBuffer[2*j] + a);
        //Add noise to Right Channel
        sampleBuffer[2*j + 1] = (short) (sampleBuffer[2*j + 1] + a);

        //Trancate Left Channel
        sampleBuffer[2*j] = (short) (sampleBuffer[2*j] >> 2);
        //Trancate Right Channel
        sampleBuffer[2*j + 1] = (short) (sampleBuffer[2*j + 1] >> 2);
    }
 
    afWriteFrames( afOutputFileHandle, trackId, sampleBuffer, numberOfReadFrames );
}

Triangular Probability Density Function Dither

Reply #4
It seems correct, but wouldn't you just need to add (approximately) 2 bits of noise? Before truncating there would be values between 0 and 3 in the 2 last significant bits, so you'd only need to add a number between -2 and 1 (actually, shouldn't that be -2 and 2? or perhaps -1 and 2) to make it swing either way. Or am I missing something here.

Triangular Probability Density Function Dither

Reply #5
Hey Jasper..thanks for your post.

The decision to add 3 bits of noise comes from the http://www.cadenzarecording.com/dither.html example. They go from 24 bit to 16 bit and add 9 bits of noise. So the formula for determining how many bit of noise to add is:

(original bit value - bit value to be lowered to) + 1 = bit length of noise to be added

Example: (24 - 16) + 1 = 9

At least thatis how I understood it 

According to their example.... to go from 16 bit to 14 i will need to add 3 bits of noise..that way...once its truncated to 14 bit..then only the first bit has noise?

Triangular Probability Density Function Dither

Reply #6
You might want to consider the fact that with most C libraries rand() % 8 will not give you high quality random numbers. The least significant bits returned by C lib PRNGs are notoriously unrandom. Whether or not this will be audible, I don't know - but you might want to think about it.
Also, I had assumed from what I have read that when dithering you would use different noise for each channel.

Based on tigre's post this is the code I would write (for one channel only) for each sample:
Code: [Select]
unsigned short ditherValue(unsigned short sample)
{
sample += hqRand(8) + hqRand(8) - 7;
sample >>= 2;
return sample;
}

This code is not perfect - samples close to clipping will cause brokenness.

The following will work acceptably well for hqRand(), but is not without it's problems. You will want to read up on better techniques:
Code: [Select]
unsigned short hqRand(int limit)
{
return (rand() >> 3) % limit;
}

Triangular Probability Density Function Dither

Reply #7
If you are looking for good random number generators, have a look at Boost (http://www.boost.org/), it's a C++ library, but you might be able to extract the code for a random number generator that suits your needs.

BTW, is there anyone that can explain why the +1 in the following formula is necessary?
Quote
(original bit value - bit value to be lowered to) + 1 = bit length of noise to be added

I gave dithering a try myself some time ago and it seemed to work alright without the +1.

Triangular Probability Density Function Dither

Reply #8
Hello, Jasper..the way I understood it was that if you are to go from 16 to 14 bits, if u add only 2 bits of noise..those two bits of the noise will be gone as soon as u trancate it to 14 so the resulting signal would be the same as it would have if simply trancated without any noise, since the two last bits are errased.

So if you add three bits of noise..then when u remove 2 bits from the signal, then one bit of the remaining 14 bits will still contain the data from the noise.


I am getting a clearer idea on this dither the more i read all of your posts.

Cabbagerat, your code makes sense, and i will take your advice and add different noise to left and right channel. I have one more question though.

In the rectangular dither I will be adding random values in the range of -4 and 3(3 bits signed)

But in the triangular where I need to add two random numbers in order to come up with a highier chance of numbers in the middle of the range, you suggested the following code:

sample += hqRand(8) + hqRand(8) - 7;

However this would result in a range between -7 and 7. This would not be a 3 bit signed range right?

So i thought of changing it to:

sample += hqRand(4) + hqRand(4) - 3;

But each random would then generate a maximum number of 3. So the maximum number generated by adding those two randoms would be 6, subrtact the 3, and that  leaves 3. So the range would be -3 to 3. So this is not equal to the -4 to 3 range of the rectangular noise.

i could change it to :

sample += hqRand(4) + hqRand(4) - 4;

This would fix the lower range to match the one of the rectangular dither of -4, but it would also lower the maximum range to 2.

ANd so once again, I am stuck! Its probably something simple and Its not comming to me! I shall continue to try and find the answer to this, but if you have any suggestions that would as usual be great! 

Thanx in advance!

Triangular Probability Density Function Dither

Reply #9
Actually the information from those two bits of noise wouldn't be completely lost, as it would result in different rounding. Suppose you were going from 4 bits to 2 bits and the current value would be 3 (0011 in binary), now add some random number between -2 and 2 (actually this would result in 5 combinations, but in that article "Dithering Explained" they also use symmetrical values), the result would between 1 (0001) and 5 (0101). So why wouldn't this be enough to give at least a small amount of dither?

EDIT:
As for those random values, if you are determined to add 3 bits of noise, why not use:
sample += hqRand(5) + hqRand(5) - 4;
This would result in values in the range [-4,4], which is comparable to what they did in the article mentioned in one of the first posts (there they add 9 bits of noise by adding values in the range [-128,128]). Of course the term "n bits of noise" is a bit misplaced in this case, but it is less biased. As an example, consider the situation above (from 4 bits to 2 bits):

Original: 0100
Possible outcomes:
0010 -> 00
0011 -> 00
0100 -> 01
0101 -> 01
0110 -> 01 *

Original: 0101
Possible outcomes:
0011 -> 00
0100 -> 01
0101 -> 01
0110 -> 01
0111 -> 01 *

Original: 0110
Possible outcomes:
0100 -> 01
0101 -> 01
0110 -> 01
0111 -> 01
1000 -> 10 *

Original: 0111
Possible outcomes:
0101 -> 01
0110 -> 01
0111 -> 01
1000 -> 10
1001 -> 10 *

The outcomes with an asterisk (*) behind them wouldn't be generated if you added numbers in the range [-2,1] (which would be true 2 bits signed), which results in a signal that's biased towards negative infinity.

Triangular Probability Density Function Dither

Reply #10
There must be a mathematical way to determine how much dither is necessary to avoid distortion and noise bumping totally, depending on dither flavour (rectangular, triangular). I don't know anything about this but I'm sure someone else does (KikeG?). You can always perform tests on this using CoolEdit / Audition (frequency analysis etc.)
Let's suppose that rain washes out a picnic. Who is feeling negative? The rain? Or YOU? What's causing the negative feeling? The rain or your reaction? - Anthony De Mello

Triangular Probability Density Function Dither

Reply #11
http://www.hydrogenaudio.org/forums/index....indpost&p=71022

This thread has tons of info... it's SSRC-specific, but hopefully useful nonetheless.

Just according to the first post, for triangular PDF: 0.9 bits are needed to avoid appreciable distortion (noise modulation remains), 1 bit needed to avoid noise modulation.

Triangular Probability Density Function Dither

Reply #12
Quote
There must be a mathematical way to determine how much dither is necessary to avoid distortion and noise bumping totally, depending on dither flavour (rectangular, triangular).

... Totally ...

What does this mean?
- inaudible?
- a certain level below audibility?
- not existing in any way?
Diocletian

Time Travel Agency
Book a journey to the Diocletian Palace. Not today!

Triangular Probability Density Function Dither

Reply #13
totally = not mesurable.

e.g. distortion: If you create a low volume sine wave, add dither and truncate, besides the original tone, no peaks must be visible in frequency analysis.
Let's suppose that rain washes out a picnic. Who is feeling negative? The rain? Or YOU? What's causing the negative feeling? The rain or your reaction? - Anthony De Mello

Triangular Probability Density Function Dither

Reply #14
Hello everybody...lots of replies i see...lots of information and as usual more questions...   

Ok..Jasper your post regarding adding 2 bits of noise and then loosing 2 bits that it is still have an effect on the remainng bits makes perfect sense. What i will do for my assignment is do both 2 bits and 3 bits of noise and explain in the documentation why i tested both of them and compare the audio with frequency analysis diagrams.

Secondly, your suggestion to use sample += hqRand(5) + hqRand(5) - 4; also makes sense, giving me a range of -4 to 4. As a range of -4 to 3 would be more negative value biased.(I had actualy scribled on a piece of paper rand() %5 + rand() % 5 -4 and calculated the range it would give me...and i had written down -4 to 6 becuase i was tired and forgot that rand() % 5 can give u a maximum of 4 and not 5. Silly me)

However, That has confused my understanding of digital audio theory. See I always thought that, a 16 bit signed short has a range of -38,768 to 32,767. According to that, ZERO is not half way between the minimum and maximum range right? So is ZERO actually more positive based? Does zero correspond to -1? and is -0.5 the actual halfway between the range? 

Thirdly, a range of -4 to 4 in the triangular code makes sense. But, in my rectangular dither i use rand() % 8 - 4  to generate the random number, giving me a range of -4 to 3. This suffers from being more negative value biased. I must make the the range to be from -4 to 4 also.  So i will change it to rand() % 9 - 4. This will give me a range of -4 to 4.

Tigre I have downloaded a 30 days trial of Adobe Audition and have been trying out the Frequency analysis feature. THanks for the suggestion

Ariakis, thanks for the link. I tried to read that and got confused (again). It talks about 0.5, 0.9 and 1.0 bits of noise! How do you get a portion of a bit noise? I thought one bit was the smallest value of noise one could add.. How does this work?

Once again, thanks to all of you, you are truly LOTs of help!!! 

Triangular Probability Density Function Dither

Reply #15
Quote
It talks about 0.5, 0.9 and 1.0 bits of noise! How do you get a portion of a bit noise? I thought one bit was the smallest value of noise one could add.. How does this work?

Do processing at higher resolution (e.g. 32bit float), including noise generating.
Let's suppose that rain washes out a picnic. Who is feeling negative? The rain? Or YOU? What's causing the negative feeling? The rain or your reaction? - Anthony De Mello

Triangular Probability Density Function Dither

Reply #16
I've only just seen this thread.

At the risk of doing your research for you...


Using your example of reducing from 16 to 14 bits. A and B are both sequences of random numbers, such that, for any given sample

A = 00 or 01 or 10 or 11
B = 00 or 01 or 10 or 11

Rectangular dither is added by adding A (only) to a signal, and removing the last two bits. Rectangular dither is sub-optimal because, though harmonic distortion is removed, noise modulation remains.

Triangular dither is added by adding A and B to a signal, or adding A and subtracting B.


To prevent DC shift or bias, you must think carefully about what kind of rounding, truncation, or quantisation you are using, and adjust accordingly. Consider the last bit you will keep as representing the least significant bit of a whole number (1), and the less significant bits (which you will remove) as representing a fractional part.

The rectangular dither will not introduce a DC shift if a round-down quantiser is used. Simple truncation (throwing away the fractional bits) acts as a round down quantiser, so simply adding A and truncating works well.

The triangular dither will not introduce a DC shift if we add A minus B, and use a "centre (center, if you're American) rise" quansier. This is the typical "rounding" function we use everyday with decimal numbers - if the fractional part is under 0.5: round down, 0.5 or above: round up.

Truncation is not the same as rounding, and does not give a centre rise quantiser. However, if you simply add 0.5, and then truncate, the result will be the same as rounding.

So, for triangular dither without DC bias, just use
A-B+0.5
or
A+B-0.5
whichever is easier.


All IIRC - it's been 6 years since I studied this.

You really should search out some good paper references. The original 1984 AES paper from Vanderkooy and Lipshitz, "Resolution Below the Least Significant Bit in Digital Audio Systems with Dither" (volume 32, issue 3, pp106-112 if the page Google found is to be believed) is well worth reading carefully.

Cheers,
David.

Triangular Probability Density Function Dither

Reply #17
Quote
There must be a mathematical way to determine how much dither is necessary to avoid distortion and noise bumping totally, depending on dither flavour (rectangular, triangular). I don't know anything about this but I'm sure someone else does (KikeG?). You can always perform tests on this using CoolEdit / Audition (frequency analysis etc.)

If I'm not wrong (2Bdecided probably knows better than me), mathematically, with rectangular dither, 1 bit amplitude is enough to totally remove distortion, but noise modulation remains. With triangular dither, 1 bit is enough to totally remove both, distortion and noise modulation. With noiseshaping dither, the amount depends on the shaping of the noise floor, but is usually below 1 bit. I don't know of a way of calculating this, but maybe the mentioned paper does. At the tests I did on the mentioned thread I used subjective listening tests for the noise modulation issue, using a critical test signal, amplified several tenths of dBs to make dither failure audible, and also frequency analysis (FFT) to detect distortion.

Triangular Probability Density Function Dither

Reply #18
Quote
Do processing at higher resolution (e.g. 32bit float), including noise generating.

I heard of audio software doing the internal processing at 32 bit float resolution..but here comes the dummy question...how?

I have never done this...this is what I have come up with..does it make sense?

Code: [Select]
for(all the samples in the audio file)
{
    float sampleFloat = (float) sampleBuffer[i];   // Change the sample into float?
    float randomNumber = (rand() % n) -n;  //This wouldn't even work would it?Generating random FLOAT?
    sampleFloat += randomNumber;
    sampleFloat >> n;   //Truncate by however many bits needed to the right
    sampleFloat << n;   //Truncate by however many bits needed to the left
    sampleBuffer = (short) sampleFloat;  //Store new sample value back to buffer array      as short data type?
}


Is my idea even close to reallity or 32 bit processing.

One last question on this matter. If we can process with 32 bit float for precision..what stops us going to the extreme and processing in something of highier precision than that even? say..64 bit??? 

Got more questions comming...just asking them as seperate posts to kep things organized..

thanx people!

Triangular Probability Density Function Dither

Reply #19
Hello 2bDecided..your post is helpful and thank you lots for your it. I have the following questions so i can finnaly get my head around this.


For two bits of triangular probability noise i could use:

(rand() % 3) + (rand() % 3) - 2;

This will give me a range of -2 to 2. The possible values are -2,-1,0,1,2. THat is five of them with 0 being the absolute centre. Does this not result in a dither without DC bias?

On your example, you generate a true 2 bit noise range of 4 values. There is no clear MIDDLE value. It this the case where the use of +0.5 or -0.5 is necessary?

Also, I assume that in order to add or subtract the 0.5, i need to be processing the samples in 32 bit float precision, so hopefully i can find some information on how to do that if my earlier guess in this post is wrong.

U mentioned the addition of 2 bits worth of noise inthe example of going from 16 to 14 bit. Does this mean you belive that the amount of bit of noise to add is equal to the amount of bits you are about to loose by truncating?

I hope this makes sense...There are too many loose questions in my head which I am not sure if they are related or not, or how to ask them appropriately...
THe feeling of learning and understanding somethng new i suppose. 

I am on my way to the library now to look up that AES journal entry you recommended.

thanks a lot for your patience!

Triangular Probability Density Function Dither

Reply #20
Quote
if I'm not wrong (2Bdecided probably knows better than me), mathematically, with rectangular dither, 1 bit amplitude is enough to totally remove distortion, but noise modulation remains. With triangular dither, 1 bit is enough to totally remove both, distortion and noise modulation. With noiseshaping dither, the amount depends on the shaping of the noise floor, but is usually below 1 bit.

Hello,

these recommended values of noise, are you suggesting them on the basis of the 16 to 14 bit scenario or in general?

At first I thought that if you are going to loose n bits of the signal then add n+1 bits of noise, so that after truncating the signal you still have 1 bit of noise in the signal.

As it was explained by Jasper,

Quote

Actually the information from those two bits of noise wouldn't be completely lost, as it would result in different rounding. Suppose you were going from 4 bits to 2 bits and the current value would be 3 (0011 in binary), now add some random number between -2 and 2 (actually this would result in 5 combinations, but in that article "Dithering Explained" they also use symetrical values), the result would between 1 (0001) and 5 (0101). So why wouldn't this be enough to give at least a small amount of dither?
[\quote]

It makes perfect sense. But how about when going from 16 bits to 8 bits. The chances of the value changing due to rounding gets smaller if adding a small size of noise.

So surely there must be some way of calculating and determining how many bits of noise are necessary/recommended depending on 2 factors: 1) the number of bits you will be truncating the signal by, and 2) the type of noise you will be adding as it seems different probabilities and noise shaping can require diferent amount of noise.


Thanx!

Triangular Probability Density Function Dither

Reply #21
Quote
However, That has confused my understanding of digital audio theory. See I always thought that, a 16 bit signed short has a range of -38,768 to 32,767. According to that, ZERO is not half way between the minimum and maximum range right? So is ZERO actually more positive based? Does zero correspond to -1? and is -0.5 the actual halfway between the range?

Last question for some time (hopefully!)

This hasn't been discussed..Does anybody have an understanding on this?

Is digital audio always a bit negatively biased as the value of the negatives(-38,768) is greater than that of the positives(32,767)?

I know this value difference is tiny..but curious in the theory behind this.


Triangular Probability Density Function Dither

Reply #22
Quote
Hello 2bDecided..your post is helpful and thank you lots for your it. I have the following questions so i can finnaly get my head around this.


For two bits of triangular probability noise i could use:

(rand() % 3) + (rand() % 3) - 2;

This will give me a range of -2 to 2. The possible values are -2,-1,0,1,2. THat is five of them with 0 being the absolute centre. Does this not result in a dither without DC bias?

On your example, you generate a true 2 bit noise range of 4 values. There is no clear MIDDLE value. It this the case where the use of +0.5 or -0.5 is necessary?

Also, I assume that in order to add or subtract the 0.5, i need to be processing the samples in 32 bit float precision, so hopefully i can find some information on how to do that if my earlier guess in this post is wrong.

You're getting confused between the value before and after truncation. It's helpful if you think in binary about what you're doing before truncation. It's also convention to quote values in decimal relative to the last remaining bit being 1 after truncation.


So, thinking in binary, (rand() %3) apparently gives you 0, 1, or 2 i.e. 00, 01, or 10. What happened to 11?! So that's the wrong amplitude to start with.

If the last remaining bit after truncation has a value of 1, then the bit that was to its right before truncation has a relative value of 0.5. So, just like you, I was simply subtracting 2 before truncation - no floating point necessary.


Quote
U mentioned the addition of 2 bits worth of noise in the example of going from 16 to 14 bit. Does this mean you believe that the amount of bit of noise to add is equal to the amount of bits you are about to loose by truncating?


An easy rule is that the rectangular dither should exactly fill the bits you remove (no more, no less), and that triangular dither can be created by adding two independent rectangular dither sources. This makes things very easy.

so 16 to 8 bits conversion is
xxxxxxxxyyyyyyyy > xxxxxxxx
you need two rectangular dither generators (i.e. two pseudo random number generators) ranging from 00000000 to 11111111 i.e. 0 to 255. You don't want 256 (100000000) because that gives you an amplitude of 1 too many.

(Think about it with a decimal example: it's just like 0,1,2,3,4,5,6,7,8,9 gives you ten possible values, but 0,1,2,3,4,5,6,7,8,9,10 gives you eleven. So unless you want a range of eleven, then if you include the number 0, you don't include the number 10. It's the same here, but in binary)


Finally, digital audio isn't DC biased one way or the other - it's just that it can go one more value negative than positive. When CDs were introduced, "good" converters had DC offsets of, say, 40 or 50 (measured in units of 1 LSB at 16-bit) so it was probably never even considered.

Hope this helps. I think the contributors to this thread deserve a credit and/or reference in your project, and a drink!

Cheers,
David.

Triangular Probability Density Function Dither

Reply #23
Quote
Hope this helps. I think the contributors to this thread deserve a credit and/or reference in your project, and a drink!

It sure has helped! thanx a lot..and you are absolutely right all the contributors deserve mention and great thanks in my project!

Please email me at ad167@york.ac.uk with your username of this forum and your real name so that I can give you all the appropriate credit you all deserve. You can post the information on this forum but i figured some might not want to post their real names on a forum. If I Dont receve your real names I can still go ahead and refere to you by your forum username 

As far as drinks!!! Absolutely! Anybody live in York UK? If yes email me at the above address 

Thank you everybody!

Triangular Probability Density Function Dither

Reply #24
Just a note on what David said about a triangular generator being a combination of two rectangular generators...

He said that to get 8 bits of triangualr pseudorands, you'd need to combine two rectangular generators with ranges of [0, 255].  This, however, would allow a total range of [0, 510], which is more than 8 bits.

So to get 8 bits of triangular dither, you'd need to combine [0, 127] and [0, 128] rectangular generators to get a [0, 255] triangular generator.  At least, I think.

So, in your case, you'd want 3 bits of noise, which is [0, 7]... so you'd want to combine [0, 3] and [0, 4] rectangular generators, I think.

Someone correct me if I'm wrong, please. =)