diff options
author | Sylvain Munaut <tnt@246tNt.com> | 2010-10-29 11:44:40 +0200 |
---|---|---|
committer | Sylvain Munaut <tnt@246tNt.com> | 2010-11-05 16:41:47 +0100 |
commit | f905983b059c28bb60aa9e6656e26ff1fb5079c5 (patch) | |
tree | e1a00ac094890b2a0446b2eba8e4bb348d8e24af | |
parent | 5e380d072699c211a0b4fd3bc951cb49d14542fd (diff) |
format: Add support for the 3GPP HR reference vocoder file/frame formats
Yes ... they use a different format for the decoder input than for the
encoder output ...
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
-rw-r--r-- | include/gapk/formats.h | 4 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/fmt_hr_ref.c | 205 | ||||
-rw-r--r-- | src/formats.c | 4 |
4 files changed, 214 insertions, 1 deletions
diff --git a/include/gapk/formats.h b/include/gapk/formats.h index 19d60b8..4be519b 100644 --- a/include/gapk/formats.h +++ b/include/gapk/formats.h @@ -28,6 +28,10 @@ enum format_type { /* Classic .gsm file for FR */ FMT_GSM, + /* 3GPP Reference HR vocodec files */ + FMT_HR_REF_DEC, + FMT_HR_REF_ENC, + _FMT_MAX, }; diff --git a/src/Makefile.am b/src/Makefile.am index 4a6689e..9383b7d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,5 +4,5 @@ AM_LDFLAGS=$(LIBOSMOCODEC_LIBS) bin_PROGRAMS = gapk gapk_SOURCES = main.c \ - formats.c fmt_gsm.c \ + formats.c fmt_gsm.c fmt_hr_ref.c \ codecs.c codec_pcm.c codec_hr.c codec_fr.c codec_efr.c diff --git a/src/fmt_hr_ref.c b/src/fmt_hr_ref.c new file mode 100644 index 0000000..7a96d3e --- /dev/null +++ b/src/fmt_hr_ref.c @@ -0,0 +1,205 @@ +/* 3GPP Reference HR vocoder file formats + * + * See http://ftp.3gpp.org/Specs/2001-06/Ph2/06_series/0606-421/0606_421.zip + */ + +/* + * This file is part of gapk (GSM Audio Pocket Knife). + * + * gapk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * gapk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with gapk. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <gapk/codecs.h> +#include <gapk/formats.h> +#include <gapk/utils.h> + + +static const int params_unvoiced[] = { + 5, /* R0 */ + 11, /* k1Tok3 */ + 9, /* k4Tok6 */ + 8, /* k7Tok10 */ + 1, /* softInterpolation */ + 2, /* voicingDecision */ + 7, /* code1_1 */ + 7, /* code2_1 */ + 5, /* gsp0_1 */ + 7, /* code1_2 */ + 7, /* code2_2 */ + 5, /* gsp0_2 */ + 7, /* code1_3 */ + 7, /* code2_3 */ + 5, /* gsp0_3 */ + 7, /* code1_4 */ + 7, /* code2_4 */ + 5, /* gsp0_4 */ +}; + +static const int params_voiced[] = { + 5, /* R0 */ + 11, /* k1Tok3 */ + 9, /* k4Tok6 */ + 8, /* k7Tok10 */ + 1, /* softInterpolation */ + 2, /* voicingDecision */ + 8, /* frameLag */ + 9, /* code_1 */ + 5, /* gsp0_1 */ + 4, /* deltaLag_2 */ + 9, /* code_2 */ + 5, /* gsp0_2 */ + 4, /* deltaLag_3 */ + 9, /* code_3 */ + 5, /* gsp0_3 */ + 4, /* deltaLag_4 */ + 9, /* code_4 */ + 5, /* gsp0_4 */ +}; + + +static int +hr_ref_from_canon(uint16_t *hr_ref, const uint8_t *canon) +{ + int i, j, voiced; + const int *params; + + voiced = (msb_get_bit(canon, 34) << 1) | msb_get_bit(canon, 35); + params = voiced ? ¶ms_voiced[0] : ¶ms_unvoiced[0]; + + for (i=0,j=0; i<18; i++) + { + uint16_t w; + int l, k; + + l = params[i]; + + w = 0; + for (k=0; k<l; k++) + w = (w << 1) | msb_get_bit(canon, j+k); + hr_ref[i] = w; + + j += l; + } + + return 0; +} + +static int +hr_ref_to_canon(uint8_t *canon, const uint16_t *hr_ref) +{ + int i, j, voiced; + const int *params; + + voiced = hr_ref[5]; /* voicingDecision */ + params = voiced ? ¶ms_voiced[0] : ¶ms_unvoiced[0]; + + for (i=0,j=0; i<18; i++) + { + uint16_t w; + int l, k; + + l = params[i]; + + w = hr_ref[i]; + for (k=0; k<l; k++) + msb_put_bit(canon, j+k, w & (1<<(l-k-1))); + + j += l; + } + + return 0; +} + +static int +hr_ref_dec_from_canon(uint8_t *dst, const uint8_t *src) +{ + uint16_t *hr_ref = (uint16_t *)dst; + int rv; + + rv = hr_ref_from_canon(hr_ref, src); + if (rv) + return rv; + + hr_ref[18] = 0; /* BFI : 1 bit */ + hr_ref[19] = 0; /* UFI : 1 bit */ + hr_ref[20] = 0; /* SID : 2 bit */ + hr_ref[21] = 0; /* TAF : 1 bit */ + + return 0; +} + +static int +hr_ref_dec_to_canon(uint8_t *dst, const uint8_t *src) +{ + const uint16_t *hr_ref = (const uint16_t *)src; + int rv; + + rv = hr_ref_to_canon(dst, hr_ref); + if (rv) + return rv; + + return 0; +} + +static int +hr_ref_enc_from_canon(uint8_t *dst, const uint8_t *src) +{ + uint16_t *hr_ref = (uint16_t *)dst; + int rv; + + rv = hr_ref_from_canon(hr_ref, src); + if (rv) + return rv; + + hr_ref[18] = 0; /* SP : 1 bit */ + hr_ref[19] = 0; /* VAD : 1 bit */ + + return 0; +} + +static int +hr_ref_enc_to_canon(uint8_t *dst, const uint8_t *src) +{ + const uint16_t *hr_ref = (const uint16_t *)src; + int rv; + + rv = hr_ref_to_canon(dst, hr_ref); + if (rv) + return rv; + + return 0; +} + + +const struct format_desc fmt_hr_ref_dec = { + .type = FMT_HR_REF_DEC, + .codec_type = CODEC_HR, + .name = "hr-ref-dec", + .description = "3GPP HR Reference decoder code parameters file format", + + .frame_len = 22 * sizeof(uint16_t), + .conv_from_canon = hr_ref_dec_from_canon, + .conv_to_canon = hr_ref_dec_to_canon, +}; + +const struct format_desc fmt_hr_ref_enc = { + .type = FMT_HR_REF_ENC, + .codec_type = CODEC_HR, + .name = "hr-ref-enc", + .description = "3GPP HR Reference encoder code parameters file format", + + .frame_len = 20 * sizeof(uint16_t), + .conv_from_canon = hr_ref_enc_from_canon, + .conv_to_canon = hr_ref_enc_to_canon, +}; diff --git a/src/formats.c b/src/formats.c index 5c91a52..1125598 100644 --- a/src/formats.c +++ b/src/formats.c @@ -23,10 +23,14 @@ /* Extern format descriptors */ extern const struct format_desc fmt_gsm; +extern const struct format_desc fmt_hr_ref_dec; +extern const struct format_desc fmt_hr_ref_enc; static const struct format_desc *supported_formats[_FMT_MAX] = { [FMT_INVALID] = NULL, [FMT_GSM] = &fmt_gsm, + [FMT_HR_REF_DEC] = &fmt_hr_ref_dec, + [FMT_HR_REF_ENC] = &fmt_hr_ref_enc, }; |