📄 vplay.c
字号:
/* vplay.c - plays and records CREATIVE LABS VOICE-files, Microsoft WAVE-files and raw data Autor: Michael Beck - beck@informatik.hu-berlin.de*/#include <stdio.h>//#include <malloc.h>//#include <unistd.h>//#include <stdlib.h>#include <string.h>//#include <fcntl.h>//#include <sys/ioctl.h>#include "fs_api.h"#include <sys/soundcard.h>#include "fmtheaders.h"//#include <netinet/in.h>#include "pcm.h"#define DEFAULT_DSP_SPEED 48000#define RECORD 0#define PLAY 1//#define AUDIO "/dev/dsp"#define min(a,b) ((a) <= (b) ? (a) : (b))#define d_printf(x) if (verbose_mode) fprintf x#define VOC_FMT 0#define WAVE_FMT 1#define RAW_DATA 2#define SND_FMT 3/* global data */int timelimit = 0, dsp_speed = DEFAULT_DSP_SPEED, dsp_stereo = 0;int samplesize = 8;int quiet_mode = 0;int verbose_mode = 0;int convert = 0;int record_type = VOC_FMT;u_long count;int audio, abuf_size, zbuf_size;int direction, omode;unsigned char *audiobuf, *zerobuf;unsigned char audiobuf1[0x1000 * 16];extern int pcm_ioctl(unsigned int cmd, unsigned long arg);char *command;int vocminor, vocmajor; /* .VOC version */FS_FILE *myfile;/* defaults for playing raw data */;struct { int timelimit, dsp_speed, dsp_stereo, samplesize;} raw_info = { 0, DEFAULT_DSP_SPEED, 0, 8 };/* needed prototypes */void record_play (char *name,int dir);void start_voc (int fd, u_long count);void start_wave (int fd, u_long count);void start_snd (int fd, u_long count);void end_voc (int fd);void end_wave_raw (int fd);void end_snd (int fd);u_long calc_count ();struct fmt_record { void (*start) (int fd, u_long count); void (*end) (int fd); char *what;} fmt_rec_table[] = { { start_voc, end_voc, "VOC" }, { start_wave, end_wave_raw, "WAVE" }, { NULL, end_wave_raw, "raw data" }, { start_snd, end_snd, "SND" }}; extern int IS_WRITE_PCM;/* test, if it is a .VOC file and return >=0 if ok (this is the length of rest) < 0 if not */int test_vocfile(void *buffer){ VocHeader *vp = buffer; if (!strcmp((const char *)vp->magic, MAGIC_STRING) ) { vocminor = vp->version & 0xFF; vocmajor = vp->version / 256; if (vp->version != (0x1233 - vp->coded_ver) ) return -2; /* coded version mismatch */ return vp->headerlen - sizeof(VocHeader); /* 0 mostly */ } return -1; /* magic string fail */}/* test, if it's a .WAV file, 0 if ok (and set the speed, stereo etc.) < 0 if not*/int test_wavefile(void *buffer){ WaveHeader *wp = buffer; if (wp->main_chunk == RIFF && wp->chunk_type == WAVE && wp->sub_chunk == FMT && wp->data_chunk == DATA) { if (wp->format != PCM_CODE) { fprintf (stderr, "%s: can't play not PCM-coded WAVE-files\n", command); exit (-1); } if (wp->modus > 2) { fprintf (stderr, "%s: can't play WAVE-files with %d tracks\n", command, wp->modus); exit (-1); } dsp_stereo = (wp->modus == WAVE_STEREO) ? 1 : 0; samplesize = wp->bit_p_spl; dsp_speed = wp->sample_fq; count = wp->data_length; return 0; } return -1;}/** test, if it's a .SND file, 0 if ok (and set the speed, stereo etc.)* < 0 if not*/int test_sndfile(void *buffer, int fd){ long infolen; char *info; SndHeader *snd = buffer; if (snd->magic == SND_MAGIC) convert = 0; else{ if( htonl(snd->magic) == SND_MAGIC){ convert = 1; snd->dataLocation = htonl(snd->dataLocation); snd->dataSize = htonl(snd->dataSize); snd->dataFormat = htonl(snd->dataFormat); snd->samplingRate = htonl(snd->samplingRate); snd->channelCount = htonl(snd->channelCount); } else{ /* No SoundFile */ return(-1); } } switch (snd->dataFormat){ case SND_FORMAT_LINEAR_8: samplesize = 8; break; case SND_FORMAT_LINEAR_16: samplesize = 16; break; default: fprintf (stderr, "%s: Unsupported SND_FORMAT\n", command); exit (-1); } dsp_stereo = (snd->channelCount == 2) ? 1 : 0; dsp_speed = snd->samplingRate; count = snd->dataSize; /* read Info-Strings */ infolen = snd->dataLocation - sizeof(SndHeader); info = (char *) malloc(infolen); read(fd, info, infolen); if(!quiet_mode) fprintf(stderr, "SoundFile Info: %s\n", info); free(info); return 0;} /* writing zeros from the zerobuf to simulate silence, perhaps it's enough to use a long var instead of zerobuf ?*/void write_zeros (unsigned x){ unsigned l; while (x) { l = min (x, zbuf_size); if (write (audio, (char *)zerobuf, l) != l) {// perror (AUDIO); exit (-1); } x -= l; }} /* if need a SYNC, (is needed if we plan to change speed, stereo ... during output)*/void sync_dsp(void){#if 0 if (ioctl (audio, SNDCTL_DSP_SYNC, NULL) < 0) { perror(AUDIO); exit (-1); }#endif}/* setting the speed for output */void set_dsp_speed (int *dsp_speed){ // if (ioctl(audio, SNDCTL_DSP_SPEED, dsp_speed) < 0) { if (pcm_ioctl(PCM_SET_SAMPLE_RATE, 16000) < 0) { fprintf (stderr, "%s: unable to set audio speed\n", command);// perror (AUDIO); exit (-1); }}/* if to_mono: compress 8 bit stereo data 2:1, needed if we want play 'one track'; this is usefull, if you habe SB 1.0 - 2.0 (I have 1.0) and want hear the sample (in Mono) if to_8: compress 16 bit to 8 by using hi-byte; wave-files use signed words, so we need to convert it in "unsigned" sample (0x80 is now zero) WARNING: this procedure can't compress 16 bit stereo to 16 bit mono, because if you have a 16 (or 12) bit card you should have stereo (or I'm wrong ?? ) */unsigned long one_channel(unsigned char *buf,unsigned long l, char to_mono, char to_8){ register unsigned char *w = buf; register unsigned char *w2 = buf; char ofs = 0; unsigned long incr = 0; unsigned long c, ret; printf("on channel---\n"); if (to_mono) ++incr; if (to_8) { ++incr; ++w2; ofs = 128; } ret = c = l >> incr; incr = incr << 1; printf("two channel---\n"); while (c--) { *w++ = *w2 + ofs; w2 += incr; }printf("two2 channel---\n"); return ret;}/* ok, let's play a .voc file*/ void vplay (int fd, int ofs, char *name){ int l, real_l; BlockType *bp; Voice_data *vd; Ext_Block *eb; u_long nextblock, in_buffer; u_char *data = audiobuf; char was_extended = 0, output = 0; u_short *sp, repeat = 0; u_long silence; int filepos = 0; char one_chn = 0;#define COUNT(x) nextblock -= x; in_buffer -=x ;data += x /* first SYNC the dsp */ sync_dsp(); if (!quiet_mode) fprintf (stderr, "Playing Creative Labs Voice file ...\n"); /* first we waste the rest of header, ugly but we don't need seek */ while (ofs > abuf_size) { read (fd, (char *)audiobuf, abuf_size); ofs -= abuf_size; } if (ofs) read (fd, audiobuf, ofs); /* .voc files are 8 bit (now) */ samplesize = VOC_SAMPLESIZE; ioctl(audio, SNDCTL_DSP_SAMPLESIZE, &samplesize); if (samplesize != VOC_SAMPLESIZE) { fprintf(stderr, "%s: unable to set 8 bit sample size!\n", command); exit (-1); } /* and there are MONO by default */ dsp_stereo = MODE_MONO; ioctl(audio, SNDCTL_DSP_STEREO, &dsp_stereo); in_buffer = nextblock = 0; while (1) { Fill_the_buffer: /* need this for repeat */ if ( in_buffer < 32 ) { /* move the rest of buffer to pos 0 and fill the audiobuf up */ if (in_buffer) memcpy ((char *)audiobuf, data, in_buffer); data = audiobuf; if ((l = read (fd, (char *)audiobuf + in_buffer, abuf_size - in_buffer) ) > 0) in_buffer += l; else if (! in_buffer) { /* the file is truncated, so simulate 'Terminator' and reduce the datablock for save landing */ nextblock = audiobuf[0] = 0; if (l == -1) { perror (name); exit (-1); } } } while (! nextblock) { /* this is a new block */ bp = (BlockType *)data; COUNT(sizeof (BlockType)); nextblock = DATALEN(bp); if (output && !quiet_mode) fprintf (stderr, "\n"); /* write /n after ASCII-out */ output = 0; switch (bp->type) { case 0: d_printf ((stderr, "Terminator\n")); return; /* VOC-file stop */ case 1: vd = (Voice_data *)data; COUNT(sizeof(Voice_data)); /* we need a SYNC, before we can set new SPEED, STEREO ... */ sync_dsp(); if (! was_extended) { dsp_speed = (int)(vd->tc); dsp_speed = 1000000 / (256 - dsp_speed); d_printf ((stderr, "Voice data %d Hz\n", dsp_speed)); if (vd->pack) { /* /dev/dsp can't it */ fprintf (stderr, "%s: can't play packed .voc files\n", command); return; } if (dsp_stereo) { /* if we are in Stereo-Mode, switch back */ dsp_stereo = MODE_MONO; ioctl(audio, SNDCTL_DSP_STEREO, &dsp_stereo); } } else { /* there was extended block */ if (one_chn) /* if one Stereo fails, why test another ? */ dsp_stereo = MODE_MONO; else if (dsp_stereo) { /* want Stereo */ /* shit, my MACRO dosn't work here */#ifdef SOUND_VERSION if (ioctl(audio, SNDCTL_DSP_STEREO, &dsp_stereo) < 0) {#else if (dsp_stereo != ioctl(audio, SNDCTL_DSP_STEREO, dsp_stereo)) { #endif dsp_stereo = MODE_MONO; fprintf (stderr, "%s: can't play in Stereo; playing only one channel\n", command); one_chn = 1; } } was_extended = 0; } set_dsp_speed (&dsp_speed); break; case 2: /* nothing to do, pure data */ d_printf ((stderr, "Voice continuation\n")); break; case 3: /* a silence block, no data, only a count */ sp = (u_short *)data; COUNT(sizeof(u_short)); dsp_speed = (int)(*data); COUNT(1); dsp_speed = 1000000 / (256 - dsp_speed); sync_dsp();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -