From: gtoal@tardis.computer-science.edinburgh.ac.uk Newsgroups: comp.sys.acorn Subject: Sun audio file update Date: 12 May 91 18:23:55 GMT Reply-To: gtoal@tardis.computer-science.edinburgh.ac.uk (Graham Toal) Some time back I asked about playing sun audio files on the Archie; here's a reply I got from Mark Taunton at Acorn; I've finally gotten round to passing it on to the net... Hi Graham, sorry there has been a little delay, but I thought I'd write anyway. I have previously looked into this, and after some difficulty with getting the Sun audio format *exactly* right, I was able to play back Sun files OK under RISC iX. The primary details of the Sun audio format you need are: Sample frequency is 8000 Hz (fixed), mono only. Sample format is 8 bits/sample: bit 7 = sign, bits 0..6 are BITWISE COMPLEMENT of mu255 (pseudo-exponential) representation of magnitude. You probably know that VIDC's audio data format is bit 0 = sign, bits 1..7 are the mu255 magnitude (not complemented). The fact that the magnitude is complemented is what caused me grief for a while: it renders the sound totally unrecognisable (i.e. it sounds like just noise). If you think about the signal transformation you can see why. As a little extra, feel free to use the following in any way you like. It's a simple UNIX filter, so it's up to you to adapt for RISC OS... Cheers. Mark. P.S. I haven't thought hard about it, but if you *really* cared about speed it might be minutely quicker to just complement the whole word (*including* the sign bits) before (or after) doing the byte-wise rotate, since not even Golden Eared people should be able to detect the reversed polarity with this quality of signal! On the other hand, it might not be. P.P.S. A quick tip on improving the perceived sound quality: if you double, triple or quadruple the playback frequency and repeat each input sample 2, 3 or 4 times (as appropriate!) you cut down on the amount of audible locally-generated mush considerably, allowing the crystal-clear beauty of the original signal to shine through. ;-) /* * stov.c: convert SparcStation audio data on stdin * to Archimedes (VIDC) format on stdout. * * Mark Taunton, January 1991. */ void *malloc(); #define BSZ 4096 main (int argc, char **argv) { unsigned char *buff = (unsigned char *)malloc (BSZ); unsigned int xm1 = 0x01010101; unsigned int xm2 = ~xm1; /* help compiler along */ int n; /* * In the following loop we convert 4 bytes at once because it's * all pure bit twiddling: there is no arithmetic to cause * overflow/underflow or other such nasty effects. Each byte is * converted using the algorithm: * * output = (input >> 7) | (~(input << 1) & 0xFE) * * i.e. we rotate the byte left by 1 and bitwise complement the * 7-bit magnitude part. On ARM the actual conversion works out * to take all of 4 S-cycles (it could be 3 but the (RISC iX 1.21) * compiler misses a trick), and since we are doing 4 bytes at once * this really ain't bad! Note that we don't worry about alignment * on any odd bytes at the end of the buffer (unlikely anyway) - we * just convert all 4 bytes. The right number still get written. */ while ((n = read (0, buff, BSZ)) > 0) { unsigned int *wp = (unsigned int *)buff; unsigned int *lim = (unsigned int *)(buff + ((n + 3) & ~3)); do { unsigned int ss = *wp; *wp++ = ((ss >> 7) & xm1) | (xm2 & ~(ss << 1)); } while (wp != lim); write (1, buff, n); } } From mark@acorn.co.uk Mon Jan 18 15:09:43 1993 From: mark@acorn.co.uk (Mark Taunton) Newsgroups: comp.sys.acorn Subject: Re: Passing on a request about sun au files. Date: 7 Nov 91 15:19:35 GMT Organization: Acorn Computers Ltd, Cambridge, UK In article <2436@tuegate.tue.nl> gtoal@gem.stack.urc.tue.nl (Graham Toal) writes: >From: Jason M Banham >Sorry to be a pain but you could post an article on UseNet for me along the >lines of: > >"I have a large collection of Sun .au files and I want to be able to use them > on my archimedes. I have tried loading them into !Armadeus and !DSEdit > but to no avail. I have even tried to convert them using the tools with > !Coconizer but I get masses of hiss and crackle. > Does anyone know how to convert them ?" > >Thanks Muchly > >Jayce. I looked again at some Sun documentation on this today. I think the following is correct.... For .au files created on SparcStations under earlier versions of SunOS (4.0.3c) there is no header on the files. For later versions, there is a file header which gives details of the format of the data: unfortunately the full structure of this header is not documented and its overall size is said to be variable. Instead Sun supply (the binary code of) routines to read & write file headers, which is not specially helpful for use outside SunOS. However they do say that the format is a subset of that used by NeXT. It seems likely that the raw data format is the same for all current .au files, since Sun's standard hardware supports only one sampling rate, and audio device drivers up to and including 4.1 only support one encoding method though the SparcStation hardware apparently supports two. Here then are the details of the raw data format, as extracted from the Sun docs: sampling rate 8kHz (that's 8000 Hz, not 8192Hz) sample format ISDN m-law companding (8-bits pseudo-log) (m-law = mu-law = u-law, I believe: it is pronounced "mew-law", i.e. >from the Greek letter mu, which looks a bit like a u, hence the funny variations) Happily, mu-law encoding is what is used by the VIDC sound output system in all Acorn's 32-bit machines. However the order and coding of the bits is different from Sun's. The Sun format for each sample byte is: Bit: 7 6 5 4 3 2 1 0 +----+-------+------+ |Sign| Chord |Offset| +----+-------+------+ Sign = 1 means positive, = 0 means negative. Both Chord and Offset are encoded as the 1's complement of the respective binary values, i.e. for Chord 0, Offset 0, the bits are all 1, whereas for Chord 7, Offset 15 the bits are all 0. [I won't bother explaining here what chord & offset mean.] In VIDC-1a format, as used on all Acorn product machines (but not on some early prototype hardware) the format is: Bit: 7 6 5 4 3 2 1 0 +-------+------+----+ | Chord |Offset|Sign| +-------+------+----+ Sign = 0 means positive, = 1 means negative. Both Chord and Offset are encoded as direct binary, i.e. Chord 0 has bits 7..4 all 0. The reason for the different bit ordering is that it makes certain common signal synthesis computations simpler on ARM (there's the advantage of designing your own hardware!). To convert from Sun format to Acorn VIDC format, you need to rotate each byte left by one bit and bitwise complement the whole byte. This turns out to be pretty easy. Here is a little program I wrote to do this: it is written in PCC style C (boo, hiss!) and runs on RISC iX. Converting to ANSI C, and for use under RISC OS should be fairly simple. Obviously, you'll have to work out for yourself where any .au file header ends and the real data begins... ---------------------------------------------------------- /* * stov.c: convert SparcStation audio data on stdin * to Archimedes (VIDC) format on stdout. * * Mark Taunton, January 1991. */ void *malloc(); #define BSZ 4096 /* Convenient for RISC iX's sound interface */ main (argc, argv) int argc; char **argv; { /* * Note that malloc always returns a word-aligned pointer. */ unsigned char *buff = (unsigned char *)malloc (BSZ); int n; while ((n = read (0, buff, BSZ)) > 0) { unsigned int *wp = (unsigned int *)buff; unsigned int *lim = (unsigned int *)(buff + ((n + 3) & ~3)); /* * In the following loop we convert 4 bytes at once because * it's all pure bit twiddling: there is no arithmetic to * cause overflow/underflow or other such nasty effects. Each * byte is converted using the algorithm: * * output = ~(((input >> 7) & 0x01) | * ((input << 1) & 0xFE) ) * * i.e. we rotate the byte left by 1 then bitwise complement * the result. On ARM the actual conversion (not including * the load & store) works out to take all of 4 S-cycles, and * since we are doing 4 bytes at once this really ain't bad! * Note that we don't worry about alignment on any odd bytes * at the end of the buffer (unlikely anyway), we just convert * all 4 bytes - the right number still get written. */ unsigned int xm = 0x01010101; do { unsigned int ss = *wp; *wp++ = ~(((ss >> 7) & xm) | (~xm & (ss << 1))); } while (wp != lim); write (1, buff, n); } } ----------------------------------------------------------------- >Jason "Archangel" Banham >Brunel University >Dept. Computer Science > >JANET: cs89jmb@brunel.ac.uk Mark. -- Mark Taunton Email: mark@acorn.co.uk Acorn Computers Ltd Phone: (+44) 223 214411 Cambridge, UK Fax: (+44) 223 214382