Article View: borland.public.cppbuilder.multimedia
Article #434Re: Recording 24-bit audio (additional info)
From: Chris Croughton
Date: Fri, 06 Aug 2004 12:56
Date: Fri, 06 Aug 2004 12:56
134 lines
6838 bytes
6838 bytes
On Thu, 05 Aug 2004 12:13:41 +0100, Mark Jacobs <> wrote: > I found that WAVEFORMATEX structures need to be naturally discovered on > the PC using the ACM. That's the problem, the ACM doesn't seem to say anything about 24 bit samples at all on my machine. > Somehow, you have to discover the formats for 24-bit > sound handling. Remember that 24-bit is 3-bytes per sample, and most > compilers align structures to 4-byte boundaries - could that be the > problem? The data buffer is simply a character array (char *) so the byte > alignment doesn't make a difference in my apps. I have to interpret > different bits per sample, using different algorithms. When I tried it with different sample sizes, for sizes up to 16 bits I simply wrote the data out to a WAV file with no interpretation and that seemed to work fine, si it seemed that what is returned is standard WAV data. For 24 bits, I've tried block alignments at 6 and 8 bytes (stereo, so 3 and 4 bytes per value) with no difference. > However, I did notice something peculiar when I went to 8-bit > sampling (for VU meters etcetera). In the following code snippets, > glbwvhdr is the pointer to the WAVEHDR structure that is ready and > has been "unprepared" successfully. Here is my 8-bit code :- No surprise there, 8 bit data is encoded as and unsigned value, with 128 representing the zero point, just subtract 128 from each (unsigned) byte and it works fine. (Historical reasons: the early soundcards used 8 bit DACs which couldn't handle negative values, so the software wrote it as an unsigned byte and the hardware either normalised it to the zero point with a capacitative coupling which removed any DC offset, or some just offset it down by half the FSD value with a resistor chain.) Unfortunately, I can't try it again and produce files at the moment because my Win2k machine seems to have developed a fault (it comes up with a BSoD telling me about configuration errors, page tables uninitialised, page faults ate weird (and nonexistent) memory addresses, etc., I think it's very sick and needs surgery). > int > lv=128-abs((int)glbwvhdr->lpData[0]),rv=128-abs((int)glbwvhdr->lpData[1]); > if (glbwvhdr->lpData[0]<0) lv=-lv; > if (glbwvhdr->lpData[1]<0) rv=-rv; I don't understand why the business with abs() and then inverting it again. What's wrong with: int lv = (int)((unsigned char)glbwvhdr->lpData[0]) - 128; int rv = (int)((unsigned char)glbwvhdr->lpData[1]) - 128; (I think that lpData is an (unsigned char *) anyway, but I'm making sure by casting it.) Your code gives the same values, except that you treat 0x80 as +128 instead of -128. A shorter (but more obscure) way of doing it is to do: int lv = (signed char)(glbwvhdr->lpData[0] ^ 128); > zcDinMeter1->Value=lv*100/128; // Value is between 0 and 100 > zcDinMeter2->Value=rv*100/128; > > Now compare that to my 16-bit code :- > > short *mybf=(short *)glbwvhdr->lpData; > zcDinMeter1->Value=(int)mybf[0]*100*/32768; // Value is between -100 and > 100 > zcDinMeter2->Value=(int)mybf[1]*100*/32768; Since you know that the endianness is the same, you can do that. > Lord knows what 24-bit decode should look like, or why I have to muck > about so much with 8-bit samples to get them right!?! Well, with WAV files 24 bit samples are long lv = sample[0] + sample[1]*256 + sample[2]*65536; (and then the same for the right channel, divide by 8388608.0 to get it as a float with range (-1,+1]). That works with 24 bit 'unpacked' formats produced by (and understood by) n-Track, CoolEdit and Creative's WaveEditor (or whatever it calls itself in the Audigy incarnation). There are also 32 bit float formats, which I think are the standard IEEE floating point ones but I haven't seen any examples yet. > But let me just say > that your symptoms of having barely any signal in the right channel, is > exactly what I got when I used the 16-bit algorithm (adapted to 8-bit) on > the 8-bit samples. Perhaps if you use my 8-bit algorithm, but change 128 > to 8388608, and the buffer has to be re-interpreted. Try this :- No, the values I'm seeing are definitely IEEE floats, they make sense if I just do float *fptr = (float*)lpData; long lv = (long)(fptr[0] * 8388608); long rv = (long)(fptr[1] * 8388608); Except that the lv (left channel) is always zero, and the right channel always has the bottom byte set to zero (i.e. the float value is (float)(short) conversion). > int > dtlv=(int)glbwvhdr->lpData[0]*256*256+(int)glbwvhdr->lpData[1]*256+(int)glbwvhdr->lpData[2]; > int > dtrv=(int)glbwvhdr->lpData[3]*256*256+(int)glbwvhdr->lpData[4]*256+(int)glbwvhdr->lpData[5]; > int lv=8388608-abs(dtlv),rv=8388608-abs(dtrv); > if (glbwvhdr->lpData[0]<0) lv=-lv; > if (glbwvhdr->lpData[1]<0) rv=-rv; > zcDinMeter1->Value=lv*100/8388608; // Value is between 0 and 100 > zcDinMeter2->Value=rv*100/8388608; > > Does that work? If not, swap the bytes round backwards, so that the first > 2 lines look like this :- > > int > dtlv=(int)glbwvhdr->lpData[2]*256*256+(int)glbwvhdr->lpData[1]*256+(int)glbwvhdr->lpData[0]; > int > dtrv=(int)glbwvhdr->lpData[5]*256*256+(int)glbwvhdr->lpData[4]*256+(int)glbwvhdr->lpData[3]; Yup, those were the first I tried (actually, I dumped them to a WAV file and used my linux WAV file utilities to swap the bytes round and interpret them as floating point). The results were, to put it mildly, painful <g>. Eventually I tried treating them as floats, just for the halibut, and that worked (for single channel). I suspect that you're right, and the FORMATEX values I'm using are incorrect and are specifying mono 16 bit input represented as floats or something silly... Chris C
Technical Details
Message-ID:
<slrnch700h.6t9.chris@ccserver.keris.net>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news2.google.com!fu-berlin.de!uni-berlin.de!not-for-mailReferences:
<slrncgs56p.j46.chris@ccserver.keris.net> <410f6b8a@newsgroups.borland.com> <slrncgvo3t.5n3.chris@ccserver.keris.net> <4110bf9b@newsgroups.borland.com> <41113590$1@newsgroups.borland.com> <slrnch2mml.ofk.chris@ccserver.keris.net> <opsb9as3elbvaws7@dk-tzx09ucg42z4.s1.sol1.co.uk>Show Full Headers
Complete Article Headers
X-Google-Thread: 10d0fc,56d63b5f0bddbea3 X-Google-Attributes: gid10d0fc,public X-Google-Language: ENGLISH,ASCII-7-bit Path: arc1-ca.pugleaf.net!g2news1.google.com!news2.google.com!fu-berlin.de!uni-berlin.de!not-for-mail From: Chris Croughton <chris@keristor.net> Newsgroups: borland.public.cppbuilder.multimedia Subject: Re: Recording 24-bit audio (additional info) Date: Fri, 6 Aug 2004 13:56:49 +0100 Lines: 134 Message-ID: <slrnch700h.6t9.chris@ccserver.keris.net> References: <slrncgs56p.j46.chris@ccserver.keris.net> <410f6b8a@newsgroups.borland.com> <slrncgvo3t.5n3.chris@ccserver.keris.net> <4110bf9b@newsgroups.borland.com> <41113590$1@newsgroups.borland.com> <slrnch2mml.ofk.chris@ccserver.keris.net> <opsb9as3elbvaws7@dk-tzx09ucg42z4.s1.sol1.co.uk> Reply-To: chris@keristor.net X-Trace: news.uni-berlin.de n9uXCXNURoW/DDVK4r8/7QrHX8syHuUzN+pYzlQxIv5WxCXiY= X-Orig-Path: ccserver.keris.net!news User-Agent: slrn/0.9.7.4 (Linux)