_REAL-TIME DATA AQUISITION_
by Mike Bunnell and Mitch Bunnell


[LISTING ONE]

    /*  dbuff.c     Double buffering program for continuous
    reading from input and continuous writing to output

    */

    #include <stdio.h>
    #include <smem.h>
    #include <sem.h>

    extern char *malloc();
    extern int errno;

    #define BSIZE 65536      /* size of each buffer */

    struct xbuff {
         char buffer[BSIZE];
         int count;
         int psem;
         int csem;
         int done;
         struct xbuff *other;
    };

    /*
         Write function that is used by the output task
    */

    outputr(p, prio)
    register struct xbuff *p;
    int prio;
    {
         int count;

         setpriority(0, getpid(), prio);
         while () {
              sem_wait(p->csem);           /* wait for buffer to fill */
              if (p->count <= 0) {
                  sem_signal(p->psem);    /* leave if finished or error */
                  break; �               }
              count = write(1, p->buffer, p->count);  /* write output */
              if (count <= 0) {
                   /* exit if error on write */
                   p->done = 1;
                   sem_signal(p->psem);
                   break;
              }

              /* tell producer buffer has been emptied */
              sem_signal(p->psem);
              p = p->other;
         }
    }

    /*

              Read function that is used by the input task
    */
    inputr(p, prio)
    register struct xbuff *p;
    int prio;
    {
        int count;

        setpriority(0, getpid(), prio);
        do {
             /* wait for consumer to empty buffer */
             sem_wait(p->psem);
             if (p->done) {
                  break;
             }
            /* read from input and fill buffer */
            count = read(0, p->buffer, BSIZE);
            p->count = count;

            /* tell consumer task buffer is filled  */
            sem_signal(p->csem);
            p = p->other;
       }  while (count > 0); /* exit when no more data */
    }

    main(argc, argv)
    int argc;
    char **argv;
    {
        register struct xbuff *buffa, *buffb;
        int inprio, outprio;

        /* default to current priority  */
        inprio = outprio = getpriority(0, 0);
        if (argc == 2) {
            /* Get input priority from command line if present */
            inprio = atoi(argv[1]);       �         }
        if (argc == 3) {
             /* Get output priority from command line if present */
             inprio = atoi(argv[1]);
             outprio = atoi(argv[2]);
        }

        /* Allocate shared memory  */
        buffa = (struct xbuff *) smem_get(
                "buffa",
                (long)sizeof(struct xbuff),
                SM_READ | SM_WRITE);
        buffb = (struct xbuff *) smem_get(
                "buffb",
                (long)sizeof(struct xbuff),
                SM_READ | SM_WRITE);

        /* delete old semaphores if they exist */
        sem_delete("buffac");
        sem_delete("buffap");
        sem_delete("buffbc");
        sem_delete("buffbp");

        buffa->csem = sem_get("buffac", 0);  /* Create new semaphores to */
        buffa->psem = sem_get("buffap", 1);  /* control access to shared */
        buffb->csem = sem_get("buffbc", 0);  /* memory                   */
        buffb->psem = sem_get("buffbp", 1);
        buffa->done = buffb->done = 0;

        buffa->other = buffb;
        buffb->other = buffa;

    /*
             Create another task to write.
             This task will read.
    */

         if (fork() != 0)             /* Create another task to  */
              inputr(buffa, inprio);  /* write.  This task will  */
         else                         /* read                    */
              outputr(buffa, outprio);
    }


[LISTING TWO]

    /* Reverb.c    IIR filter program to add reverberation */

    #include  <file.h> �
    extern char *malloc();

    ewrite(s)
    char *s;
    {
         write(2, s, strlen(s));
    }

    /*
         Read the whole size read() under UNIX returns the amount it
         read.  Last buffer is (biased) zero-filled.
    */
    fullread(fd, buff, size)
    int fd;
    char *buff;
    int size;
    {
         int i, j;

         i = 0;
         do {
             j = read(fd, &buff[i], size - i);
             if (j <= 0) {
                 /* This must be the last buffer of the file */
                 while (i < size)
                     buff[i++] = 0x800;
                 return -1;
             }
             i += j;
        }  while (i < size);

        return size;
    }

    main(ac, av)
    int ac;
    char **av;
    {
         short *ibuff, *obuff;
         int delay;
         int i;
         int fd;
         int rundown;
         int rv;
         char *fn;
         register short *p, *q;

         if (ac > 2) {
             ewrite("usage: reverb [delay]\n    (delay expressed in samples)\n");
             exit(1);
         }
         if (ac == 2)
             delay = atoi(av[1]);
         else �              delay = 10240;

         /* make sure delay is multiple of 512 bytes */
         delay -= delay & 511;

         /* make delay >= 512 andd <= 128K           */
         if (delay < 512)
             delay = 512;
         if (delay > 128*1024)
             delay = 128*1024;

         fd = 0;

         ibuff = (short *) malloc(delay * sizeof(*ibuff));
         obuff = (short *) calloc(delay * sizeof(*obuff));

         do {
             /* Read a buffer, but don't check error status yet */
             rv = fullread(fd, ibuff, delay * sizeof(short));

             /*
               Add the fresh input samples to the old samples, after
               dividing the old samples by 2
             */
             for (p = ibuff, q = obuff, i = 0; i < delay; ++i, ++p, ++q)
                *q = ((*q - 0x800) >> 1) + *p;

             /*
                Write the output reverbed buffer
             */
             write(1, obuff, delay * sizeof(short));
         } while (rv != -1);

         /*
             Allow sound in output buffer to "die down"
         */
         for (rundown = 11; --rundown >= 0; ) {
             for (q = obuff, i = 0; i < delay; ++i)
                  *q = (*q - 0x800) >> 1;

             write(1, obuff, delay * sizeof(short));
         }
    }

[LISTING THREE]

    /*  reverse.c   Write a file in reverse to standard output */

    #include  <file.h>
    #include  <types.h> �     #include  <time.h>
    #include  <stat.h>

    main(ac, av)

    int ac;
    char **av;
    {
         int fd;
         short buff[4096];
         int rc;
         int i, j, t;
         long pos;
         struct stat s;

         ++av;
         if ((fd = open(*av, O_RDONLY, 0)) == -1) {
             perror(*av);            /* exit if can't open file */
             exit(1);
         }

          fstat(fd, &s);             /* find the size of the file */
         pos = s.st_size &  1;

         while (pos > 0) {
             /* See how many bytes can be read now */
             if (pos < sizeof(buff))
                 rc = pos;
             else
                 rc = sizeof(buff);

             pos -= rc;
            /* Seek back a block and read */
            lseek(fd, pos, 0);
            read(fd, buff, rc);

            /* Reverse the samples in the block */
            for (i = 0, j = (rc / 2) - 1; i < j; ++i, --j) {
                t = buff[i];
                buff[i] = buff[j];
                buff[j] = t;
            }

            /* Write the reversed block */
            write(1, buff, rc);
          }

         close(fd);
    }