[linux-audio-dev] 8bit sound wav playing to a 16bit sound card...

Ralfs Kurmis kurmisk at inbox.lv
Thu Jun 12 13:50:01 UTC 2003

> I'm new to OSS Programming, and I'm attempting to play some 8bit wav files.
> However OSS is telling me that my sound card will not play 8bit , only
> 16bit.
> If I force it. The sound changes pitch, and is very fast. ( obviously ).
> Is there anyway to convert 8bit to 16bit on the fly? I've noticed that XMMS 
> also fails to play the 8bit wav file correctly. 
> I've even tryed to convert the file from 8bit to 16bit using SOX. But with
> the 
> same results. I would like to support 8bit file wavs in my program as MOST of
> the wavs available are in 8bit format...
> Any one Have some pointers?
> PS: The command I used with sox is " sox -V -r 11025 -w -c 1 backup.wav 
> temp.wav "

try out also self generated sines write to /dev/dsp

hope following example helps

Advanced Sound Programming

This section describes some miscellaneous sound programming issues that require
special consideration or are less commonly used.

We saw earlier that /dev/dsp operates using unsigned data, either 8 or 16 bits
in size, while /dev/audio uses mu-law encoded data. It is
possible to change the data formats a device uses with the SOUND_PCM_SETFMT
ioctl call. A number of data formats are defined in the
soundcard.h header file, all prefixed with the string AFMT_. For example, to set
the coding format to mu-law, you could use:

fmt = AFMT_MU_LAW;
ioctl(fd, SOUND_PCM_SETFMT, &fmt);

The argument will be returned with the coding format that was selected by the
kernel (which will be the same as the one selected unless the
device does not support it). The special format AFMT_QUERY will return default
format for the device. To find out all of the formats that a
given device supports, you can use the SOUND_PCM_GETFMTS ioctl. It returns a
bitmask that has bits set for each of the supported

The SNDCTL_DSP_GETBLKSIZE ioctl returns the block size that the sound driver
uses for data transfers. The returned value is an integer,
indicating the number in bytes. This information can be useful in an application
program for selecting a buffer size that ensures that the data
passed to the driver is transferred in complete blocks.

The SNDCTL_DSP_GETCAPS ioctl returns a bitmask identifying various capabilities
of a sound card DSP device. They are listed in
soundcard.h with labels prefixed by DSP_CAP. A typical capability is
DSP_CAP_DUPLEX, a boolean flag indicating whether the device
supports full duplex mode (simultaneous record and playback).

Example 14-6 illustrates these system calls, displaying information about a DSP
device (/dev/dsp by default).Determining DSP Capabilities
 * dsp_info.c
 * Example program to display sound device capabilities

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/soundcard.h>

/* utility function for displaying boolean status */
static char *yes_no(int condition)
  if (condition) return "yes"; else return "no";

 * Set sound device parameters to given values. Return -1 if
 * values not valid. Sampling rate is returned.
static int set_dsp_params(int fd, int channels, int bits, int *rate) 
  int status, val = channels;

  status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &val);
  if (status == -1)
    perror("SOUND_PCM_WRITE_CHANNELS ioctl failed");
  if (val != channels) /* not valid, so return */
    return -1;
  val = bits;
  status = ioctl(fd, SOUND_PCM_WRITE_BITS, &val);
  if (status == -1)
    perror("SOUND_PCM_WRITE_BITS ioctl failed");
  if (val != bits)
    return -1;
  status = ioctl(fd, SOUND_PCM_WRITE_RATE, rate);
  if (status == -1)
    perror("SOUND_PCM_WRITE_RATE ioctl failed");
  return 0;

int main(int argc, char *argv[])
  int rate;
  int channels;            /* number of channels */
  int bits;                /* sample size */
  int blocksize;           /* block size */
  int formats;             /* data formats */
  int caps;                /* capabilities */
  int deffmt;              /* default format */
  int min_rate, max_rate;  /* min and max sampling rates */
  char *device;            /* name of device to report on */
  int fd;                  /* file descriptor for device */
  int status;              /* return value from ioctl */

  /* get device name from command line or use default */
  if (argc == 2)
    device = argv[1];
    device = "/dev/dsp";

  /* try to open device */
  fd = open(device, O_RDWR);
  if (fd == -1) {
    fprintf(stderr, "%s: unable to open `%s', ", argv[0], device);
    return 1;

  status = ioctl(fd, SOUND_PCM_READ_RATE, &rate);
  if (status ==  -1)
    perror("SOUND_PCM_READ_RATE ioctl failed");
  status = ioctl(fd, SOUND_PCM_READ_CHANNELS, &channels);
  if (status ==  -1)
    perror("SOUND_PCM_READ_CHANNELS ioctl failed");
  status = ioctl(fd, SOUND_PCM_READ_BITS, &bits);
  if (status ==  -1)
    perror("SOUND_PCM_READ_BITS ioctl failed");
  status = ioctl(fd, SNDCTL_DSP_GETBLKSIZE, &blocksize);
  if (status ==  -1)
    perror("SNFCTL_DSP_GETBLKSIZE ioctl failed");

         "Information on %s:\n\n"
         "  sampling rate: %d Hz\n"
         "  channels: %d\n"
         "  sample size: %d bits\n"
         "  block size: %d bytes\n",
         device, rate, channels, bits, blocksize

/* this requires a more recent version of the sound driver */
// #if SOUND_VERSION >= 301
  printf("\nSupported Formats:\n");
  deffmt = AFMT_QUERY;
  status = ioctl(fd, SOUND_PCM_SETFMT, &deffmt);
  if (status ==  -1)
    perror("SOUND_PCM_SETFMT ioctl failed");
  status = ioctl(fd, SOUND_PCM_GETFMTS, &formats);
  if (status ==  -1)
    perror("SOUND_PCM_GETFMTS ioctl failed");

  if (formats & AFMT_MU_LAW) {
    printf("  mu-law");
    (deffmt == AFMT_MU_LAW) ? printf(" (default)\n") : printf("\n");
  if (formats & AFMT_A_LAW) {
    printf("  A-law");
    (deffmt == AFMT_A_LAW) ? printf(" (default)\n") : printf("\n");
  if (formats & AFMT_IMA_ADPCM) {
    printf("  IMA ADPCM");
    (deffmt == AFMT_IMA_ADPCM) ? printf(" (default)\n") : printf("\n");
  if (formats & AFMT_U8) {
    printf("  unsigned 8-bit");
    (deffmt == AFMT_U8) ? printf(" (default)\n") : printf("\n");
  if (formats & AFMT_S16_LE) {
    printf("  signed 16-bit little-endian");
    (deffmt == AFMT_S16_LE) ? printf(" (default)\n") : printf("\n");
  if (formats & AFMT_S16_BE) {
    printf("  signed 16-bit big-endian");
    (deffmt == AFMT_S16_BE) ? printf(" (default)\n") : printf("\n");

  if (formats & AFMT_S8) {
    printf("  signed 8-bit");
    (deffmt == AFMT_S8) ? printf(" (default)\n") : printf("\n");
  if (formats & AFMT_U16_LE) {
    printf("  unsigned 16-bit little-endian");
    (deffmt == AFMT_U16_LE) ? printf(" (default)\n") : printf("\n");
  if (formats & AFMT_U16_BE) {
    printf("  unsigned 16-bit big-endian");
    (deffmt == AFMT_U16_BE) ? printf(" (default)\n") : printf("\n");
  if (formats & AFMT_MPEG) {
    printf("  MPEG 2");
    (deffmt == AFMT_MPEG) ? printf(" (default)\n") : printf("\n");

  status = ioctl(fd, SNDCTL_DSP_GETCAPS, &caps);
  if (status ==  -1)
    perror("SNDCTL_DSP_GETCAPS ioctl failed");
         "  revision:  %d\n"
         "  full duplex: %s\n"
         "  real-time: %s\n"
         "  batch:     %s\n"
         "  coprocessor: %s\n"
         "  trigger:  %s\n"
         "  mmap:     %s\n",
         caps & DSP_CAP_REVISION,
         yes_no(caps & DSP_CAP_DUPLEX),
         yes_no(caps & DSP_CAP_REALTIME),
         yes_no(caps & DSP_CAP_BATCH),
         yes_no(caps & DSP_CAP_COPROC),
         yes_no(caps & DSP_CAP_TRIGGER),
         yes_no(caps & DSP_CAP_MMAP));

// #endif /* SOUND_VERSION >= 301 */

  /* display table heading */
         "\nModes and Limits:\n"
         "Device    Sample    Minimum   Maximum\n"
         "Channels  Size      Rate      Rate\n"
         "--------  --------  --------  --------\n"

  /* do mono and stereo */
  for (channels = 1; channels <= 2 ; channels++) {
    /* do 8 and 16 bits */
    for (bits = 8; bits <= 16 ; bits += 8) {
      /* To find the minimum and maximum sampling rates we rely on
         the fact that the kernel sound driver will round them to
         the closest legal value. */
      min_rate = 1;
      if (set_dsp_params(fd, channels, bits, &min_rate) == -1)
      max_rate = 100000;
      if (set_dsp_params(fd, channels, bits, &max_rate) == -1)
      /* display the results */
      printf("%8d  %8d  %8d  %8d\n", channels, bits, min_rate, max_rate);
  return 0;

Typical output from the dsp_info program looks like this:

Information on /dev/dsp:
  sampling rate: 8000 Hz
  channels: 1
  sample size: 8 bits
  block size: 4096 bytes
Supported Formats:
  unsigned 8-bit (default)
  revision: 1
  full duplex: no
  real-time: no
  batch: no
  coprocessor: no
  trigger: yes
  mmap: yes
Modes and Limits:
Device    Sample    Minimum   Maximum
Channels  Size      Rate      Rate
--------  --------  --------  --------
       1         8      4000     43478
       2         8      4000     21739

I mentioned earlier that you can't record and play back at the same time with
one sound device. You can, however, change parameters such
as sampling rate and sample size "on the fly." First, you need to open the PCM
device for read and write. Then, before changing any
parameters, use the ioctl call

ioctl(fd, SOUND_PCM_SYNC, 0);

in order to inform the sound driver that it should complete any data transfers
that are in progress. You can now change parameters, or even
switch between recording and playback. I used this feature earlier in the parrot
example program.

You can also stop record or playback immediately using

ioctl(fd, SOUND_PCM_RESET, 0).

Unfortunately, a true bidirectional mode that allows simultaneous recording and
playback is not supported (it likely will be in the future,
though). This mode would be useful, for example, for implementing a computerized
telephone utility that allows users to communicate using
a sound card. There is one other alternative: some sound cards, such as the
ProAudioSpectrum, have two independent PCM
devices--/dev/dsp and /dev/dsp1. You can use one for read and one for write,
resulting in simultaneous recording and playback. In order to
perform the simultaneous data transfers, it would probably be best to implement
the system as two separate processes.

Some applications are time critical. The sound driver transfers data using DMA
buffers, a typical buffer size being 64 kilobytes. This can
impact real-time applications because of the time needed to fill up buffers for
transfer. Transferring 64K of data at 8 kHz would take eight
seconds. If a multimedia application was performing an animation, for example,
it would be unacceptable to have the display stop for eight
seconds while the process was waiting for a full buffer of sound data. You can
reduce the buffer size using the ioctl call in this form:

ioctl(fd, SOUND_PCM_SUBDIVIDE, &divisor);

The divisor parameter takes the value 1, 2, or 4; it reduces the DMA buffer size
by the corresponding factor. Note that the divisor operates
on the default buffer size, not the current value, so you cannot call the
function repeatedly to keep reducing the divisor.

For some applications, the smaller DMA buffer size may still not be enough. When
the program DOOM was ported to Linux, the
performance of the game was impacted by the pauses required to play sound
effects. A new real-time ioctl was added to address
applications such as this one. The ioctl call is called SNDCTL_DSP_SETFRAGMENT,
and is explained in the file experimental.txt
included in the kernel sound driver source.


This message contains no viruses. 
Guaranteed by Kaspersky Anti-Virus.

More information about the Linux-audio-dev mailing list