From 70c8a6a47190c1e92b61f2f1a1ecf7aa5093b9c8 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Sat, 8 Sep 2018 12:11:33 +0200 Subject: [PATCH] New audio formats: 32 bit float (little and big endian). At least the little endian version seems to be popular these days. It is only supported by ALSA, however. To check whether a given wave file employs one of the two SF_FLOAT formats (aka IEEE float) we have to consult the format code, a 16 bit integer stored at offset 20 of the wave header which describes the waveform data according to the table below. 0x0001 PCM 0x0003 IEEE float 0x0006 8-bit ITU-T G.711 A-law 0x0007 8-bit ITU-T G.711 MU-law 0xFFFE Determined by SubFormat Additional checks are added to check_wav_post_select() which make sure that the format code is either 1 or 3, and that the number is compatible with the bits per sample value. --- alsa_write.c | 2 ++ ao_write.c | 2 ++ check_wav.c | 20 +++++++++++++++++--- m4/lls/include/sample-format.m4 | 4 +++- para.h | 2 ++ 5 files changed, 26 insertions(+), 4 deletions(-) diff --git a/alsa_write.c b/alsa_write.c index 53d7b1b4..7e71d4ae 100644 --- a/alsa_write.c +++ b/alsa_write.c @@ -61,6 +61,8 @@ static snd_pcm_format_t get_alsa_pcm_format(enum sample_format sf) case SF_S16_BE: return SND_PCM_FORMAT_S16_BE; case SF_U16_LE: return SND_PCM_FORMAT_U16_LE; case SF_U16_BE: return SND_PCM_FORMAT_U16_BE; + case SF_FLOAT_LE: return SND_PCM_FORMAT_FLOAT_LE; + case SF_FLOAT_BE: return SND_PCM_FORMAT_FLOAT_BE; default: return SND_PCM_FORMAT_S16_LE; } } diff --git a/ao_write.c b/ao_write.c index 43a58dd6..cc1a4f0f 100644 --- a/ao_write.c +++ b/ao_write.c @@ -87,6 +87,8 @@ static int aow_set_sample_format(unsigned sample_rate, unsigned channels, case SF_U8: case SF_U16_LE: case SF_U16_BE: + case SF_FLOAT_LE: + case SF_FLOAT_BE: return -E_BAD_SAMPLE_FORMAT; case SF_S8: /* no need to set byte_format */ diff --git a/check_wav.c b/check_wav.c index cb39eb54..48a204bb 100644 --- a/check_wav.c +++ b/check_wav.c @@ -127,7 +127,7 @@ int check_wav_post_monitor(struct check_wav_context *cwc) unsigned char *a; size_t sz; int ret; - uint16_t bps; /* bits per sample */ + uint16_t format_code, bps; /* bits per sample */ const char *sample_formats[] = {SAMPLE_FORMATS}; if (!btrn) @@ -157,13 +157,24 @@ int check_wav_post_monitor(struct check_wav_context *cwc) cwc->state = CWS_HAVE_HEADER; /* Only set those values which have not already been set. */ cwc->channels = a[22]; + format_code = read_u16(a + 20); + if (format_code != 1 && format_code != 3) { + cwc->state = CWS_NO_HEADER; + goto out; + } cwc->sample_rate = read_u32(a + 24); bps = read_u16(a + 34); - if (bps != 8 && bps != 16) { + if (bps != 8 && bps != 16 && bps != 32) { PARA_WARNING_LOG("%u bps not supported, assuming 16\n", bps); bps = 16; } + if ((bps < 32 && format_code != 1) || (bps == 32 && format_code != 3)) { + PARA_WARNING_LOG("invalid bps/format_code (%u/%u)\n", + bps, format_code); + cwc->state = CWS_NO_HEADER; + goto out; + } /* * 8-bit samples are stored as unsigned bytes, ranging from 0 * to 255. 16-bit samples are stored as 2's-complement signed @@ -171,9 +182,12 @@ int check_wav_post_monitor(struct check_wav_context *cwc) */ if (bps == 8) cwc->sample_format = SF_U8; - else + else if (bps == 16) cwc->sample_format = (a[3] == 'F')? SF_S16_LE : SF_S16_BE; + else /* 32 bit */ + cwc->sample_format = (a[3] == 'F')? + SF_FLOAT_LE : SF_FLOAT_BE; PARA_NOTICE_LOG("%uHz, %s, %s\n", cwc->sample_rate, cwc->channels == 1? "mono" : "stereo", sample_formats[cwc->sample_format]); diff --git a/m4/lls/include/sample-format.m4 b/m4/lls/include/sample-format.m4 index 0daad192..030ab7d5 100644 --- a/m4/lls/include/sample-format.m4 +++ b/m4/lls/include/sample-format.m4 @@ -11,7 +11,9 @@ SAMPLE_FORMAT_S16_LE = "S16_LE", SAMPLE_FORMAT_S16_BE = "S16_BE", SAMPLE_FORMAT_U16_LE = "U16_LE", - SAMPLE_FORMAT_U16_BE = "U16_BE" + SAMPLE_FORMAT_U16_BE = "U16_BE", + SAMPLE_FORMAT_FLOAT_LE = "FLOAT_LE", + SAMPLE_FORMAT_FLOAT_BE = "FLOAT_BE" } default_val = S16_LE [help] diff --git a/para.h b/para.h index 280c2823..6f1565aa 100644 --- a/para.h +++ b/para.h @@ -203,6 +203,8 @@ _static_inline_ bool iov_valid(const struct iovec *iov) SAMPLE_FORMAT(SF_S16_BE, "16 bit signed, big endian"), \ SAMPLE_FORMAT(SF_U16_LE, "16 bit unsigned, little endian"), \ SAMPLE_FORMAT(SF_U16_BE, "16 bit unsigned, big endian"), \ + SAMPLE_FORMAT(SF_FLOAT_LE, "32 bit float, little endian"), \ + SAMPLE_FORMAT(SF_FLOAT_BE, "32 bit float, big endian"), \ /** \cond sample_format */ #define SAMPLE_FORMAT(a, b) a -- 2.39.5