changeset 4:286d5f097eb4

libgsmfrp: implement comfort noise generation
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 19 Nov 2022 20:16:09 +0000
parents 3cd5ad24b1d4
children 4812e00bc100
files libgsmfrp/Makefile libgsmfrp/comfort_noise.c libgsmfrp/internal.h libgsmfrp/state.c
diffstat 4 files changed, 126 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/libgsmfrp/Makefile	Sat Nov 19 09:03:57 2022 +0000
+++ b/libgsmfrp/Makefile	Sat Nov 19 20:16:09 2022 +0000
@@ -1,6 +1,6 @@
 CC=	gcc
 CFLAGS=	-O2
-OBJS=	sidclass.o silence_frame.o state.o
+OBJS=	comfort_noise.o sidclass.o silence_frame.o state.o
 LIB=	libgsmfrp.a
 
 all:	${LIB}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgsmfrp/comfort_noise.c	Sat Nov 19 20:16:09 2022 +0000
@@ -0,0 +1,112 @@
+/*
+ * In this module we implement comfort noise generation per GSM 06.12
+ * or 3GPP TS 46.012.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include "gsm_fr_preproc.h"
+#include "internal.h"
+
+static const uint8_t fold_table_8to6[24] = {
+	1, 2, 3, 4, 5, 6, 1, 2,
+	1, 2, 3, 4, 5, 6, 3, 4,
+	1, 2, 3, 4, 5, 6, 5, 6,
+};
+
+static const uint8_t bc[4] = {0, 0, 0, 0};
+static const uint8_t Nc[4] = {40, 120, 40, 120};
+
+/* pseudonoise() function is based on ETSI EFR code */
+
+static uint16_t pseudonoise(struct gsmfr_preproc_state *st, uint16_t no_bits)
+{
+    uint16_t noise_bits, Sn, i;
+
+    noise_bits = 0;
+    for (i = 0; i < no_bits; i++)
+    {
+        /* State n == 31 */
+        if ((st->cn_random_lfsr & 0x00000001L) != 0)
+        {
+            Sn = 1;
+        }
+        else
+        {
+            Sn = 0;
+        }
+
+        /* State n == 3 */
+        if ((st->cn_random_lfsr & 0x10000000L) != 0)
+        {
+            Sn = Sn ^ 1;
+        }
+        else
+        {
+            Sn = Sn ^ 0;
+        }
+
+        noise_bits = noise_bits << 1;
+        noise_bits = noise_bits | st->cn_random_lfsr & 1;
+
+        st->cn_random_lfsr >>= 1;
+        if (Sn & 1)
+        {
+            st->cn_random_lfsr |= 0x40000000L;
+        }
+    }
+
+    return noise_bits;
+}
+
+static uint8_t random_1to6(struct gsmfr_preproc_state *st)
+{
+	uint8_t range8, range6;
+
+	range8 = pseudonoise(st, 3);
+	range6 = fold_table_8to6[(st->cn_random_6fold << 3) | range8];
+	st->cn_random_6fold++;
+	if (st->cn_random_6fold >= 3)
+		st->cn_random_6fold = 0;
+	return range6;
+}
+
+void gsmfr_preproc_gen_cn(struct gsmfr_preproc_state *st, gsm_byte *frame)
+{
+	unsigned sub, pulse;
+	uint8_t Mc, xmc[13];
+	gsm_byte *c;
+
+	/* global bytes (magic and LARc) are fixed */
+	memcpy(frame, st->sid_prefix, 5);
+	c = frame + 5;
+	/* now do the 4 subframes, mostly PRNG output */
+	for (sub = 0; sub < 4; sub++) {
+		Mc = pseudonoise(st, 2);
+		for (pulse = 0; pulse < 13; pulse++)
+			xmc[pulse] = random_1to6(st);
+		/* packing code from libgsm */
+		*c++ =   ((Nc[sub] & 0x7F) << 1)
+		       | ((bc[sub] >> 1) & 0x1);
+		*c++ =   ((bc[sub] & 0x1) << 7)
+		       | ((Mc & 0x3) << 5)
+		       | ((st->sid_xmaxc[sub] >> 1) & 0x1F);
+		*c++ =   ((st->sid_xmaxc[sub] & 0x1) << 7)
+		       | ((xmc[0] & 0x7) << 4)
+		       | ((xmc[1] & 0x7) << 1)
+		       | ((xmc[2] >> 2) & 0x1);
+		*c++ =   ((xmc[2] & 0x3) << 6)
+		       | ((xmc[3] & 0x7) << 3)
+		       | (xmc[4] & 0x7);
+		*c++ =   ((xmc[5] & 0x7) << 5)
+		       | ((xmc[6] & 0x7) << 2)
+		       | ((xmc[7] >> 1) & 0x3);
+		*c++ =   ((xmc[7] & 0x1) << 7)
+		       | ((xmc[8] & 0x7) << 4)
+		       | ((xmc[9] & 0x7) << 1)
+		       | ((xmc[10] >> 2) & 0x1);
+		*c++ =   ((xmc[10] & 0x3) << 6)
+		       | ((xmc[11] & 0x7) << 3)
+		       | (xmc[12] & 0x7);
+	}
+}
--- a/libgsmfrp/internal.h	Sat Nov 19 09:03:57 2022 +0000
+++ b/libgsmfrp/internal.h	Sat Nov 19 20:16:09 2022 +0000
@@ -11,12 +11,19 @@
 	LOST_SID,
 };
 
-typedef unsigned char cparam;
-
 struct gsmfr_preproc_state {
 	enum rx_state	rx_state;
 	int		got_valid_sid;
 	gsm_frame	speech_frame;
-	cparam		cnoise_larc[8];
-	cparam		cnoise_xmaxc[4];
+	gsm_byte	sid_prefix[5];
+	uint8_t		sid_xmaxc[4];
+	uint32_t	cn_random_lfsr;
+	unsigned	cn_random_6fold;
 };
+
+/* we use the same LFSR PRNG for CN as ETSI EFR implementation */
+#define PN_INITIAL_SEED 0x70816958L   /* Pseudo noise generator seed value  */
+
+/* internal function */
+extern void gsmfr_preproc_gen_cn(struct gsmfr_preproc_state *state,
+				 gsm_byte *frame);
--- a/libgsmfrp/state.c	Sat Nov 19 09:03:57 2022 +0000
+++ b/libgsmfrp/state.c	Sat Nov 19 20:16:09 2022 +0000
@@ -3,6 +3,7 @@
  * of state structures for our GSM FR preprocessor.
  */
 
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include "gsm_fr_preproc.h"
@@ -21,4 +22,5 @@
 void gsmfr_preproc_reset(struct gsmfr_preproc_state *st)
 {
 	memset(st, 0, sizeof(struct gsmfr_preproc_state));
+	st->cn_random_lfsr = PN_INITIAL_SEED;
 }