shithub: leaf

Download patch

ref: 74dc8f99954d1a1543ebfa33c1a4e2f70b9fbb31
parent: 3eca39b695e0bd406858823fa977cb74e1936730
author: Matthew Wang <mjw7@princeton.edu>
date: Fri Sep 25 13:29:55 EDT 2020

negative frequency support for all mb oscs and sync fixes

--- a/TestPlugin/Source/MyTest.cpp
+++ b/TestPlugin/Source/MyTest.cpp
@@ -55,9 +55,11 @@
     LEAF_init(&leaf, sampleRate, blockSize, memory, MSIZE, &getRandomFloat);
     
     tMBSaw_init(&bsaw, &leaf);
-    tMBSaw_setFreq(&bsaw, -500);
+    tMBSaw_setFreq(&bsaw, 100);
     tMBTriangle_init(&btri, &leaf);
+    tMBTriangle_setFreq(&btri, 200);
     tMBPulse_init(&bpulse, &leaf);
+    tMBPulse_setFreq(&bpulse, -500);
     
     bufIn = (float*) leaf_alloc(&leaf, sizeof(float) * 4096);
     bufOut = (float*) leaf_alloc(&leaf, sizeof(float) * 4096);
@@ -99,8 +101,9 @@
 //
 //    return tMBSampler_tick(&sampler);
     
+    tMBTriangle_tick(&btri);
+    tMBSaw_syncIn(&bsaw, tMBTriangle_syncOut(&btri));
     return tMBSaw_tick(&bsaw);
-    
     
 //    tMBSaw_setFreq(&bsaw, x);
 //    tMBTriangle_setFreq(&btri, x);
--- a/leaf/Src/leaf-oscillators.c
+++ b/leaf/Src/leaf-oscillators.c
@@ -921,7 +921,7 @@
     
     int    j, k;
     float  freq, syncin;
-    float  a, b, db, p, t, w, dw, x, z;
+    float  a, b, db, p, tw, tb, w, dw, x, z;
     
     syncin  = c->syncin;
     freq = c->freq;
@@ -937,11 +937,21 @@
         p = 0.0f;
         
         w = freq / leaf->sampleRate;
-        if (w < 1e-5f) w = 1e-5f;
-        if (w > 0.5f) w = 0.5f;
         b = 0.5f * (1.0f + c->waveform );
-        if (b < w) b = w;
-        if (b > 1.0f - w) b = 1.0f - w;
+        if (w >= 0)
+        {
+            if (w < 1e-5f) w = 1e-5f;
+            if (w > 0.5f) w = 0.5f;
+            if (b < w) b = w;
+            if (b > 1.0f - w) b = 1.0f - w;
+        }
+        else
+        {
+            if (w > -1e-5f) w = -1e-5f;
+            if (w < -0.5f) w = -0.5f;
+            if (b < -w) b = -w;
+            if (b > 1.0f + w) b = 1.0f + w;
+        }
         /* for variable-width rectangular wave, we could do DC compensation with:
          *     x = 1.0f - b;
          * but that doesn't work well with highly modulated hard sync.  Instead,
@@ -957,15 +967,33 @@
     //    a = 0.2 + 0.8 * vco->_port [FILT];
     a = 0.5f; // when a = 1, LPfilter is disabled
     
-    t = freq / leaf->sampleRate;
-    if (t < 1e-5f) t = 1e-5f;
-    if (t > 0.5f) t = 0.5f;
-    dw = (t - w) ;
-    t = 0.5f * (1.0f + c->waveform );
-    if (t < w) t = w;
-    if (t > 1.0f - w) t = 1.0f - w;
-    db = (t - b) ;
+    tw = freq / leaf->sampleRate;
+    if (tw >= 0)
+    {
+        if (tw < 1e-5f) tw = 1e-5f;
+        if (tw > 0.5f) tw = 0.5f;
+    }
+    else
+    {
+        if (tw > -1e-5f) tw = -1e-5f;
+        if (tw < -0.5f) tw = -0.5f;
+    }
     
+    tb = 0.5f * (1.0f + c->waveform);
+    if (w >= 0)
+    {
+        if (tb < w) tb = w;
+        if (tb > 1.0f - w) tb = 1.0f - w;
+    }
+    else
+    {
+        if (tb < -w) tb = -w;
+        if (tb > 1.0f + w) tb = 1.0f + w;
+    }
+    
+    dw = (tw - w);
+    db = (tb - b);
+    
     w += dw;
     b += db;
     p += w;
@@ -974,81 +1002,174 @@
         //
         float eof_offset = (syncin - 1e-20f) * w;
         float p_at_reset = p - eof_offset;
-        p = eof_offset;
+    
+        if (w > 0) p = eof_offset;
+        else p = 1.0f - eof_offset;
         
         /* place any DDs that may have occurred in subsample before reset */
         if (!k) {
-            if (p_at_reset >= b) {
-                place_step_dd(c->_f, j, p_at_reset - b + eof_offset, w, -1.0f);
-                k = 1;
-                x = -0.5f;
+            if (w > 0)
+            {
+                if (p_at_reset >= b) {
+                    place_step_dd(c->_f, j, p_at_reset - b + eof_offset, w, -1.0f);
+                    k = 1;
+                    x = -0.5f;
+                }
+                if (p_at_reset >= 1.0f) {
+                    p_at_reset -= 1.0f;
+                    place_step_dd(c->_f, j, p_at_reset + eof_offset, w, 1.0f);
+                    k = 0;
+                    x = 0.5f;
+                }
             }
-            if (p_at_reset >= 1.0f) {
-                p_at_reset -= 1.0f;
-                place_step_dd(c->_f, j, p_at_reset + eof_offset, w, 1.0f);
-                k = 0;
-                x = 0.5f;
+            else
+            {
+                if (p_at_reset < 0.0f) {
+                    p_at_reset += 1.0f;
+                    place_step_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -w, -1.0f);
+                    k = 1;
+                    x = -0.5f;
+                }
+                if (k && p_at_reset < b) {
+                    place_step_dd(c->_f, j, b - p_at_reset - eof_offset, -w, 1.0f);
+                    k = 0;
+                    x = 0.5f;
+                }
             }
         } else {
-            if (p_at_reset >= 1.0f) {
-                p_at_reset -= 1.0f;
-                place_step_dd(c->_f, j, p_at_reset + eof_offset, w, 1.0f);
+            if (w > 0)
+            {
+                if (p_at_reset >= 1.0f) {
+                    p_at_reset -= 1.0f;
+                    place_step_dd(c->_f, j, p_at_reset + eof_offset, w, 1.0f);
+                    k = 0;
+                    x = 0.5f;
+                }
+                if (!k && p_at_reset >= b) {
+                    place_step_dd(c->_f, j, p_at_reset - b + eof_offset, w, -1.0f);
+                    k = 1;
+                    x = -0.5f;
+                }
+            }
+            else
+            {
+                if (p_at_reset < b) {
+                    place_step_dd(c->_f, j, b - p_at_reset - eof_offset, -w, 1.0f);
+                    k = 0;
+                    x = 0.5f;
+                }
+                if (p_at_reset < 0.0f) {
+                    p_at_reset += 1.0f;
+                    place_step_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -w, -1.0f);
+                    k = 1;
+                    x = -0.5f;
+                }
+            }
+        }
+        
+        /* now place reset DD */
+        if (w > 0)
+        {
+            if (k) {
+                place_step_dd(c->_f, j, p, w, 1.0f);
                 k = 0;
                 x = 0.5f;
             }
-            if (!k && p_at_reset >= b) {
-                place_step_dd(c->_f, j, p_at_reset - b + eof_offset, w, -1.0f);
+            if (p >= b) {
+                place_step_dd(c->_f, j, p - b, w, -1.0f);
                 k = 1;
                 x = -0.5f;
             }
         }
-        
-        /* now place reset DD */
-        if (k) {
-            place_step_dd(c->_f, j, p, w, 1.0f);
-            k = 0;
-            x = 0.5f;
+        else
+        {
+            if (!k) {
+                place_step_dd(c->_f, j, 1.0f - p, -w, -1.0f);
+                k = 1;
+                x = -0.5f;
+            }
+            if (p < b) {
+                place_step_dd(c->_f, j, b - p, -w, 1.0f);
+                k = 0;
+                x = 0.5f;
+            }
         }
-        if (p >= b) {
-            place_step_dd(c->_f, j, p - b, w, -1.0f);
-            k = 1;
-            x = -0.5f;
-        }
         
         c->syncout = syncin;  /* best we can do is pass on upstream sync */
         
     } else if (!k) {  /* normal operation, signal currently high */
         
-        if (p >= b) {
-            place_step_dd(c->_f, j, p - b, w, -1.0f);
-            k = 1;
-            x = -0.5f;
+        if (w > 0)
+        {
+            if (p >= b) {
+                place_step_dd(c->_f, j, p - b, w, -1.0f);
+                k = 1;
+                x = -0.5f;
+            }
+            if (p >= 1.0f) {
+                p -= 1.0f;
+                c->syncout = p / w + 1e-20f;
+                place_step_dd(c->_f, j, p, w, 1.0f);
+                k = 0;
+                x = 0.5f;
+            } else {
+                c->syncout = 0.0f;
+            }
         }
-        if (p >= 1.0f) {
-            p -= 1.0f;
-            c->syncout = p / w + 1e-20f;
-            place_step_dd(c->_f, j, p, w, 1.0f);
-            k = 0;
-            x = 0.5f;
-        } else {
-            c->syncout = 0.0f;
+        else
+        {
+            if (p < 0.0f) {
+                p += 1.0f;
+                c->syncout = p / -w + 1e-20f;
+                place_step_dd(c->_f, j, 1.0f - p, -w, -1.0f);
+                k = 1;
+                x = -0.5f;
+            } else {
+                c->syncout = 0.0f;
+            }
+            if (k && p < b) {
+                place_step_dd(c->_f, j, b - p, -w, 1.0f);
+                k = 0;
+                x = 0.5f;
+            }
         }
         
     } else {  /* normal operation, signal currently low */
         
-        if (p >= 1.0f) {
-            p -= 1.0f;
-            c->syncout = p / w + 1e-20f;
-            place_step_dd(c->_f, j, p, w, 1.0f);
-            k = 0;
-            x = 0.5f;
-        } else {
-            c->syncout = 0.0f;
+        if (w > 0)
+        {
+            if (p >= 1.0f) {
+                p -= 1.0f;
+                c->syncout = p / w + 1e-20f;
+                place_step_dd(c->_f, j, p, w, 1.0f);
+                k = 0;
+                x = 0.5f;
+            } else {
+                c->syncout = 0.0f;
+            }
+            if (!k && p >= b) {
+                place_step_dd(c->_f, j, p - b, w, -1.0f);
+                k = 1;
+                x = -0.5f;
+            }
         }
-        if (!k && p >= b) {
-            place_step_dd(c->_f, j, p - b, w, -1.0f);
-            k = 1;
-            x = -0.5f;
+        else
+        {
+            if (p < b) {
+                place_step_dd(c->_f, j, b - p, -w, 1.0f);
+                k = 0;
+                x = 0.5f;
+            }
+            if (p < 0.0f) {
+                p += 1.0f;
+                c->syncout = p / -w + 1e-20f;
+                place_step_dd(c->_f, j, 1.0f - p, -w, -1.0f);
+                k = 1;
+                x = -0.5f;
+            } else {
+                c->syncout = 0.0f;
+            }
+            
         }
     }
     c->_f[j + DD_SAMPLE_DELAY] += x;
@@ -1134,7 +1255,7 @@
     
     int    j, k;
     float  freq, syncin;
-    float  a, b, b1, db, p, t, w, dw, x, z;
+    float  a, b, b1, db, p, tw, tb, w, dw, x, z;
     
     syncin  = c->syncin;
     freq = c->freq;
@@ -1149,11 +1270,22 @@
         //        w = (exp2ap (freq[1] + vco->_port[OCTN] + vco->_port[TUNE] + expm[1] * vco->_port[EXPG] + 8.03136)
         //                + 1e3 * linm[1] * vco->_port[LING]) / SAMPLERATE;
         w = freq / leaf->sampleRate;
-        if (w < 1e-5f) w = 1e-5f;
-        if (w > 0.5f) w = 0.5f;
         b = 0.5f * (1.0f + c->waveform);
-        if (b < w) b = w;
-        if (b > 1.0f - w) b = 1.0f - w;
+        if (w >= 0)
+        {
+            if (w < 1e-5f) w = 1e-5f;
+            if (w > 0.5f) w = 0.5f;
+            if (b < w) b = w;
+            if (b > 1.0f - w) b = 1.0f - w;
+        }
+        else
+        {
+            if (w > -1e-5f) w = -1e-5f;
+            if (w < -0.5f) w = -0.5f;
+            if (b < -w) b = -w;
+            if (b > 1.0f + w) b = 1.0f + w;
+        }
+        
         p = 0.5f * b;
         /* if we valued alias-free startup over low startup time, we could do:
          *   p -= w;
@@ -1165,24 +1297,32 @@
     //    a = 0.2 + 0.8 * vco->_port [FILT];
     a = 0.5f; // when a = 1, LPfilter is disabled
     
-    t = freq / leaf->sampleRate;
+    tw = freq / leaf->sampleRate;
+    if (tw >= 0)
+    {
+        if (tw < 1e-5f) tw = 1e-5f;
+        if (tw > 0.5f) tw = 0.5f;
+    }
+    else
+    {
+        if (tw > -1e-5f) tw = -1e-5f;
+        if (tw < -0.5f) tw = -0.5f;
+    }
     
-    if (t >= 0)
+    tb = 0.5f * (1.0f + c->waveform);
+    if (w >= 0)
     {
-        if (t < 1e-5f) t = 1e-5f;
-        if (t > 0.5f) t = 0.5f;
+        if (tb < w) tb = w;
+        if (tb > 1.0f - w) tb = 1.0f - w;
     }
     else
     {
-        if (t > -1e-5f) t = -1e-5f;
-        if (t < -0.5f) t = -0.5f;
+        if (tb < -w) tb = -w;
+        if (tb > 1.0f + w) tb = 1.0f + w;
     }
     
-    dw = (t - w);
-    t = 0.5f * (1.0f + c->waveform );
-    if (t < w) t = w;
-    if (t > 1.0f - w) t = 1.0f - w;
-    db = (t - b);
+    dw = (tw - w);
+    db = (tb - b);
     
     w += dw;
     b += db;
@@ -1193,84 +1333,178 @@
         
         float eof_offset = (syncin - 1e-20f) * w;
         float p_at_reset = p - eof_offset;
-        p = eof_offset;
+        
+        if (w > 0) p = eof_offset;
+        else p = 1.0f - eof_offset;
         //
         /* place any DDs that may have occurred in subsample before reset */
+            
         if (!k) {
             x = -0.5f + p_at_reset / b;
-            if (p_at_reset >= b) {
-                x = 0.5f - (p_at_reset - b) / b1;
-                place_slope_dd(c->_f, j, p_at_reset - b + eof_offset, w, -1.0f / b1 - 1.0f / b);
-                k = 1;
+            if (w > 0)
+            {
+                if (p_at_reset >= b) {
+                    x = 0.5f - (p_at_reset - b) / b1;
+                    place_slope_dd(c->_f, j, p_at_reset - b + eof_offset, w, -1.0f / b1 - 1.0f / b);
+                    k = 1;
+                }
+                if (p_at_reset >= 1.0f) {
+                    p_at_reset -= 1.0f;
+                    x = -0.5f + p_at_reset / b;
+                    place_slope_dd(c->_f, j, p_at_reset + eof_offset, w, 1.0f / b + 1.0f / b1);
+                    k = 0;
+                }
             }
-            if (p_at_reset >= 1.0f) {
-                p_at_reset -= 1.0f;
-                x = -0.5f + p_at_reset / b;
-                place_slope_dd(c->_f, j, p_at_reset + eof_offset, w, 1.0f / b + 1.0f / b1);
-                k = 0;
+            else
+            {
+                if (p_at_reset < 0.0f) {
+                    p_at_reset += 1.0f;
+                    x = 0.5f - (p_at_reset - b) / b1;
+                    place_slope_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -w, 1.0f / b + 1.0f / b1);
+                    k = 1;
+                }
+                if (k && p_at_reset < b) {
+                    x = -0.5f + p_at_reset / b;
+                    place_slope_dd(c->_f, j, b - p_at_reset - eof_offset, -w, -1.0f / b1 - 1.0f / b);
+                    k = 0;
+                }
             }
         } else {
             x = 0.5f - (p_at_reset - b) / b1;
-            if (p_at_reset >= 1.0f) {
-                p_at_reset -= 1.0f;
-                x = -0.5f + p_at_reset / b;
-                place_slope_dd(c->_f, j, p_at_reset + eof_offset, w, 1.0f / b + 1.0f / b1);
-                k = 0;
+            if (w > 0)
+            {
+                if (p_at_reset >= 1.0f) {
+                    p_at_reset -= 1.0f;
+                    x = -0.5f + p_at_reset / b;
+                    place_slope_dd(c->_f, j, p_at_reset + eof_offset, w, 1.0f / b + 1.0f / b1);
+                    k = 0;
+                }
+                if (!k && p_at_reset >= b) {
+                    x = 0.5f - (p_at_reset - b) / b1;
+                    place_slope_dd(c->_f, j, p_at_reset - b + eof_offset, w, -1.0f / b1 - 1.0f / b);
+                    k = 1;
+                }
             }
-            if (!k && p_at_reset >= b) {
-                x = 0.5f - (p_at_reset - b) / b1;
-                place_slope_dd(c->_f, j, p_at_reset - b + eof_offset, w, -1.0f / b1 - 1.0f / b);
-                k = 1;
+            else
+            {
+                if (p_at_reset < b) {
+                    x = -0.5f + p_at_reset / b;
+                    place_slope_dd(c->_f, j, b - p_at_reset - eof_offset, -w, -1.0f / b1 - 1.0f / b);
+                    k = 0;
+                }
+                if (p_at_reset < 0.0f) {
+                    p_at_reset += 1.0f;
+                    x = 0.5f - (p_at_reset - b) / b1;
+                    place_slope_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -w, 1.0f / b + 1.0f / b1);
+                    k = 1;
+                }
             }
         }
         
         /* now place reset DDs */
-        if (k)
-            place_slope_dd(c->_f, j, p, w, 1.0f / b + 1.0f / b1);
-        place_step_dd(c->_f, j, p, w, -0.5f - x);
-        x = -0.5f + p / b;
-        k = 0;
-        if (p >= b) {
+        if (w > 0)
+        {
+            if (k)
+                place_slope_dd(c->_f, j, p, w, 1.0f / b + 1.0f / b1);
+            place_step_dd(c->_f, j, p, w, -0.5f - x);
+            x = -0.5f + p / b;
+            k = 0;
+            if (p >= b) {
+                x = 0.5f - (p - b) / b1;
+                place_slope_dd(c->_f, j, p - b, w, -1.0f / b1 - 1.0f / b);
+                k = 1;
+            }
+        }
+        else
+        {
+            if (!k)
+                place_slope_dd(c->_f, j, 1.0f - p, -w, 1.0f / b + 1.0f / b1);
+            place_step_dd(c->_f, j, 1.0f - p, -w, -0.5f - x);
             x = 0.5f - (p - b) / b1;
-            place_slope_dd(c->_f, j, p - b, w, -1.0f / b1 - 1.0f / b);
             k = 1;
+            if (p < b) {
+                x = -0.5f + p / b;
+                place_slope_dd(c->_f, j, b - p, -w, -1.0f / b1 - 1.0f / b);
+                k = 0;
+            }
         }
+        
         c->syncout = syncin;  /* best we can do is pass on upstream sync */
         
     } else if (!k) {  /* normal operation, slope currently up */
         
         x = -0.5f + p / b;
-        if (p >= b) {
-            x = 0.5f - (p - b) / b1;
-            place_slope_dd(c->_f, j, p - b, w, -1.0f / b1 - 1.0f / b);
-            k = 1;
+        if (w > 0)
+        {
+            if (p >= b) {
+                x = 0.5f - (p - b) / b1;
+                place_slope_dd(c->_f, j, p - b, w, -1.0f / b1 - 1.0f / b);
+                k = 1;
+            }
+            if (p >= 1.0f) {
+                p -= 1.0f;
+                c->syncout = p / w + 1e-20f;
+                x = -0.5f + p / b;
+                place_slope_dd(c->_f, j, p, w, 1.0f / b + 1.0f / b1);
+                k = 0;
+            } else {
+                c->syncout = 0.0f;
+            }
         }
-        if (p >= 1.0f) {
-            p -= 1.0f;
-            c->syncout = p / w + 1e-20f;
-            x = -0.5f + p / b;
-            place_slope_dd(c->_f, j, p, w, 1.0f / b + 1.0f / b1);
-            k = 0;
-        } else {
-            c->syncout = 0.0f;
+        else
+        {
+            if (p < 0.0f) {
+                p += 1.0f;
+                c->syncout = p / -w + 1e-20f;
+                x = 0.5f - (p - b) / b1;
+                place_slope_dd(c->_f, j, 1.0f - p, -w, 1.0f / b + 1.0f / b1);
+                k = 1;
+            } else {
+                c->syncout = 0.0f;
+            }
+            if (k && p < b) {
+                x = -0.5f + p / b;
+                place_slope_dd(c->_f, j, b - p, -w, -1.0f / b1 - 1.0f / b);
+                k = 0;
+            }
         }
         
     } else {  /* normal operation, slope currently down */
         
         x = 0.5f - (p - b) / b1;
-        if (p >= 1.0f) {
-            p -= 1.0f;
-            c->syncout = p / w + 1e-20f;
-            x = -0.5f + p / b;
-            place_slope_dd(c->_f, j, p, w, 1.0f / b + 1.0f / b1);
-            k = 0;
-        } else {
-            c->syncout = 0.0f;
+        if (w > 0)
+        {
+            if (p >= 1.0f) {
+                p -= 1.0f;
+                c->syncout = p / w + 1e-20f;
+                x = -0.5f + p / b;
+                place_slope_dd(c->_f, j, p, w, 1.0f / b + 1.0f / b1);
+                k = 0;
+            } else {
+                c->syncout = 0.0f;
+            }
+            if (!k && p >= b) {
+                x = 0.5f - (p - b) / b1;
+                place_slope_dd(c->_f, j, p - b, w, -1.0f / b1 - 1.0f / b);
+                k = 1;
+            }
         }
-        if (!k && p >= b) {
-            x = 0.5f - (p - b) / b1;
-            place_slope_dd(c->_f, j, p - b, w, -1.0f / b1 - 1.0f / b);
-            k = 1;
+        else
+        {
+            if (p < b) {
+                x = -0.5f + p / b;
+                place_slope_dd(c->_f, j, b - p, -w, -1.0f / b1 - 1.0f / b);
+                k = 0;
+            }
+            if (p < 0.0f) {
+                p += 1.0f;
+                c->syncout = p / -w + 1e-20f;
+                x = 0.5f - (p - b) / b1;
+                place_slope_dd(c->_f, j, 1.0f - p, -w, 1.0f / b + 1.0f / b1);
+                k = 1;
+            } else {
+                c->syncout = 0.0f;
+            }
         }
     }
     c->_f[j + DD_SAMPLE_DELAY] += x;
@@ -1409,16 +1643,25 @@
         
         float eof_offset = (syncin - 1e-20f) * w;
         float p_at_reset = p - eof_offset;
-        p = eof_offset;
         
+        if (w > 0) p = eof_offset;
+        else p = 1.0f - eof_offset;
+        
         /* place any DD that may have occurred in subsample before reset */
         if (p_at_reset >= 1.0f) {
             p_at_reset -= 1.0f;
             place_step_dd(c->_f, j, p_at_reset + eof_offset, w, 1.0f);
         }
+        if (p_at_reset < 0.0f) {
+            p_at_reset += 1.0f;
+            place_step_dd(c->_f, j, 1.0f - p_at_reset - eof_offset, -w, -1.0f);
+        }
         
         /* now place reset DD */
-        place_step_dd(c->_f, j, p, w, p_at_reset);
+        if (w > 0)
+            place_step_dd(c->_f, j, p, w, p_at_reset);
+        else
+            place_step_dd(c->_f, j, 1.0f - p, -w, -p_at_reset);
         
         c->syncout = syncin;  /* best we can do is pass on upstream sync */
         
@@ -1430,7 +1673,7 @@
         
     } else if (p < 0.0f) {
         p += 1.0f;
-        c->syncout = p / w + 1e-20f;
+        c->syncout = p / -w + 1e-20f;
         place_step_dd(c->_f, j, 1.0f - p, -w, -1.0f);
     }
     else {