fix: Gain adjustment during second quantization phase can exceed minimum gain
diff --git a/src/spec.c b/src/spec.c
index 7b13578..f857f47 100644
--- a/src/spec.c
+++ b/src/spec.c
@@ -44,11 +44,12 @@
  * nbits_off       Offset on the available bits, temporarily smoothed
  * g_off           Gain index offset
  * reset_off       Return True when the nbits_off must be reset
+ * g_min           Return lower bound of quantized gain value
  * return          The quantized gain value
  */
 LC3_HOT static int estimate_gain(
     enum lc3_dt dt, enum lc3_srate sr, const float *x,
-    int nbits_budget, float nbits_off, int g_off, bool *reset_off)
+    int nbits_budget, float nbits_off, int g_off, bool *reset_off, int *g_min)
 {
     int ne = LC3_NE(dt, sr) >> 2;
     int e[LC3_MAX_NE];
@@ -102,12 +103,12 @@
 
     /* --- Limit gain index --- */
 
-    int g_min = x2_max == 0 ? -g_off :
+    *g_min = x2_max == 0 ? -g_off :
         ceilf(28 * log10f(sqrtf(x2_max) / (32768 - 0.375f)));
 
-    *reset_off = g_int < g_min || x2_max == 0;
+    *reset_off = g_int < *g_min || x2_max == 0;
     if (*reset_off)
-        g_int = g_min;
+        g_int = *g_min;
 
     return g_int;
 }
@@ -118,10 +119,11 @@
  * g_idx           The estimated quantized gain index
  * nbits           Computed number of bits coding the spectrum
  * nbits_budget    Number of bits available for coding the spectrum
+ * g_idx_min       Minimum gain index value
  * return          Gain adjust value (-1 to 2)
  */
-LC3_HOT static int adjust_gain(
-    enum lc3_srate sr, int g_idx, int nbits, int nbits_budget)
+LC3_HOT static int adjust_gain(enum lc3_srate sr, int g_idx,
+    int nbits, int nbits_budget, int g_idx_min)
 {
     /* --- Compute delta threshold --- */
 
@@ -149,7 +151,7 @@
     /* --- Adjust gain --- */
 
     if (nbits < nbits_budget - (delta + 2))
-        return -(g_idx > 0);
+        return -(g_idx > g_idx_min);
 
     if (nbits > nbits_budget)
         return (g_idx < 255) + (g_idx < 254 && nbits >= nbits_budget + delta);
@@ -789,8 +791,8 @@
 
     int g_off = resolve_gain_offset(sr, nbytes);
 
-    int g_int = estimate_gain(dt, sr,
-        x, nbits_budget, nbits_off, g_off, &reset_off);
+    int g_min, g_int = estimate_gain(dt, sr,
+        x, nbits_budget, nbits_off, g_off, &reset_off, &g_min);
 
     /* --- Quantization --- */
 
@@ -803,7 +805,8 @@
 
     /* --- Adjust gain and requantize --- */
 
-    int g_adj = adjust_gain(sr, g_int + g_off, nbits, nbits_budget);
+    int g_adj = adjust_gain(sr, g_off + g_int,
+        nbits, nbits_budget, g_off + g_min);
 
     if (g_adj)
         quantize(dt, sr, g_adj, x, xq, &side->nq);
diff --git a/test/spec.py b/test/spec.py
index 898c9a1..22c5e3e 100644
--- a/test/spec.py
+++ b/test/spec.py
@@ -589,7 +589,7 @@
         (g_int, reset_off) = \
             analysis.estimate_gain(x, nbits_budget, nbits_off, g_off)
 
-        (g_int_c, reset_off_c) = lc3.spec_estimate_gain(
+        (g_int_c, reset_off_c, _) = lc3.spec_estimate_gain(
             dt, sr, x, nbits_budget, nbits_off, -g_off)
 
         ok = ok and g_int_c == g_int
@@ -664,7 +664,7 @@
 
             g_adj = analysis.adjust_gain(g_idx, nbits, nbits_budget)
 
-            g_adj_c = lc3.spec_adjust_gain(sr, g_idx, nbits, nbits_budget)
+            g_adj_c = lc3.spec_adjust_gain(sr, g_idx, nbits, nbits_budget, 0)
 
             ok = ok and g_adj_c == g_adj
 
@@ -752,7 +752,7 @@
         ok = ok and nbits == C.NBITS_EST[dt][i]
 
         g_adj = lc3.spec_adjust_gain(sr,
-            C.GG_IND[dt][i], C.NBITS_EST[dt][i], C.NBITS_SPEC[dt][i])
+            C.GG_IND[dt][i], C.NBITS_EST[dt][i], C.NBITS_SPEC[dt][i], 0)
         ok = ok and g_adj == C.GG_IND_ADJ[dt][i] - C.GG_IND[dt][i]
 
         if C.GG_IND_ADJ[dt][i] != C.GG_IND[dt][i]:
diff --git a/test/spec_py.c b/test/spec_py.c
index 814f253..730f68f 100644
--- a/test/spec_py.c
+++ b/test/spec_py.c
@@ -30,7 +30,7 @@
     float *x;
     int nbits_budget;
     float nbits_off;
-    int g_off;
+    int g_off, g_min;
     bool reset_off;
 
     if (!PyArg_ParseTuple(args, "IIOifi", &dt, &sr,
@@ -45,23 +45,24 @@
     CTYPES_CHECK("x", x_obj = to_1d_ptr(x_obj, NPY_FLOAT, ne, &x));
 
     int g_int = estimate_gain(dt, sr,
-        x, nbits_budget, nbits_off, g_off, &reset_off);
+        x, nbits_budget, nbits_off, g_off, &reset_off, &g_min);
 
-    return Py_BuildValue("ii", g_int, reset_off);
+    return Py_BuildValue("iii", g_int, reset_off, g_min);
 }
 
 static PyObject *adjust_gain_py(PyObject *m, PyObject *args)
 {
     unsigned sr;
-    int g_idx, nbits, nbits_budget;
+    int g_idx, nbits, nbits_budget, g_idx_min;
 
-    if (!PyArg_ParseTuple(args, "Iiii", &sr, &g_idx, &nbits, &nbits_budget))
+    if (!PyArg_ParseTuple(args, "Iiiii", &sr, &g_idx,
+                &nbits, &nbits_budget, &g_idx_min))
         return NULL;
 
     CTYPES_CHECK("sr", (unsigned)sr < LC3_NUM_SRATE);
     CTYPES_CHECK("g_idx", g_idx >= 0 && g_idx <= 255);
 
-    g_idx = adjust_gain(sr, g_idx, nbits, nbits_budget);
+    g_idx = adjust_gain(sr, g_idx, nbits, nbits_budget, g_idx_min);
 
     return Py_BuildValue("i", g_idx);
 }