X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=write.c;h=424286b5a4c21613517d632777d3052578e869fd;hp=7dc9f85ce3223b24678214b526dd76e35c1d2dcf;hb=d5538ff0dd9f6531a1a319b49c32bd72597fb2c3;hpb=d4d37bb32a8d6219f9f52aa2ee3de55eb7e099c8 diff --git a/write.c b/write.c index 7dc9f85c..424286b5 100644 --- a/write.c +++ b/write.c @@ -32,10 +32,12 @@ enum check_wav_state { CWS_NO_HEADER, }; +/* Information extracted from the wav header. */ struct check_wav_task { int state; - /** Number of channels specified in wav header given by \a buf. */ + /** Number of channels. */ unsigned channels; + unsigned sample_format; /** Sample rate specified in wav header given by \a buf. */ unsigned sample_rate; /** The task structure used by the scheduler. */ @@ -51,12 +53,6 @@ static struct stdin_task sit; /** Length of a standard wav header. */ #define WAV_HEADER_LEN 44 -/** - * Test if audio buffer contains a valid wave header. - * - * \return If not, return -E_NO_WAV_HEADER, otherwise, return zero. If - * there is less than WAV_HEADER_LEN bytes available, return one. - */ static void check_wav_pre_select(struct sched *s, struct task *t) { struct check_wav_task *cwt = container_of(t, struct check_wav_task, task); @@ -67,23 +63,23 @@ static void check_wav_pre_select(struct sched *s, struct task *t) sched_min_delay(s); } +#define HANDLE_EXEC(_cmd) \ + if (!strcmp(cmd, #_cmd)) { \ + if (!conf._cmd ## _given && cwt->state == CWS_NEED_HEADER) \ + return -E_BTR_NAVAIL; \ + *result = make_message("%d", cwt->state == CWS_NO_HEADER || conf._cmd ## _given? \ + conf._cmd ## _arg : cwt->_cmd); \ + return 1; \ + } \ + + static int check_wav_exec(struct btr_node *btrn, const char *cmd, char **result) { struct check_wav_task *cwt = btr_context(btrn); - - if (!strcmp(cmd, "sample_rate")) { - if (cwt->state != CWS_HAVE_HEADER) - return -E_BTR_NAVAIL; - *result = make_message("%d", cwt->sample_rate); - return 1; - } - if (!strcmp(cmd, "channels")) { - if (cwt->state != CWS_HAVE_HEADER) - return -E_BTR_NAVAIL; - *result = make_message("%d", cwt->channels); - return 1; - } + HANDLE_EXEC(sample_rate); + HANDLE_EXEC(channels); + HANDLE_EXEC(sample_format); return -ERRNO_TO_PARA_ERROR(ENOTSUP); } @@ -94,6 +90,8 @@ static void check_wav_post_select(__a_unused struct sched *s, struct task *t) unsigned char *a; size_t sz; int ret; + uint16_t bps; /* bits per sample */ + const char *sample_formats[] = {SAMPLE_FORMATS}; t->error = 0; ret = btr_node_status(btrn, cwt->min_iqs, BTR_NT_INTERNAL); @@ -106,9 +104,13 @@ static void check_wav_post_select(__a_unused struct sched *s, struct task *t) if (sz < cwt->min_iqs) /* file size less than WAV_HEADER_SIZE */ goto pushdown; cwt->min_iqs = 0; - cwt->channels = 2; - cwt->sample_rate = 44100; - if (a[0] != 'R' || a[1] != 'I' || a[2] != 'F' || a[3] != 'F') { + /* + * The default byte ordering assumed for WAVE data files is + * little-endian. Files written using the big-endian byte ordering + * scheme have the identifier RIFX instead of RIFF. + */ + if (a[0] != 'R' || a[1] != 'I' || a[2] != 'F' || + (a[3] != 'F' && a[3] != 'X')) { PARA_NOTICE_LOG("wav header not found\n"); cwt->state = CWS_NO_HEADER; sprintf(t->status, "check wav: no header"); @@ -119,7 +121,23 @@ static void check_wav_post_select(__a_unused struct sched *s, struct task *t) sprintf(t->status, "check wav: have header"); cwt->channels = (unsigned) a[22]; cwt->sample_rate = a[24] + (a[25] << 8) + (a[26] << 16) + (a[27] << 24); - PARA_INFO_LOG("channels: %d, sample rate: %d\n", cwt->channels, cwt->sample_rate); + bps = a[34] + ((unsigned)a[35] << 8); + if (bps != 8 && bps != 16) { + PARA_WARNING_LOG("%u bps not supported, assuming 16\n", bps); + bps = 16; + } + /* + * 8-bit samples are stored as unsigned bytes, ranging from 0 to 255. + * 16-bit samples are stored as 2's-complement signed integers, ranging + * from -32768 to 32767. + */ + if (bps == 8) + cwt->sample_format = SF_U8; + else + cwt->sample_format = (a[3] == 'F')? SF_S16_LE : SF_S16_BE; + PARA_NOTICE_LOG("%dHz, %s, %s\n", cwt->sample_rate, + cwt->channels == 1? "mono" : "stereo", + sample_formats[cwt->sample_format]); btr_consume(btrn, WAV_HEADER_LEN); pushdown: btr_pushdown(btrn);