aboutsummaryrefslogtreecommitdiffstats
path: root/codec/ir77_ambe_decode.c
diff options
context:
space:
mode:
authorSylvain Munaut <tnt@246tNt.com>2015-12-23 20:53:29 +0100
committerSylvain Munaut <tnt@246tNt.com>2015-12-23 20:53:29 +0100
commit39141a86bbaf43ccc7543e0bdf46107d59f539c0 (patch)
treef45ac20895394e558fedd9d19ce52db13fd722df /codec/ir77_ambe_decode.c
parent30e476ab5f4302f12c6f1af08d3b7c35a3cd6416 (diff)
codec: Import current codec code
Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
Diffstat (limited to 'codec/ir77_ambe_decode.c')
-rw-r--r--codec/ir77_ambe_decode.c199
1 files changed, 199 insertions, 0 deletions
diff --git a/codec/ir77_ambe_decode.c b/codec/ir77_ambe_decode.c
new file mode 100644
index 0000000..4d8fd7b
--- /dev/null
+++ b/codec/ir77_ambe_decode.c
@@ -0,0 +1,199 @@
+/* Iridium AMBE vocoder - Decoder tool */
+
+/* (C) 2015 by Sylvain Munaut <tnt@246tNt.com>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "ambe.h"
+
+
+static const uint8_t wav_hdr[] = {
+ /* WAV header */
+ 'R', 'I', 'F', 'F', /* ChunkID */
+ 0x00, 0x00, 0x00, 0x00, /* ChunkSize */
+ 'W', 'A', 'V', 'E', /* Format */
+
+ /* Sub chunk: format */
+ 'f', 'm', 't', ' ', /* Subchunk1ID */
+ 0x10, 0x00, 0x00, 0x00, /* Subchunk1Size */
+ 0x01, 0x00, /* AudioFormat: PCM */
+ 0x01, 0x00, /* NumChannels: Mono */
+ 0x40, 0x1f, 0x00, 0x00, /* SampleRate: 8000 Hz */
+ 0x80, 0x3e, 0x00, 0x00, /* ByteRate: 16k/s */
+ 0x02, 0x00, /* BlockAlign: 2 bytes */
+ 0x10, 0x00, /* BitsPerSample: 16 */
+
+ /* Sub chunk: data */
+ 'd', 'a', 't', 'a', /* Subchunk2ID */
+ 0x00, 0x00, 0x00, 0x00, /* Subchunk2Size */
+};
+
+static uint32_t
+le32(uint32_t v)
+{
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ return v;
+#else
+ return ((v & 0x000000ff) << 24) |
+ ((v & 0x0000ff00) << 8) |
+ ((v & 0x00ff0000) >> 8) |
+ ((v & 0xff000000) >> 24);
+#endif
+}
+
+static uint16_t
+le16(uint16_t v)
+{
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+ return v;
+#else
+ return ((v & 0x00ff) << 8) |
+ ((v & 0xff00) >> 8);
+#endif
+}
+
+int main(int argc, char *argv[])
+{
+ struct ir77_ambe_decoder *dec = NULL;
+ FILE *fin, *fout;
+ int is_wave = 0, l, rv;
+
+ /* Arguments */
+ if (argc > 3) {
+ fprintf(stderr, "Usage: %s [in_file [out_file]]\n", argv[0]);
+ return -1;
+ }
+
+ if ((argc < 2) || !strcmp(argv[1], "-"))
+ fin = stdin;
+ else {
+ fin = fopen(argv[1], "rb");
+ if (!fin) {
+ fprintf(stderr, "[!] Unable to open input file\n");
+ return -1;
+ }
+ }
+
+ if ((argc < 3) || !strcmp(argv[2], "-"))
+ fout = stdout;
+ else {
+ fout = fopen(argv[2], "wb");
+ if (!fout) {
+ fprintf(stderr, "[!] Unable to open output file\n");
+ return -1;
+ }
+
+ l = strlen(argv[2]);
+
+ if ((l > 4) && (!strcmp(".wav", &argv[2][l-4])))
+ is_wave = 1;
+ }
+
+ /* Write inital wave header */
+ if (is_wave) {
+ rv = fwrite(wav_hdr, sizeof(wav_hdr), 1, fout);
+ if (rv != 1) {
+ fprintf(stderr, "[!] Failed to write WAV header\n");
+ goto exit;
+ }
+ }
+
+ /* Init decoder */
+ dec = ir77_ambe_decode_alloc();
+ if (!dec)
+ goto exit;
+
+ /* Process all frames */
+ l = 0;
+
+ while (!feof(fin))
+ {
+ uint8_t superframe[39];
+ int16_t audio[2*360];
+ int rv, i;
+
+ /* Read input frame */
+ rv = fread(superframe, 1, 39, fin);
+ if (rv != 39)
+ break;
+
+ /* Skip dummy frames */
+ if ((superframe[0] == 0xff) && (superframe[38] == 0xff))
+ continue;
+
+ /* Decompress */
+ rv = ir77_ambe_decode_superframe(dec, audio, 2*360, superframe);
+ if (rv) {
+ fprintf(stderr, "[!] codec error\n");
+ break;
+ }
+
+ /* Write audio output */
+ for (i=0; i<2*360; i++)
+ audio[i] = le16(audio[i]);
+
+ rv = fwrite(audio, 2, 2*360, fout);
+ if (rv != 2*360) {
+ fprintf(stderr, "[!] short write\n");
+ break;
+ }
+
+ /* Keep track of number of samples */
+ l += 2*360;
+ }
+
+ /* Release decoder */
+ ir77_ambe_decode_release(dec);
+
+ /* Fix wave header */
+ if (is_wave)
+ {
+ uint32_t v;
+
+ /* Fixup Subchunk2Size */
+ v = le32(l * 2);
+
+ rv = fseek(fout, 40, SEEK_SET);
+ if (rv < 0)
+ goto exit;
+
+ rv = fwrite(&v, 4, 1, fout);
+ if (rv < 0)
+ goto exit;
+
+ /* Fixup ChunkSize */
+ v = le32(l * 2 + 36);
+
+ rv = fseek(fout, 4, SEEK_SET);
+ if (rv < 0)
+ goto exit;
+
+ rv = fwrite(&v, 4, 1, fout);
+ if (rv < 0)
+ goto exit;
+ }
+
+exit:
+ /* Close in/out */
+ fclose(fout);
+ fclose(fin);
+
+ /* All done ! */
+ return 0;
+}