By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,918 Members | 2,258 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,918 IT Pros & Developers. It's quick & easy.

24 bit words

P: n/a
Thanks for the comments on my last post, they were very useful. Here is another
question that it would be useful to get some comments on. I deal a lot with
sound data which comes in a fixed format of either signed 16 or 24 bit
integers. What is the best way of defining these types to allow some level
of portability? Is it simply a matter of using conditional preprocessor
inclusions to create a type suitable for a particular machine? Such as:

#ifdef SUN
typedef word16_t short;
#else
.... define for other platforms.

Also, for converting 24 bit integers to 32 bit (so I can use them) I have
written this:
#define WORD24_LEN 3

typedef long s32word_t; /* OK for Max OS X/G5 but not nesc. other platforms */

union word32 {
s32word_t lword;
unsigned char byte[4];
};

s32word_t word24toword32(const char *pWord24) {

union word32 outputword;
register unsigned int i;

for(i=0;i<WORD24_LEN;i++) outputword.byte[i+1] = pWord24[i];

if (outputword.byte[1] >= 0x80) outputword.byte[0] = 0xff;
else outputword.byte[0] = 0x00;

return(outputword.lword);

}

void word32toword24(s32word_t inword, char *pWord24) {

union word32 inputword;
register unsigned int i;

inputword.lword = inword;
for(i=0;i<WORD24_LEN;i++) pWord24[i] = inputword.byte[i+1];

}
I am wondering if there is a nicer way to do this?

Robert
Jul 10 '06 #1
Share this Question
Share on Google+
9 Replies


P: n/a
Robert Dow wrote:
Thanks for the comments on my last post, they were very useful. Here is another
question that it would be useful to get some comments on. I deal a lot with
sound data which comes in a fixed format of either signed 16 or 24 bit
integers. What is the best way of defining these types to allow some level
of portability? Is it simply a matter of using conditional preprocessor
inclusions to create a type suitable for a particular machine? Such as:
<snip unions>

No. Load the bytes by shifting and ORing. That's the portable way.

Does your device actually send 24 bit words though? I'd think most
would just pack them in a 32-bit word for shipping over the bus.

Tom

Jul 10 '06 #2

P: n/a
Tom St Denis <to********@gmail.comwrote:
Does your device actually send 24 bit words though? I'd think most
would just pack them in a 32-bit word for shipping over the bus.

Tom
I should have mentioned that the data comes from files and is in the format of
24 bit words.

Robert
Jul 10 '06 #3

P: n/a
Robert Dow wrote:
Thanks for the comments on my last post, they were very useful. Here is another
question that it would be useful to get some comments on. I deal a lot with
sound data which comes in a fixed format of either signed 16 or 24 bit
integers. What is the best way of defining these types to allow some level
of portability? Is it simply a matter of using conditional preprocessor
inclusions to create a type suitable for a particular machine? Such as:

#ifdef SUN
typedef word16_t short;
#else
... define for other platforms.
On every C99 platform where there is a 16 bit data type available,
there's int16_t in inttypes.h, you don't have to recreate it yourself.

Philipp
Jul 10 '06 #4

P: n/a
In article <e8**********@scotsman.ed.ac.uk>
Robert Dow <rj*@music.ed.ac.ukwrote:
>... I deal a lot with sound data which comes in a fixed format
of either signed 16 or 24 bit integers. What is the best way of
defining these types to allow some level of portability?
First, you need to decide "how much portability", because:

- most machines today have signed, 16-bit, two's complement "short",
so you can just use that for the first;

- any system that supports "enough" C99 will also have <inttypes.h>
which will define the type "int16_t" for you; and

- it is possible to do all your 16-bit work with "unsigned short"
(which is guaranteed to be at least 16 bits) or plain (signed)
long in such a way that it is 100% portable, i.e., will work on
*any* conforming C implementation, even if it has ones' complement
signed arithmetic and/or 18- or 64-bit "short" -- but it will
take more work.

Having made such a decision...
>Also, for converting 24 bit integers to 32 bit (so I can use them) I have
written this:

#define WORD24_LEN 3

typedef long s32word_t; /* OK for Max OS X/G5 but not nesc. other platforms */

union word32 {
s32word_t lword;
unsigned char byte[4];
};
(and complicated code to manipulate them)

The phrases that come to mind here are "ew" and "don't do that". :-)

Given 3 8-bit octets that should from a "FILE *fp", do this -- note
that you can do the obvious thing if these octet-bytes are already
in an array of "unsigned char":

unsigned long accum;
long val;
unsigned char c[3];

/* fread takes (base, width, nelements, FILE *) */
if (fread(c, 1, 3, fp) != 3) ... handle error ...

#if UCHAR_MAX != 255 /* this #if is optional */
/*
* This step is optional, and a no-op if UCHAR_MAX is 255 as usual;
* or you could inspect the values to see if they are out of range,
* which implies something went wrong in reading 8-bit octets on
* your 9- or 18- or 24-bit "unsigned char" machine.
*
* Note that a good C compiler should generate no code here even
* without the "#if" above, in the usual (UCHAR_MAX == 255) case.
*/
c[0] &= 0xff;
c[1] &= 0xff;
c[2] &= 0xff;
#endif

/* here is where you decide on File Byte Order */
accum = (unsigned long)c[0] << 16; /* if c0 is the topmost bits */
accum |= (unsigned)c[1] << 8;
accum |= c[2];

#define SIGNBIT (1UL << 23)
/* now convert unsigned 24-bit value to signed 32-bit value */
val = (long)(accum ^ SIGNBIT) - (long)SIGNBIT;

Note that this code can be adapted to force the correct interpretation
of any bit-length word up to 31, or in C99, 63 using "long long".
This code works even if the target machine has 72-bit "int" or uses
ones' complement, because it operates strictly on the *values*
in the 24-bit field.

You can see how this works if we make a table for a 3-bit two's
complement number, which can go from -4 to +3:

desired value (as unsigned) value after
"sign" bit1 bit0 value after flipping "sign" subtracting 4
------ ---- ---- ---- --------------------- -------------
0 0 0 0 4 0
0 0 1 1 5 1
0 1 0 2 6 2
0 1 1 3 7 3

1 0 0 -4 0 -4
1 0 1 -3 1 -3
1 1 0 -2 2 -2
1 1 1 -1 3 -1

The only gimmick here is that the intermediate and final signed
values (after flipping the top bit and converting to the signed
variant) have to fit within LONG_MIN..LONG_MAX. Since these are
guaranteed to be at least -2147483647..+2147483647, we can certainly
go to 31 bits, which needs only a range of -1073741824..+1073741823.
(Going to 32 fails if LONG_MIN is -2147483647 instead of -2147483648,
but otherwise actually still works.)

To convert back, use the obvious corresponding technique (add bias
with native signed arithmetic, convert to "unsigned long", and flip
top bit).
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Jul 10 '06 #5

P: n/a
On Mon, 10 Jul 2006 18:50:01 +0000, Chris Torek wrote:
- any system that supports "enough" C99 will also have <inttypes.h>
which will define the type "int16_t" for you; and
Chris would have intended to write <stdint.habove. Though I'm glad to
discover the <inttypes.h("Format conversion of integer types") header.
It will assist in the portable printing and scanning of fixed integer
types.

Regards,
Adam
Jul 11 '06 #6

P: n/a
jjf

Adam Warner wrote:
On Mon, 10 Jul 2006 18:50:01 +0000, Chris Torek wrote:
- any system that supports "enough" C99 will also have <inttypes.h>
which will define the type "int16_t" for you; and

Chris would have intended to write <stdint.habove. Though I'm glad to
discover the <inttypes.h("Format conversion of integer types") header.
It will assist in the portable printing and scanning of fixed integer
types.
Brave assumption. <inttypes.hincludes <stdint.h>. Chris may choose to
always use the former when he needs the specified width types, to make
sure that the gubbins to do I/O on them is always to hand.

Jul 11 '06 #7

P: n/a
In article <pa****************************@consulting.net.n z>
Adam Warner <us****@consulting.net.nzwrote:
>On Mon, 10 Jul 2006 18:50:01 +0000, Chris Torek wrote:
> - any system that supports "enough" C99 will also have <inttypes.h>
which will define the type "int16_t" for you; and

Chris would have intended to write <stdint.habove.
Indeed -- although my C99 text-only draft is sufficiently old that it
says inttypes.h instead of stdint.h (everywhere). Since this was
<inttypes.hat various points during C99 development, it is possible
there are systems that have <inttypes.hand not <stdint.h>, too.

(I would be more tempted to buy a "proper" C99 PDF if PDF files were
grep-able, etc. :-) )
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Jul 11 '06 #8

P: n/a
On Tue, 11 Jul 2006 05:54:28 +0000, Chris Torek wrote:
In article <pa****************************@consulting.net.n z>
Adam Warner <us****@consulting.net.nzwrote:
>>On Mon, 10 Jul 2006 18:50:01 +0000, Chris Torek wrote:
>> - any system that supports "enough" C99 will also have <inttypes.h>
which will define the type "int16_t" for you; and

Chris would have intended to write <stdint.habove.

Indeed -- although my C99 text-only draft is sufficiently old that it
says inttypes.h instead of stdint.h (everywhere). Since this was
<inttypes.hat various points during C99 development, it is possible
there are systems that have <inttypes.hand not <stdint.h>, too.

(I would be more tempted to buy a "proper" C99 PDF if PDF files were
grep-able, etc. :-) )
I'm a tad ashamed that the reference I consulted was the headers in
/usr/include/* from Debian sid's GNU libc 2.3.6:
$ dpkg -S /usr/include/stdint.h
libc6-dev: /usr/include/stdint.h
<http://packages.debian.org/changelogs/pool/main/g/glibc/glibc_2.3.6-15/changelog>

...

/*
* ISO C99: 7.18 Integer types <stdint.h>
*/

...

/* Exact integral types. */

/* Signed. */

/* There is some amount of overlap with <sys/types.has known by inet code */
#ifndef __int8_t_defined
# define __int8_t_defined
typedef signed char int8_t;
typedef short int int16_t;
typedef int int32_t;
...

Platform specific and certainly not authoritative, but grep-able :-)

I am familiar with GNU C's C99 compatibility caveats:
<http://gcc.gnu.org/c99status.html>

Regards,
Adam
Jul 11 '06 #9

P: n/a
Thank you all for your advice.

Robert
Jul 11 '06 #10

This discussion thread is closed

Replies have been disabled for this discussion.