Example #1
0
long audio_poll(snd_type snd)
{
   oss_info dp = get_oss_info(snd);

   /* Note that this returns frames while audio_write
      returns bytes */

   if (snd->write_flag == SND_READ)
      return (dp->len / snd_bytes_per_frame(snd));
   else
      return ((dp->buffersize - dp->len) /
              snd_bytes_per_frame(snd));
}
Example #2
0
void snd_print_info(snd_type snd)
{
    if (snd->device == SND_DEVICE_AUDIO) {
        if (snd->write_flag == SND_READ) {
            printf("audio input");
        } else {
            printf("audio output");
        }
    } else if (snd->device == SND_DEVICE_MEM) {
        if (snd->write_flag == SND_READ) {
            printf("from memory buffer");
        } else {
            printf("to memory buffer");
        }
    } else {
        printf("header %s", header_to_string(snd->u.file.header));
    }
    printf(", channels %d, mode %s, bits %d, srate %g",
           snd->format.channels,
           snd_mode_to_string(snd->format.mode),
           snd->format.bits, snd->format.srate);
    if (snd->device == SND_DEVICE_MEM) {
        if (snd->write_flag == SND_READ) {
            printf("length %d\n", snd->u.mem.buffer_len);
        } else {
            printf("length %d\n", snd->u.mem.buffer_max);
        }
    } else if (snd->device == SND_DEVICE_FILE &&
               snd->write_flag == SND_READ) {
        printf(", length %d\n", (snd->u.file.end_offset -
                                 snd->u.file.byte_offset) / snd_bytes_per_frame(snd));
    } else printf("\n");
}
Example #3
0
void *audio_descr_build(snd_type snd)
{    
    int i, j;
    buffer_state *bufstate;
    double bufsize_in_frames;

    bufstate = (buffer_state *) snd_alloc(sizeof(buffer_state));

    if (snd->u.audio.protocol == SND_REALTIME){
        bufstate->numofbuffers = 3;        
    }
    else { 
        if (snd->u.audio.protocol != SND_COMPUTEAHEAD)
            snd_fail("Invalid protocol identifier. COMPUTEAHEAD method used instead");
        bufstate->numofbuffers = 2;    
    }
    

    if (NULL == (bufstate->whdr = 
                (LPWAVEHDR)snd_alloc(bufstate->numofbuffers * sizeof(WAVEHDR)))){
        snd_fail("Not enough memory, or similar");
        snd_free(bufstate);
        return NULL;
    }
    bufsize_in_frames = max(Audio_out_min_buffersize, 
                            snd->format.srate * snd->u.audio.latency);
    if (bufsize_in_frames > snd->format.srate * snd->u.audio.latency)
        snd->u.audio.latency = bufsize_in_frames / snd->format.srate;
    for (i=0; i<bufstate->numofbuffers; i++){
        bufstate->whdr[i].dwBufferLength = (long)(bufsize_in_frames + 0.5) * snd_bytes_per_frame(snd); 
        if (NULL == (bufstate->whdr[i].lpData = (char *) snd_alloc(bufstate->whdr[i].dwBufferLength))){
            snd_fail("Not enough memory, or similar");
            for (j=0; j<i-1; j++){
                snd_free(bufstate->whdr[j].lpData);
            }
            snd_free(bufstate);
            return NULL;
        }
        bufstate->whdr[i].dwUser = bufstate->whdr[i].dwLoops = 0;    //idrk, what's that
        bufstate->whdr[i].dwFlags = WHDR_DONE;
    }

    bufstate->pollee = 0;
    bufstate->posinbuffer = 0;

    if (snd->u.audio.protocol == SND_REALTIME){
        bufstate->sync_buffer = 0;
        bufstate->prev_time = timeGetTime();
        bufstate->sync_time = bufstate->prev_time - (long)(2 * 1000 * snd->u.audio.latency + .5);
    }


    return (void *) bufstate;
}
Example #4
0
MMRESULT win_wave_open(snd_type snd, UINT devtoopen, HWAVE *hptr)
{
    WAVEFORMATEX wfmt;
    int bperf;

    switch (snd->format.mode) {
      case SND_MODE_UNKNOWN:
      case SND_MODE_PCM:
        /* note: Windows uses signed PCM (PCM) for 16-bit data, and
         * unsigned PCM (UPCM) for 8-bit data
         */
        if (snd->format.bits != 8) {
            wfmt.wFormatTag = WAVE_FORMAT_PCM;
            break;
        } else return WAVERR_BADFORMAT;    
      case SND_MODE_ADPCM:
      case SND_MODE_ALAW:
      case SND_MODE_ULAW:
      case SND_MODE_FLOAT:
      case SND_MODE_UPCM:
        if (snd->format.bits == 8) {
            wfmt.wFormatTag = WAVE_FORMAT_PCM;
            break;
        } else return(WAVERR_BADFORMAT);
      default:
        return(MMSYSERR_INVALPARAM);
    }    

    wfmt.nChannels       =  (unsigned short) snd->format.channels;
    wfmt.nSamplesPerSec  =  (long) (snd->format.srate + 0.5);
    bperf = snd_bytes_per_frame(snd);
    wfmt.nAvgBytesPerSec =  (long) (bperf * snd->format.srate + 0.5);
    wfmt.nBlockAlign     =  (unsigned short) bperf;
    wfmt.wBitsPerSample     =  (unsigned short) snd->format.bits;
    wfmt.cbSize            =  0;    
    if (snd->write_flag != SND_READ) {
        /* Under Windows2000 on an IBM A21p Thinkpad, waveOutOpen will 
           CRASH (!) if snd->format.srate is 110250, but it actually 
           worked with 4000, and it worked with 96000, so I will assume
           sample rates above 96000 are bad. -RBD 24Jul02
         */
        if (wfmt.nSamplesPerSec > 96000) {
            return WAVERR_BADFORMAT;
        }
        /* otherwise, we're ready to open the device */
        return waveOutOpen((LPHWAVEOUT) hptr, devtoopen, &wfmt, 0L, 0L, 
                           (DWORD) CALLBACK_NULL);
    } else {
        return waveInOpen((LPHWAVEIN) hptr, devtoopen, &wfmt, 0L, 0L,
                          (DWORD) CALLBACK_NULL);
    }
}
Example #5
0
long audio_write(snd_type snd, void *buffer, long length_in_bytes)
{
   oss_info dp = get_oss_info(snd);

   pthread_mutex_lock(&dp->mutex);

   if (dp->len + length_in_bytes > dp->buffersize)
      length_in_bytes = dp->buffersize - dp->len;

   copy_to_wrap_buffer(dp, buffer, length_in_bytes);

   pthread_mutex_unlock(&dp->mutex);

   return (length_in_bytes / snd_bytes_per_frame(snd));
}
Example #6
0
/*
 * We want to write as soon as space is available so that
 * a full sound buffer can be queued up for output. This
 * may require transferring only part of buf, so we keep
 * track of progress and output whenever space is available.
 */
void write_to_audio(snd_type player, void *buf, long buflen)
{
    long rslt;
    while (buflen) {
            /* this loop is a busy-wait loop! */
        rslt = snd_poll(player); /* wait for buffer space */
        rslt = min(rslt, buflen);
        if (rslt) {
            snd_write(player, buf, rslt);
            buf = (void *) ((char *) buf + 
                            (rslt * snd_bytes_per_frame(player)));
            buflen -= rslt;
        }
    }    
}
Example #7
0
long audio_read(snd_type snd, void *buffer, long length_in_bytes)
{
   oss_info dp = get_oss_info(snd);

   if (length_in_bytes <= 0)
      return 0;

   pthread_mutex_lock(&dp->mutex);

   if (length_in_bytes > dp->len)
      length_in_bytes = dp->len;

   copy_from_wrap_buffer(dp, buffer, length_in_bytes);

   pthread_mutex_unlock(&dp->mutex);

   return (length_in_bytes / snd_bytes_per_frame(snd));
}
Example #8
0
int audio_open(snd_type snd, long *flags)
{
   int format;
   int channels;
   int rate;
   oss_info dp;
   const char *device = "/dev/dsp";
   pthread_t thread;

   snd->u.audio.descriptor = (oss_info) malloc(sizeof(oss_info_struct));
   dp = get_oss_info(snd);

   if (snd->u.audio.devicename[0] != 0)
      device = snd->u.audio.devicename;

   if (snd->write_flag == SND_READ) {
      /* open audio input */

      /* Open /dev/dsp */
      dp->audio_fd = open(device, O_RDONLY, 0);
	
      if (dp->audio_fd == -1)
         return !SND_SUCCESS;

   }
   else {
      /* open audio output */

      /* Open /dev/dsp */
      dp->audio_fd = open(device, O_WRONLY, 0);
	
      if (dp->audio_fd == -1)
         return !SND_SUCCESS;
   }

	
   /* Set format to signed 16-bit little-endian */
   format = AFMT_S16_LE;
   if (ioctl(dp->audio_fd, SNDCTL_DSP_SETFMT, &format) == -1)
      return !SND_SUCCESS;
   if (format != AFMT_S16_LE) /* this format is not supported */
      return !SND_SUCCESS;
  
   /* Set number of channels */
   channels = snd->format.channels;
   if (ioctl(dp->audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1)
      return !SND_SUCCESS;
   if (channels != snd->format.channels)
      return !SND_SUCCESS;
  
   /* Set sampling rate.  Must set sampling rate AFTER setting
      number of channels. */
   rate = (int)(snd->format.srate + 0.5);
   if (ioctl(dp->audio_fd, SNDCTL_DSP_SPEED, &rate) == -1)
      return !SND_SUCCESS;
   if (rate - (int)(snd->format.srate + 0.5) > 100 ||
       rate - (int)(snd->format.srate + 0.5) < -100)
      return !SND_SUCCESS;

   /* finish initialization and start the thread */

   if (snd->write_flag == SND_READ) {
      /* always buffer 10 seconds of audio for reading
         (no reason not to for this implementation */
      dp->buffersize = rate * 10.0 * snd_bytes_per_frame(snd); 
   }
   else {
      if (snd->u.audio.latency > 0.0)
         dp->buffersize = rate * snd->u.audio.latency * 
            snd_bytes_per_frame(snd);
      else
         dp->buffersize = rate * 1.0 * snd_bytes_per_frame(snd);
   }

   dp->buffer = malloc(dp->buffersize);
   
   dp->start = 0;
   dp->len = 0;
   dp->error_count = 0;
   dp->stop_flag = 0;

   pthread_mutex_init (&dp->mutex, 0);

   if (snd->write_flag == SND_READ) {
      if (0 != pthread_create(&dp->thread, NULL,
                              record_thread, (void *)dp))
         return !SND_SUCCESS;
   }
   else {
      if (0 != pthread_create(&dp->thread, NULL,
                              playback_thread, (void *)dp))
         return !SND_SUCCESS;
   }
  
   return SND_SUCCESS;
}
Example #9
0
long audio_poll(snd_type snd)
{
    long availtemp;
    buffer_state *cur = ((buffer_state*) snd->u.audio.descriptor);
    LPWAVEHDR whdrs = cur->whdr;
    int i, test = 0; 
    int numbuf = cur->numofbuffers;

    for (i=0; i<numbuf; i++){ 
        if (whdrs[i].dwFlags & WHDR_DONE){
            test++;
        }
    }

    if (snd->u.audio.protocol == SND_REALTIME) {
        int last_buf, k;

        if (test < numbuf) { 
            /* there is at least one buffer being processed by the 
             * device (not "done")
               */
            if (test) { /* there is at last one buffer done */
                long bufferbytes;
                if (whdrs[cur->sync_buffer].dwFlags & WHDR_DONE){
                    k = (cur->sync_buffer + 1) % numbuf;
                    while (k != cur->sync_buffer){
                        if (!(whdrs[k].dwFlags & WHDR_DONE)){
                            cur->sync_buffer = k;
                            break;
                        }
                        k = (k + 1) % numbuf;
                    }
                    cur->sync_time = cur->prev_time;
                } else 
                    cur->prev_time = timeGetTime();
                availtemp = (long)
                    (((double)(cur->prev_time - cur->sync_time) *
                     max_srate_dev / 1000 
                     /*+ 2 * snd->u.audio.latency*/) *
                     snd->format.srate);
                last_buf = (cur->sync_buffer + numbuf - 1) % numbuf;
                while (last_buf != cur->pollee) {
                    availtemp += whdrs[last_buf].dwBufferLength;
                    last_buf = (last_buf + numbuf - 1) % numbuf;
                }
                bufferbytes = test * (long) whdrs[0].dwBufferLength;
                if (bufferbytes < availtemp * snd_bytes_per_frame(snd)) {
                    return bufferbytes / snd_bytes_per_frame(snd);
                } else {
                    return availtemp;
                }
            } else { 
                /* all buffer already passed to the device, it 
                 * should happen only just because we "overestimate"
                 * the sample-rate
                  */
                cur->prev_time = timeGetTime();
                cur->sync_time = cur->prev_time;
                return 0;
            }
        } else { //all buffers are done
            cur->prev_time = timeGetTime();
            cur->sync_time = cur->prev_time;
            return ((numbuf - 1) * whdrs[0].dwBufferLength) / 
                   snd_bytes_per_frame(snd);
        }
    } else { /* protocol SND_COPMUTEAHEAD */
        /* here is suppose that all buffer have the same length 
         * (otherwise, sg like "for(i=0;i<numbuf;i++) 
         * available+=whdrs[i].dwBufferLength" should be used)
         */             
        return (test * whdrs[0].dwBufferLength - cur->posinbuffer) / 
               snd_bytes_per_frame(snd);
    }
}
Example #10
0
int audio_open(snd_node *n, long *f)
{
  buffer_state *data = (buffer_state *)malloc(sizeof(buffer_state));
  n->u.audio.descriptor = (void *)data;
  OSErr	err;
  Fixed sampleRateFixed;

  data->frameSize = snd_bytes_per_frame(n);

  data->bufferSize = (int) (n->format.srate * (double)data->frameSize);
  if (n->u.audio.latency > 0.0)
    data->bufferSize = (int)(n->format.srate * n->u.audio.latency) * data->frameSize;

  /* Calculate sample rate as an unsigned fixed-point number */
  if (n->format.srate > 65535.0 ||
    n->format.srate < 1.0)
    sampleRateFixed = 0xAC440000; /* Fixed for 44100 */
  else {
    unsigned short numerator = (unsigned short)n->format.srate;
    unsigned short denominator = (unsigned short)(65536.0*(n->format.srate - numerator));
    sampleRateFixed = (numerator << 16) | denominator;
  }

  /* Open device for recording or playback, depending on mode selected */

  if (n->write_flag == SND_READ) {
    /* recording */
    short gainControl = 0; /* off */
    short numChannels = n->format.channels;
    short continuousRecording = 1; /* on */
    short playthroughVolume = 0; /* off */
    OSType quality = 'cd  ';
    short sampleSize = 16;
    short twos = 0; /* i.e. signed */
    OSType compression = 'NONE';
    SoundInfoList infoList;
    int len, i, x, y, z;
    short selected = 0;
    char *device;
    char *input;
    char **buffer;
    char oneInput[256];
    char *deviceData;
  
    data->recording = 1;
    
    len = strlen(n->u.audio.devicename);
    device = new char[len+1];
    input = new char[len+1];
    
    strcpy(device, n->u.audio.devicename);
    input[0] = 0;
    for(i=0; i<len; i++) {
       if (device[i] == '\n') {
          device[i] = 0;
          strcpy(input, &device[i+1]);
          i = len;
       }
    }
    
    err = SPBOpenDevice(c2pstr(device), siWritePermission, &data->refnum);
    if (err)
      return !SND_SUCCESS;
    
    SPBGetDeviceInfo (data->refnum, siInputAvailable, &infoList);

    SPBGetDeviceInfo (data->refnum, siInputSourceNames, &buffer);
    deviceData = buffer[0] + 2;
   
    for(int x=0; x<infoList.count; x++) {
      int y = *deviceData++;
      z = 0;
      while(y) {
        oneInput[z++] = *deviceData++;
        y--;
      }
      oneInput[z] = 0;
      if (!strcmp(oneInput, input))
        selected = x;
    }
    
    selected++;
    SPBSetDeviceInfo (data->refnum, siInputSource, &selected);
    
    SPBSetDeviceInfo(data->refnum, 'qual', &quality);

    SPBSetDeviceInfo(data->refnum, 'agc ', &gainControl);
    
    SPBSetDeviceInfo(data->refnum, 'srat', &sampleRateFixed);

    SPBSetDeviceInfo(data->refnum, 'plth', &playthroughVolume);
    
    err = SPBSetDeviceInfo(data->refnum, 'ssiz', &sampleSize);
    if (err)
      return !SND_SUCCESS;

    err = SPBSetDeviceInfo(data->refnum, 'chan', &numChannels);
    if (err)
      return !SND_SUCCESS;
  
    err = SPBSetDeviceInfo(data->refnum, 'cont', &continuousRecording);
    if (err)
      return !SND_SUCCESS;
  
    err = SPBSetDeviceInfo(data->refnum, 'twos', &twos);
    if (err)
      return !SND_SUCCESS;

    err = SPBSetDeviceInfo(data->refnum, 'comp', &compression);
    if (err)
      return !SND_SUCCESS;
      
    data->recBuffer = (char *)malloc(data->bufferSize);
    data->recqStart = 0;
    data->recqEnd = 0;
    data->starved = 0;
    
    data->params.inRefNum = data->refnum;
    data->params.count = 0; /* data->bufferSize; /* bytes to record */
    data->params.milliseconds = 0; /* param will be ignored; use count */
    data->params.bufferLength = 0; /* ignore buffer */
    data->params.bufferPtr = NULL; /* ignore buffer */
    data->params.completionRoutine = NULL;
    data->params.userLong = (long)data;
    data->params.unused1 = 0;
    data->params.interruptRoutine = NewSIInterruptUPP(recordingCallback);

    err = SPBRecord(&data->params, true);
    if (err)
      return !SND_SUCCESS;
    
  }
  else {
    /* playback */

    data->recording = 0;
    data->chan = NULL;
    
    
    
    
    
    ////////////////////////
    
    
    err = SndNewChannel(&data->chan, sampledSynth, 0, NULL);
  	
    if (err)
      return !SND_SUCCESS;
  	  
    data->buffer = (char *)malloc(data->bufferSize);
    
    data->nextBufferSize = data->bufferSize * 3;
    data->nextBuffer = (char *)malloc(data->nextBufferSize);   

    if (!data->buffer || !data->nextBuffer)
      return !SND_SUCCESS;
    
    data->chan->callBack = NewSndCallBackUPP(playbackCallback);
    
    data->header.samplePtr = data->buffer;
    data->header.numChannels = n->format.channels;
    data->header.sampleRate = sampleRateFixed;
    data->header.loopStart = 0;
    data->header.loopEnd = 0;
    data->header.encode = cmpSH;
    data->header.baseFrequency = kMiddleC;
    // data->header.AIFFSampleRate = 0;  -- this parameter is unused
    data->header.markerChunk = NULL;
    data->header.format = kSoundNotCompressed;
    data->header.futureUse2 = NULL;
    data->header.stateVars = NULL;
    data->header.leftOverSamples = NULL;
    data->header.compressionID = 0;
    data->header.packetSize = 0;
    data->header.snthID = 0;
    data->header.sampleSize = 16;
    data->header.sampleArea[0] = 0;
    
    data->playCmd.cmd = bufferCmd;
    data->playCmd.param1 = 0; //unused
    data->playCmd.param2 = (long)&data->header;
    
    data->callCmd.cmd = callBackCmd;
    data->callCmd.param1 = 0;
    data->callCmd.param2 = (long)data;
    
    data->curBuffer = 0;
    data->curSize = 0;
    data->firstTime = 1;
    data->finished = 0;
    data->busy = 0;
    data->flushing = 0;
  }
  
  return SND_SUCCESS;
}
Example #11
0
int main(int argc, char *argv[])
{
    char *fromfile = NULL;
    char *tofile = NULL;
    int i;
    long flags = 0;
    long frames;
    long len;
    long checksum = 0;
    long count = 0;

    int format = SND_HEAD_AIFF;
    int mode = SND_MODE_PCM;
    int channels = 1;
    int bits = 16;
    double srate = 44100.0;
    snd_node from_snd, to_snd;
    char from_buf[MAXLEN];
    char to_buf[MAXLEN];
    long frames_from_len;
    long frames_to_len;
    long from_len = 0;
    long to_len = 0;

    for (i = 1; i < argc; i++) {
        if (*(argv[i]) != '-') {
            if (!fromfile) fromfile = argv[i];
            else if (!tofile) tofile = argv[i];
            else {
                printf("%s: don't know what to do with 3rd file\n", argv[i]);
                return 1;
            }
        } else {
            char *flag = argv[i] + 1;
            if (*flag == '?') {
                printf("convert -- sound file conversion utility\n\n");
                printf("usage: convert fromfile tofile -flag1 -flag2 ...\n");
                printf("  -fa -- AIFF file format\n");
                printf("  -fi -- IRCAM file format\n");
                printf("  -fn -- NeXT/Sun file format\n");
                printf("  -fw -- Wave file format\n");
                printf("  -ep -- PCM\n");
                printf("  -em -- u-Law\n");
                printf("  -ef -- float\n");
                printf("  -eu -- unsigned PCM\n");
                printf("  -b1 -- 8-bit\n");
                printf("  -b2 -- 16-bit\n");
                printf("  -b4 -- 32-bit\n");
                printf("  -c1 -- 1 channel, etc.\n");
                printf("use 'ada' to get audio input or output\n");
            } else if (*flag == 'f') {
                switch (flag[1]) {
                case 'a':
                    format = SND_HEAD_AIFF;
                    break;
                case 'i':
                    format = SND_HEAD_IRCAM;
                    break;
                case 'n':
                    format = SND_HEAD_NEXT;
                    break;
                case 'w':
                    format = SND_HEAD_WAVE;
                    break;
                default:
                    printf("flag %s ignored\n", argv[i]);
                    break;
                }
            } else if (*flag == 'e') {
                switch (flag[1]) {
                case 'p':
                    mode = SND_MODE_PCM;
                    break;
                case 'm':
                    mode = SND_MODE_ULAW;
                    break;
                case 'f':
                    mode = SND_MODE_FLOAT;
                    break;
                case 'u':
                    mode = SND_MODE_UPCM;
                    break;
                default:
                    printf("flag %s ignored\n", argv[i]);
                    break;
                }
            } else if (*flag == 'b') {
                switch (flag[1]) {
                case '1':
                    bits = 8;
                    break;
                case '2':
                    bits = 16;
                    break;
                case '4':
                    bits = 32;
                    break;
                default:
                    printf("flag %s ignored\n", argv[i]);
                    break;
                }
            } else if (*flag == 'r') {
                switch (flag[1]) {
                case '4':
                    srate = 44100.0;
                    break;
                case '2':
                    srate = 22050.0;
                    break;
                case '1':
                    srate = 11025.0;
                    break;
                case '8':
                    srate = 8000.0;
                    break;
                default:
                    printf("flag %s ignored\n", argv[i]);
                    break;
                }
            } else if (*flag == 'c') {
                channels = atoi(flag+1);
                if (channels < 1 || channels > 16) {
                    channels = 1;
                    printf("flag %s ignored, using 1 channel\n",
                           argv[i]);
                }
            }
        }
    }
    if (!tofile) {
        printf("2 files not found, use -? for help\n");
        return 1;
    }

    from_snd.device = SND_DEVICE_FILE;
    from_snd.write_flag = SND_READ;
    from_snd.u.file.byte_offset = 0;
    from_snd.format.channels = channels;
    from_snd.format.mode = mode;
    from_snd.format.bits = bits;
    from_snd.format.srate = srate;

    if (strcmp(fromfile, "ada") == 0) {
        from_snd.device = SND_DEVICE_AUDIO;
        from_snd.u.audio.protocol = SND_COMPUTEAHEAD;
        from_snd.u.audio.latency = 1.0;
        from_snd.u.audio.granularity = 0.1;
        strcpy(from_snd.u.file.filename, "");
    } else {
        strcpy(from_snd.u.file.filename, fromfile);
    }
    if (snd_open(&from_snd, &flags) != SND_SUCCESS) {
        printf("error opening %s for input\n", fromfile);
        exit(1);
    }
    printf("Opened %s for input: ", from_snd.u.file.filename);
    snd_print_info(&from_snd);

    to_snd.device = SND_DEVICE_FILE;
    to_snd.write_flag = SND_WRITE;
    to_snd.format.channels = channels;
    to_snd.format.mode = mode;
    to_snd.format.bits = bits;
    to_snd.format.srate = from_snd.format.srate;
    to_snd.u.file.header = format;	/* header format, e.g. AIFF */
    if (to_snd.u.file.header == SND_HEAD_WAVE && to_snd.format.mode == SND_MODE_PCM &&
            to_snd.format.bits == 8) to_snd.format.mode = SND_MODE_UPCM;
    if (strcmp(tofile, "ada") == 0) {
        to_snd.device = SND_DEVICE_AUDIO;
        to_snd.u.audio.protocol = SND_COMPUTEAHEAD;
        to_snd.u.audio.latency = 0.0;
        to_snd.u.audio.granularity = 0.1;
        strcpy(to_snd.u.audio.interfacename, "");
        strcpy(to_snd.u.audio.devicename, "");
    } else {
        strcpy(to_snd.u.file.filename, tofile);
    }
    if (snd_open(&to_snd, &flags) != SND_SUCCESS) {
        printf("error opening %s for output\n", tofile);
        exit(1);
    }
    printf("Opened %s for output: ", to_snd.u.file.filename);
    snd_print_info(&to_snd);

    /* figure out how much to convert on each iteration */

    /* first, compute how many frames could fit in each buffer */
    from_len = MAXLEN / snd_bytes_per_frame(&from_snd);
    to_len = MAXLEN / snd_bytes_per_frame(&to_snd);

    /* then compute the minimum of the two frame counts */
    frames = min(from_len, to_len);

    while (1) {
        /* then convert back from frame counts to byte counts: */
        while ((frames_from_len = snd_poll(&from_snd)) <=0);
        frames_from_len = min(frames_from_len, frames);
        while ((frames_to_len = snd_poll(&to_snd)) <= 0);
        frames_to_len = min(frames_to_len, frames);
        len = min(frames_to_len, frames_from_len);
        len = snd_read(&from_snd, from_buf, len);
        if (((from_snd.device == SND_DEVICE_AUDIO) &&
                (count > from_snd.format.srate * 10)) || (!len)) {
            break;
        }
        for (i = 0; i < len * snd_bytes_per_frame(&from_snd); i++) {
            checksum += from_buf[i];
            count++;
        }
        len = snd_convert(&to_snd, to_buf, &from_snd, from_buf, len);
        len = snd_write(&to_snd, to_buf, len);
        printf("#");
        fflush(stdout);
    }
    snd_close(&from_snd);
    if (to_snd.device == SND_DEVICE_AUDIO) {
        while (snd_flush(&to_snd) != SND_SUCCESS) ;
    }
    snd_close(&to_snd);

    printf("Read %ld frames, checksum = %ld\n", count, checksum);
    exit(0);
}