[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Reading an Unsigned Short from a Stream



There is a well-documented bit of sample source code called
parrot.c for which I am very thankful. It demonstrates how to
use ioctl to set the sound card to the desired sample rate and
sample type such as mono or stereo.

	It worked fine, but an experimental modification I made
isn't working so I must not correctly understand the read
function. In the original code, he reads /dev/dsp in to a buffer
as follows:

    status = read(fd, buf, sizeof(buf)); /* record some sound */

	I want a 16-bit mono sample so I set an unsigned short
variable called sample which is 2-bytes long. My read of a
single sample is:

read(fd, &sample, sizeof(sample));

	It blocks forever. Shouldn't it stick one A/D reading
there and go on?

	I have written code before to read the raw /dev/dsp with
no ioctl. You get 8,000 8-bit samples per second and fgetc reads
precisely 1 sample from /dev/dsp and then unblocks so your
program can do whatever it needs to do with the sample. When
your loop gets back around to the next read, it blocks until
1/8000 of a second has passed and then you get another read.
fgetc is good for reading a byte, but not suitable for 16 or 32
bits.

	The original parrot.c code follows with all due credit to
it's author. Thanks for any explanation as to why a single-word
sample isn't behaving like a buffer of many bytes. I even tried
to set a pointer to that variable but it still blocked.

Martin McCormick

/*
 * parrot.c
 * Program to illustrate /dev/dsp device
 * Records several seconds of sound, then echoes it back.
 * Runs until Control-C is pressed.
 */

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

#define LENGTH 3    /* how many seconds of speech to store */
#define RATE 8000   /* the sampling rate */
#define SIZE 8      /* sample size: 8 or 16 bits */
#define CHANNELS 1  /* 1 = mono 2 = stereo */

/* this buffer holds the digitized audio */
unsigned char buf[LENGTH*RATE*SIZE*CHANNELS/8];

int main()
{
  int fd;       /* sound device file descriptor */
  int arg;      /* argument for ioctl calls */
  int status;   /* return status of system calls */

  /* open sound device */
  fd = open("/dev/dsp", O_RDWR);
  if (fd < 0) {
    perror("open of /dev/dsp failed");
    exit(1);
  }

  /* set sampling parameters */
  arg = SIZE;      /* sample size */
  status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
  if (status == -1)
    perror("SOUND_PCM_WRITE_BITS ioctl failed");
  if (arg != SIZE)
    perror("unable to set sample size");

  arg = CHANNELS;  /* mono or stereo */
  status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);
  if (status == -1)
    perror("SOUND_PCM_WRITE_CHANNELS ioctl failed");
  if (arg != CHANNELS)
    perror("unable to set number of channels");

  arg = RATE;      /* sampling rate */
  status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
  if (status == -1)
    perror("SOUND_PCM_WRITE_WRITE ioctl failed");

  while (1) { /* loop until Control-C */
    printf("Say something:\n");
    status = read(fd, buf, sizeof(buf)); /* record some sound */
    if (status != sizeof(buf))
      perror("read wrong number of bytes");
    printf("You said:\n");
    status = write(fd, buf, sizeof(buf)); /* play it back */
    if (status != sizeof(buf))
      perror("wrote wrong number of bytes");
    /* wait for playback to complete before recording again */
    status = ioctl(fd, SOUND_PCM_SYNC, 0);
  if (status == -1)
    perror("SOUND_PCM_SYNC ioctl failed");
  }
}


Reply to: