shithub: leaf

Download patch

ref: 635257887ab374a68acf386814df0c59aeec41a1
parent: ffa74901871dab0d6d96ba82414d800748cb01c1
author: Matthew Wang <mjw7@princeton.edu>
date: Fri Apr 24 16:58:20 EDT 2020

trying to fix sampler issues

--- a/LEAF/Inc/leaf-sampling.h
+++ b/LEAF/Inc/leaf-sampling.h
@@ -103,7 +103,7 @@
         
         int32_t start, targetstart;
         int32_t end, targetend;
-
+        
         uint32_t len;
         uint32_t cfxlen;
         float numticks;
@@ -112,6 +112,11 @@
         
         int active;
         
+        uint8_t inCrossfade;
+        
+        float flipStart;
+        float flipIdx;
+        
     } _tSampler;
     
     typedef _tSampler* tSampler;
@@ -132,10 +137,10 @@
     
     void    tSampler_setStart           (tSampler* const, int32_t start);
     void    tSampler_setEnd             (tSampler* const, int32_t end);
-
+    
     static void handleStartEndChange    (tSampler* const sp);
-
-    void 	tSampler_setCrossfadeLength (tSampler* const sp, uint32_t length);
+    
+    void     tSampler_setCrossfadeLength (tSampler* const sp, uint32_t length);
     
     void    tSampler_setRate            (tSampler* const, float rate);
     
--- a/LEAF/Src/leaf-sampling.c
+++ b/LEAF/Src/leaf-sampling.c
@@ -52,7 +52,7 @@
 {
     _tMempool* m = *mp;
     _tBuffer* s = *sb;
-
+    
     mpool_free(s->buff, m);
     mpool_free(s, m);
 }
@@ -194,6 +194,10 @@
     
     p->targetstart = -1;
     p->targetend = -1;
+    
+    p->inCrossfade = 0;
+    p->flipStart = -1;
+    p->flipIdx = -1;
 }
 
 void tSampler_freeFromPool         (tSampler* const sp, tMempool* const mp)
@@ -211,12 +215,12 @@
     _tBuffer* s = *b;
     
     p->samp = s;
-
+    
     p->start = 0;
     p->end = p->samp->bufferLength - 1;
-
+    
     p->len = p->end - p->start;
-
+    
     p->idx = 0.f;
 }
 
@@ -227,26 +231,22 @@
     _tSampler* p = *sp;
     
     if (p->active == 0)         return 0.f;
-
-    if ((p->inc == 0.0f) || (p->len == 0))
+    
+    if ((p->inc == 0.0f) || (p->len < 2))
     {
+        p->inCrossfade = 0;
         return p->last;
     }
-
+    
     attemptStartEndChange(sp);
-
-    float sample = 0.f;
-    float cfxsample = 0.f;
-    float numticks;
-    float g1 = 1.f, g2 = 0.f;
-
+    
+    float sample = 0.0f;
+    float cfxsample = 0.0f;
+    float crossfadeMix = 0.0f;
+    
     float* buff = p->samp->buff;
-
     
-
-    int idx, revidx;
-    float alpha, revalpha;
-
+    // Variables so start is also before end
     int32_t start = p->start;
     int32_t end = p->end;
     if (p->flip < 0)
@@ -254,185 +254,150 @@
         start = p->end;
         end = p->start;
     }
-
-
-
+    
+    // Get the direction and a reverse flag for some calcs
     int dir = p->bnf * p->dir * p->flip;
-    idx = (int) p->idx;
-    alpha = p->idx - idx;
+    int rev = 0;
+    if (dir < 0) rev = 1;
     
-    revidx = idx + 1;// we think this is because flooring on int works different when reading backwards
-    revalpha = 1.f - alpha;
+    // Get the current integer index and alpha for interpolation
+    int idx = (int) p->idx;
+    float alpha = rev + (p->idx - idx) * dir;
+    idx += rev;
     
+    // Get the indexes for interpolation
+    int i1 = idx-(1*dir);
+    int i2 = idx;
+    int i3 = idx+(1*dir);
+    int i4 = idx+(2*dir);
     
-
-
+    int length = p->samp->recordedLength;
     
+    // Wrap as needed
+    i1 = (i1 < length*rev) ? i1 + (length * (1-rev)) : i1 - (length * rev);
+    i2 = (i2 < length*rev) ? i2 + (length * (1-rev)) : i2 - (length * rev);
+    i3 = (i3 < length*(1-rev)) ? i3 + (length * rev) : i3 - (length * (1-rev));
+    i4 = (i4 < length*(1-rev)) ? i4 + (length * rev) : i4 - (length * (1-rev));
+    
+    sample = LEAF_interpolate_hermite_x (buff[i1],
+                                         buff[idx],
+                                         buff[i3],
+                                         buff[i4],
+                                         alpha);
+    
     uint32_t cfxlen = p->cfxlen;
-    if (p->len < cfxlen) cfxlen = p->len * 0.25f;//p->len;
+    if (p->len * 0.25f < cfxlen) cfxlen = p->len * 0.25f;
     
-    int length = p->samp->recordedLength;
+    // Determine crossfade points
+    uint32_t fadeLeftStart = 0;
+    if (start >= cfxlen) fadeLeftStart = start - cfxlen;
+    uint32_t fadeLeftEnd = fadeLeftStart + cfxlen;
     
-    if (dir > 0)
-    {			// num samples (hopping the increment size) to end of loop
-		numticks = (end-idx) * p->iinc;
-    }
-    else
+    uint32_t fadeRightEnd = end + (fadeLeftEnd - start);
+    if (fadeRightEnd >= length) fadeRightEnd = length - 1;
+    uint32_t fadeRightStart = fadeRightEnd - cfxlen;
+    
+    p->inCrossfade = 0;
+    if (p->mode == PlayLoop)
     {
-		numticks = (revidx-start) * p->iinc;
-    }
-
-	// Check dir (direction) to interpolate properly
-	if (dir > 0)
-	{
-		// FORWARD NORMAL SAMPLE
-		int i1 = ((idx-1) < 0) ? 0 : idx-1;
-		int i3 = ((idx+1) >= length) ? (idx) : (idx+1);
-		int i4 = ((idx+2) >= length) ? (length-1) : (idx+2);
-
-		sample =     LEAF_interpolate_hermite_x (buff[i1],
-											   buff[idx],
-											   buff[i3],
-											   buff[i4],
-											   alpha);
-
-		if (cfxlen > 0)// necessary to avoid divide by zero, also a waste of computation otherwise
-		{
-
-			if (p->mode == PlayLoop)
-			{
-
-
-
-				if (numticks <= (float) cfxlen)
-				{
-					// CROSSFADE SAMPLE
-					int cdx = start - (numticks * p->inc);
-					if (cdx < 1)
-					{
-						cdx = -cdx;
-
-						i1 = ((cdx+1) >= length) ? (length-1) : cdx+1;
-						i3 = ((cdx-1) < 0) ? cdx : (cdx-1);
-						i4 = ((cdx-2) < 0) ? 0 : (cdx-2);
-
-						cfxsample =     LEAF_interpolate_hermite_x (buff[i1],
-																  buff[cdx],
-																  buff[i3],
-																  buff[i4],
-																  revalpha);
-					}
-					else
-					{
-						i1 = ((cdx-1) < 0) ? 0 : cdx-1;
-						i3 = ((cdx+1) >= length) ? (cdx) : (cdx+1);
-						i4 = ((cdx+2) >= length) ? (length-1) : (cdx+2);
-
-						cfxsample =     LEAF_interpolate_hermite_x (buff[i1],
-																  buff[cdx],
-																  buff[i3],
-																  buff[i4],
-																  alpha);
-					}
-
-					g2 = (float) (cfxlen - numticks) / (float) cfxlen;
-
-				}
-
-			}
-		}
-	    else
-	    {
-	    	g2 = 0.0f;
-	    }
-
-	}
-	else
-	{
-		// REVERSE
-		int i1 = ((revidx+1) >= length) ? (length-1) : revidx+1;
-		int i3 = ((revidx-1) < 0) ? revidx : (revidx-1);
-		int i4 = ((revidx-2) < 0) ? 0 : (revidx-2);
-
-		sample =     LEAF_interpolate_hermite_x (buff[i1],
-											   buff[revidx],
-											   buff[i3],
-											   buff[i4],
-											   revalpha);
-
-
-
-		if (cfxlen > 0)// necessary to avoid divide by zero, also a waste of computation otherwise
-		{
-
-			if (p->mode == PlayLoop)
-			{
-				if (numticks <= (float) cfxlen)
-				{
-					// CROSSFADE SAMPLE
-					int cdx = end + (numticks * p->inc);
-					if (cdx > length - 2)
-					{
-
-						//the problem with the click is here --- at some point it crosses this threshold and jumps from a point near the boundary to a point far away from the boundary - that's not correct
-						///// ooooops
-
-						cdx = end - (numticks * p->inc);
-
-						i1 = ((cdx-1) < 0) ? 0 : cdx-1;
-						i3 = ((cdx+1) >= length) ? (cdx) : (cdx+1);
-						i4 = ((cdx+2) >= length) ? (length-1) : (cdx+2);
-
-						cfxsample =     LEAF_interpolate_hermite_x (buff[i1],
-																  buff[cdx],
-																  buff[i3],
-																  buff[i4],
-																  revalpha);
-					}
-					else
-					{
-						i1 = ((cdx+1) >= length) ? (length-1) : cdx+1;
-						i3 = ((cdx-1) < 0) ? cdx : (cdx-1);
-						i4 = ((cdx-2) < 0) ? 0 : (cdx-2);
-
-						cfxsample =     LEAF_interpolate_hermite_x (buff[i1],
-																  buff[cdx],
-																  buff[i3],
-																  buff[i4],
-																  alpha);
-					}
-					g2 = (float) (cfxlen - numticks) / (float) cfxlen;
-				}
-
-			}
-		}
-	    else
-	    {
-	    	g2 = 0.0f;
-	    }
-
-	}
-
-
+        float flipLength = fabsf(p->flipIdx - p->flipStart);
+        if (flipLength > cfxlen)
+        {
+            p->flipStart = -1;
+            p->flipIdx = -1;
+        }
+        if (p->flipIdx >= 0)
+        {
+            if (p->flipStart == -1)
+            {
+                p->flipStart = p->idx;
+                p->flipIdx = p->idx;
+            }
+            flipLength = fabsf(p->flipIdx - p->flipStart);
+            
+            int fdx = (int) p->flipIdx;
+            float falpha = (1-rev) - (p->flipIdx - fdx) * dir;
+            idx += (1-rev);
+            
+            // Get the indexes for interpolation
+            int f1 = fdx+(1*dir);
+            int f2 = fdx;
+            int f3 = fdx-(1*dir);
+            int f4 = fdx-(2*dir);
+            
+            // Wrap as needed
+            f1 = (f1 < length*(1-rev)) ? f1 + (length * rev) : f1 - (length * (1-rev));
+            f2 = (f2 < length*(1-rev)) ? f2 + (length * rev) : f2 - (length * (1-rev));
+            f3 = (f3 < length*rev) ? f3 + (length * (1-rev)) : f3 - (length * rev);
+            f4 = (f4 < length*rev) ? f4 + (length * (1-rev)) : f4 - (length * rev);
+            
+            cfxsample = LEAF_interpolate_hermite_x (buff[f1],
+                                                    buff[fdx],
+                                                    buff[f3],
+                                                    buff[f4],
+                                                    falpha);
+            crossfadeMix = (float) (cfxlen - flipLength) / (float) cfxlen;
+        }
+        else
+        {
+            int offset = 0;
+            int cdx = 0;
+            if ((fadeLeftStart <= idx) && (idx <= fadeLeftEnd))
+            {
+                offset = fadeLeftEnd - idx;
+                cdx = fadeRightEnd - offset;
+                p->inCrossfade = 1;
+            }
+            else if ((fadeRightStart <= idx) && (idx <= fadeRightEnd))
+            {
+                offset = idx - fadeRightStart;
+                cdx = fadeLeftStart + offset;
+                p->inCrossfade = 1;
+            }
+            
+            if (p->inCrossfade)
+            {
+                int c1 = cdx-(1*dir);
+                int c2 = cdx;
+                int c3 = cdx+(1*dir);
+                int c4 = cdx+(2*dir);
+                
+                // Wrap as needed
+                c1 = (c1 < length * rev) ? c1 + (length * (1-rev)) : c1 - (length * rev);
+                c2 = (c2 < length * rev) ? c2 + (length * (1-rev)) : c2 - (length * rev);
+                c3 = (c3 < length * (1-rev)) ? c3 + (length * rev) : c3 - (length * (1-rev));
+                c4 = (c4 < length * (1-rev)) ? c4 + (length * rev) : c4 - (length * (1-rev));
+                
+                cfxsample = LEAF_interpolate_hermite_x (buff[c1],
+                                                        buff[c2],
+                                                        buff[c3],
+                                                        buff[c4],
+                                                        alpha);
+                crossfadeMix = (float) offset / (float) cfxlen;
+            }
+        }
+    }
     
     float inc = fmod(p->inc, p->len);
     p->idx += (dir * inc);
-
-    //handle start and end cases for looping and back and forth modes
+    if (p->flipIdx >= 0)
+    {
+        p->flipIdx += (-dir * inc);
+    }
+    
     if (p->mode == PlayLoop)
     {
-
-        while((int)p->idx < start)
+        if((int)p->idx < start)
         {
-            p->idx += (float)(p->len);
+            p->idx += (float)(fadeRightEnd - fadeLeftEnd);
         }
-        while((int)p->idx > end)
+        if((int)p->idx > end)
         {
-
-            p->idx -= (float)(p->len);
+            
+            p->idx -= (float)(fadeRightEnd - fadeLeftEnd);
         }
     }
-    else // == PlayBackAndForth
+    else if (p->mode == PlayBackAndForth)
     {
         if (p->idx < start)
         {
@@ -445,21 +410,18 @@
             p->idx = end - 1;
         }
     }
-
-
-    //handle very short fade out for end of one-shot normal playback
+    
+    float ticksToEnd = rev ? ((idx - start) * p->iinc) : ((end - idx) * p->iinc);
     if (p->mode == PlayNormal)
     {
-        if (numticks < (0.007f * leaf.sampleRate))
+        if (ticksToEnd < (0.007f * leaf.sampleRate))
         {
             tRamp_setDest(&p->gain, 0.f);
             p->active = -1;
         }
     }
-
-    g1 = 1.f - g2;
     
-    sample = sample * g1 + cfxsample * g2;
+    sample = (sample * (1.0f - crossfadeMix)) + (cfxsample * crossfadeMix);
     
     sample = sample * tRamp_tick(&p->gain);
     
@@ -491,15 +453,15 @@
             
         }
     }
-
+    
     if (fabsf(sample-p->last) > 0.1f)
     {
-    	errorState = 1;
+        errorState = 1;
     }
-
+    
     p->last = sample;
     
-
+    
     return p->last;
 }
 
@@ -513,10 +475,8 @@
 {
     _tSampler* p = *sp;
     
-    uint32_t cfxlen = LEAF_clip(0, length, 1000);
+    uint32_t cfxlen = LEAF_clip(0, length, p->len * 0.25f);
     
-    if (cfxlen > (p->len * 0.25f))  cfxlen = p->len * 0.25f;
-    
     p->cfxlen = cfxlen;
 }
 
@@ -564,11 +524,11 @@
 static void handleStartEndChange(tSampler* const sp)
 {
     _tSampler* p = *sp;
-
+    
     p->len = abs(p->end - p->start);
-
-    if (p->len < (p->cfxlen * 0.25f)) p->cfxlen = p->len * 0.25f;
-
+    
+    if (p->cfxlen > (p->len * 0.25f)) p->cfxlen = p->len * 0.25f;
+    
     if (p->start > p->end)
     {
         p->flip = -1;
@@ -597,15 +557,15 @@
 void tSampler_setStart     (tSampler* const sp, int32_t start)
 {
     _tSampler* p = *sp;
-
+    
     int tempflip;
     if (start == p->end)
     {
-    	return;
+        return;
     }
-   // if (p->active)
+    // if (p->active)
     {
-
+        
         if (start > p->end)
         {
             tempflip = -1;
@@ -614,12 +574,20 @@
         {
             tempflip = 1;
         }
-
-    	int dir = p->bnf * p->dir * tempflip;
-        uint32_t cfxlen = (p->len < p->cfxlen) ? 0 : p->cfxlen;
+        
+        int dir = p->bnf * p->dir * tempflip;
+        
+        uint32_t cfxlen = p->cfxlen;
+        if (p->len * 0.25f < cfxlen) cfxlen = p->len * 0.25f;
+        
+        if (p->inCrossfade)
+        {
+            p->targetstart = start;
+            return;
+        }
         if ((tempflip > 0) && (dir > 0)) // start is start and we're playing forward
         {
-            if (((start > p->idx) || (p->end-p->idx <= cfxlen)) && (start > p->end))// start given is after current index or we're in a crossfade
+            if (start > p->idx)// start given is after current index or we're in a crossfade
             {
                 p->targetstart = start;
                 return;
@@ -627,7 +595,7 @@
         }
         else if ((tempflip < 0) && (dir < 0)) // start is end and we're playing in reverse
         {
-            if (((start < p->idx) || (p->idx-p->end <= cfxlen)) && (start < p->end))// start given is before current index or we're in a crossfade
+            if (start < p->idx)// start given is before current index or we're in a crossfade
             {
                 p->targetstart = start;
                 return;
@@ -634,27 +602,29 @@
             }
         }
     }
-
-	p->start = LEAF_clipInt(0, start, p->samp->recordedLength - 1);
-	handleStartEndChange(sp);
-	p->targetstart = -1;
-
+    
+    if (tempflip != p->flip && p->flipIdx < 0) p->flipIdx = 0;
+    
+    p->start = LEAF_clipInt(0, start, p->samp->recordedLength - 1);
+    handleStartEndChange(sp);
+    p->targetstart = -1;
+    
 }
 
 void tSampler_setEnd       (tSampler* const sp, int32_t end)
 {
     _tSampler* p = *sp;
-
+    
     int tempflip;
-
+    
     if (end == p->start)
     {
-    	return;
+        return;
     }
     //if (p->active)
     {
-
-
+        
+        
         if (p->start > end)
         {
             tempflip = -1;
@@ -661,13 +631,22 @@
         }
         else
         {
-        	tempflip = 1;
+            tempflip = 1;
         }
-    	int dir = p->bnf * p->dir * tempflip;
-        uint32_t cfxlen = (p->len < p->cfxlen) ? 0 : p->cfxlen;
+        
+        int dir = p->bnf * p->dir * tempflip;
+        
+        uint32_t cfxlen = p->cfxlen;
+        if (p->len * 0.25f < cfxlen) cfxlen = p->len * 0.25f;
+        
+        if (p->inCrossfade)
+        {
+            p->targetend = end;
+            return;
+        }
         if (tempflip > 0 && dir < 0) // end is end and we're playing in reverse
         {
-            if (((end < p->idx) || (p->idx-p->start <= cfxlen)) && (end < p->start)) // end given is before current index or we're in a crossfade
+            if (end < p->idx) // end given is before current index or we're in a crossfade
             {
                 p->targetend = end;
                 return;
@@ -675,7 +654,7 @@
         }
         else if (tempflip < 0 && dir > 0) // end is start and we're playing forward
         {
-            if (((end > p->idx) || (p->start-p->idx <= cfxlen)) && (end > p->start)) // end given is after current index or we're in a crossfade
+            if (end > p->idx) // end given is after current index or we're in a crossfade
             {
                 p->targetend = end;
                 return;
@@ -682,6 +661,9 @@
             }
         }
     }
+    
+    if (tempflip != p->flip && p->flipIdx < 0) p->flipIdx = 0;
+    
     p->end = LEAF_clipInt(0, end, (p->samp->recordedLength - 1));
     handleStartEndChange(sp);
     p->targetend = -1;
@@ -700,7 +682,7 @@
     {
         p->dir = 1;
     }
-
+    
     p->inc = rate;
     p->iinc = 1.f / p->inc;
 }