hello,
I'm a little stuck with how to talk to the DAC of the wave shield. specifically, i've been trying to expand the wave.hc library by a bitshift function a la setSampleRate, like so:
//------------------------------------------------------------------------------
/** Set bit rate.
*
* \param[in] bits. The nr of bits to be shifted.
*/
void WaveHC::setBitShift(uint8_t bits)
{
cli();
while (TCNT0 != 0);
if (bits > 12) {bitShift = 12; }
else {bitShift = bits;}
sei();
}
//
where bitShift is a global variable. there's a few lines in WaveHC.cpp where it talks to the DAC, which I tried to modify to shift by the value of that bitShift variable:
uint8_t dh, dl, shiftHIGH, shiftLOW;
if (playing->BitsPerSample == 16) {
if (bitShift > 4) {
shiftLOW = 8; shiftHIGH = bitShift - 4;
}
else {
shiftLOW = bitShift + 4; shiftHIGH = 0;
}
// 16-bit is signed
dh = 0X80 ^ playpos[1];
dh = dh >> shiftHIGH << shiftHIGH;
dl = playpos[0];
dl = dl >> shiftLOW << shiftLOW;
playpos += 2;
}
else {
// 8-bit is unsigned
dh = playpos[0];
dh = dh >> bitShift << bitShift;
dl = 0;
playpos++;
}
this seems to work alright (for 16 bit files), but only for values of bitShift up to 7. I guess I'm not really understanding how the low/high bit coding scheme actually works. I was assuming that if you wanted to bitshift playpos by, say, 10 bits, you'd have to shift the high bits by 8 (dh), and then the low bits by 2 (dl), so that you'd still send two bits to the DAC, but this isn't what's happening, the DAC just turns silent.
anyone has got an understanding of this?
many thanks
DAC question -- wave shield / bit crushing ?
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- ubiubu
- Posts: 8
- Joined: Thu Jun 21, 2012 6:56 am
DAC question -- wave shield / bit crushing ?
Last edited by ubiubu on Fri Jun 22, 2012 6:30 am, edited 2 times in total.
-
- Posts: 12151
- Joined: Thu Apr 06, 2006 4:21 pm
Re: DAC question -- wave shield / bit crushing ?
why are you trying to change the low level code? we don't suggest it...
- ubiubu
- Posts: 8
- Joined: Thu Jun 21, 2012 6:56 am
Re: DAC question -- wave shield / bit crushing ?
hi,
well, because I couldn't figure out how else to get access to single bits sent to the DAC. and i need to, if i want to reduce the bit depth. my problem is less about accessing low level code, but about how to properly reduce the bit depth.
edit: sorry, my bad. i guess i confused low and high bits
well, because I couldn't figure out how else to get access to single bits sent to the DAC. and i need to, if i want to reduce the bit depth. my problem is less about accessing low level code, but about how to properly reduce the bit depth.
edit: sorry, my bad. i guess i confused low and high bits
-
- Posts: 12151
- Joined: Thu Apr 06, 2006 4:21 pm
Re: DAC question -- wave shield / bit crushing ?
why would you reduce the bit depth?
- ubiubu
- Posts: 8
- Joined: Thu Jun 21, 2012 6:56 am
- pburgess
- Posts: 4161
- Joined: Sun Oct 26, 2008 2:29 am
Re: DAC question -- wave shield / bit crushing ?
I'd suggest using a remapping table (most likely in PROGMEM, since RAM is tight w/the SD library), reason being that proper quantization requires a combination of operations that might be asking a lot of the Arduino in realtime.
Consider an 8 bit sample, and we'll identify each bit as 'A' through 'H':
ABCDEFGH
Suppose we want to reduce this to 4 bits. Doing a 4-bit shift right and then left (or alternately, masking out the low bits) would yield:
ABCD0000
But this isn't correct, because the output doesn't scale to the full range. What's really wanted is:
ABCDABCD
As proof, consider an extreme case of 8- to 1-bit reduction. The double-shift or mask would yield A0000000, which can have one of two values: 0 or 128, only half the available output range (if applied to a grayscale image, that would yield black and gray). Scaling yields AAAAAAAA, still only two values, but these are 0 and 255, filling out the range in a way we would expect of 1-bit output (e.g. black and white in the image case).
You can generate a table in your language of choice, then copy the program's output into your Arduino sketch as a PROGMEM array (tutorial here).
The pseudocode for generating an 8-bit table might look something like this:
You might be able to pull off that inner loop on each sample in realtime, depending on the sample rate and input & output bit depths. Extreme cases (like 16-to-1) would be a lot of iterations on 16-bit types though, which is why I think a canned table might be the safer bet. Try it though.
Consider an 8 bit sample, and we'll identify each bit as 'A' through 'H':
ABCDEFGH
Suppose we want to reduce this to 4 bits. Doing a 4-bit shift right and then left (or alternately, masking out the low bits) would yield:
ABCD0000
But this isn't correct, because the output doesn't scale to the full range. What's really wanted is:
ABCDABCD
As proof, consider an extreme case of 8- to 1-bit reduction. The double-shift or mask would yield A0000000, which can have one of two values: 0 or 128, only half the available output range (if applied to a grayscale image, that would yield black and gray). Scaling yields AAAAAAAA, still only two values, but these are 0 and 255, filling out the range in a way we would expect of 1-bit output (e.g. black and white in the image case).
You can generate a table in your language of choice, then copy the program's output into your Arduino sketch as a PROGMEM array (tutorial here).
The pseudocode for generating an 8-bit table might look something like this:
Code: Select all
mask = 0xff << (8 - bits); // Initial bitmask -- most significant bits
for(i=0; i<256; i++) { // For each table entry...
a = i & mask; // Most significant bits of input 'i'
for(b = bits; b < 8; b *= 2) { // Repeat until all 8 bits are full
a |= (a >> b); // Clone upper bits downward
}
print(a);
print(',');
}
Last edited by pburgess on Sat Jun 23, 2012 1:53 pm, edited 1 time in total.
- ubiubu
- Posts: 8
- Joined: Thu Jun 21, 2012 6:56 am
Re: DAC question -- wave shield / bit crushing ?
i see ... thanks! i'll give it a shot.
- pburgess
- Posts: 4161
- Joined: Sun Oct 26, 2008 2:29 am
Re: DAC question -- wave shield / bit crushing ?
Typo in code.
should be:
(fixed in original reply now, in case anyone else comes looking for the same thing)
Code: Select all
a |= (a >> bits); // Clone upper bits downward
Code: Select all
a |= (a >> b); // Clone upper bits downward
- ubiubu
- Posts: 8
- Joined: Thu Jun 21, 2012 6:56 am
Re: DAC question -- wave shield / bit crushing ?
ps. so i've tried to implement the inner loop above, and it seems the arduino can pull off the bit cloning (thanks again, pburgess), but things got terribly loud when reducing a lot of bits. (i might have coded wrongly though...). i've been toying around a bit trying to improve on the bit truncation version and added some pseudo dither mask ... or, for what it's worth:
/** Set bit rate.
*
* \param[in] bits to be truncated.
*/
void WaveHC::setBitShift(uint8_t bits)
{
cli();
while (TCNT0 != 0);
bitShift = bits;
uint8_t dither = rand() % 255;
if (bits < 5) {mask = (0xff << bits + 4) | dither;} // lower byte, 4 bits are already truncated (DAC is 12 bit)
else {mask = (0xff << bits - 4) | dither;} // higher byte
sei();
}
then it's just applying the mask:
// 16-bit is signed
dh = 0X80 ^ playpos[1];
dl = playpos[0];
if (bitShift < 5) { dl & = mask;} // mask lower byte
else {
dh & = mask; // mask higher byte
dl = mask << (12 - bitShift); // random part of the mask
}
playpos += 2;
//
there's no way, it seems, calling something like rand() for each sample.
/** Set bit rate.
*
* \param[in] bits to be truncated.
*/
void WaveHC::setBitShift(uint8_t bits)
{
cli();
while (TCNT0 != 0);
bitShift = bits;
uint8_t dither = rand() % 255;
if (bits < 5) {mask = (0xff << bits + 4) | dither;} // lower byte, 4 bits are already truncated (DAC is 12 bit)
else {mask = (0xff << bits - 4) | dither;} // higher byte
sei();
}
then it's just applying the mask:
// 16-bit is signed
dh = 0X80 ^ playpos[1];
dl = playpos[0];
if (bitShift < 5) { dl & = mask;} // mask lower byte
else {
dh & = mask; // mask higher byte
dl = mask << (12 - bitShift); // random part of the mask
}
playpos += 2;
//
there's no way, it seems, calling something like rand() for each sample.
- ubiubu
- Posts: 8
- Joined: Thu Jun 21, 2012 6:56 am
Re: DAC question -- wave shield / bit crushing ?
ps.
here's a waveHC version with bitcrushing options, it seems http://www.standuino.eu/devices/instrum ... crogranny/
here's a waveHC version with bitcrushing options, it seems http://www.standuino.eu/devices/instrum ... crogranny/
Please be positive and constructive with your questions and comments.