mirror of
https://github.com/alsa-project/alsa-utils
synced 2025-01-03 08:29:47 +01:00
Recoded WAV file parser
This commit is contained in:
parent
1e5289de13
commit
8013b4b934
2 changed files with 93 additions and 46 deletions
135
aplay/aplay.c
135
aplay/aplay.c
|
@ -618,28 +618,63 @@ static int test_vocfile(void *buffer)
|
||||||
return -1; /* magic string fail */
|
return -1; /* magic string fail */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* helper for test_wavefile
|
||||||
|
*/
|
||||||
|
|
||||||
|
size_t test_wavefile_read(int fd, char *buffer, size_t *size, size_t reqsize, int line)
|
||||||
|
{
|
||||||
|
if (*size >= reqsize)
|
||||||
|
return *size;
|
||||||
|
if (safe_read(fd, buffer + *size, reqsize - *size) != reqsize - *size) {
|
||||||
|
error("read error (called from line %i)", line);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
return *size = reqsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* test, if it's a .WAV file, > 0 if ok (and set the speed, stereo etc.)
|
* test, if it's a .WAV file, > 0 if ok (and set the speed, stereo etc.)
|
||||||
* == 0 if not
|
* == 0 if not
|
||||||
* Value returned is bytes to be discarded.
|
* Value returned is bytes to be discarded.
|
||||||
*/
|
*/
|
||||||
static int test_wavefile(void *buffer, size_t size)
|
static ssize_t test_wavefile(int fd, char *buffer, size_t size)
|
||||||
{
|
{
|
||||||
WaveHeader *h = buffer;
|
WaveHeader *h = (WaveHeader *)buffer;
|
||||||
WaveFmtHeader *f;
|
WaveFmtBody *f;
|
||||||
WaveChunkHeader *c;
|
WaveChunkHeader *c;
|
||||||
|
u_int type, len;
|
||||||
|
|
||||||
|
if (size < sizeof(WaveHeader))
|
||||||
|
return -1;
|
||||||
if (h->magic != WAV_RIFF || h->type != WAV_WAVE)
|
if (h->magic != WAV_RIFF || h->type != WAV_WAVE)
|
||||||
return 0;
|
return -1;
|
||||||
c = (WaveChunkHeader*)((char *)buffer + sizeof(WaveHeader));
|
if (size > sizeof(WaveHeader))
|
||||||
while (c->type != WAV_FMT) {
|
memmove(buffer, buffer + sizeof(WaveHeader), size - sizeof(WaveHeader));
|
||||||
c = (WaveChunkHeader*)((char*)c + sizeof(*c) + LE_INT(c->length));
|
size -= sizeof(WaveHeader);
|
||||||
if ((char *)c + sizeof(*c) > (char*) buffer + size) {
|
while (1) {
|
||||||
error("cannot found WAVE fmt chunk");
|
test_wavefile_read(fd, buffer, &size, sizeof(WaveChunkHeader), __LINE__);
|
||||||
exit(EXIT_FAILURE);
|
c = (WaveChunkHeader*)buffer;
|
||||||
}
|
type = c->type;
|
||||||
|
len = LE_INT(c->length);
|
||||||
|
if (size > sizeof(WaveChunkHeader))
|
||||||
|
memmove(buffer, buffer + sizeof(WaveChunkHeader), size - sizeof(WaveChunkHeader));
|
||||||
|
size -= sizeof(WaveChunkHeader);
|
||||||
|
if (type == WAV_FMT)
|
||||||
|
break;
|
||||||
|
test_wavefile_read(fd, buffer, &size, len, __LINE__);
|
||||||
|
if (size > len)
|
||||||
|
memmove(buffer, buffer + len, size - len);
|
||||||
|
size -= len;
|
||||||
}
|
}
|
||||||
f = (WaveFmtHeader*) c;
|
|
||||||
|
if (len < sizeof(WaveFmtBody)) {
|
||||||
|
error("unknown length of 'fmt ' chunk (read %u, should be %u at least)", len, (u_int)sizeof(WaveFmtBody));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
test_wavefile_read(fd, buffer, &size, len, __LINE__);
|
||||||
|
f = (WaveFmtBody*) buffer;
|
||||||
if (LE_SHORT(f->format) != WAV_PCM_CODE) {
|
if (LE_SHORT(f->format) != WAV_PCM_CODE) {
|
||||||
error("can't play not PCM-coded WAVE-files");
|
error("can't play not PCM-coded WAVE-files");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
@ -661,18 +696,35 @@ static int test_wavefile(void *buffer, size_t size)
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
format.rate = LE_INT(f->sample_fq);
|
format.rate = LE_INT(f->sample_fq);
|
||||||
while (c->type != WAV_DATA) {
|
|
||||||
c = (WaveChunkHeader*)((char*)c + sizeof(*c) + LE_INT(c->length));
|
if (size > len)
|
||||||
if ((char *)c + sizeof(*c) > (char*) buffer + size) {
|
memmove(buffer, buffer + len, size - len);
|
||||||
error("cannot found WAVE data chunk");
|
size -= len;
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
|
while (1) {
|
||||||
|
u_int type, len;
|
||||||
|
|
||||||
|
test_wavefile_read(fd, buffer, &size, sizeof(WaveChunkHeader), __LINE__);
|
||||||
|
c = (WaveChunkHeader*)buffer;
|
||||||
|
type = c->type;
|
||||||
|
len = LE_INT(c->length);
|
||||||
|
if (size > sizeof(WaveChunkHeader))
|
||||||
|
memmove(buffer, buffer + sizeof(WaveChunkHeader), size - sizeof(WaveChunkHeader));
|
||||||
|
size -= sizeof(WaveChunkHeader);
|
||||||
|
if (type == WAV_DATA) {
|
||||||
|
if (len < count)
|
||||||
|
count = len;
|
||||||
|
check_new_format(&format);
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
test_wavefile_read(fd, buffer, &size, len, __LINE__);
|
||||||
|
if (size > len)
|
||||||
|
memmove(buffer, buffer + len, size - len);
|
||||||
|
size -= len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LE_INT(c->length) < count)
|
/* shouldn't be reached */
|
||||||
count = LE_INT(c->length);
|
return -1;
|
||||||
check_new_format(&format);
|
|
||||||
return (char *)c + sizeof(*c) - (char *) buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1348,8 +1400,8 @@ static void begin_voc(int fd, size_t cnt)
|
||||||
static void begin_wave(int fd, size_t cnt)
|
static void begin_wave(int fd, size_t cnt)
|
||||||
{
|
{
|
||||||
WaveHeader h;
|
WaveHeader h;
|
||||||
WaveFmtHeader f;
|
WaveFmtBody f;
|
||||||
WaveChunkHeader c;
|
WaveChunkHeader cf, cd;
|
||||||
int bits;
|
int bits;
|
||||||
u_int tmp;
|
u_int tmp;
|
||||||
u_short tmp2;
|
u_short tmp2;
|
||||||
|
@ -1367,12 +1419,13 @@ static void begin_wave(int fd, size_t cnt)
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
h.magic = WAV_RIFF;
|
h.magic = WAV_RIFF;
|
||||||
tmp = cnt + sizeof(WaveHeader) + sizeof(WaveFmtHeader) + sizeof(WaveChunkHeader) - 8;
|
tmp = cnt + sizeof(WaveHeader) + sizeof(WaveChunkHeader) + sizeof(WaveFmtBody) + sizeof(WaveChunkHeader) - 8;
|
||||||
h.length = LE_INT(tmp);
|
h.length = LE_INT(tmp);
|
||||||
h.type = WAV_WAVE;
|
h.type = WAV_WAVE;
|
||||||
|
|
||||||
f.type = WAV_FMT;
|
cf.type = WAV_FMT;
|
||||||
f.length = LE_INT(16);
|
cf.length = LE_INT(16);
|
||||||
|
|
||||||
f.format = LE_INT(WAV_PCM_CODE);
|
f.format = LE_INT(WAV_PCM_CODE);
|
||||||
f.modus = LE_SHORT(format.channels);
|
f.modus = LE_SHORT(format.channels);
|
||||||
f.sample_fq = LE_INT(format.rate);
|
f.sample_fq = LE_INT(format.rate);
|
||||||
|
@ -1389,12 +1442,13 @@ static void begin_wave(int fd, size_t cnt)
|
||||||
#endif
|
#endif
|
||||||
f.bit_p_spl = LE_SHORT(bits);
|
f.bit_p_spl = LE_SHORT(bits);
|
||||||
|
|
||||||
c.type = WAV_DATA;
|
cd.type = WAV_DATA;
|
||||||
c.length = LE_INT(cnt);
|
cd.length = LE_INT(cnt);
|
||||||
|
|
||||||
if (write(fd, &h, sizeof(WaveHeader)) != sizeof(WaveHeader) ||
|
if (write(fd, &h, sizeof(WaveHeader)) != sizeof(WaveHeader) ||
|
||||||
write(fd, &f, sizeof(WaveFmtHeader)) != sizeof(WaveFmtHeader) ||
|
write(fd, &cf, sizeof(WaveChunkHeader)) != sizeof(WaveChunkHeader) ||
|
||||||
write(fd, &c, sizeof(WaveChunkHeader)) != sizeof(WaveChunkHeader)) {
|
write(fd, &f, sizeof(WaveFmtBody)) != sizeof(WaveFmtBody) ||
|
||||||
|
write(fd, &cd, sizeof(WaveChunkHeader)) != sizeof(WaveChunkHeader)) {
|
||||||
error("write error");
|
error("write error");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -1550,6 +1604,7 @@ void capture_go(int fd, size_t count, int rtype, char *name)
|
||||||
static void playback(char *name)
|
static void playback(char *name)
|
||||||
{
|
{
|
||||||
int fd, ofs;
|
int fd, ofs;
|
||||||
|
size_t dta, dtawave;
|
||||||
|
|
||||||
count = calc_count();
|
count = calc_count();
|
||||||
snd_pcm_flush(handle);
|
snd_pcm_flush(handle);
|
||||||
|
@ -1563,7 +1618,8 @@ static void playback(char *name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* read the file header */
|
/* read the file header */
|
||||||
if (safe_read(fd, audiobuf, sizeof(AuHeader)) != sizeof(AuHeader)) {
|
dta = sizeof(AuHeader);
|
||||||
|
if (safe_read(fd, audiobuf, dta) != dta) {
|
||||||
error("read error");
|
error("read error");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -1572,9 +1628,9 @@ static void playback(char *name)
|
||||||
playback_go(fd, 0, count, FORMAT_AU, name);
|
playback_go(fd, 0, count, FORMAT_AU, name);
|
||||||
goto __end;
|
goto __end;
|
||||||
}
|
}
|
||||||
|
dta = sizeof(VocHeader);
|
||||||
if (safe_read(fd, audiobuf + sizeof(AuHeader),
|
if (safe_read(fd, audiobuf + sizeof(AuHeader),
|
||||||
sizeof(VocHeader) - sizeof(AuHeader)) !=
|
dta - sizeof(AuHeader)) != dta - sizeof(AuHeader)) {
|
||||||
sizeof(VocHeader) - sizeof(AuHeader)) {
|
|
||||||
error("read error");
|
error("read error");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
@ -1583,20 +1639,13 @@ static void playback(char *name)
|
||||||
goto __end;
|
goto __end;
|
||||||
}
|
}
|
||||||
/* read bytes for WAVE-header */
|
/* read bytes for WAVE-header */
|
||||||
if (safe_read(fd, audiobuf + sizeof(VocHeader),
|
if ((dtawave = test_wavefile(fd, audiobuf, dta)) >= 0) {
|
||||||
64 - sizeof(VocHeader)) !=
|
playback_go(fd, dtawave, count, FORMAT_WAVE, name);
|
||||||
64 - sizeof(VocHeader)) {
|
|
||||||
error("read error");
|
|
||||||
exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
if ((ofs = test_wavefile(audiobuf, 64)) > 0) {
|
|
||||||
memmove(audiobuf, audiobuf + ofs, 64 - ofs);
|
|
||||||
playback_go(fd, 64 - ofs, count, FORMAT_WAVE, name);
|
|
||||||
} else {
|
} else {
|
||||||
/* should be raw data */
|
/* should be raw data */
|
||||||
check_new_format(&rformat);
|
check_new_format(&rformat);
|
||||||
init_raw_data();
|
init_raw_data();
|
||||||
playback_go(fd, 64, count, FORMAT_RAW, name);
|
playback_go(fd, dta, count, FORMAT_RAW, name);
|
||||||
}
|
}
|
||||||
__end:
|
__end:
|
||||||
if (fd != 0)
|
if (fd != 0)
|
||||||
|
|
|
@ -75,15 +75,13 @@ typedef struct {
|
||||||
} WaveHeader;
|
} WaveHeader;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u_int type; /* 'fmt ' */
|
|
||||||
u_int length; /* length of chunk */
|
|
||||||
u_short format; /* should be 1 for PCM-code */
|
u_short format; /* should be 1 for PCM-code */
|
||||||
u_short modus; /* 1 Mono, 2 Stereo */
|
u_short modus; /* 1 Mono, 2 Stereo */
|
||||||
u_int sample_fq; /* frequence of sample */
|
u_int sample_fq; /* frequence of sample */
|
||||||
u_int byte_p_sec;
|
u_int byte_p_sec;
|
||||||
u_short byte_p_spl; /* samplesize; 1 or 2 bytes */
|
u_short byte_p_spl; /* samplesize; 1 or 2 bytes */
|
||||||
u_short bit_p_spl; /* 8, 12 or 16 bit */
|
u_short bit_p_spl; /* 8, 12 or 16 bit */
|
||||||
} WaveFmtHeader;
|
} WaveFmtBody;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u_int type; /* 'data' */
|
u_int type; /* 'data' */
|
||||||
|
|
Loading…
Reference in a new issue