Skip to content

Instantly share code, notes, and snippets.

@patrickdk77
Created March 5, 2026 02:22
Show Gist options
  • Select an option

  • Save patrickdk77/330dd3f593696d103e831c4c1d78d1f9 to your computer and use it in GitHub Desktop.

Select an option

Save patrickdk77/330dd3f593696d103e831c4c1d78d1f9 to your computer and use it in GitHub Desktop.
DS2 codec
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index fb22541f8d..3b98da18a3 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -344,6 +344,7 @@ OBJS-$(CONFIG_DSD_MSBF_PLANAR_DECODER) += dsddec.o dsd.o
OBJS-$(CONFIG_DSICINAUDIO_DECODER) += dsicinaudio.o
OBJS-$(CONFIG_DSICINVIDEO_DECODER) += dsicinvideo.o
OBJS-$(CONFIG_DSS_SP_DECODER) += dss_sp.o
+OBJS-$(CONFIG_DS2_DECODER) += ds2.o
OBJS-$(CONFIG_DST_DECODER) += dstdec.o dsd.o
OBJS-$(CONFIG_DVBSUB_DECODER) += dvbsubdec.o
OBJS-$(CONFIG_DVBSUB_ENCODER) += dvbsubenc.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index f5ec2e01e8..c7a19029b6 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -461,6 +461,7 @@ extern const FFCodec ff_dca_decoder;
extern const FFCodec ff_dfpwm_encoder;
extern const FFCodec ff_dfpwm_decoder;
extern const FFCodec ff_dolby_e_decoder;
+extern const FFCodec ff_ds2_decoder;
extern const FFCodec ff_dsd_lsbf_decoder;
extern const FFCodec ff_dsd_msbf_decoder;
extern const FFCodec ff_dsd_lsbf_planar_decoder;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index a065556e51..2ea12d440c 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -3495,6 +3495,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("G.728"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
},
+ {
+ .id = AV_CODEC_ID_DS2,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "ds2",
+ .long_name = NULL_IF_CONFIG_SMALL("Digital Speech Standard Pro (DS2)"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+ },
/* subtitle codecs */
{
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index c4842e61ff..97ad9b200b 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -556,6 +556,7 @@ enum AVCodecID {
AV_CODEC_ID_QOA,
AV_CODEC_ID_LC3,
AV_CODEC_ID_G728,
+ AV_CODEC_ID_DS2,
/* subtitle codecs */
AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs.
diff --git a/libavcodec/ds2.c b/libavcodec/ds2.c
new file mode 100644
index 0000000000..fc6e1a473a
--- /dev/null
+++ b/libavcodec/ds2.c
@@ -0,0 +1,982 @@
+/*
+ * Digital Speech Standard Pro (DS2) audio decoder
+ */
+
+/**
+ * @file
+ * DS2 (DSS Pro) CELP audio decoder
+ *
+ * Supports two modes:
+ * - SP mode: 12000 Hz, 14 reflection coefficients, 4×72-sample subframes,
+ * C(72,7) combinatorial codebook, 328-bit frames
+ * - QP mode: 16000 Hz, 16 reflection coefficients, 4×64-sample subframes,
+ * C(64,11) combinatorial codebook, 448-bit frames
+ *
+ * Based on technical documentation from FFmpeg trac ticket #6091.
+ *
+ */
+
+#include <math.h>
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/common.h"
+#include "libavutil/mem_internal.h"
+
+#include "avcodec.h"
+#include "codec_internal.h"
+#include "decode.h"
+#include "get_bits.h"
+
+/* ---- Constants ---- */
+
+#define DS2_SUBFRAMES 4
+
+/* SP mode */
+#define DS2_SP_FORMAT 0
+#define DS2_SP_SAMPLE_RATE 12000
+#define DS2_SP_SUBFRAME_SIZE 72
+#define DS2_SP_FRAME_SAMPLES (DS2_SP_SUBFRAME_SIZE * DS2_SUBFRAMES) /* 288 */
+#define DS2_SP_FRAME_SIZE 42 /* bytes per packet from demuxer */
+#define DS2_SP_FRAME_BITS 328
+#define DS2_SP_NUM_REFL 14
+#define DS2_SP_NUM_PULSES 7
+#define DS2_SP_COMB_N 72
+#define DS2_SP_COMB_BITS 31
+#define DS2_SP_PITCH_MIN 36
+#define DS2_SP_PITCH_MAX 186
+#define DS2_SP_PITCH_RANGE (DS2_SP_PITCH_MAX - DS2_SP_PITCH_MIN + 1) /* 151 */
+#define DS2_SP_DELTA_RANGE 48
+
+/* QP mode */
+#define DS2_QP_FORMAT 6
+#define DS2_QP_SAMPLE_RATE 16000
+#define DS2_QP_SUBFRAME_SIZE 64
+#define DS2_QP_FRAME_SAMPLES (DS2_QP_SUBFRAME_SIZE * DS2_SUBFRAMES) /* 256 */
+#define DS2_QP_FRAME_SIZE 56 /* bytes per packet from demuxer */
+#define DS2_QP_FRAME_BITS 448
+#define DS2_QP_NUM_REFL 16
+#define DS2_QP_NUM_PULSES 11
+#define DS2_QP_COMB_N 64
+#define DS2_QP_COMB_BITS 40
+#define DS2_QP_PITCH_MIN 45
+#define DS2_QP_PITCH_MAX 300
+
+/* Maximum values across both modes */
+#define DS2_MAX_REFL 16
+#define DS2_MAX_PULSES 11
+#define DS2_MAX_SUBFRAME 72
+#define DS2_MAX_FRAME_SIZE 56
+#define DS2_MAX_FRAME_SAMPLES 288
+#define DS2_MAX_PITCH 300
+
+/* ---- Quantization tables (from DssDecoder.dll via hirparak/dss-codec) ---- */
+
+static const int ds2_sp_refl_cb_sizes[DS2_SP_NUM_REFL] = {
+ 32, 32, 16, 16, 16, 16, 16, 16, 8, 8, 8, 8, 8, 8};
+
+static const int ds2_sp_refl_bits[DS2_SP_NUM_REFL] = {5, 5, 4, 4, 4, 4, 4,
+ 4, 3, 3, 3, 3, 3, 3};
+
+static const double ds2_sp_refl_cb[DS2_SP_NUM_REFL][32] = {
+ /* codebook 0: 32 entries (5 bits) */
+ {
+ -0.996490, -0.994475, -0.992274, -0.989923, -0.986979, -0.983156, -0.978457, -0.972945,
+ -0.966344, -0.958182, -0.948497, -0.937621, -0.924654, -0.909824, -0.892581, -0.871936,
+ -0.844538, -0.806867, -0.752737, -0.685593, -0.593059, -0.492327, -0.372867, -0.237519,
+ -0.086492, 0.055505, 0.199702, 0.343643, 0.489801, 0.617074, 0.756038, 0.858146,
+ },
+ /* codebook 1: 32 entries (5 bits) */
+ {
+ -0.839325, -0.747960, -0.630004, -0.533942, -0.432954, -0.344139, -0.256963, -0.170734,
+ -0.091958, -0.019039, 0.052224, 0.118393, 0.178355, 0.237254, 0.297215, 0.353767,
+ 0.407842, 0.454813, 0.501291, 0.546275, 0.587472, 0.628223, 0.665388, 0.702075,
+ 0.736745, 0.770544, 0.801860, 0.833128, 0.865451, 0.892610, 0.919122, 0.951620,
+ },
+ /* codebook 2: 16 entries (4 bits) */
+ {
+ -0.849219, -0.738774, -0.639128, -0.542629, -0.452975, -0.361563, -0.276658, -0.192157,
+ -0.111700, -0.027783, 0.058547, 0.153345, 0.250940, 0.355490, 0.460400, 0.562225,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 3: 16 entries (4 bits) */
+ {
+ -0.522694, -0.365443, -0.252366, -0.156340, -0.070064, 0.005590, 0.076400, 0.143647,
+ 0.207452, 0.272966, 0.337068, 0.404016, 0.473864, 0.556895, 0.644373, 0.756378,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 4: 16 entries (4 bits) */
+ {
+ -0.657867, -0.527349, -0.435986, -0.355341, -0.282832, -0.216282, -0.150720, -0.086403,
+ -0.021073, 0.042924, 0.107923, 0.174593, 0.247943, 0.325844, 0.418718, 0.541122,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 5: 16 entries (4 bits) */
+ {
+ -0.458685, -0.316669, -0.214667, -0.132058, -0.057968, 0.011117, 0.075008, 0.135795,
+ 0.195985, 0.255549, 0.316590, 0.381044, 0.449024, 0.518693, 0.598949, 0.700509,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 6: 16 entries (4 bits) */
+ {
+ -0.493011, -0.377254, -0.295947, -0.227659, -0.160461, -0.102515, -0.047207, 0.006675,
+ 0.058478, 0.109825, 0.161717, 0.213432, 0.273530, 0.342584, 0.418583, 0.518245,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 7: 16 entries (4 bits) */
+ {
+ -0.449880, -0.300532, -0.211206, -0.141852, -0.084516, -0.032514, 0.015220, 0.063580,
+ 0.110867, 0.159284, 0.209267, 0.261856, 0.317693, 0.386711, 0.474887, 0.613438,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 8: 8 entries (3 bits) */
+ {
+ -0.338720, -0.214064, -0.117633, -0.031277, 0.051259, 0.138659, 0.238260, 0.364144,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 9: 8 entries (3 bits) */
+ {
+ -0.276501, -0.139475, -0.042152, 0.043296, 0.123121, 0.205330, 0.301063, 0.431780,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 10: 8 entries (3 bits) */
+ {
+ -0.379946, -0.243693, -0.140265, -0.052907, 0.029329, 0.110756, 0.209498, 0.340020,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 11: 8 entries (3 bits) */
+ {
+ -0.361040, -0.225940, -0.122373, -0.033455, 0.049012, 0.130947, 0.225389, 0.350395,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 12: 8 entries (3 bits) */
+ {
+ -0.409067, -0.282274, -0.182942, -0.101077, -0.027164, 0.048645, 0.136240, 0.250184,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 13: 8 entries (3 bits) */
+ {
+ -0.342987, -0.220337, -0.123291, -0.042908, 0.029633, 0.101349, 0.183289, 0.295929,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+};
+
+/* SP pitch gain: 32 entries (5-bit) at VA 0x1004CF90 */
+static const double ds2_sp_pitch_gain[32] = {
+ 0.049805, 0.112793, 0.175781, 0.238281, 0.301270, 0.364258, 0.427246, 0.490234,
+ 0.553223, 0.615723, 0.678711, 0.741699, 0.804688, 0.867676, 0.930176, 0.993164,
+ 1.056152, 1.119141, 1.182129, 1.245117, 1.307617, 1.370605, 1.433594, 1.496582,
+ 1.559570, 1.622559, 1.685059, 1.748047, 1.811035, 1.874023, 1.937012, 2.000000,
+};
+
+/* SP excitation gain: 64 entries (6-bit) at VA 0x1004DF80 */
+static const double ds2_sp_exc_gain[64] = {
+ 0, 4, 8, 13, 17, 22, 26, 31, 35, 40,
+ 44, 48, 53, 58, 63, 69, 76, 83, 91, 99,
+ 109, 119, 130, 142, 155, 170, 185, 203, 222, 242,
+ 265, 290, 317, 346, 378, 414, 452, 494, 540, 591,
+ 646, 706, 771, 843, 922, 1007, 1101, 1204, 1316, 1438,
+ 1572, 1719, 1879, 2053, 2244, 2453, 2682, 2931, 3204, 3502,
+ 3828, 4184, 4574, 5000,
+};
+
+/* SP pulse amplitude: 8 entries (3-bit) at VA 0x1004EF70 */
+static const double ds2_sp_pulse_amp[8] = {
+ -0.951599, -0.679718, -0.407837, -0.135956, 0.135956, 0.407837, 0.679718, 0.951599,
+};
+
+static const int ds2_qp_refl_cb_sizes[DS2_QP_NUM_REFL] = {
+ 128, 128, 64, 64, 32, 32, 32, 32, 32, 16, 16, 16, 16, 8, 8, 8};
+
+static const int ds2_qp_refl_bits[DS2_QP_NUM_REFL] = {7, 7, 6, 6, 5, 5, 5, 5,
+ 5, 4, 4, 4, 4, 3, 3, 3};
+
+static const double ds2_qp_refl_cb[DS2_QP_NUM_REFL][128] = {
+ /* codebook 0: 128 entries (7 bits) */
+ {
+ -0.998625, -0.997661, -0.996599, -0.995565, -0.994543, -0.993491, -0.992388, -0.991230,
+ -0.990023, -0.988774, -0.987484, -0.986156, -0.984772, -0.983336, -0.981849, -0.980306,
+ -0.978698, -0.977036, -0.975326, -0.973557, -0.971730, -0.969817, -0.967830, -0.965767,
+ -0.963617, -0.961358, -0.958986, -0.956532, -0.953973, -0.951304, -0.948517, -0.945580,
+ -0.942517, -0.939292, -0.935919, -0.932382, -0.928627, -0.924691, -0.920565, -0.916220,
+ -0.911672, -0.906908, -0.901909, -0.896650, -0.891154, -0.885378, -0.879331, -0.873053,
+ -0.866477, -0.859569, -0.852378, -0.844956, -0.837212, -0.829238, -0.820897, -0.812297,
+ -0.803364, -0.794100, -0.784575, -0.774668, -0.764433, -0.753852, -0.743069, -0.731850,
+ -0.720141, -0.707839, -0.695049, -0.681824, -0.668123, -0.654004, -0.639425, -0.624341,
+ -0.608685, -0.592626, -0.575763, -0.558598, -0.540993, -0.522682, -0.503785, -0.484018,
+ -0.464117, -0.443659, -0.422977, -0.401829, -0.380472, -0.358738, -0.337042, -0.315200,
+ -0.292816, -0.269804, -0.246840, -0.223819, -0.200574, -0.176809, -0.152793, -0.128330,
+ -0.103243, -0.078064, -0.052123, -0.025868, 0.000503, 0.032633, 0.065304, 0.098316,
+ 0.130992, 0.163876, 0.197635, 0.231801, 0.266734, 0.300840, 0.334427, 0.368009,
+ 0.401816, 0.434818, 0.467743, 0.500737, 0.533103, 0.566143, 0.599057, 0.631503,
+ 0.663943, 0.696451, 0.729205, 0.762428, 0.795263, 0.829412, 0.866713, 0.910326,
+ },
+ /* codebook 1: 128 entries (7 bits) */
+ {
+ -0.865978, -0.801655, -0.751056, -0.707177, -0.667018, -0.629630, -0.593900, -0.560117,
+ -0.529107, -0.501775, -0.477329, -0.455520, -0.435556, -0.417392, -0.400411, -0.384593,
+ -0.369412, -0.354722, -0.340281, -0.325968, -0.311620, -0.297118, -0.282403, -0.267459,
+ -0.252110, -0.236259, -0.220193, -0.204047, -0.187752, -0.171201, -0.154549, -0.137981,
+ -0.121239, -0.104248, -0.087220, -0.070049, -0.052835, -0.035604, -0.018345, -0.000989,
+ 0.013341, 0.027691, 0.042198, 0.056848, 0.071551, 0.086361, 0.101247, 0.116275,
+ 0.131413, 0.146502, 0.161609, 0.176928, 0.192267, 0.207584, 0.223239, 0.238667,
+ 0.254052, 0.269405, 0.284689, 0.299822, 0.314990, 0.329889, 0.344662, 0.359470,
+ 0.374096, 0.388852, 0.403536, 0.418103, 0.432528, 0.446911, 0.458448, 0.469920,
+ 0.481265, 0.492536, 0.503570, 0.514533, 0.525419, 0.536162, 0.546901, 0.557527,
+ 0.568032, 0.578325, 0.588612, 0.598800, 0.608864, 0.618771, 0.628586, 0.638361,
+ 0.648084, 0.657681, 0.667230, 0.676748, 0.686191, 0.695626, 0.704918, 0.714094,
+ 0.723141, 0.731977, 0.740690, 0.749332, 0.757905, 0.766358, 0.774776, 0.783032,
+ 0.791223, 0.799327, 0.807335, 0.815280, 0.823165, 0.830937, 0.838722, 0.846445,
+ 0.854029, 0.861501, 0.868889, 0.876232, 0.883524, 0.890694, 0.897831, 0.904884,
+ 0.911897, 0.918903, 0.925945, 0.933146, 0.940675, 0.948957, 0.958556, 0.970177,
+ },
+ /* codebook 2: 64 entries (6 bits) */
+ {
+ -0.878298, -0.824992, -0.785065, -0.751040, -0.720251, -0.691891, -0.665181, -0.639786,
+ -0.615369, -0.591615, -0.568490, -0.545987, -0.523926, -0.502127, -0.480738, -0.459651,
+ -0.438673, -0.417783, -0.397059, -0.376483, -0.356260, -0.336413, -0.316974, -0.297934,
+ -0.279303, -0.260922, -0.242715, -0.224602, -0.206399, -0.187986, -0.169304, -0.150560,
+ -0.131689, -0.112776, -0.093829, -0.075030, -0.056117, -0.037019, -0.017915, 0.001264,
+ 0.021956, 0.042920, 0.064134, 0.085565, 0.107325, 0.129603, 0.152421, 0.175870,
+ 0.200016, 0.224916, 0.250766, 0.277574, 0.305699, 0.335073, 0.365590, 0.397311,
+ 0.430498, 0.464755, 0.497242, 0.530987, 0.567807, 0.615533, 0.677622, 0.762953,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 3: 64 entries (6 bits) */
+ {
+ -0.678301, -0.588324, -0.523419, -0.470562, -0.425205, -0.385018, -0.348530, -0.315336,
+ -0.284695, -0.255877, -0.228880, -0.203303, -0.178950, -0.155800, -0.133970, -0.113249,
+ -0.093394, -0.074330, -0.055708, -0.037490, -0.019546, -0.001718, 0.014539, 0.030657,
+ 0.046714, 0.062695, 0.078703, 0.094689, 0.110696, 0.126759, 0.142860, 0.158969,
+ 0.175153, 0.191502, 0.207935, 0.224561, 0.241260, 0.258094, 0.275189, 0.292432,
+ 0.307372, 0.322453, 0.337726, 0.353530, 0.369788, 0.386586, 0.403952, 0.421954,
+ 0.440682, 0.460037, 0.479761, 0.499936, 0.520518, 0.541623, 0.563237, 0.585518,
+ 0.608755, 0.633034, 0.658787, 0.686368, 0.716820, 0.751347, 0.793450, 0.849863,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 4: 32 entries (5 bits) */
+ {
+ -0.686023, -0.590033, -0.522276, -0.465560, -0.415065, -0.369456, -0.327471, -0.288452,
+ -0.251939, -0.217904, -0.185983, -0.156000, -0.127564, -0.100169, -0.073317, -0.046679,
+ -0.019984, 0.006884, 0.037317, 0.068121, 0.099353, 0.130970, 0.161878, 0.193212,
+ 0.225897, 0.261272, 0.301182, 0.346922, 0.398337, 0.456646, 0.526277, 0.619643,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 5: 32 entries (5 bits) */
+ {
+ -0.527743, -0.424492, -0.352527, -0.294102, -0.243637, -0.198721, -0.158197, -0.121422,
+ -0.087780, -0.056634, -0.027564, -0.000057, 0.026333, 0.051882, 0.076891, 0.101336,
+ 0.125239, 0.148710, 0.172091, 0.195743, 0.219951, 0.245374, 0.272629, 0.302507,
+ 0.334789, 0.369369, 0.406797, 0.447397, 0.492493, 0.544022, 0.606679, 0.691200,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 6: 32 entries (5 bits) */
+ {
+ -0.601019, -0.499809, -0.428508, -0.371195, -0.322148, -0.278716, -0.239398, -0.203176,
+ -0.169584, -0.138470, -0.109415, -0.081977, -0.055553, -0.029524, -0.004614, 0.018106,
+ 0.040751, 0.063446, 0.086254, 0.109317, 0.133064, 0.157973, 0.184758, 0.214130,
+ 0.246852, 0.282811, 0.321893, 0.364386, 0.410975, 0.463634, 0.526693, 0.612511,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 7: 32 entries (5 bits) */
+ {
+ -0.463201, -0.366113, -0.303086, -0.254487, -0.213519, -0.177606, -0.145363, -0.116011,
+ -0.089086, -0.064222, -0.040750, -0.018223, 0.003277, 0.025510, 0.047020, 0.068122,
+ 0.089031, 0.110133, 0.131587, 0.153729, 0.176942, 0.201557, 0.228146, 0.257067,
+ 0.288453, 0.322393, 0.358870, 0.398374, 0.442175, 0.492459, 0.552623, 0.636121,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 8: 32 entries (5 bits) */
+ {
+ -0.509145, -0.418749, -0.358351, -0.311239, -0.271890, -0.237792, -0.207221, -0.179058,
+ -0.152976, -0.128516, -0.105298, -0.083077, -0.061680, -0.040969, -0.020397, -0.000226,
+ 0.019619, 0.039298, 0.059006, 0.079040, 0.099577, 0.120854, 0.143279, 0.167235,
+ 0.193205, 0.221520, 0.252694, 0.287225, 0.326977, 0.373768, 0.432608, 0.518828,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 9: 16 entries (4 bits) */
+ {
+ -0.332855, -0.231237, -0.159643, -0.102155, -0.053615, -0.012904, 0.021531, 0.054450,
+ 0.086850, 0.119913, 0.155290, 0.195219, 0.242115, 0.298426, 0.369436, 0.471129,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 10: 16 entries (4 bits) */
+ {
+ -0.376020, -0.278260, -0.212618, -0.160891, -0.117377, -0.079398, -0.045440, -0.014884,
+ 0.014776, 0.047827, 0.082969, 0.122059, 0.167728, 0.222525, 0.291029, 0.387801,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 11: 16 entries (4 bits) */
+ {
+ -0.342852, -0.248889, -0.183868, -0.132410, -0.089601, -0.053097, -0.020720, 0.011049,
+ 0.043759, 0.076197, 0.109914, 0.146761, 0.189409, 0.241277, 0.308095, 0.407348,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 12: 16 entries (4 bits) */
+ {
+ -0.400796, -0.311045, -0.247060, -0.195185, -0.150538, -0.111345, -0.076540, -0.045016,
+ -0.015976, 0.012588, 0.044647, 0.079552, 0.119807, 0.169084, 0.233651, 0.331372,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 13: 8 entries (3 bits) */
+ {
+ -0.287554, -0.179259, -0.098331, -0.034309, 0.021941, 0.079790, 0.147318, 0.251007,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 14: 8 entries (3 bits) */
+ {
+ -0.307008, -0.197848, -0.118523, -0.056781, -0.004304, 0.048868, 0.113937, 0.212073,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+ /* codebook 15: 8 entries (3 bits) */
+ {
+ -0.269441, -0.164866, -0.087872, -0.028712, 0.024066, 0.079931, 0.147043, 0.246413,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
+ },
+};
+
+/* QP pitch gain: 64 entries (6-bit) at VA 0x1004BA10 */
+static const double ds2_qp_pitch_gain[64] = {
+ 0.004913, 0.056367, 0.102669, 0.145092, 0.184286, 0.220170, 0.252640, 0.281841,
+ 0.308202, 0.332237, 0.354531, 0.375491, 0.395460, 0.414675, 0.433337, 0.451622,
+ 0.469648, 0.487486, 0.505255, 0.523016, 0.540824, 0.558764, 0.576890, 0.595276,
+ 0.613963, 0.632917, 0.652245, 0.671900, 0.691902, 0.712322, 0.733015, 0.753909,
+ 0.774967, 0.796116, 0.817233, 0.838156, 0.858900, 0.879346, 0.899405, 0.919040,
+ 0.938366, 0.957462, 0.976668, 0.996526, 1.017693, 1.041066, 1.066882, 1.095219,
+ 1.126158, 1.159959, 1.196753, 1.236515, 1.279487, 1.325996, 1.376201, 1.429902,
+ 1.487140, 1.548301, 1.613491, 1.682657, 1.755914, 1.833605, 1.914886, 1.999406,
+};
+
+/* QP excitation gain: 64 entries (6-bit) at VA 0x1004BC10 */
+static const double ds2_qp_exc_gain[64] = {
+ 3.928000, 7.069000, 10.993000, 16.465000, 23.856000, 32.753000, 42.893000, 54.076000,
+ 66.160000, 79.016000, 92.493000, 106.558000, 121.106000, 136.128000, 151.663000, 167.700000,
+ 184.251000, 201.424000, 219.212000, 237.740000, 257.014000, 277.134000, 298.164000, 320.054000,
+ 342.913000, 366.849000, 391.851000, 418.102000, 445.564000, 474.334000, 504.476000, 536.280000,
+ 569.771000, 604.926000, 642.050000, 681.112000, 722.397000, 766.071000, 812.234000, 861.189000,
+ 913.161000, 968.356000, 1027.220000, 1089.687000, 1156.595000, 1228.228000, 1305.279000, 1387.811000,
+ 1476.597000, 1572.636000, 1675.856000, 1789.017000, 1911.832000, 2045.863000, 2194.195000, 2360.133000,
+ 2545.084000, 2752.592000, 2991.921000, 3271.340000, 3603.855000, 4004.808000, 4476.587000, 4970.296000,
+};
+
+/* QP pulse amplitude: 8 entries (3-bit) at VA 0x1004BE10 */
+static const double ds2_qp_pulse_amp[8] = {
+ -0.921705, -0.628998, -0.397315, -0.140886, 0.206959, 0.433678, 0.652927, 0.931249,
+};
+
+/* De-emphasis coefficient for QP mode */
+#define DS2_QP_DEEMPH_COEFF 0.1
+
+/* ---- Combinatorial number computation ---- */
+
+/**
+ * Compute binomial coefficient C(n, k) = n! / (k! * (n-k)!)
+ */
+static uint64_t ds2_comb(int n, int k) {
+ uint64_t result = 1;
+ int i;
+
+ if (k > n)
+ return 0;
+ if (k > n - k)
+ k = n - k;
+
+ for (i = 0; i < k; i++) {
+ result *= (n - i);
+ result /= (i + 1);
+ }
+
+ return result;
+}
+
+/**
+ * Decode a combinatorial index into k positions from {0..n-1}.
+ * Positions are returned in DESCENDING order (do NOT sort).
+ */
+static void ds2_decode_combinatorial(uint64_t index, int n, int k,
+ int *positions) {
+ uint64_t remaining = index;
+ int i, v;
+
+ for (i = k; i >= 1; i--) {
+ v = i - 1;
+ while (v + 1 < n && ds2_comb(v + 1, i) <= remaining)
+ v++;
+ positions[k - i] = v;
+ remaining -= ds2_comb(v, i);
+ }
+}
+
+/* ---- Codec context ---- */
+
+typedef struct DS2Subframe {
+ double pitch_gain;
+ int pitch_lag;
+ double exc_gain;
+ uint64_t cb_index; /* combinatorial codebook index */
+ int pulse_positions[DS2_MAX_PULSES];
+ int pulse_indices[DS2_MAX_PULSES]; /* indices into pulse_amp table */
+} DS2Subframe;
+
+typedef struct DS2Context {
+ AVCodecContext *avctx;
+ int mode; /* DS2_SP_FORMAT or DS2_QP_FORMAT */
+ int num_refl; /* 14 (SP) or 16 (QP) */
+ int subframe_size; /* 72 (SP) or 64 (QP) */
+ int frame_samples; /* 288 (SP) or 256 (QP) */
+ int num_pulses; /* 7 (SP) or 11 (QP) */
+ int comb_n; /* 72 (SP) or 64 (QP) */
+ int frame_size; /* bytes: 42 (SP) or 56 (QP) */
+
+ /* Per-frame decoded parameters */
+ double refl_coeffs[DS2_MAX_REFL];
+ DS2Subframe sf[DS2_SUBFRAMES];
+
+ /* Persistent state */
+ double lattice_state[DS2_MAX_REFL]; /* lattice filter state */
+ double pitch_memory[DS2_MAX_PITCH + DS2_MAX_SUBFRAME];
+ int pitch_mem_len;
+ double deemph_state; /* QP de-emphasis */
+
+ /* Working buffers */
+ double excitation[DS2_MAX_SUBFRAME];
+ double fixed_exc[DS2_MAX_SUBFRAME];
+ double adaptive_exc[DS2_MAX_SUBFRAME];
+ double synth_out[DS2_MAX_SUBFRAME];
+
+ DECLARE_ALIGNED(16, uint8_t, bits)
+ [DS2_MAX_FRAME_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
+} DS2Context;
+
+/* ---- Bitstream unpacking ---- */
+
+/**
+ * Prepare bitstream: swap bytes within 16-bit LE words for MSB-first reading.
+ * This is the same bit order as FFmpeg's existing DSS SP reader.
+ */
+static void ds2_swap_bytes(DS2Context *p, const uint8_t *src, int size) {
+ int i;
+ for (i = 0; i < size - 1; i += 2) {
+ p->bits[i] = src[i + 1];
+ p->bits[i + 1] = src[i];
+ }
+ if (size & 1)
+ p->bits[size - 1] = src[size - 1];
+}
+
+static void ds2_sp_unpack_frame(DS2Context *p, const uint8_t *src) {
+ GetBitContext gb;
+ int i, sf_idx;
+ uint32_t combined_pitch;
+
+ ds2_swap_bytes(p, src, DS2_SP_FRAME_SIZE);
+ init_get_bits(&gb, p->bits, DS2_SP_FRAME_BITS);
+
+ /* Reflection coefficients */
+ for (i = 0; i < DS2_SP_NUM_REFL; i++) {
+ int idx = get_bits(&gb, ds2_sp_refl_bits[i]);
+ p->refl_coeffs[i] = ds2_sp_refl_cb[i][idx];
+ }
+
+ /* Per-subframe parameters */
+ for (sf_idx = 0; sf_idx < DS2_SUBFRAMES; sf_idx++) {
+ DS2Subframe *sf = &p->sf[sf_idx];
+ int pg_idx, eg_idx;
+
+ pg_idx = get_bits(&gb, 5);
+ sf->cb_index = get_bits_long(&gb, DS2_SP_COMB_BITS);
+ eg_idx = get_bits(&gb, 6);
+
+ sf->pitch_gain = ds2_sp_pitch_gain[pg_idx];
+ sf->exc_gain = ds2_sp_exc_gain[eg_idx];
+
+ for (i = 0; i < DS2_SP_NUM_PULSES; i++)
+ sf->pulse_indices[i] = get_bits(&gb, 3);
+
+ /* Decode combinatorial pulse positions */
+ ds2_decode_combinatorial(sf->cb_index, DS2_SP_COMB_N, DS2_SP_NUM_PULSES,
+ sf->pulse_positions);
+ }
+
+ /* Combined pitch: 24 bits encoding 4 pitch lags */
+ combined_pitch = get_bits_long(&gb, 24);
+
+ p->sf[0].pitch_lag = (combined_pitch % DS2_SP_PITCH_RANGE) + DS2_SP_PITCH_MIN;
+ combined_pitch /= DS2_SP_PITCH_RANGE;
+
+ for (i = 1; i < DS2_SUBFRAMES - 1; i++) {
+ p->sf[i].pitch_lag = combined_pitch % DS2_SP_DELTA_RANGE;
+ combined_pitch /= DS2_SP_DELTA_RANGE;
+ }
+ if (combined_pitch > DS2_SP_DELTA_RANGE - 1)
+ combined_pitch = 0;
+ p->sf[DS2_SUBFRAMES - 1].pitch_lag = combined_pitch;
+
+ /* Convert delta pitch lags to absolute */
+ {
+ int prev_pitch = p->sf[0].pitch_lag;
+ int half_delta = DS2_SP_DELTA_RANGE / 2 - 1; /* 23 */
+
+ for (i = 1; i < DS2_SUBFRAMES; i++) {
+ int base;
+ if (prev_pitch > DS2_SP_PITCH_MAX - half_delta)
+ base = DS2_SP_PITCH_MAX - half_delta - half_delta;
+ else if (prev_pitch >= DS2_SP_PITCH_MIN + half_delta)
+ base = prev_pitch - half_delta;
+ else
+ base = DS2_SP_PITCH_MIN;
+
+ p->sf[i].pitch_lag += base;
+ prev_pitch = p->sf[i].pitch_lag;
+ }
+ }
+}
+
+static void ds2_qp_unpack_frame(DS2Context *p, const uint8_t *src) {
+ GetBitContext gb;
+ int i, sf_idx;
+
+ ds2_swap_bytes(p, src, DS2_QP_FRAME_SIZE);
+ init_get_bits(&gb, p->bits, DS2_QP_FRAME_BITS);
+
+ /* Reflection coefficients */
+ for (i = 0; i < DS2_QP_NUM_REFL; i++) {
+ int idx = get_bits(&gb, ds2_qp_refl_bits[i]);
+ p->refl_coeffs[i] = ds2_qp_refl_cb[i][idx];
+ }
+
+ /* Per-subframe parameters */
+ for (sf_idx = 0; sf_idx < DS2_SUBFRAMES; sf_idx++) {
+ DS2Subframe *sf = &p->sf[sf_idx];
+ int pg_idx, eg_idx;
+
+ /* QP: pitch is 8 bits direct per subframe */
+ sf->pitch_lag = get_bits(&gb, 8) + DS2_QP_PITCH_MIN;
+
+ pg_idx = get_bits(&gb, 6);
+ sf->cb_index = get_bits64(&gb, DS2_QP_COMB_BITS);
+ eg_idx = get_bits(&gb, 6);
+
+ sf->pitch_gain = ds2_qp_pitch_gain[pg_idx];
+ sf->exc_gain = ds2_qp_exc_gain[eg_idx];
+
+ for (i = 0; i < DS2_QP_NUM_PULSES; i++)
+ sf->pulse_indices[i] = get_bits(&gb, 3);
+
+ /* Decode combinatorial pulse positions */
+ ds2_decode_combinatorial(sf->cb_index, DS2_QP_COMB_N, DS2_QP_NUM_PULSES,
+ sf->pulse_positions);
+ }
+}
+
+/**
+ * Generate adaptive excitation by repeating pitch memory at pitch period.
+ */
+static void ds2_gen_adaptive_exc(DS2Context *p, int pitch_lag,
+ int subframe_size) {
+ int i;
+ int mem_end = p->pitch_mem_len;
+
+ for (i = 0; i < subframe_size; i++) {
+ if (pitch_lag < subframe_size) {
+ p->adaptive_exc[i] =
+ p->pitch_memory[mem_end - pitch_lag + (i % pitch_lag)];
+ } else {
+ p->adaptive_exc[i] = p->pitch_memory[mem_end - pitch_lag + i];
+ }
+ }
+}
+
+/**
+ * Generate fixed (sparse pulse) excitation.
+ */
+static void ds2_gen_fixed_exc(DS2Context *p, int sf_idx, int subframe_size) {
+ int i;
+ DS2Subframe *sf = &p->sf[sf_idx];
+ const double *pulse_amp;
+ int num_pulses;
+
+ if (p->mode == DS2_SP_FORMAT) {
+ pulse_amp = ds2_sp_pulse_amp;
+ num_pulses = DS2_SP_NUM_PULSES;
+ } else {
+ pulse_amp = ds2_qp_pulse_amp;
+ num_pulses = DS2_QP_NUM_PULSES;
+ }
+
+ memset(p->fixed_exc, 0, sizeof(double) * subframe_size);
+
+ for (i = 0; i < num_pulses; i++) {
+ int pos = sf->pulse_positions[i];
+ if (pos >= 0 && pos < subframe_size)
+ p->fixed_exc[pos] += pulse_amp[sf->pulse_indices[i]] * sf->exc_gain;
+ }
+}
+
+/**
+ * Combine adaptive and fixed excitation.
+ */
+static void ds2_gen_excitation(DS2Context *p, int sf_idx, int subframe_size) {
+ int i;
+ DS2Subframe *sf = &p->sf[sf_idx];
+
+ for (i = 0; i < subframe_size; i++)
+ p->excitation[i] = sf->pitch_gain * p->adaptive_exc[i] + p->fixed_exc[i];
+}
+
+/**
+ * Lattice synthesis filter.
+ * Normalized form with reflection coefficients.
+ */
+static void ds2_lattice_filter(DS2Context *p, int subframe_size) {
+ int n, k;
+ int num_refl = p->num_refl;
+
+ for (n = 0; n < subframe_size; n++) {
+ double acc = p->excitation[n] -
+ p->lattice_state[num_refl - 1] * p->refl_coeffs[num_refl - 1];
+
+ for (k = num_refl - 2; k >= 0; k--) {
+ acc -= p->lattice_state[k] * p->refl_coeffs[k];
+ p->lattice_state[k + 1] = p->refl_coeffs[k] * acc + p->lattice_state[k];
+ }
+
+ p->lattice_state[0] = acc;
+ p->synth_out[n] = acc;
+ }
+}
+
+/**
+ * Update pitch memory with new excitation.
+ */
+static void ds2_update_pitch_memory(DS2Context *p, int subframe_size) {
+ int max_pitch =
+ (p->mode == DS2_SP_FORMAT) ? DS2_SP_PITCH_MAX : DS2_QP_PITCH_MAX;
+ int total = max_pitch + subframe_size;
+ int i;
+
+ /* Shift old data */
+ for (i = 0; i < max_pitch; i++)
+ p->pitch_memory[i] = p->pitch_memory[i + subframe_size];
+
+ /* Append new excitation */
+ for (i = 0; i < subframe_size; i++)
+ p->pitch_memory[max_pitch + i] = p->excitation[i];
+
+ p->pitch_mem_len = total;
+}
+
+/**
+ * QP de-emphasis: y[n] = x[n] + 0.1 * y[n-1]
+ */
+static void ds2_qp_deemphasis(DS2Context *p, double *samples, int size) {
+ int i;
+ double prev = p->deemph_state;
+
+ for (i = 0; i < size; i++) {
+ samples[i] = samples[i] + DS2_QP_DEEMPH_COEFF * prev;
+ prev = samples[i];
+ }
+
+ p->deemph_state = prev;
+}
+
+/* ---- Main decode entry points ---- */
+
+static av_cold int ds2_decode_init(AVCodecContext *avctx) {
+ DS2Context *p = avctx->priv_data;
+ p->avctx = avctx;
+
+ avctx->sample_fmt = AV_SAMPLE_FMT_S16;
+ av_channel_layout_uninit(&avctx->ch_layout);
+ avctx->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
+
+ /* Determine mode from codec_tag set by demuxer */
+ if (avctx->codec_tag == DS2_QP_FORMAT) {
+ p->mode = DS2_QP_FORMAT;
+ p->num_refl = DS2_QP_NUM_REFL;
+ p->subframe_size = DS2_QP_SUBFRAME_SIZE;
+ p->frame_samples = DS2_QP_FRAME_SAMPLES;
+ p->num_pulses = DS2_QP_NUM_PULSES;
+ p->comb_n = DS2_QP_COMB_N;
+ p->frame_size = DS2_QP_FRAME_SIZE;
+ avctx->sample_rate = DS2_QP_SAMPLE_RATE;
+ } else {
+ /* Default to SP */
+ p->mode = DS2_SP_FORMAT;
+ p->num_refl = DS2_SP_NUM_REFL;
+ p->subframe_size = DS2_SP_SUBFRAME_SIZE;
+ p->frame_samples = DS2_SP_FRAME_SAMPLES;
+ p->num_pulses = DS2_SP_NUM_PULSES;
+ p->comb_n = DS2_SP_COMB_N;
+ p->frame_size = DS2_SP_FRAME_SIZE;
+ avctx->sample_rate = DS2_SP_SAMPLE_RATE;
+ }
+
+ /* Initialize pitch memory */
+ memset(p->pitch_memory, 0, sizeof(p->pitch_memory));
+ p->pitch_mem_len = (p->mode == DS2_SP_FORMAT)
+ ? DS2_SP_PITCH_MAX + DS2_SP_SUBFRAME_SIZE
+ : DS2_QP_PITCH_MAX + DS2_QP_SUBFRAME_SIZE;
+
+ memset(p->lattice_state, 0, sizeof(p->lattice_state));
+ p->deemph_state = 0.0;
+
+ return 0;
+}
+
+static int ds2_decode_frame(AVCodecContext *avctx, AVFrame *frame,
+ int *got_frame_ptr, AVPacket *avpkt) {
+ DS2Context *p = avctx->priv_data;
+ const uint8_t *buf = avpkt->data;
+ int buf_size = avpkt->size;
+ int16_t *out;
+ int ret, j, i;
+
+ if (buf_size < p->frame_size) {
+ if (buf_size)
+ av_log(avctx, AV_LOG_WARNING,
+ "Expected %d bytes, got %d - skipping packet.\n", p->frame_size,
+ buf_size);
+ *got_frame_ptr = 0;
+ return AVERROR_INVALIDDATA;
+ }
+
+ frame->nb_samples = p->frame_samples;
+ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+ return ret;
+
+ out = (int16_t *)frame->data[0];
+
+ /* Unpack frame parameters from bitstream */
+ if (p->mode == DS2_SP_FORMAT)
+ ds2_sp_unpack_frame(p, buf);
+ else
+ ds2_qp_unpack_frame(p, buf);
+
+ /* Decode each subframe */
+ for (j = 0; j < DS2_SUBFRAMES; j++) {
+ /* Generate adaptive excitation from pitch memory */
+ ds2_gen_adaptive_exc(p, p->sf[j].pitch_lag, p->subframe_size);
+
+ /* Generate fixed excitation from pulse codebook */
+ ds2_gen_fixed_exc(p, j, p->subframe_size);
+
+ /* Combine: excitation = pitch_gain * adaptive + fixed */
+ ds2_gen_excitation(p, j, p->subframe_size);
+
+ /* Update pitch memory */
+ ds2_update_pitch_memory(p, p->subframe_size);
+
+ /* Lattice synthesis filter */
+ ds2_lattice_filter(p, p->subframe_size);
+
+ /* QP de-emphasis */
+ if (p->mode == DS2_QP_FORMAT)
+ ds2_qp_deemphasis(p, p->synth_out, p->subframe_size);
+
+ /* Convert to int16 output */
+ for (i = 0; i < p->subframe_size; i++) {
+ double sample = p->synth_out[i];
+ if (sample > 32767.0)
+ sample = 32767.0;
+ else if (sample < -32768.0)
+ sample = -32768.0;
+ out[j * p->subframe_size + i] = (int16_t)lrint(sample);
+ }
+ }
+
+ *got_frame_ptr = 1;
+ return p->frame_size;
+}
+
+const FFCodec ff_ds2_decoder = {
+ .p.name = "ds2",
+ CODEC_LONG_NAME("Digital Speech Standard Pro (DS2)"),
+ .p.type = AVMEDIA_TYPE_AUDIO,
+ .p.id = AV_CODEC_ID_DS2,
+ .priv_data_size = sizeof(DS2Context),
+ .init = ds2_decode_init,
+ FF_CODEC_DECODE_CB(ds2_decode_frame),
+ .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF,
+};
diff --git a/libavformat/Makefile b/libavformat/Makefile
index ab5551a735..ed872b56ff 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -195,6 +195,7 @@ OBJS-$(CONFIG_DNXHD_MUXER) += rawenc.o
OBJS-$(CONFIG_DSF_DEMUXER) += dsfdec.o
OBJS-$(CONFIG_DSICIN_DEMUXER) += dsicin.o
OBJS-$(CONFIG_DSS_DEMUXER) += dss.o
+OBJS-$(CONFIG_DS2_DEMUXER) += ds2.o
OBJS-$(CONFIG_DTSHD_DEMUXER) += dtshddec.o
OBJS-$(CONFIG_DTS_DEMUXER) += dtsdec.o rawdec.o
OBJS-$(CONFIG_DTS_MUXER) += rawenc.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index e39eab8e85..7db5389eea 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -148,6 +148,7 @@ extern const FFInputFormat ff_dsf_demuxer;
extern const FFInputFormat ff_dsicin_demuxer;
extern const FFInputFormat ff_dss_demuxer;
extern const FFInputFormat ff_dts_demuxer;
+extern const FFInputFormat ff_ds2_demuxer;
extern const FFOutputFormat ff_dts_muxer;
extern const FFInputFormat ff_dtshd_demuxer;
extern const FFInputFormat ff_dv_demuxer;
diff --git a/libavformat/ds2.c b/libavformat/ds2.c
new file mode 100644
index 0000000000..9c0326c0cb
--- /dev/null
+++ b/libavformat/ds2.c
@@ -0,0 +1,369 @@
+/*
+ * Digital Speech Standard Pro (DS2) demuxer
+ */
+
+/**
+ * @file
+ * DS2 (DSS Pro) demuxer
+ *
+ * DS2 is an evolution of the Digital Speech Standard (DSS) format used by
+ * Olympus dictation recorders. It supports two codec modes:
+ * - SP (Standard Play): 12000 Hz, CELP with C(72,7) codebook
+ * - QP (Quality Play): 16000 Hz, CELP with C(64,11) codebook
+ *
+ * Format details from FFmpeg trac ticket #6091.
+ */
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mem.h"
+
+#include "avformat.h"
+#include "demux.h"
+#include "internal.h"
+
+#define DS2_HEADER_SIZE 0x600 /* 1536 bytes */
+#define DS2_BLOCK_SIZE 512
+#define DS2_AUDIO_BLOCK_HEADER_SIZE 6
+#define DS2_BLOCK_PAYLOAD_SIZE (DS2_BLOCK_SIZE - DS2_AUDIO_BLOCK_HEADER_SIZE)
+
+#define DS2_FORMAT_SP 0 /* Standard Play, 12000 Hz */
+#define DS2_FORMAT_QP 6 /* Quality Play, 16000 Hz */
+
+#define DS2_SP_FRAME_SIZE 42 /* SP: 328 bits ~ 41 bytes, padded to 42 */
+#define DS2_SP_FRAME_BITS 328
+#define DS2_SP_SAMPLES_PER_FRAME 288 /* 72 samples * 4 subframes */
+#define DS2_SP_SAMPLE_RATE 12000
+
+#define DS2_QP_FRAME_BITS 448
+#define DS2_QP_FRAME_SIZE 56 /* 448 bits = 56 bytes */
+#define DS2_QP_SAMPLES_PER_FRAME 256 /* 64 samples * 4 subframes */
+#define DS2_QP_SAMPLE_RATE 16000
+
+/* Metadata offsets (same layout as DSS) */
+#define DS2_HEAD_OFFSET_AUTHOR 0xc
+#define DS2_AUTHOR_SIZE 16
+#define DS2_HEAD_OFFSET_START_TIME 0x26
+#define DS2_HEAD_OFFSET_END_TIME 0x32
+#define DS2_TIME_SIZE 12
+#define DS2_HEAD_OFFSET_COMMENT 0x31e
+#define DS2_COMMENT_SIZE 64
+
+typedef struct DS2DemuxContext {
+ int format_type; /* DS2_FORMAT_SP or DS2_FORMAT_QP */
+ int counter; /* bytes remaining in current block payload */
+ int swap; /* SP byte-swap state */
+ int ds2_sp_swap_byte; /* saved swap byte for SP mode */
+ int total_frames; /* total frame count from block headers */
+ int frames_read; /* frames read so far */
+} DS2DemuxContext;
+
+static int ds2_probe(const AVProbeData *p) {
+ if (AV_RL32(p->buf) != MKTAG(0x3, 'd', 's', '2'))
+ return 0;
+
+ return AVPROBE_SCORE_MAX;
+}
+
+static int ds2_read_metadata_date(AVFormatContext *s, unsigned int offset,
+ const char *key) {
+ AVIOContext *pb = s->pb;
+ char datetime[64], string[DS2_TIME_SIZE + 1] = {0};
+ int y, month, d, h, minute, sec;
+ int ret;
+
+ avio_seek(pb, offset, SEEK_SET);
+
+ ret = avio_read(pb, string, DS2_TIME_SIZE);
+ if (ret < DS2_TIME_SIZE)
+ return ret < 0 ? ret : AVERROR_EOF;
+
+ if (sscanf(string, "%2d%2d%2d%2d%2d%2d", &y, &month, &d, &h, &minute, &sec) !=
+ 6)
+ return AVERROR_INVALIDDATA;
+
+ snprintf(datetime, sizeof(datetime), "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d",
+ y + 2000, month, d, h, minute, sec);
+ return av_dict_set(&s->metadata, key, datetime, 0);
+}
+
+static int ds2_read_metadata_string(AVFormatContext *s, unsigned int offset,
+ unsigned int size, const char *key) {
+ AVIOContext *pb = s->pb;
+ char *value;
+ int ret;
+
+ avio_seek(pb, offset, SEEK_SET);
+
+ value = av_mallocz(size + 1);
+ if (!value)
+ return AVERROR(ENOMEM);
+
+ ret = avio_read(pb, value, size);
+ if (ret < size) {
+ av_free(value);
+ return ret < 0 ? ret : AVERROR_EOF;
+ }
+
+ return av_dict_set(&s->metadata, key, value, AV_DICT_DONT_STRDUP_VAL);
+}
+
+static int ds2_read_header(AVFormatContext *s) {
+ DS2DemuxContext *ctx = s->priv_data;
+ AVIOContext *pb = s->pb;
+ AVStream *st;
+ uint8_t block_header[DS2_AUDIO_BLOCK_HEADER_SIZE];
+ int ret;
+ int64_t ret64;
+
+ st = avformat_new_stream(s, NULL);
+ if (!st)
+ return AVERROR(ENOMEM);
+
+ /* Read metadata */
+ ret = ds2_read_metadata_string(s, DS2_HEAD_OFFSET_AUTHOR, DS2_AUTHOR_SIZE,
+ "author");
+ if (ret)
+ return ret;
+
+ ret = ds2_read_metadata_date(s, DS2_HEAD_OFFSET_END_TIME, "date");
+ if (ret)
+ return ret;
+
+ ret = ds2_read_metadata_string(s, DS2_HEAD_OFFSET_COMMENT, DS2_COMMENT_SIZE,
+ "comment");
+ if (ret)
+ return ret;
+
+ /* Seek to first audio block to read its header */
+ if ((ret64 = avio_seek(pb, DS2_HEADER_SIZE, SEEK_SET)) < 0)
+ return (int)ret64;
+
+ ret = avio_read(pb, block_header, DS2_AUDIO_BLOCK_HEADER_SIZE);
+ if (ret < DS2_AUDIO_BLOCK_HEADER_SIZE)
+ return ret < 0 ? ret : AVERROR_EOF;
+
+ /* byte4 of block header is the format type */
+ ctx->format_type = block_header[4];
+
+ st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
+ st->codecpar->codec_id = AV_CODEC_ID_DS2;
+ st->codecpar->codec_tag = ctx->format_type;
+ st->codecpar->ch_layout = (AVChannelLayout)AV_CHANNEL_LAYOUT_MONO;
+
+ if (ctx->format_type == DS2_FORMAT_SP) {
+ st->codecpar->sample_rate = DS2_SP_SAMPLE_RATE;
+ } else if (ctx->format_type == DS2_FORMAT_QP) {
+ st->codecpar->sample_rate = DS2_QP_SAMPLE_RATE;
+ } else {
+ avpriv_request_sample(s, "DS2 format type %d", ctx->format_type);
+ return AVERROR_PATCHWELCOME;
+ }
+
+ avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate);
+ st->start_time = 0;
+
+ /* Initialize SP swap state from bit 7 of first block's byte0 */
+ ctx->swap = !!(block_header[0] & 0x80);
+ ctx->ds2_sp_swap_byte = -1;
+
+ /* Seek back to start of first block payload (after the header we just read)
+ */
+ ctx->counter = DS2_BLOCK_PAYLOAD_SIZE;
+
+ return 0;
+}
+
+static void ds2_skip_audio_header(AVFormatContext *s) {
+ DS2DemuxContext *ctx = s->priv_data;
+
+ avio_skip(s->pb, DS2_AUDIO_BLOCK_HEADER_SIZE);
+ ctx->counter = DS2_BLOCK_PAYLOAD_SIZE;
+}
+
+/**
+ * SP byte-swap logic.
+ *
+ * DS2 SP uses an alternating byte-swap scheme similar to DSS:
+ * - No-swap frame: read 42 bytes, save byte[40] as swap_byte, zero byte[40]
+ * - Swap frame: read 40 bytes into pkt[3..], shift even-indexed bytes:
+ * pkt[i] = pkt[i+4] for i in 0..40 step 2, set pkt[1] = swap_byte
+ * - Zero pkt[40] before decoding, toggle swap state
+ */
+static void ds2_sp_byte_swap(DS2DemuxContext *ctx, uint8_t *data) {
+ int i;
+
+ if (ctx->swap) {
+ for (i = 0; i < DS2_SP_FRAME_SIZE - 2; i += 2)
+ data[i] = data[i + 4];
+
+ data[DS2_SP_FRAME_SIZE] = 0;
+ data[1] = ctx->ds2_sp_swap_byte;
+ } else {
+ ctx->ds2_sp_swap_byte = data[DS2_SP_FRAME_SIZE - 2];
+ }
+
+ /* Ensure byte 40 is always 0 */
+ data[DS2_SP_FRAME_SIZE - 2] = 0;
+ ctx->swap ^= 1;
+}
+
+static int ds2_sp_read_packet(AVFormatContext *s, AVPacket *pkt) {
+ DS2DemuxContext *ctx = s->priv_data;
+ int read_size, ret, offset = 0, buff_offset = 0;
+ int64_t pos = avio_tell(s->pb);
+
+ if (ctx->counter == 0)
+ ds2_skip_audio_header(s);
+
+ if (ctx->swap) {
+ read_size = DS2_SP_FRAME_SIZE - 2; /* 40 bytes */
+ buff_offset = 3;
+ } else {
+ read_size = DS2_SP_FRAME_SIZE; /* 42 bytes */
+ }
+
+ ret = av_new_packet(pkt, DS2_SP_FRAME_SIZE + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (ret < 0)
+ return ret;
+ pkt->size = DS2_SP_FRAME_SIZE;
+
+ pkt->duration = DS2_SP_SAMPLES_PER_FRAME;
+ pkt->pos = pos;
+ pkt->stream_index = 0;
+
+ if (ctx->counter < read_size) {
+ ret = avio_read(s->pb, pkt->data + buff_offset, ctx->counter);
+ if (ret < ctx->counter)
+ goto error_eof;
+
+ offset = ctx->counter;
+ ds2_skip_audio_header(s);
+ }
+ ctx->counter -= (read_size - offset);
+
+ ret = avio_read(s->pb, pkt->data + offset + buff_offset, read_size - offset);
+ if (ret < read_size - offset)
+ goto error_eof;
+
+ ds2_sp_byte_swap(ctx, pkt->data);
+
+ if (ctx->ds2_sp_swap_byte < 0)
+ return AVERROR(EAGAIN);
+
+ return 0;
+
+error_eof:
+ return ret < 0 ? ret : AVERROR_EOF;
+}
+
+static int ds2_qp_read_packet(AVFormatContext *s, AVPacket *pkt) {
+ DS2DemuxContext *ctx = s->priv_data;
+ int ret, offset = 0;
+ int64_t pos = avio_tell(s->pb);
+
+ if (ctx->counter == 0)
+ ds2_skip_audio_header(s);
+
+ ret = av_new_packet(pkt, DS2_QP_FRAME_SIZE + AV_INPUT_BUFFER_PADDING_SIZE);
+ if (ret < 0)
+ return ret;
+ pkt->size = DS2_QP_FRAME_SIZE;
+
+ pkt->duration = DS2_QP_SAMPLES_PER_FRAME;
+ pkt->pos = pos;
+ pkt->stream_index = 0;
+
+ /*
+ * QP frames are 56 bytes in a continuous bitstream across blocks.
+ * Frames can span block boundaries, so we read in pieces if needed.
+ */
+ while (offset < DS2_QP_FRAME_SIZE) {
+ int to_read = FFMIN(DS2_QP_FRAME_SIZE - offset, ctx->counter);
+ if (to_read <= 0) {
+ ds2_skip_audio_header(s);
+ to_read = FFMIN(DS2_QP_FRAME_SIZE - offset, ctx->counter);
+ }
+
+ ret = avio_read(s->pb, pkt->data + offset, to_read);
+ if (ret < to_read) {
+ return ret < 0 ? ret : AVERROR_EOF;
+ }
+
+ offset += to_read;
+ ctx->counter -= to_read;
+ }
+
+ return 0;
+}
+
+static int ds2_read_packet(AVFormatContext *s, AVPacket *pkt) {
+ DS2DemuxContext *ctx = s->priv_data;
+
+ if (ctx->format_type == DS2_FORMAT_SP)
+ return ds2_sp_read_packet(s, pkt);
+ else
+ return ds2_qp_read_packet(s, pkt);
+}
+
+static int ds2_read_seek(AVFormatContext *s, int stream_index,
+ int64_t timestamp, int flags) {
+ DS2DemuxContext *ctx = s->priv_data;
+ int64_t ret, seekto;
+ uint8_t header[DS2_AUDIO_BLOCK_HEADER_SIZE];
+ int offset;
+
+ if (ctx->format_type == DS2_FORMAT_SP) {
+ /* SP: 42-byte frames (avg 41 bytes with swap interleaving) */
+ seekto = timestamp / DS2_SP_SAMPLES_PER_FRAME * 41 /
+ DS2_BLOCK_PAYLOAD_SIZE * DS2_BLOCK_SIZE;
+ } else {
+ /* QP: 56-byte frames */
+ seekto = timestamp / DS2_QP_SAMPLES_PER_FRAME * DS2_QP_FRAME_SIZE /
+ DS2_BLOCK_PAYLOAD_SIZE * DS2_BLOCK_SIZE;
+ }
+
+ if (seekto < 0)
+ seekto = 0;
+
+ seekto += DS2_HEADER_SIZE;
+
+ ret = avio_seek(s->pb, seekto, SEEK_SET);
+ if (ret < 0)
+ return ret;
+
+ ret = avio_read(s->pb, header, DS2_AUDIO_BLOCK_HEADER_SIZE);
+ if (ret < DS2_AUDIO_BLOCK_HEADER_SIZE)
+ return ret < 0 ? ret : AVERROR_EOF;
+
+ if (ctx->format_type == DS2_FORMAT_SP) {
+ ctx->swap = !!(header[0] & 0x80);
+ offset = 2 * header[1] + 2 * ctx->swap;
+ if (offset < DS2_AUDIO_BLOCK_HEADER_SIZE)
+ return AVERROR_INVALIDDATA;
+ if (offset == DS2_AUDIO_BLOCK_HEADER_SIZE) {
+ ctx->counter = 0;
+ avio_skip(s->pb, -DS2_AUDIO_BLOCK_HEADER_SIZE);
+ } else {
+ ctx->counter = DS2_BLOCK_SIZE - offset;
+ avio_skip(s->pb, offset - DS2_AUDIO_BLOCK_HEADER_SIZE);
+ }
+ ctx->ds2_sp_swap_byte = -1;
+ } else {
+ /* QP: just start at block payload boundary */
+ ctx->counter = DS2_BLOCK_PAYLOAD_SIZE;
+ }
+
+ return 0;
+}
+
+const FFInputFormat ff_ds2_demuxer = {
+ .p.name = "ds2",
+ .p.long_name = NULL_IF_CONFIG_SMALL("Digital Speech Standard Pro (DS2)"),
+ .p.extensions = "ds2",
+ .priv_data_size = sizeof(DS2DemuxContext),
+ .read_probe = ds2_probe,
+ .read_header = ds2_read_header,
+ .read_packet = ds2_read_packet,
+ .read_seek = ds2_read_seek,
+};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment