📄 wav.c
字号:
break; case WAVE_FORMAT_ADPCM: case WAVE_FORMAT_IMA_ADPCM: if (ft->info.style == -1 || ft->info.style == ADPCM) ft->info.style = ADPCM; else warn("User options overriding style read in .wav header"); break; case WAVE_FORMAT_ALAW: /* Think I can handle this */ if (ft->info.style == -1 || ft->info.style == ALAW) ft->info.style = ALAW; else warn("User options overriding style read in .wav header"); break; case WAVE_FORMAT_MULAW: /* Think I can handle this */ if (ft->info.style == -1 || ft->info.style == ULAW) ft->info.style = ULAW; else warn("User options overriding style read in .wav header"); break; case WAVE_FORMAT_OKI_ADPCM: fail("Sorry, this WAV file is in OKI ADPCM format."); case WAVE_FORMAT_DIGISTD: fail("Sorry, this WAV file is in Digistd format."); case WAVE_FORMAT_DIGIFIX: fail("Sorry, this WAV file is in Digifix format."); case IBM_FORMAT_MULAW: fail("Sorry, this WAV file is in IBM U-law format."); case IBM_FORMAT_ALAW: fail("Sorry, this WAV file is in IBM A-law format."); case IBM_FORMAT_ADPCM: fail("Sorry, this WAV file is in IBM ADPCM format."); default: fail("WAV file has unknown format type"); } wChannels = rlshort(ft); len -= 2; /* User options take precedence */ if (ft->info.channels == -1 || ft->info.channels == wChannels) ft->info.channels = wChannels; else warn("User options overriding channels read in .wav header"); wSamplesPerSecond = rllong(ft); len -= 4; if (ft->info.rate == 0 || ft->info.rate == wSamplesPerSecond) ft->info.rate = wSamplesPerSecond; else warn("User options overriding rate read in .wav header"); wAvgBytesPerSec = rllong(ft); /* Average bytes/second */ wav->blockAlign = rlshort(ft); /* Block align */ len -= 6; /* bits per sample per channel */ wBitsPerSample = rlshort(ft); len -= 2; /* ADPCM formats have extended fmt chunk. Check for those cases. */ if (wav->formatTag == WAVE_FORMAT_ADPCM) { if (wBitsPerSample != 4) fail("Can only handle 4-bit MS ADPCM in wav files"); wExtSize = rlshort(ft); wav->samplesPerBlock = rlshort(ft); wav->bytesPerBlock = (wav->samplesPerBlock + 7)/2 * ft->info.channels; wNumCoefs = rlshort(ft); wav->packet = (unsigned char *)malloc(wav->blockAlign); len -= 6; wav->samples[1] = wav->samples[0] = 0; /* Use ft->info.channels after this becuase wChannels is now bad */ while (wChannels-- > 0) wav->samples[wChannels] = (short *)malloc(wav->samplesPerBlock*sizeof(short)); } else if (wav->formatTag == WAVE_FORMAT_IMA_ADPCM) { if (wBitsPerSample != 4) fail("Can only handle 4-bit IMA ADPCM in wav files"); wExtSize = rlshort(ft); wav->samplesPerBlock = rlshort(ft); wav->bytesPerBlock = (wav->samplesPerBlock + 7)/2 * ft->info.channels; wav->packet = (unsigned char *)malloc(wav->blockAlign); len -= 4; wav->samples[1] = wav->samples[0] = 0; /* Use ft->info.channels after this becuase wChannels is now bad */ while (wChannels-- > 0) wav->samples[wChannels] = (short *)malloc(wav->samplesPerBlock*sizeof(short)); } bytespersample = (wBitsPerSample + 7)/8; switch (bytespersample) { case BYTE: /* User options take precedence */ if (ft->info.size == -1 || ft->info.size == BYTE) ft->info.size = BYTE; else warn("User options overriding size read in .wav header"); if (ft->info.style == -1 || ft->info.style == UNSIGNED) ft->info.style = UNSIGNED; else if (ft->info.style != ALAW && ft->info.style != ULAW && ft->info.style != ADPCM) warn("User options overriding style read in .wav header"); break; case WORD: if (ft->info.size == -1 || ft->info.size == WORD) ft->info.size = WORD; else warn("User options overriding size read in .wav header"); if (ft->info.style == -1 || ft->info.style == SIGN2) ft->info.style = SIGN2; else warn("User options overriding style read in .wav header"); break; case DWORD: if (ft->info.size == -1 || ft->info.size == DWORD) ft->info.size = DWORD; else warn("User options overriding size read in .wav header"); if (ft->info.style == -1 || ft->info.style == SIGN2) ft->info.style = SIGN2; else warn("User options overriding style read in .wav header"); break; default: fail("Sorry, don't understand .wav size"); } /* Skip past the rest of any left over fmt chunk */ while (len > 0 && !feof(ft->fp)) { getc(ft->fp); len--; } /* Now look for the wave data chunk */ for (;;) { if ( fread(magic, 1, 4, ft->fp) != 4 ) fail("WAVE file has missing data chunk"); len = rllong(ft); if (strncmp("data", magic, 4) == 0) break; /* Found the data chunk */ while (len > 0 && !feof(ft->fp)) /* skip to next chunk */ { getc(ft->fp); len--; } } data_length = len; if (wav->formatTag == WAVE_FORMAT_ADPCM) { /* Compute easiest part of number of samples. For every block, there are samplesPerBlock samples to read. */ wav->numSamples = (((data_length / wav->blockAlign) * wav->samplesPerBlock) * ft->info.channels); /* Next, for any partial blocks, substract overhead from it and it will leave # of samples to read. */ wav->numSamples += ((data_length - ((data_length/wav->blockAlign) *wav->blockAlign)) - (6 * ft->info.channels)) * ft->info.channels; wav->blockSamplesRemaining = 0; /* Samples left in buffer */ } else if (wav->formatTag == WAVE_FORMAT_IMA_ADPCM) { /* Compute easiest part of number of samples. For every block, there are samplesPerBlock samples to read. */ wav->numSamples = (((data_length / wav->blockAlign) * wav->samplesPerBlock) * ft->info.channels); /* Next, for any partial blocks, substract overhead from it and it will leave # of samples to read. */ wav->numSamples += ((data_length - ((data_length/wav->blockAlign) *wav->blockAlign)) - (3 * ft->info.channels)) * ft->info.channels; wav->blockSamplesRemaining = 0; /* Samples left in buffer */ } else wav->numSamples = data_length/ft->info.size; /* total samples */ report("Reading Wave file: %s format, %d channel%s, %d samp/sec", wav_format_str(wav->formatTag), ft->info.channels, wChannels == 1 ? "" : "s", wSamplesPerSecond); report(" %d byte/sec, %d block align, %d bits/samp, %u data bytes", wAvgBytesPerSec, wav->blockAlign, wBitsPerSample, data_length); /* Can also report exteded fmt information */ if (wav->formatTag == WAVE_FORMAT_ADPCM) report(" %d Extsize, %d Samps/block, %d bytes/block %d Num Coefs\n",wExtSize,wav->samplesPerBlock,wav->bytesPerBlock,wNumCoefs); else if (wav->formatTag == WAVE_FORMAT_IMA_ADPCM) report(" %d Extsize, %d Samps/block, %d bytes/block\n",wExtSize,wav->samplesPerBlock,wav->bytesPerBlock);}/* * Read up to len samples from file. * Convert to signed longs. * Place in buf[]. * Return number of samples read. */LONG wavread(ft, buf, len) ft_t ft;LONG *buf, len;{ wav_t wav = (wav_t) ft->priv; LONG done; if (len > wav->numSamples) len = wav->numSamples; /* If file is in ADPCM style then read in multiple blocks else */ /* read as much as possible and return quickly. */ if (ft->info.style == ADPCM) { done = 0; while (done < len) { /* Still want data? */ /* See if need to read more from disk */ if (wav->blockSamplesRemaining == 0) { if (wav->formatTag == WAVE_FORMAT_IMA_ADPCM) wav->blockSamplesRemaining = ImaAdpcmNextBlock(ft); else wav->blockSamplesRemaining = MsAdpcmNextBlock(ft); if (wav->blockSamplesRemaining == 0) { /* Don't try to read any more samples */ wav->numSamples = 0; return done; } wav->samplePtr[0] = wav->samples[0]; wav->samplePtr[1] = wav->samples[1]; } switch(ft->info.channels) { /* Copy data into buf */ case 1: /* Mono: Just copy left channel data */ while ((wav->blockSamplesRemaining > 0) && (done < len)) { /* Output is already signed */ *buf++ = LEFT(*(wav->samplePtr[0]++), 16); done++; wav->blockSamplesRemaining--; } break; case 2: /* Stereo: Interleave samples */ while ((wav->blockSamplesRemaining > 0) && (done < len)) { /* Output is already signed */ *buf++ = LEFT(*(wav->samplePtr[0]++),16); /* Left */ *buf++ = LEFT(*(wav->samplePtr[1]++),16); /* Right */ done += 2; wav->blockSamplesRemaining--; } break; default: fail ("Can only handle stereo or mono files"); } } } else /* else not ADPCM style */ { done = rawread(ft, buf, len); /* If software thinks there are more samples but I/O */ /* says otherwise, let the user no about this. */ if (done == 0 && wav->numSamples != 0) warn("Premature EOF on .wav input file"); } wav->numSamples -= done; return done;}/* * Do anything required when you stop reading samples. * Don't close input file! */void wavstopread(ft) ft_t ft;{ wav_t wav = (wav_t) ft->priv; if (wav->packet) free(wav->packet); if (wav->samples[0]) free(wav->samples[0]); if (wav->samples[1]) free(wav->samples[1]);}void wavstartwrite(ft) ft_t ft;{ wav_t wav = (wav_t) ft->priv; int littlendian = 1; char *endptr; endptr = (char *) &littlendian; if (!*endptr) ft->swap = 1; wav->numSamples = 0; wav->second_header = 0; if (! ft->seekable) warn("Length in output .wav header will wrong since can't seek to fix it"); wavwritehdr(ft);}void wavwritehdr(ft) ft_t ft;{ wav_t wav = (wav_t) ft->priv; /* wave file characteristics */ unsigned short wFormatTag = 0; /* data format */ unsigned short wChannels; /* number of channels */ ULONG wSamplesPerSecond; /* samples per second per channel */ ULONG wAvgBytesPerSec; /* estimate of bytes per second needed */ unsigned short wBlockAlign; /* byte alignment of a basic sample block */ unsigned short wBitsPerSample; /* bits per sample */ ULONG data_length; /* length of sound data in bytes */ ULONG bytespersample; /* bytes per sample (per channel) */ switch (ft->info.size) { case BYTE: if (ft->info.style == -1 || ft->info.style == UNSIGNED) ft->info.style = UNSIGNED; else if (!wav->second_header && ft->info.style != ALAW && ft->info.style != ULAW && ft->info.style != ADPCM) warn("User options overriding style written to .wav header"); if (ft->info.style == ADPCM) { warn("Can not support writing ADPCM style. Overriding to UNSIGNED\n"); ft->info.style = UNSIGNED; wBitsPerSample = 8; /* wBitsPerSample = 4; */ } else wBitsPerSample = 8; break; case WORD: wBitsPerSample = 16; if (ft->info.style == -1 || ft->info.style == SIGN2) ft->info.style = SIGN2; else if (!wav->second_header) warn("User options overriding style written to .wav header"); break; case DWORD: wBitsPerSample = 32; if (ft->info.style == -1 || ft->info.style == SIGN2) ft->info.style = SIGN2; else if (!wav->second_header) warn("User options overriding style written to .wav header"); break; default: wBitsPerSample = 32; if (ft->info.style == -1) ft->info.style = SIGN2; if (!wav->second_header) warn("Warning - writing bad .wav file using %s",sizes[ft->info.size]); break; } switch (ft->info.style) { case UNSIGNED: wFormatTag = WAVE_FORMAT_PCM; if (wBitsPerSample != 8 && !wav->second_header) warn("Warning - writing bad .wav file using unsigned data and %d bits/sample",wBitsPerSample); break; case SIGN2: wFormatTag = WAVE_FORMAT_PCM; if (wBitsPerSample == 8 && !wav->second_header) warn("Warning - writing bad .wav file using signed data and %d bits/sample",wBitsPerSample); break; case ALAW: wFormatTag = WAVE_FORMAT_ALAW; if (wBitsPerSample != 8 && !wav->second_header) warn("Warning - writing bad .wav file using A-law data and %d bits/sample",wBitsPerSample); break; case ULAW: wFormatTag = WAVE_FORMAT_MULAW; if (wBitsPerSample != 8 && !wav->second_header) warn("Warning - writing bad .wav file using U-law data and %d bits/sample",wBitsPerSample); break; case ADPCM: wFormatTag = WAVE_FORMAT_IMA_ADPCM; if (wBitsPerSample != 4 && !wav->second_header) warn("Warning - writing bad .wav file using IMA ADPCM and %d bits/sample",wBitsPerSample); break; } wSamplesPerSecond = ft->info.rate; bytespersample = (wBitsPerSample + 7)/8; wAvgBytesPerSec = ft->info.rate * ft->info.channels * bytespersample; wChannels = ft->info.channels; wBlockAlign = ft->info.channels * bytespersample; if (!wav->second_header) /* use max length value first time */ data_length = 0x7fffffffL - (8+16+12); else /* fixup with real length */ { if (ft->info.style == ADPCM) data_length = wav->numSamples / 2; else data_length = bytespersample * wav->numSamples; } /* figured out header info, so write it */ fputs("RIFF", ft->fp); wllong(ft, data_length + 8+16+12); /* Waveform chunk size: FIXUP(4) */ fputs("WAVE", ft->fp); fputs("fmt ", ft->fp); wllong(ft, (LONG)16); /* fmt chunk size */ wlshort(ft, wFormatTag); wlshort(ft, wChannels); wllong(ft, wSamplesPerSecond); wllong(ft, wAvgBytesPerSec); wlshort(ft, wBlockAlign); wlshort(ft, wBitsPerSample); fputs("data", ft->fp); wllong(ft, data_length); /* data chunk size: FIXUP(40) */ if (!wav->second_header) { report("Writing Wave file: %s format, %d channel%s, %d samp/sec", wav_format_str(wFormatTag), wChannels, wChannels == 1 ? "" : "s", wSamplesPerSecond); report(" %d byte/sec, %d block align, %d bits/samp", wAvgBytesPerSec, wBlockAlign, wBitsPerSample); } else report("Finished writing Wave file, %u data bytes\n",data_length);}void wavwrite(ft, buf, len) ft_t ft;LONG *buf, len;{ wav_t wav = (wav_t) ft->priv; wav->numSamples += len; rawwrite(ft, buf, len);}voidwavstopwrite(ft) ft_t ft;{ /* All samples are already written out. */ /* If file header needs fixing up, for example it needs the */ /* the number of samples in a field, seek back and write them here. */ if (!ft->seekable) return; if (fseek(ft->fp, 0L, 0) != 0) fail("Sorry, can't rewind output file to rewrite .wav header."); ((wav_t) ft->priv)->second_header = 1; wavwritehdr(ft);}/* * Return a string corresponding to the wave format type. */static char *wav_format_str(wFormatTag) unsigned wFormatTag;{ switch (wFormatTag) { case WAVE_FORMAT_UNKNOWN: return "Microsoft Official Unknown"; case WAVE_FORMAT_PCM: return "Microsoft PCM"; case WAVE_FORMAT_ADPCM: return "Microsoft ADPCM"; case WAVE_FORMAT_ALAW: return "Microsoft A-law"; case WAVE_FORMAT_MULAW: return "Microsoft U-law"; case WAVE_FORMAT_OKI_ADPCM: return "OKI ADPCM format."; case WAVE_FORMAT_IMA_ADPCM: return "IMA ADPCM"; case WAVE_FORMAT_DIGISTD: return "Digistd format."; case WAVE_FORMAT_DIGIFIX: return "Digifix format."; case IBM_FORMAT_MULAW: return "IBM U-law format."; case IBM_FORMAT_ALAW: return "IBM A-law"; case IBM_FORMAT_ADPCM: return "IBM ADPCM"; default: return "Unknown"; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -