Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 18 Jan 1996 14:07:16 -0600
From:      Jim Lowe <james@miller.cs.uwm.edu>
To:        luigi@labinfo.iet.unipi.it
Cc:        multimedia@freebsd.org, multimedia@rah.star-gate.com, tlehman@becky.acet.org, toml@mitre.org
Subject:   Re: FreeBSD and VAT
Message-ID:  <199601182007.OAA10985@miller.cs.uwm.edu>

next in thread | raw e-mail | index | archive | help
> > The soundblaster will probably always sound a little choppy just because it
> > really doesn't run at 8khz.  The way to fix that is to purchase a full duplex
>          ^^^^^^^^^^^^^^^^^^^
> 
> What do you mean by that ? You cannot expect any two cards to have
> exactly the same rate, so the software (and I mean the user-level
> software, not the device driver) must compensate speed mismatches
> by removing/adding samples. If it doesn't in a soft way (by means
> of small corrections at every segment), sooner or later you will
> be way out of sync and you will hear clicks.
> 
> I cannot tell what is the maximum % difference in sample rates
> which can give acceptable results (it depends a lot on the block
> size you are using), but my feeling is that 1% or less should not
> give too bad results.
> 

Usually the sound cards are not even close to 8khz.  They are sometimes
off by > 1khz depending on the sound card.  Vat doesn't take this into
consideration.  In fact, Vat uses the sound card for a timer.  It assumes
that the packets are arriving at 8khz and uses this value, no matter what
the record rate actually is, as Vat's internal clock.  The block/packet
size in vat is 160 bytes (or 20ms @ 8khz).

I don't think that 1% would be a problem for short bursty conversations.
If one was playing a CD for a long period of time (say 40 minutes), or
listening to a conference, then 1% compounded could be a problem --
since then it is 1% per second for 40 minutes.  I don't know that I
agree with the way they implemented the internal clock in vat, 
but I am not sure they had much to choose from.  

They wanted the program to run on a variety of systems.  The only thing that
I can think of that will give you 20ms resolution would be the system
interval timer (which I am not sure if it available on all systems such at
NT, Macs, Windows, etc...) or reading 8000hz samples (160 byte blocks)
from a sound card.

Now on Sun, Dec, and workstation type systems, the variance in the sound cards
is about .001%.  This is also true about the CS4231 codec on the GUS PnP cards
if my test program was working correctly when Amancio ran it.  My GUS Max card
has a variance of about 2% at 8000hz if I tell it to run at 8230hz.  I can
make a PAS-16 have a variance of about .1% if I run it at 8116hz.  The problem
is that not every PC sound card works the same.  Some of this depends on the
bus and chipset timing.

The CS4231 actually goes through a calibration cycle to set the correct
frequency.  The VOXware sound drivers that are in FreeBSD/Linux do not
attempt to do frequency correction in the drivers.  But if someone would
like to do this, the code is certainly available :-).  Vmix attempts to
correct for this utilizing interval timers -- but doesn't do a real good
job. 

Attached is the program I used for timing of various sound cards.

	-Jim
-----------------------------------------------
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/file.h>
#include <errno.h>
#include <machine/soundcard.h>
/* #define BROKEN_SELECT /* soundcard needs read before select */

char	*dev="/dev/dsp1";	/* or on command line */
int	blocksize = 160;

main(int ac, char **av)
{
        struct timeval  tv, start;
        int             fd;
        fd_set          rfd;
        int cc;
        int i;
        double u;

	if(ac>1)
		dev = av[1];

        if((fd=open(dev, O_RDONLY)) < 0) {
                perror(dev);
                exit(-1);
        }
	if(ioctl(fd, SNDCTL_DSP_SETBLKSIZE, &blocksize) < 0) {
		printf("Setting blocksize failed: %s\n", strerror(errno));
	}
#ifdef BROKEN_SELECT
	read(fd, dev, 1);
#endif

        gettimeofday(&start, 0);

        cc = 0;
        i = 0;
        FD_ZERO(&rfd);
        while (1) {
                int n;
                char buf[blocksize];
                FD_SET(fd, &rfd);
                select(fd+1, &rfd, 0, 0, 0);
                n = read(fd, buf, blocksize);
                if (n < 0) {
                        perror("read");
                        exit(1);
                }
		if(n!=blocksize) printf("read %d, wanted blocksize\n", n);
                cc += n;
                if (++i >= 50) {
                        i = 0;
                        gettimeofday(&tv, 0);
                        u = tv.tv_sec - start.tv_sec;
                        u += 1e-6 * (tv.tv_usec - start.tv_usec);
                        printf("%d %lg %lg\n", cc, u,
                               (double)cc / u);
			fflush(stdout);
                }
        }
}




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199601182007.OAA10985>