Better .wav detection

This commit is contained in:
Abramo Bagnara 2000-05-29 18:54:23 +00:00
parent 749b454304
commit 048c2000f8
2 changed files with 92 additions and 62 deletions

View file

@ -377,7 +377,6 @@ int main(int argc, char *argv[])
fprintf(stderr, "Error: wrong extended format '%s'\n", optarg);
exit(EXIT_FAILURE);
}
active_format = FORMAT_RAW;
break;
case 'm':
case 'M':
@ -514,26 +513,38 @@ static int test_vocfile(void *buffer)
}
/*
* test, if it's a .WAV file, 0 if ok (and set the speed, stereo etc.)
* < 0 if not
* test, if it's a .WAV file, > 0 if ok (and set the speed, stereo etc.)
* == 0 if not
* Value returned is bytes to be discarded.
*/
static int test_wavefile(void *buffer)
static int test_wavefile(void *buffer, size_t size)
{
WaveHeader *wp = buffer;
WaveHeader *h = buffer;
WaveFmtHeader *f;
WaveChunkHeader *c;
if (wp->main_chunk == WAV_RIFF && wp->chunk_type == WAV_WAVE &&
wp->sub_chunk == WAV_FMT && wp->data_chunk == WAV_DATA) {
if (LE_SHORT(wp->format) != WAV_PCM_CODE) {
if (h->magic != WAV_RIFF || h->type != WAV_WAVE)
return 0;
c = (WaveChunkHeader*)((char *)buffer + sizeof(WaveHeader));
while (c->type != WAV_FMT) {
c = (WaveChunkHeader*)((char*)c + sizeof(*c) + c->length);
if ((char *)c + sizeof(*c) > (char*) buffer + size) {
fprintf(stderr, "%s: cannot found WAVE fmt chunk\n", command);
exit(EXIT_FAILURE);
}
}
f = (WaveFmtHeader*) c;
if (LE_SHORT(f->format) != WAV_PCM_CODE) {
fprintf(stderr, "%s: can't play not PCM-coded WAVE-files\n", command);
exit(EXIT_FAILURE);
}
if (LE_SHORT(wp->modus) < 1 || LE_SHORT(wp->modus) > 32) {
if (LE_SHORT(f->modus) < 1) {
fprintf(stderr, "%s: can't play WAVE-files with %d tracks\n",
command, LE_SHORT(wp->modus));
command, LE_SHORT(f->modus));
exit(EXIT_FAILURE);
}
format.channels = LE_SHORT(wp->modus);
switch (LE_SHORT(wp->bit_p_spl)) {
format.channels = LE_SHORT(f->modus);
switch (LE_SHORT(f->bit_p_spl)) {
case 8:
format.format = SND_PCM_SFMT_U8;
break;
@ -542,14 +553,21 @@ static int test_wavefile(void *buffer)
break;
default:
fprintf(stderr, "%s: can't play WAVE-files with sample %d bits wide\n",
command, LE_SHORT(wp->bit_p_spl));
command, LE_SHORT(f->bit_p_spl));
exit(EXIT_FAILURE);
}
format.rate = LE_INT(wp->sample_fq);
count = LE_INT(wp->data_length);
format.rate = LE_INT(f->sample_fq);
while (c->type != WAV_DATA) {
c = (WaveChunkHeader*)((char*)c + sizeof(*c) + c->length);
if ((char *)c + sizeof(*c) > (char*) buffer + size) {
fprintf(stderr, "%s: cannot found WAVE data chunk\n", command);
exit(EXIT_FAILURE);
}
}
count = LE_INT(c->length);
check_new_format(&format);
return 0;
}
return -1;
return (char *)c + sizeof(*c) - (char *) buffer;
}
/*
@ -1209,7 +1227,9 @@ static void begin_voc(int fd, size_t cnt)
/* write a WAVE-header */
static void begin_wave(int fd, size_t cnt)
{
WaveHeader wh;
WaveHeader h;
WaveFmtHeader f;
WaveChunkHeader c;
int bits;
bits = 8;
@ -1224,25 +1244,30 @@ static void begin_wave(int fd, size_t cnt)
fprintf(stderr, "%s: Wave doesn't support %s format...\n", command, snd_pcm_get_format_name(format.format));
exit(EXIT_FAILURE);
}
wh.main_chunk = WAV_RIFF;
wh.length = cnt + sizeof(WaveHeader) - 8;
wh.chunk_type = WAV_WAVE;
wh.sub_chunk = WAV_FMT;
wh.sc_len = 16;
wh.format = WAV_PCM_CODE;
wh.modus = format.channels;
wh.sample_fq = format.rate;
h.magic = WAV_RIFF;
h.length = cnt + sizeof(WaveHeader) + sizeof(WaveFmtHeader) + sizeof(WaveChunkHeader) - 8;
h.type = WAV_WAVE;
f.type = WAV_FMT;
f.length = 16;
f.format = WAV_PCM_CODE;
f.modus = format.channels;
f.sample_fq = format.rate;
#if 0
wh.byte_p_spl = (samplesize == 8) ? 1 : 2;
wh.byte_p_sec = dsp_speed * wh.modus * wh.byte_p_spl;
f.byte_p_spl = (samplesize == 8) ? 1 : 2;
f.byte_p_sec = dsp_speed * f.modus * f.byte_p_spl;
#else
wh.byte_p_spl = wh.modus * ((bits + 7) / 8);
wh.byte_p_sec = wh.byte_p_spl * format.rate;
f.byte_p_spl = f.modus * ((bits + 7) / 8);
f.byte_p_sec = f.byte_p_spl * format.rate;
#endif
wh.bit_p_spl = bits;
wh.data_chunk = WAV_DATA;
wh.data_length = cnt;
if (write(fd, &wh, sizeof(WaveHeader)) != sizeof(WaveHeader)) {
f.bit_p_spl = bits;
c.type = WAV_DATA;
c.length = cnt;
if (write(fd, &h, sizeof(WaveHeader)) != sizeof(WaveHeader) ||
write(fd, &f, sizeof(WaveFmtHeader)) != sizeof(WaveFmtHeader) ||
write(fd, &c, sizeof(WaveChunkHeader)) != sizeof(WaveChunkHeader)) {
fprintf(stderr, "%s: write error\n", command);
exit(EXIT_FAILURE);
}
@ -1427,19 +1452,20 @@ static void playback(char *name)
}
/* read bytes for WAVE-header */
if (read(fd, audiobuf + sizeof(VocHeader),
sizeof(WaveHeader) - sizeof(VocHeader)) !=
sizeof(WaveHeader) - sizeof(VocHeader)) {
64 - sizeof(VocHeader)) !=
64 - sizeof(VocHeader)) {
fprintf(stderr, "%s: read error", command);
exit(EXIT_FAILURE);
}
if (test_wavefile(audiobuf) >= 0) {
playback_go(fd, 0, count, FORMAT_WAVE, name);
if ((ofs = test_wavefile(audiobuf, 64)) > 0) {
memmove(audiobuf, audiobuf + ofs, 64 - ofs);
playback_go(fd, 64 - ofs, count, FORMAT_WAVE, name);
} else {
/* should be raw data */
check_new_format(&rformat);
init_raw_data();
count = calc_count();
playback_go(fd, sizeof(WaveHeader), count, FORMAT_RAW, name);
playback_go(fd, 50, count, FORMAT_RAW, name);
}
__end:
if (fd != 0)

View file

@ -64,23 +64,27 @@ typedef struct voc_ext_block {
are in only in this combination, so I combined them in one header;
it works on all WAVE-file I have
*/
typedef struct wav_header {
u_int main_chunk; /* 'RIFF' */
typedef struct {
u_int magic; /* 'RIFF' */
u_int length; /* filelen */
u_int chunk_type; /* 'WAVE' */
u_int type; /* 'WAVE' */
} WaveHeader;
u_int sub_chunk; /* 'fmt ' */
u_int sc_len; /* length of sub_chunk, =16 */
typedef struct {
u_int type; /* 'fmt ' */
u_int length; /* length of chunk */
u_short format; /* should be 1 for PCM-code */
u_short modus; /* 1 Mono, 2 Stereo */
u_int sample_fq; /* frequence of sample */
u_int byte_p_sec;
u_short byte_p_spl; /* samplesize; 1 or 2 bytes */
u_short bit_p_spl; /* 8, 12 or 16 bit */
} WaveFmtHeader;
u_int data_chunk; /* 'data' */
u_int data_length; /* samplecount */
} WaveHeader;
typedef struct {
u_int type; /* 'data' */
u_int length; /* samplecount */
} WaveChunkHeader;
/* Definitions for Sparc .au header */