📄 wavfile.c
字号:
/* * Put little endian value into 32 bit value: */ dbytes = ubuf[3]; dbytes = (dbytes << 8) | ubuf[2]; dbytes = (dbytes << 8) | ubuf[1]; dbytes = (dbytes << 8) | ubuf[0]; wfile->wavinfo.DataBytes = dbytes; /* * Open succeeded: */ return wfile; /* Return open descriptor */ /* * Return error after failed open: */errxit: e = errno; /* Save errno */ free(wfile->Pathname); /* Dispose of copied pathname */ free(wfile); /* Dispose of WAVFILE struct */ errno = e; /* Restore error number */ return NULL; /* Return error indication */}/* * Apply command line option overrides to the interpretation of the input * wav file: * */voidWavReadOverrides(WAVFILE *wfile,WavPlayOpts *wavopts) { UInt32 num_samples; /* * Override sampling rate: -s sampling_rate */ if ( wavopts->SamplingRate.optChar != 0 ) { wfile->wavinfo.SamplingRate = wavopts->SamplingRate.optValue; wfile->wavinfo.bOvrSampling = 1; } /* * Override mono/stereo mode: -S / -M */ if ( wavopts->Channels.optChar != 0 ) { wfile->wavinfo.Channels = wavopts->Channels.optValue; wfile->wavinfo.bOvrMode = 1; } /* * Override the sample size in bits: -b bits */ if ( wavopts->DataBits.optChar != 0 ) { wfile->wavinfo.DataBits = wavopts->DataBits.optValue; wfile->wavinfo.bOvrBits = 1; } /* * Set the first sample: */ wfile->StartSample = 0; num_samples = wfile->wavinfo.Samples = wfile->num_samples; if ( wavopts->StartSample != 0 ) { wfile->StartSample = wavopts->StartSample; wfile->wavinfo.Samples -= wfile->StartSample; } /* * Override # of samples if -t seconds option given: */ if ( wavopts->Seconds != 0 ) { wfile->wavinfo.Samples = wavopts->Seconds * wfile->wavinfo.SamplingRate; if (wfile->StartSample+wfile->wavinfo.Samples > num_samples) wfile->wavinfo.Samples = num_samples-1; }}/* * Close a WAVFILE */intWavClose(WAVFILE *wfile,ErrFunc erf) { int e = 0; /* Returned error code */ int channels; /* Channels recorded in this wav file */ u_long samplerate; /* Sampling rate */ int sample_bits; /* data bit size (8/12/16) */ u_long samples; /* The number of samples in this file */ u_long datastart; /* The offset to the wav data */ long fpos; /* File position in bytes */ v_erf = erf; /* Set error reporting function */ if ( wfile == NULL ) { err("%s: WAVFILE pointer is NULL!",sys_errlist[EINVAL]); errno = EINVAL; return -1; } /* * If the wav file was open for write, update the actual number * of samples written to the file: */ if ( wfile->rw == 'W' ) { fpos = lseek(wfile->fd,0L,SEEK_CUR); /* Get out file position */ if ( (e = WaveReadHeader(wfile->fd,&channels,&samplerate,&sample_bits,&samples,&datastart,_v_erf)) != 0 ) err("%s:\nReading WAV header from %s",emsg,wfile->Pathname); else if ( lseek(wfile->fd,(long)(datastart-4),SEEK_SET) != (long)(datastart-4) ) err("%s:\nSeeking in WAV header file %s",sys_errlist[errno],wfile->Pathname); else if ( write(wfile->fd,&wfile->wavinfo.Samples,sizeof wfile->wavinfo.Samples) != sizeof wfile->wavinfo.Samples ) err("%s:\nWriting in WAV header file %s",sys_errlist[errno],wfile->Pathname); else { /* * 'data' chunk was updated OK: Now we have to update the RIFF block * count. Someday very soon, a real RIFF module is going to replace * this fudging. */ if ( ftruncate(wfile->fd,(size_t)fpos) ) err("%s:\nTruncating file %s to correct size", sys_errlist[errno], wfile->Pathname); else if ( lseek(wfile->fd,4L,SEEK_SET) < 0L ) err("%s:\nSeek 4 for RIFF block update of %s", sys_errlist[errno], wfile->Pathname); else { fpos -= 8; /* Byte count for RIFF block */ if ( write(wfile->fd,&fpos,sizeof fpos) != sizeof fpos ) err("%s:\nUpdate of RIFF block count in %s failed", sys_errlist[errno], wfile->Pathname); } } } if ( close(wfile->fd) < 0 ) { err("%s:\nClosing WAV file",sys_errlist[errno]); e = errno; /* Save errno value to return */ } wavfile_free(wfile); /* Release WAVFILE structure */ if ( (errno = e) != 0 ) return -1; /* Failed exit */ return 0; /* Successful exit */}/*/* * Open /dev/dsp for reading or writing: */DSPFILE *OpenDSP(WAVFILE *wfile,int omode,ErrFunc erf) { int e; /* Saved errno value */ int t; /* Work int */ unsigned long ul; /* Work unsigned long */ DSPFILE *dfile = (DSPFILE *) malloc(sizeof (DSPFILE)); v_erf = erf; /* Set error reporting function */ if ( dfile == NULL ) { err("%s: Opening DSP device",sys_errlist[errno=ENOMEM]); return NULL; } memset(dfile,0,sizeof *dfile); dfile->dspbuf = NULL; /* * Open the device driver: */ if ( (dfile->fd = open(AUDIODEV,omode,0)) < 0 ) { err("%s:\nOpening audio device %s", sys_errlist[errno], AUDIODEV); goto errxit; } /* * Determine the audio device's block size. Should be done after * setting sampling rate etc. */ if ( ioctl(dfile->fd,SNDCTL_DSP_GETBLKSIZE,&dfile->dspblksiz) < 0 ) { err("%s: Optaining DSP's block size",sys_errlist[errno]); goto errxit; } /* * Check the range on the buffer sizes: */ /* Minimum was 4096 but es1370 returns 1024 for 44.1kHz, 16 bit */ /* and 64 for 8130Hz, 8 bit */ if ( dfile->dspblksiz < 32 || dfile->dspblksiz > 65536 ) { err("%s: Audio block size (%d bytes)", sys_errlist[errno=EINVAL], (int)dfile->dspblksiz); goto errxit; } /* * Allocate a buffer to do the I/O through: */ if ( (dfile->dspbuf = (char *) malloc(dfile->dspblksiz)) == NULL ) { err("%s: For DSP I/O buffer",sys_errlist[errno]); goto errxit; } /* * Set the data bit size: */ t = wfile->wavinfo.DataBits; if ( ioctl(dfile->fd,SNDCTL_DSP_SAMPLESIZE,&t) < 0 ) { err("%s: Setting DSP to %u bits",sys_errlist[errno],(unsigned)t); goto errxit; } /* * Set the mode to be Stereo or Mono: */ t = wfile->wavinfo.Channels == Stereo ? 1 : 0; if ( ioctl(dfile->fd,SNDCTL_DSP_STEREO,&t) < 0 ) { err("%s: Unable to set DSP to %s mode", sys_errlist[errno], t?"Stereo":"Mono"); goto errxit; } /* * Set the sampling rate: */ ul = wfile->wavinfo.SamplingRate; if ( ioctl(dfile->fd,SNDCTL_DSP_SPEED,&ul) < 0 ) { err("Unable to set audio sampling rate",sys_errlist[errno]); goto errxit; } /* * Return successfully opened device: */ return dfile; /* Return file descriptor */ /* * Failed to open/initialize properly: */errxit: e = errno; /* Save the errno value */ fprintf(stdout, "error %s : \n",sys_errlist[errno]); if ( dfile->fd >= 0 ) close(dfile->fd); /* Close device */ if ( dfile->dspbuf != NULL ) free(dfile->dspbuf); free(dfile); errno = e; /* Restore error code */ return NULL; /* Return error indication */}/* * Close the DSP device: */intCloseDSP(DSPFILE *dfile,ErrFunc erf) { int fd; v_erf = erf; /* Set error reporting function */ if ( dfile == NULL ) { err("%s: DSPFILE is not open",sys_errlist[errno=EINVAL]); return -1; } fd = dfile->fd; if ( dfile->dspbuf != NULL ) free(dfile->dspbuf); free(dfile); if ( close(fd) ) { err("%s: Closing DSP fd %d",sys_errlist[errno],fd); return -1; } return 0;}/* * Play DSP from WAV file: */intPlayDSP(DSPFILE *dfile,WAVFILE *wfile,DSPPROC work_proc,ErrFunc erf) { UInt32 byte_count = (UInt32) wfile->wavinfo.Samples; int bytes; int n; int byte_modulo; int total_bytes, update_bytes; SVRMSG msg; v_erf = erf; /* Set error reporting function */ /* * Check that the WAVFILE is open for reading: */ if ( wfile->rw != 'R' ) { err("%s: WAVFILE must be open for reading",sys_errlist[errno=EINVAL]); return -1; } /* * First determine how many bytes are required for each channel's sample: */ switch ( wfile->wavinfo.DataBits ) { case 8 : byte_count = 1; break; case 16 : byte_count = 2; break; default : err("%s: Cannot process %u bit samples", sys_errlist[errno=EINVAL], (unsigned)wfile->wavinfo.DataBits); return -1; } /* * Allow for Mono/Stereo difference: */ if ( wfile->wavinfo.Channels == Stereo ) byte_count *= 2; /* Twice as many bytes for stereo */ else if ( wfile->wavinfo.Channels != Mono ) { err("%s: DSPFILE control block is corrupted (chan_mode)", sys_errlist[errno=EINVAL]); return -1; } byte_modulo = byte_count; /* This many bytes per sample */ byte_count = wfile->wavinfo.Samples * byte_modulo; /* Total bytes to process */ total_bytes = byte_count; /* Number of bytes to write between client updates. Must be */ /* a multiple of dspblksiz. */ update_bytes = ((wfile->wavinfo.SamplingRate*byte_modulo) / (RECPLAY_UPDATES_PER_SEC*dfile->dspblksiz)) * dfile->dspblksiz; if ( ioctl(dfile->fd,SNDCTL_DSP_SYNC,0) != 0 ) err("%s: ioctl(%d,SNDCTL_DSP_SYNC,0)",sys_errlist[errno]); /* Seek to requested start sample */ lseek(wfile->fd,wfile->StartSample*byte_modulo,SEEK_CUR); for ( ; byte_count > 0 && wfile->wavinfo.DataBytes > 0; byte_count -= (UInt32) n ) { bytes = (int) ( byte_count > dfile->dspblksiz ? dfile->dspblksiz : byte_count ); if ( bytes > wfile->wavinfo.DataBytes ) /* Size bigger than data chunk? */ bytes = wfile->wavinfo.DataBytes; /* Data chunk only has this much left */ if ( (n = read(wfile->fd,dfile->dspbuf,bytes)) != bytes ) { if ( n >= 0 ) err("Unexpected EOF reading samples from WAV file",sys_errlist[errno=EIO]); else err("Reading samples from WAV file",sys_errlist[errno]); goto errxit; } /* if ((clntIPC >= 0) && !((total_bytes-byte_count) % update_bytes)) { msg.msg_type = ToClnt_PlayState; msg.bytes = sizeof(msg.u.toclnt_playstate); msg.u.toclnt_playstate.SamplesLeft = byte_count / byte_modulo; msg.u.toclnt_playstate.CurrentSample = wfile->num_samples - msg.u.toclnt_playstate.SamplesLeft; MsgToClient(clntIPC,&msg,0); } /* Tell client playback status */ if ( write(dfile->fd,dfile->dspbuf,n) != n ) { err("Writing samples to audio device",sys_errlist[errno]); goto errxit; } wfile->wavinfo.DataBytes -= (UInt32) bytes; /* We have fewer bytes left to read */ /* * The work procedure function is called when operating * in server mode to check for more server messages: */ if ( work_proc != NULL && work_proc(dfile) ) /* Did work_proc() return TRUE? */ break; /* Yes, quit playing */ }#if 0 /* I think this is doing a destructive flush: disabled */ if ( ioctl(dfile->fd,SNDCTL_DSP_SYNC,0) != 0 ) err("%s: ioctl(%d,SNDCTL_DSP_SYNC,0)",sys_errlist[errno]);#endif /* Update client time display at end of sucessful play if (clntIPC >= 0) { msg.msg_type = ToClnt_PlayState; msg.bytes = sizeof(msg.u.toclnt_playstate); msg.u.toclnt_playstate.SamplesLeft = byte_count / byte_modulo; msg.u.toclnt_playstate.CurrentSample = wfile->num_samples - msg.u.toclnt_playstate.SamplesLeft; MsgToClient(clntIPC,&msg,0); } /* Tell client playback status */ return 0; /* All samples played successfully */errxit: return -1; /* Indicate error return */}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -