aplay.c
来自「alsa-utils-1.0.14编译声卡驱动所需要的一些文件源码」· C语言 代码 · 共 2,374 行 · 第 1/5 页
C
2,374 行
static void voc_write_silence(unsigned x){ unsigned l; u_char *buf; buf = (u_char *) malloc(chunk_bytes); if (buf == NULL) { error(_("can't allocate buffer for silence")); return; /* not fatal error */ } snd_pcm_format_set_silence(hwparams.format, buf, chunk_size * hwparams.channels); while (x > 0) { l = x; if (l > chunk_size) l = chunk_size; if (voc_pcm_write(buf, l) != (ssize_t)l) { error(_("write error")); exit(EXIT_FAILURE); } x -= l; } free(buf);}static void voc_pcm_flush(void){ if (buffer_pos > 0) { size_t b; if (sleep_min == 0) { if (snd_pcm_format_set_silence(hwparams.format, audiobuf + buffer_pos, chunk_bytes - buffer_pos * 8 / bits_per_sample) < 0) fprintf(stderr, _("voc_pcm_flush - silence error")); b = chunk_size; } else { b = buffer_pos * 8 / bits_per_frame; } if (pcm_write(audiobuf, b) != (ssize_t)b) error(_("voc_pcm_flush error")); } snd_pcm_drain(handle);}static void voc_play(int fd, int ofs, char *name){ int l; VocBlockType *bp; VocVoiceData *vd; VocExtBlock *eb; size_t nextblock, in_buffer; u_char *data, *buf; char was_extended = 0, output = 0; u_short *sp, repeat = 0; size_t silence; off64_t filepos = 0;#define COUNT(x) nextblock -= x; in_buffer -= x; data += x#define COUNT1(x) in_buffer -= x; data += x data = buf = (u_char *)malloc(64 * 1024); buffer_pos = 0; if (data == NULL) { error(_("malloc error")); exit(EXIT_FAILURE); } if (!quiet_mode) { fprintf(stderr, _("Playing Creative Labs Channel file '%s'...\n"), name); } /* first we waste the rest of header, ugly but we don't need seek */ while (ofs > (ssize_t)chunk_bytes) { if ((size_t)safe_read(fd, buf, chunk_bytes) != chunk_bytes) { error(_("read error")); exit(EXIT_FAILURE); } ofs -= chunk_bytes; } if (ofs) { if (safe_read(fd, buf, ofs) != ofs) { error(_("read error")); exit(EXIT_FAILURE); } } hwparams.format = DEFAULT_FORMAT; hwparams.channels = 1; hwparams.rate = DEFAULT_SPEED; set_params(); 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 buf up */ if (in_buffer) memcpy(buf, data, in_buffer); data = buf; if ((l = safe_read(fd, buf + in_buffer, chunk_bytes - in_buffer)) > 0) in_buffer += l; else if (!in_buffer) { /* the file is truncated, so simulate 'Terminator' and reduce the datablock for safe landing */ nextblock = buf[0] = 0; if (l == -1) { perror(name); exit(EXIT_FAILURE); } } } while (!nextblock) { /* this is a new block */ if (in_buffer < sizeof(VocBlockType)) goto __end; bp = (VocBlockType *) data; COUNT1(sizeof(VocBlockType)); nextblock = VOC_DATALEN(bp); if (output && !quiet_mode) fprintf(stderr, "\n"); /* write /n after ASCII-out */ output = 0; switch (bp->type) { case 0:#if 0 d_printf("Terminator\n");#endif return; /* VOC-file stop */ case 1: vd = (VocVoiceData *) data; COUNT1(sizeof(VocVoiceData)); /* we need a SYNC, before we can set new SPEED, STEREO ... */ if (!was_extended) { hwparams.rate = (int) (vd->tc); hwparams.rate = 1000000 / (256 - hwparams.rate);#if 0 d_printf("Channel data %d Hz\n", dsp_speed);#endif if (vd->pack) { /* /dev/dsp can't it */ error(_("can't play packed .voc files")); return; } if (hwparams.channels == 2) /* if we are in Stereo-Mode, switch back */ hwparams.channels = 1; } else { /* there was extended block */ hwparams.channels = 2; was_extended = 0; } set_params(); break; case 2: /* nothing to do, pure data */#if 0 d_printf("Channel continuation\n");#endif break; case 3: /* a silence block, no data, only a count */ sp = (u_short *) data; COUNT1(sizeof(u_short)); hwparams.rate = (int) (*data); COUNT1(1); hwparams.rate = 1000000 / (256 - hwparams.rate); set_params(); silence = (((size_t) * sp) * 1000) / hwparams.rate;#if 0 d_printf("Silence for %d ms\n", (int) silence);#endif voc_write_silence(*sp); break; case 4: /* a marker for syncronisation, no effect */ sp = (u_short *) data; COUNT1(sizeof(u_short));#if 0 d_printf("Marker %d\n", *sp);#endif break; case 5: /* ASCII text, we copy to stderr */ output = 1;#if 0 d_printf("ASCII - text :\n");#endif break; case 6: /* repeat marker, says repeatcount */ /* my specs don't say it: maybe this can be recursive, but I don't think somebody use it */ repeat = *(u_short *) data; COUNT1(sizeof(u_short));#if 0 d_printf("Repeat loop %d times\n", repeat);#endif if (filepos >= 0) { /* if < 0, one seek fails, why test another */ if ((filepos = lseek64(fd, 0, 1)) < 0) { error(_("can't play loops; %s isn't seekable\n"), name); repeat = 0; } else { filepos -= in_buffer; /* set filepos after repeat */ } } else { repeat = 0; } break; case 7: /* ok, lets repeat that be rewinding tape */ if (repeat) { if (repeat != 0xFFFF) {#if 0 d_printf("Repeat loop %d\n", repeat);#endif --repeat; }#if 0 else d_printf("Neverending loop\n");#endif lseek64(fd, filepos, 0); in_buffer = 0; /* clear the buffer */ goto Fill_the_buffer; }#if 0 else d_printf("End repeat loop\n");#endif break; case 8: /* the extension to play Stereo, I have SB 1.0 :-( */ was_extended = 1; eb = (VocExtBlock *) data; COUNT1(sizeof(VocExtBlock)); hwparams.rate = (int) (eb->tc); hwparams.rate = 256000000L / (65536 - hwparams.rate); hwparams.channels = eb->mode == VOC_MODE_STEREO ? 2 : 1; if (hwparams.channels == 2) hwparams.rate = hwparams.rate >> 1; if (eb->pack) { /* /dev/dsp can't it */ error(_("can't play packed .voc files")); return; }#if 0 d_printf("Extended block %s %d Hz\n", (eb->mode ? "Stereo" : "Mono"), dsp_speed);#endif break; default: error(_("unknown blocktype %d. terminate."), bp->type); return; } /* switch (bp->type) */ } /* while (! nextblock) */ /* put nextblock data bytes to dsp */ l = in_buffer; if (nextblock < (size_t)l) l = nextblock; if (l) { if (output && !quiet_mode) { if (write(2, data, l) != l) { /* to stderr */ error(_("write error")); exit(EXIT_FAILURE); } } else { if (voc_pcm_write(data, l) != l) { error(_("write error")); exit(EXIT_FAILURE); } } COUNT(l); } } /* while(1) */ __end: voc_pcm_flush(); free(buf);}/* that was a big one, perhaps somebody split it :-) *//* setting the globals for playing raw data */static void init_raw_data(void){ hwparams = rhwparams;}/* calculate the data count to read from/to dsp */static off64_t calc_count(void){ off64_t count; if (timelimit == 0) { count = pbrec_count; } else { count = snd_pcm_format_size(hwparams.format, hwparams.rate * hwparams.channels); count *= (off64_t)timelimit; } return count < pbrec_count ? count : pbrec_count;}/* write a .VOC-header */static void begin_voc(int fd, size_t cnt){ VocHeader vh; VocBlockType bt; VocVoiceData vd; VocExtBlock eb; memcpy(vh.magic, VOC_MAGIC_STRING, 20); vh.headerlen = LE_SHORT(sizeof(VocHeader)); vh.version = LE_SHORT(VOC_ACTUAL_VERSION); vh.coded_ver = LE_SHORT(0x1233 - VOC_ACTUAL_VERSION); if (write(fd, &vh, sizeof(VocHeader)) != sizeof(VocHeader)) { error(_("write error")); exit(EXIT_FAILURE); } if (hwparams.channels > 1) { /* write an extended block */ bt.type = 8; bt.datalen = 4; bt.datalen_m = bt.datalen_h = 0; if (write(fd, &bt, sizeof(VocBlockType)) != sizeof(VocBlockType)) { error(_("write error")); exit(EXIT_FAILURE); } eb.tc = LE_SHORT(65536 - 256000000L / (hwparams.rate << 1)); eb.pack = 0; eb.mode = 1; if (write(fd, &eb, sizeof(VocExtBlock)) != sizeof(VocExtBlock)) { error(_("write error")); exit(EXIT_FAILURE); } } bt.type = 1; cnt += sizeof(VocVoiceData); /* Channel_data block follows */ bt.datalen = (u_char) (cnt & 0xFF); bt.datalen_m = (u_char) ((cnt & 0xFF00) >> 8); bt.datalen_h = (u_char) ((cnt & 0xFF0000) >> 16); if (write(fd, &bt, sizeof(VocBlockType)) != sizeof(VocBlockType)) { error(_("write error")); exit(EXIT_FAILURE); } vd.tc = (u_char) (256 - (1000000 / hwparams.rate)); vd.pack = 0; if (write(fd, &vd, sizeof(VocVoiceData)) != sizeof(VocVoiceData)) { error(_("write error")); exit(EXIT_FAILURE); }}/* write a WAVE-header */static void begin_wave(int fd, size_t cnt){ WaveHeader h; WaveFmtBody f; WaveChunkHeader cf, cd; int bits; u_int tmp; u_short tmp2; /* WAVE cannot handle greater than 32bit (signed?) int */ if (cnt == (size_t)-2) cnt = 0x7fffff00; bits = 8; switch ((unsigned long) hwparams.format) { case SND_PCM_FORMAT_U8: bits = 8; break; case SND_PCM_FORMAT_S16_LE: bits = 16; break; case SND_PCM_FORMAT_S32_LE: bits = 32; break; case SND_PCM_FORMAT_S24_LE: case SND_PCM_FORMAT_S24_3LE: bits = 24; break; default: error(_("Wave doesn't support %s format..."), snd_pcm_format_name(hwparams.format)); exit(EXIT_FAILURE); } h.magic = WAV_RIFF; tmp = cnt + sizeof(WaveHeader) + sizeof(WaveChunkHeader) + sizeof(WaveFmtBody) + sizeof(WaveChunkHeader) - 8; h.length = LE_INT(tmp); h.type = WAV_WAVE; cf.type = WAV_FMT; cf.length = LE_INT(16); f.format = LE_SHORT(WAV_PCM_CODE); f.modus = LE_SHORT(hwparams.channels); f.sample_fq = LE_INT(hwparams.rate);#if 0 tmp2 = (samplesize == 8) ? 1 : 2; f.byte_p_spl = LE_SHORT(tmp2); tmp = dsp_speed * hwparams.channels * (u_int) tmp2;#else tmp2 = hwparams.channels * snd_pcm_format_physical_width(hwparams.format) / 8; f.byte_p_spl = LE_SHORT(tmp2); tmp = (u_int) tmp2 * hwparams.rate;#endif f.byte_p_sec = LE_INT(tmp); f.bit_p_spl = LE_SHORT(bits); cd.type = WAV_DATA; cd.length = LE_INT(cnt); if (write(fd, &h, sizeof(WaveHeader)) != sizeof(WaveHeader) || write(fd, &cf, sizeof(WaveChunkHeader)) != sizeof(WaveChunkHeader) || write(fd, &f, sizeof(WaveFmtBody)) != sizeof(WaveFmtBody) || write(fd, &cd, sizeof(WaveChunkHeader)) != sizeof(WaveChunkHeader)) { error(_("write error")); exit(EXIT_FAILURE); }}/* write a Au-header */static void begin_au(int fd, size_t cnt){ AuHeader ah; ah.magic = AU_MAGIC; ah.hdr_size = BE_INT(24); ah.data_size = BE_INT(cnt); switch ((unsigned long) hwparams.format) { case SND_PCM_FORMAT_MU_LAW: ah.encoding = BE_INT(AU_FMT_ULAW); break; case SND_PCM_FORMAT_U8: ah.encoding = BE_INT(AU_FMT_LIN8); break; case SND_PCM_FORMAT_S16_BE: ah.encoding = BE_INT(AU_FMT_LIN16); break; default: error(_("Sparc Audio doesn't support %s format..."), snd_pcm_format_name(hwparams.format)); exit(EXIT_FAILURE); } ah.sample_rate = BE_INT(hwparams.rate); ah.channels = BE_INT(hwparams.channels); if (write(fd, &ah, sizeof(AuHeader)) != sizeof(AuHeader)) { error(_("write error")); exit(EXIT_FAILURE); }}/* closing .VOC */static void end_voc(int fd){ off64_t length_seek; VocBlockType bt; size_t cnt; char dummy = 0; /* Write a Terminator */ if (write(fd, &dummy, 1) != 1) { error(_("write error")); exit(EXIT_FAILURE); } length_seek = sizeof(VocHeader); if (hwparams.channels > 1) length_seek += sizeof(VocBlockType) + sizeof(VocExtBlock); bt.type = 1; cnt = fdcount; cnt += sizeof(VocVoiceData); /* Channel_data block follows */ if (cnt > 0x00ffffff) cnt = 0x00ffffff; bt.datalen = (u_char) (cnt & 0xFF); bt.datalen_m = (u_char) ((cnt & 0xFF00) >> 8); bt.datalen_h = (u_char) ((cnt & 0xFF0000) >> 16); if (lseek64(fd, length_seek, SEEK_SET) == length_seek) write(fd, &bt, sizeof(VocBlockType)); if (fd != 1) close(fd);}static void end_wave(int fd){ /* only close output */ WaveChunkHeader cd; off64_t length_seek; off64_t filelen; u_int rifflen; length_seek = sizeof(WaveHeader) + sizeof(WaveChunkHeader) + sizeof(WaveFmtBody); cd.type = WAV_DATA; cd.length = fdcount > 0x7fffffff ? LE_INT(0x7fffffff) : LE_INT(fdcount); filelen = fdcount + 2*sizeof(WaveChunkHeader) + sizeof(WaveFmtBody) + 4; rifflen = filelen > 0x7fffffff ? LE_INT(0x7fffffff) : LE_INT(filelen); if (lseek64(fd, 4, SEEK_SET) == 4)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?