Open Sound System
|Do you have problems with sound/audio application development? Don't panic! Click here for help!|
Unfortunately different architectures use different ways of storing the 16 and 32 bit variables in memory. "Intel" based systems use so called little endian approach and most Risc systems use big endian.
The big endian systems store integers so that the the most significant byte is stored first. In this way 32 bit value of 0x12345678 gets stored in 4 subsequent bytes as 0x12, 0x34, 0x56 and 0x78. It's easy to examine big endian data files using hexadecimal dump programs because the values will be displayed correctly.
The little endian systems store integers so that the the least significant byte is stored first. In this way 32 bit value of 0x12345678 gets stored in 4 subsequent bytes as 0x78, 0x56, 0x34 and 0x12. Little endian data files will look garbled in hexadecimal dumps.
Endianess is a problem because different systems use different formats. It's also possible that the sound hardware uses opposite endianess than the processor (this is the normal case in big endian risc systems).
OSS definess 4 different endianess models.
|LE||Little endian. This is the format used in "Intel" systems and also by most audio devices. Audio file formats such as .wav uses little endian.|
|BE||Big endian. This is the native format used in most Risc systems.|
|NE||Native or natural endianess. This means the endianess used in the processor architecture the program is currently running. These formats match the integer data types (short, int) so program can handle "NE" sample formats without conversions.|
|OE||Opposite or alien endianess. This model is useless because the samples need to ne byte swapped before any computations can be done on them. The "OE" endianess model is defined by OSS to make it easier to identify formats that require byte swapping.|
The addition of the NE and OE endianess models may look stupid because it introduces two new models when there was already on too much. However they will actually make programmer's life easier.
Lets take a look at the 16 bit sample formats. There are four of them. Each with different endianess model. The same applies also to the 24/32 bit formats.
The 16 bit formats are AFMT_S16_LE, AFMT_S16_BE, AFMT_S16_NE and AFMT_S16_OE (there are also some unsigned 16 bit formats but they are not used in practice).
Let's design a simple program that reads a audio file (for example .wav one), increases it's volume and plays it to an audio device.
The "LE" format (AFMT_S16_LE) is the format that should be used as the "file" format so we will use it so in our example. The application loads the file to memory as an array of 16 bit integers (short). It also initializes the local
format variable to AFMT_S16_LE.
Before changing the volume the application needs to figure out if the endianess is correct or if the samples will need to be byte swapped. This is where the NE and OE endianess models are needed. Now the application only needs to check if the
format is AFMT_S16_NE or AFMT_S16_OE. If it's OE then the application simply byte swaps the samples and stores AFMT_S16_NE in the
format variable. This happens if the program is rinning in a big endian machine. No conversion is needed in a little endian machine.
Now the application knows the samples are in the native format. This means it can perform the volume computations without any need to be worried about the endianess.
Now it's time to open the audio device and to play the file. The application can simply set the device to use AFMT_S16_NE by calling SNDCTL_DSP_SETFMT. In little endian systems AFMT_S16_NE equals to AFMT_S16_LE which is being used by the device so no conversions are needed. If the same program is run in a big endian system then OSS will automatically do the byte swapping. The application doesn't need to care about it.
Finally the application wants to write the samples back to a .wav file which is always little endian. Now it checks if the
format variable is set to AFMT_S16_LE. In little endian systems the current endianess (NE) equals to LE so the file can be written without conversions. In big endian systems the format is not AFMT_S16_LE (AFMT_S16_NE==AFMT_S16_BE) so byte swapping is necessary.
As you see everything is easy if you use the LE, BE, NE and OE models in the right way. The same applies to the 24/32 bit formats too.
When an application wants to read 16 bit samples from a .wav file (AFMT_S16_LE) and play them using an audio device there is no need to do computations on the data. So the program can simply set the device to the "file" format (AFMT_S16_LE) using SNDCTL_DSP_SETFMT. OSS will automatically possible endianess conversions if it appears that the device doesn't support the little endian format.
Let's take a computer music program that plays fully synthetic audio signals (without reading anything from a file). Such application can simply set the device to use AFMT_S16_NE. OSS will convert the samples to the right format regardless of the enedianess of the processor or the sound device.
As you see OSS is carefully designed to handle endianess and also sample size issues automatically. The application programmer can focus on the real business without wasting time on probing for the formats supported by the device and trying to find devices that can be used for testing with less frequently used formsts. Yes, we have made even this possible but that doesn't mean that such features should to be used.