desc:Separate sinusoids, noise, transients (mono) // Version 0.1 // Written by Olli Niemitalo (o@iki.fi), 2016 // License: Do What the Fuck You Want to Public License. // // This effect separates sinusoidal, noise and transient // components of audio. It works on mono input so you need two // of these for stereo. @init function memAdd(dest, source, length) ( loop(length, dest[] = dest[] + source[]; dest += 1; source += 1; ); ); function memWindowedAdd(dest, source, win, length) ( loop(length, dest[] += source[]*win[]; dest += 1; source += 1; win += 1; ); ); function memWindowedCopy(dest, source, win, length) ( loop(length, dest[] = source[]*win[]; dest += 1; source += 1; win += 1; ); ); stepSize = 1; windowSize = 64; transformSize = 128; decay = 0.9; tDecay = 0.98; tempBuf = 0; // Length = transformSize thresholds = tempBuf + transformSize; // Length = transformSize/2 thresholds2 = thresholds + transformSize/2; // Length = transformSize/2 inBuf = thresholds2 + transformSize/2; // Length = windowSize accuBuf = inBuf + windowSize; // Length = windowSize window = accuBuf + windowSize; // Length = windowSize power = window + windowSize; // Length = transformSize/2 filtPower = power + transformSize/2; // Length = transformSize/2 k = 1; loop (transformSize/2, thresholds[k] = 0.9*pow(k, -0.25); thresholds2[k] = thresholds[k]^2; k += 1; ); thresholds[0] = thresholds[1]; k = 0; loop (windowSize, window[k] = sin($pi*k/windowSize)*sqrt(0.5/transformSize); // window[k] = (0.355768 - 0.487396*cos(2*$pi*k/windowSize) + 0.144232*cos(2*$pi*k/windowSize) - 0.012604*cos(3*$pi*k/windowSize))*sqrt(0.5/transformSize); k += 1; ); scale = stepSize/windowSize*2;///2.046633324; i = 0; // Sample index inside inBuf j = 0; // Sample index inside accuBuf nextStep = stepSize; @sample inBuf[i] = spl0; spl0 = accuBuf[i]*scale;// 2.046633324; i += 1; i === nextStep ? ( // We have enough data to do another transform // i windowSize transformSize // | | | // inbuf: AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD | // tempBuf: BBBBBBBBCCCCCCCCDDDDDDDDEEEEEEEE00000000000000000000000000000000 memset(tempBuf + windowSize, 0, transformSize-windowSize); memWindowedCopy(tempBuf, inBuf+i, window, windowSize-i); // Copy data for transform (first part) memWindowedCopy(tempBuf + windowSize-i, inBuf, window+windowSize-i, i); // Copy data for transform (second part) i === windowSize ? ( i = 0; // Wraparound ); fft_real(tempBuf, transformSize); fft_permute(tempBuf, transformSize/2); //tempBuf[0] = 0; // DC bin tempBuf[1] = 0; // Nyquist bin k = 0; filtReg = 0; loop (transformSize/2, power[k] = ; filtReg < power[k] ? ( filtReg = power[k]; ); power[k] = filtReg; filtReg *= decay; k += 1; ); loop (transformSize/2, k -= 1; filtReg < power[k] ? ( filtReg = power[k]; ); power[k] = filtReg; filtPower[k] *= tDecay; power[k] > filtPower[k] ? ( filtPower[k] = power[k]; ); filtReg *= decay; ); k = 0; loop (transformSize/2, powah = tempBuf[2*k]*tempBuf[2*k] + tempBuf[2*k+1]*tempBuf[2*k+1]; powah > thresholds2[k] ? ( multiOverUnity = thresholds[k]*invsqrt(filtPower[k])-1; tempBuf[2*k] *= multi; tempBuf[2*k+1] *= multi; ) : ( multiOverUnity = 0; ); lastMultiOverUnity k += 1; ); fft_ipermute(tempBuf, transformSize/2); ifft_real(tempBuf, transformSize); // j i windowSize // | | | // accuBuf: AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD // Accumulate output memWindowedCopy(accuBuf+j, tempBuf+windowSize-stepSize, window+windowSize-stepSize, stepSize); windowSize <= i+windowSize-stepSize ? ( //Must split into two memWindowedAdd(accuBuf+i, tempBuf, window, windowSize-i); memWindowedAdd(accuBuf, tempBuf+windowSize-i, window+windowSize-i, j); ) : ( // Need not split memWindowedAdd(accuBuf+i, tempBuf, window, windowSize-stepSize); ); j = i; nextStep = i + stepSize; // Schedule next MDCT );