🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.multimedia
Article #434

Re: Recording 24-bit audio (additional info)

#434
From: Chris Croughton
Date: Fri, 06 Aug 2004 12:56
134 lines
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-mail
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>

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)