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 <cs89jmb@brunel.ac.uk>
>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
