diff --git a/Vocaluxe/Lib/Sound/Record/PitchTracker/CPtSharp.cs b/Vocaluxe/Lib/Sound/Record/PitchTracker/CPtSharp.cs
deleted file mode 100644
index 53e7a26c..00000000
--- a/Vocaluxe/Lib/Sound/Record/PitchTracker/CPtSharp.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-#region license
-// This file is part of Vocaluxe.
-//
-// Vocaluxe is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Vocaluxe is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Vocaluxe. If not, see .
-#endregion
-
-using System;
-
-namespace Vocaluxe.Lib.Sound.Record.PitchTracker
-{
- ///
- /// Pitchtracker (Pt) in C# that uses IIR filters for smoothing and an intelligent detection algorithm to reduce calculations
- /// DO NOT USE in 32 Bit! Due to floating point errors the filter will raise all values to NAN (TODO: FIX it!)
- ///
- class CPtSharp : CPitchTracker
- {
- private Pitch.PitchTracker _Instance;
-
- public CPtSharp()
- {
- _Instance = new Pitch.PitchTracker {SampleRate = 44100, DetectLevelThreshold = 0.01f, PitchRecordHistorySize = 1};
- }
-
- public override void Input(byte[] data)
- {
- short[] samplesShort = new short[data.Length / 2];
- Buffer.BlockCopy(data, 0, samplesShort, 0, data.Length);
- float[] samplesFloat = new float[samplesShort.Length];
- for (int i = 0; i < samplesShort.Length; i++)
- samplesFloat[i] = (float)samplesShort[i] / short.MaxValue;
- _Instance.ProcessBuffer(samplesFloat);
- }
-
- public override int GetNote(out float maxVolume, float[] weights)
- {
- int note = _Instance.CurrentPitchRecord.MidiNote - 15 - 21;
- maxVolume = _Instance.LastMaxVol;
- _SetWeights(note, weights);
- return note;
- }
-
- public override int GetNumHalfTones()
- {
- return NumHalfTonesDef;
- }
-
- public override float VolumeTreshold
- {
- get { return _Instance.DetectLevelThreshold; }
- set { _Instance.DetectLevelThreshold = value; }
- }
-
- protected override void _Dispose(bool disposing)
- {
- if (_Instance == null)
- throw new ObjectDisposedException(GetType().Name);
- _Instance = null;
- }
- }
-}
\ No newline at end of file
diff --git a/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/CircularBuffer.cs b/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/CircularBuffer.cs
deleted file mode 100644
index 07b6836b..00000000
--- a/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/CircularBuffer.cs
+++ /dev/null
@@ -1,173 +0,0 @@
-using System;
-
-namespace Vocaluxe.Lib.Sound.Record.PitchTracker.Pitch
-{
- public class CircularBuffer : IDisposable
- {
- int m_bufSize;
- int m_begBufOffset;
- int m_availBuf;
- long m_startPos; // total circular buffer position
- T[] m_buffer;
-
- ///
- /// Constructor
- ///
- public CircularBuffer()
- {
- }
-
- ///
- /// Constructor
- ///
- ///
- public CircularBuffer(int bufCount)
- {
- SetSize(bufCount);
- }
-
- ///
- /// Dispose
- ///
- public void Dispose()
- {
- SetSize(0);
- }
-
- ///
- /// Reset to the beginning of the buffer
- ///
- public void Reset()
- {
- m_begBufOffset = 0;
- m_availBuf = 0;
- m_startPos = 0;
- }
-
- ///
- /// Set the buffer to the specified size
- ///
- ///
- public void SetSize(int newSize)
- {
- Reset();
-
- if (m_bufSize == newSize)
- return;
-
- if (m_buffer != null)
- m_buffer = null;
-
- m_bufSize = newSize;
-
- if (m_bufSize > 0)
- m_buffer = new T[m_bufSize];
- }
-
- ///
- /// Clear the buffer
- ///
- public void Clear()
- {
- Array.Clear(m_buffer, 0, m_buffer.Length);
- }
-
- ///
- /// Get or set the start position
- ///
- public long StartPosition
- {
- get { return m_startPos; }
- set { m_startPos = value; }
- }
-
- ///
- /// Get the end position
- ///
- public long EndPosition
- {
- get { return m_startPos + m_availBuf; }
- }
-
- ///
- /// Get or set the amount of avaliable space
- ///
- public int Available
- {
- get { return m_availBuf; }
- set { m_availBuf = Math.Min(value, m_bufSize); }
- }
-
- ///
- /// Write data into the buffer
- ///
- ///
- ///
- ///
- public int WriteBuffer(T[] m_pInBuffer, int count)
- {
- count = Math.Min(count, m_bufSize);
-
- var startPos = m_availBuf != m_bufSize ? m_availBuf : m_begBufOffset;
- var pass1Count = Math.Min(count, m_bufSize - startPos);
- var pass2Count = count - pass1Count;
-
- PitchDsp.CopyBuffer(m_pInBuffer, 0, m_buffer, startPos, pass1Count);
-
- if (pass2Count > 0)
- PitchDsp.CopyBuffer(m_pInBuffer, pass1Count, m_buffer, 0, pass2Count);
-
- if (pass2Count == 0)
- {
- // did not wrap around
- if (m_availBuf != m_bufSize)
- m_availBuf += count; // have never wrapped around
- else
- {
- m_begBufOffset += count;
- m_startPos += count;
- }
- }
- else
- {
- // wrapped around
- if (m_availBuf != m_bufSize)
- m_startPos += pass2Count; // first time wrap-around
- else
- m_startPos += count;
-
- m_begBufOffset = pass2Count;
- m_availBuf = m_bufSize;
- }
-
- return count;
- }
-
- ///
- /// Read from the buffer
- ///
- ///
- ///
- ///
- ///
- public bool ReadBuffer(T[] outBuffer, long startRead, int readCount)
- {
- var endRead = (int)(startRead + readCount);
- var endAvail = (int)(m_startPos + m_availBuf);
-
- if (startRead < m_startPos || endRead > endAvail)
- return false;
-
- var startReadPos = (int)(((startRead - m_startPos) + m_begBufOffset) % m_bufSize);
- var block1Samples = Math.Min(readCount, m_bufSize - startReadPos);
- var block2Samples = readCount - block1Samples;
-
- PitchDsp.CopyBuffer(m_buffer, startReadPos, outBuffer, 0, block1Samples);
-
- if (block2Samples > 0)
- PitchDsp.CopyBuffer(m_buffer, 0, outBuffer, block1Samples, block2Samples);
-
- return true;
- }
- }
-}
diff --git a/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/Extensions.cs b/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/Extensions.cs
deleted file mode 100644
index 4cbd7c81..00000000
--- a/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/Extensions.cs
+++ /dev/null
@@ -1,105 +0,0 @@
-using System;
-
-namespace Vocaluxe.Lib.Sound.Record.PitchTracker.Pitch
-{
- public static class Extensions
- {
- ///
- /// Clear the buffer
- ///
- ///
- ///
- public static void Clear(this float[] buffer)
- {
- Array.Clear(buffer, 0, buffer.Length);
- }
-
- ///
- /// Clear the buffer
- ///
- ///
- ///
- public static void Clear(this double[] buffer)
- {
- Array.Clear(buffer, 0, buffer.Length);
- }
-
- ///
- /// Copy the values from one buffer to a different or the same buffer.
- /// It is safe to copy to the same buffer, even if the areas overlap
- ///
- ///
- ///
- ///
- ///
- public static void Copy(this float[] fromBuffer, float[] toBuffer, int fromStart, int toStart, int length)
- {
- if (toBuffer == null || fromBuffer.Length == 0 || toBuffer.Length == 0)
- return;
-
- int fromBegIdx = fromStart;
- int fromEndIdx = fromStart + length;
- int toBegIdx = toStart;
- int toEndIdx = toStart + length;
-
- if (fromBegIdx < 0)
- {
- toBegIdx -= fromBegIdx;
- fromBegIdx = 0;
- }
-
- if (toBegIdx < 0)
- {
- fromBegIdx -= toBegIdx;
- toBegIdx = 0;
- }
-
- if (fromEndIdx >= fromBuffer.Length)
- {
- toEndIdx -= fromEndIdx - fromBuffer.Length + 1;
- fromEndIdx = fromBuffer.Length - 1;
- }
-
- if (toEndIdx >= toBuffer.Length)
- {
- fromEndIdx -= toEndIdx - toBuffer.Length + 1;
- toEndIdx = fromBuffer.Length - 1;
- }
-
- if (fromBegIdx < toBegIdx)
- {
- // Shift right, so start at the right
- for (int fromIdx = fromEndIdx, toIdx = toEndIdx; fromIdx >= fromBegIdx; fromIdx--, toIdx--)
- toBuffer[toIdx] = fromBuffer[fromIdx];
- }
- else
- {
- // Shift left, so start at the left
- for (int fromIdx = fromBegIdx, toIdx = toBegIdx; fromIdx <= fromEndIdx; fromIdx++, toIdx++)
- toBuffer[toIdx] = fromBuffer[fromIdx];
- }
- }
-
- ///
- ///
- ///
- ///
- ///
- public static void Clear(this float[] buffer, int startIdx, int endIdx)
- {
- Array.Clear(buffer, startIdx, endIdx - startIdx + 1);
- }
-
- ///
- /// Fill the buffer with the specified value
- ///
- ///
- ///
- ///
- public static void Fill(this double[] buffer, double value)
- {
- for (int idx = 0; idx < buffer.Length; idx++)
- buffer[idx] = value;
- }
- }
-}
\ No newline at end of file
diff --git a/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/IIRFilter.cs b/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/IIRFilter.cs
deleted file mode 100644
index e180ff72..00000000
--- a/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/IIRFilter.cs
+++ /dev/null
@@ -1,613 +0,0 @@
-using System;
-
-namespace Vocaluxe.Lib.Sound.Record.PitchTracker.Pitch
-{
- ///
- /// Infinite impulse response filter (old style analog filters)
- ///
- class IIRFilter
- {
- ///
- /// The type of filter
- ///
- public enum FilterType
- {
- None = 0,
- LP,
- HP,
- BP
- }
-
- ///
- /// The filter prototype
- ///
- public enum ProtoType
- {
- None = 0,
- Butterworth,
- Chebyshev,
- }
-
- const int kHistMask = 31;
- const int kHistSize = 32;
-
- private int m_order;
- private ProtoType m_protoType;
- private FilterType m_filterType;
-
- private float m_fp1;
- private float m_fp2;
- private float m_fN;
- private float m_ripple;
- private float m_sampleRate;
- private double[] m_real;
- private double[] m_imag;
- private double[] m_z;
- private double[] m_aCoeff;
- private double[] m_bCoeff;
- private double[] m_inHistory;
- private double[] m_outHistory;
- private int m_histIdx;
- private bool m_invertDenormal;
-
- public IIRFilter()
- {
- }
-
- ///
- /// Returns true if all the filter parameters are valid
- ///
- public bool FilterValid
- {
- get
- {
- if (m_order < 1 || m_order > 16 ||
- m_protoType == ProtoType.None ||
- m_filterType == FilterType.None ||
- m_sampleRate <= 0.0f ||
- m_fN <= 0.0f)
- return false;
-
- switch (m_filterType)
- {
- case FilterType.LP:
- if (m_fp2 <= 0.0f)
- return false;
- break;
-
- case FilterType.BP:
- if (m_fp1 <= 0.0f || m_fp2 <= 0.0f || m_fp1 >= m_fp2)
- return false;
- break;
-
- case FilterType.HP:
- if (m_fp1 <= 0.0f)
- return false;
- break;
- }
-
- // For bandpass, the order must be even
- if (m_filterType == FilterType.BP && (m_order & 1) != 0)
- return false;
-
- return true;
- }
- }
-
- ///
- /// Set the filter prototype
- ///
- public ProtoType Proto
- {
- get { return m_protoType; }
-
- set
- {
- m_protoType = value;
- Design();
- }
- }
-
- ///
- /// Set the filter type
- ///
- public FilterType Type
- {
- get { return m_filterType; }
-
- set
- {
- m_filterType = value;
- Design();
- }
- }
-
- public int Order
- {
- get { return m_order; }
-
- set
- {
- m_order = Math.Min(16, Math.Max(1, Math.Abs(value)));
-
- if (m_filterType == FilterType.BP && Odd(m_order))
- m_order++;
-
- Design();
- }
- }
-
- public float SampleRate
- {
- get { return m_sampleRate; }
-
- set
- {
- m_sampleRate = value;
- m_fN = 0.5f * m_sampleRate;
- Design();
- }
- }
-
- public float FreqLow
- {
- get { return m_fp1; }
-
- set
- {
- m_fp1 = value;
- Design();
- }
- }
-
- public float FreqHigh
- {
- get { return m_fp2; }
-
- set
- {
- m_fp2 = value;
- Design();
- }
- }
-
- public float Ripple
- {
- get { return m_ripple; }
-
- set
- {
- m_ripple = value;
- Design();
- }
- }
-
- ///
- /// Returns true if n is odd
- ///
- ///
- ///
- private bool Odd(int n)
- {
- return (n & 1) == 1;
- }
-
- ///
- /// Square
- ///
- ///
- ///
- private float Sqr(float value)
- {
- return value * value;
- }
-
- ///
- /// Square
- ///
- ///
- ///
- private double Sqr(double value)
- {
- return value * value;
- }
-
- ///
- /// Determines poles and zeros of IIR filter
- /// based on bilinear transform method
- ///
- private void LocatePolesAndZeros()
- {
- m_real = new double[m_order + 1];
- m_imag = new double[m_order + 1];
- m_z = new double[m_order + 1];
- double ln10 = Math.Log(10.0);
-
- // Butterworth, Chebyshev parameters
- int n = m_order;
-
- if (m_filterType == FilterType.BP)
- n = n / 2;
-
- int ir = n % 2;
- int n1 = n + ir;
- int n2 = (3 * n + ir) / 2 - 1;
- double f1;
-
- switch (m_filterType)
- {
- case FilterType.LP:
- f1 = m_fp2;
- break;
-
- case FilterType.HP:
- f1 = m_fN - m_fp1;
- break;
-
- case FilterType.BP:
- f1 = m_fp2 - m_fp1;
- break;
-
- default:
- f1 = 0.0;
- break;
- }
-
- double tanw1 = Math.Tan(0.5 * Math.PI * f1 / m_fN);
- double tansqw1 = Sqr(tanw1);
-
- // Real and Imaginary parts of low-pass poles
- double t, a = 1.0, r = 1.0, i = 1.0;
-
- for (int k = n1; k <= n2; k++)
- {
- t = 0.5 * (2 * k + 1 - ir) * Math.PI / (double)n;
-
- switch (m_protoType)
- {
- case ProtoType.Butterworth:
- double b3 = 1.0 - 2.0 * tanw1 * Math.Cos(t) + tansqw1;
- r = (1.0 - tansqw1) / b3;
- i = 2.0 * tanw1 * Math.Sin(t) / b3;
- break;
-
- case ProtoType.Chebyshev:
- double d = 1.0 - Math.Exp(-0.05 * m_ripple * ln10);
- double e = 1.0 / Math.Sqrt(1.0 / Sqr(1.0 - d) - 1.0);
- double x = Math.Pow(Math.Sqrt(e * e + 1.0) + e, 1.0 / (double)n);
- a = 0.5 * (x - 1.0 / x);
- double b = 0.5 * (x + 1.0 / x);
- double c3 = a * tanw1 * Math.Cos(t);
- double c4 = b * tanw1 * Math.Sin(t);
- double c5 = Sqr(1.0 - c3) + Sqr(c4);
- r = 2.0 * (1.0 - c3) / c5 - 1.0;
- i = 2.0 * c4 / c5;
- break;
- }
-
- int m = 2 * (n2 - k) + 1;
- m_real[m + ir] = r;
- m_imag[m + ir] = Math.Abs(i);
- m_real[m + ir + 1] = r;
- m_imag[m + ir + 1] = -Math.Abs(i);
- }
-
- if (Odd(n))
- {
- if (m_protoType == ProtoType.Butterworth)
- r = (1.0 - tansqw1) / (1.0 + 2.0 * tanw1 + tansqw1);
-
- if (m_protoType == ProtoType.Chebyshev)
- r = 2.0 / (1.0 + a * tanw1) - 1.0;
-
- m_real[1] = r;
- m_imag[1] = 0.0;
- }
-
- switch (m_filterType)
- {
- case FilterType.LP:
- for (int m = 1; m <= n; m++)
- m_z[m] = -1.0;
- break;
-
- case FilterType.HP:
- // Low-pass to high-pass transformation
- for (int m = 1; m <= n; m++)
- {
- m_real[m] = -m_real[m];
- m_z[m] = 1.0;
- }
- break;
-
- case FilterType.BP:
- // Low-pass to bandpass transformation
- for (int m = 1; m <= n; m++)
- {
- m_z[m] = 1.0;
- m_z[m + n] = -1.0;
- }
-
- double f4 = 0.5 * Math.PI * m_fp1 / m_fN;
- double f5 = 0.5 * Math.PI * m_fp2 / m_fN;
- double aa = Math.Cos(f4 + f5) / Math.Cos(f5 - f4);
- double aR, aI, h1, h2, p1R, p2R, p1I, p2I;
-
- for (int m1 = 0; m1 <= (m_order - 1) / 2; m1++)
- {
- int m = 1 + 2 * m1;
- aR = m_real[m];
- aI = m_imag[m];
-
- if (Math.Abs(aI) < 0.0001)
- {
- h1 = 0.5 * aa * (1.0 + aR);
- h2 = Sqr(h1) - aR;
- if (h2 > 0.0)
- {
- p1R = h1 + Math.Sqrt(h2);
- p2R = h1 - Math.Sqrt(h2);
- p1I = 0.0;
- p2I = 0.0;
- }
- else
- {
- p1R = h1;
- p2R = h1;
- p1I = Math.Sqrt(Math.Abs(h2));
- p2I = -p1I;
- }
- }
- else
- {
- double fR = aa * 0.5 * (1.0 + aR);
- double fI = aa * 0.5 * aI;
- double gR = Sqr(fR) - Sqr(fI) - aR;
- double gI = 2 * fR * fI - aI;
- double sR = Math.Sqrt(0.5 * Math.Abs(gR + Math.Sqrt(Sqr(gR) + Sqr(gI))));
- double sI = gI / (2.0 * sR);
- p1R = fR + sR;
- p1I = fI + sI;
- p2R = fR - sR;
- p2I = fI - sI;
- }
-
- m_real[m] = p1R;
- m_real[m + 1] = p2R;
- m_imag[m] = p1I;
- m_imag[m + 1] = p2I;
- }
-
- if (Odd(n))
- {
- m_real[2] = m_real[n + 1];
- m_imag[2] = m_imag[n + 1];
- }
-
- for (int k = n; k >= 1; k--)
- {
- int m = 2 * k - 1;
- m_real[m] = m_real[k];
- m_real[m + 1] = m_real[k];
- m_imag[m] = Math.Abs(m_imag[k]);
- m_imag[m + 1] = -Math.Abs(m_imag[k]);
- }
-
- break;
- }
- }
-
- ///
- /// Calculate all the values
- ///
- public void Design()
- {
- if (!this.FilterValid)
- return;
-
- m_aCoeff = new double[m_order + 1];
- m_bCoeff = new double[m_order + 1];
- m_inHistory = new double[kHistSize];
- m_outHistory = new double[kHistSize];
-
- double[] newA = new double[m_order + 1];
- double[] newB = new double[m_order + 1];
-
- // Find filter poles and zeros
- LocatePolesAndZeros();
-
- // Compute filter coefficients from pole/zero values
- m_aCoeff[0] = 1.0;
- m_bCoeff[0] = 1.0;
-
- for (int i = 1; i <= m_order; i++)
- {
- m_aCoeff[i] = 0.0;
- m_bCoeff[i] = 0.0;
- }
-
- int k = 0;
- int n = m_order;
- int pairs = n / 2;
-
- if (Odd(m_order))
- {
- // First subfilter is first order
- m_aCoeff[1] = -m_z[1];
- m_bCoeff[1] = -m_real[1];
- k = 1;
- }
-
- for (int p = 1; p <= pairs; p++)
- {
- int m = 2 * p - 1 + k;
- double alpha1 = -(m_z[m] + m_z[m + 1]);
- double alpha2 = m_z[m] * m_z[m + 1];
- double beta1 = -2.0 * m_real[m];
- double beta2 = Sqr(m_real[m]) + Sqr(m_imag[m]);
-
- newA[1] = m_aCoeff[1] + alpha1 * m_aCoeff[0];
- newB[1] = m_bCoeff[1] + beta1 * m_bCoeff[0];
-
- for (int i = 2; i <= n; i++)
- {
- newA[i] = m_aCoeff[i] + alpha1 * m_aCoeff[i - 1] + alpha2 * m_aCoeff[i - 2];
- newB[i] = m_bCoeff[i] + beta1 * m_bCoeff[i - 1] + beta2 * m_bCoeff[i - 2];
- }
-
- for (int i = 1; i <= n; i++)
- {
- m_aCoeff[i] = newA[i];
- m_bCoeff[i] = newB[i];
- }
- }
-
- // Ensure the filter is normalized
- FilterGain(1000);
- }
-
- ///
- /// Reset the history buffers
- ///
- public void Reset()
- {
- if (m_inHistory != null)
- m_inHistory.Clear();
-
- if (m_outHistory != null)
- m_outHistory.Clear();
-
- m_histIdx = 0;
- }
-
- ///
- /// Reset the filter, and fill the appropriate history buffers with the specified value
- ///
- ///
- public void Reset(double startValue)
- {
- m_histIdx = 0;
-
- if (m_inHistory == null || m_outHistory == null)
- return;
-
- m_inHistory.Fill(startValue);
-
- if (m_inHistory != null)
- {
- switch (m_filterType)
- {
- case FilterType.LP:
- m_outHistory.Fill(startValue);
- break;
-
- default:
- m_outHistory.Clear();
- break;
- }
- }
- }
-
- ///
- /// Apply the filter to the buffer
- ///
- ///
- public void FilterBuffer(float[] srcBuf, long srcPos, float[] dstBuf, long dstPos, long nLen)
- {
- const double kDenormal = 0.000000000000001;
- double denormal = m_invertDenormal ? -kDenormal : kDenormal;
- m_invertDenormal = !m_invertDenormal;
-
- for (int sampleIdx = 0; sampleIdx < nLen; sampleIdx++)
- {
- double sum = 0.0f;
-
- m_inHistory[m_histIdx] = srcBuf[srcPos + sampleIdx] + denormal;
-
- for (int idx = 0; idx < m_aCoeff.Length; idx++)
- sum += m_aCoeff[idx] * m_inHistory[(m_histIdx - idx) & kHistMask];
-
- for (int idx = 1; idx < m_bCoeff.Length; idx++)
- sum -= m_bCoeff[idx] * m_outHistory[(m_histIdx - idx) & kHistMask];
-
- m_outHistory[m_histIdx] = sum;
- m_histIdx = (m_histIdx + 1) & kHistMask;
- dstBuf[dstPos + sampleIdx] = (float)sum;
- }
- }
-
- public float FilterSample(float inVal)
- {
- double sum = 0.0f;
-
- m_inHistory[m_histIdx] = inVal;
-
- for (int idx = 0; idx < m_aCoeff.Length; idx++)
- sum += m_aCoeff[idx] * m_inHistory[(m_histIdx - idx) & kHistMask];
-
- for (int idx = 1; idx < m_bCoeff.Length; idx++)
- sum -= m_bCoeff[idx] * m_outHistory[(m_histIdx - idx) & kHistMask];
-
- m_outHistory[m_histIdx] = sum;
- m_histIdx = (m_histIdx + 1) & kHistMask;
-
- return (float)sum;
- }
-
- ///
- /// Get the gain at the specified number of frequency points
- ///
- ///
- ///
- public float[] FilterGain(int freqPoints)
- {
- // Filter gain at uniform frequency intervals
- float[] g = new float[freqPoints];
- double theta, s, c, sac, sas, sbc, sbs;
- float gMax = -100.0f;
- float sc = 10.0f / (float)Math.Log(10.0f);
- double t = Math.PI / (freqPoints - 1);
-
- for (int i = 0; i < freqPoints; i++)
- {
- theta = i * t;
-
- if (i == 0)
- theta = Math.PI * 0.0001;
-
- if (i == freqPoints - 1)
- theta = Math.PI * 0.9999;
-
- sac = 0.0f;
- sas = 0.0f;
- sbc = 0.0f;
- sbs = 0.0f;
-
- for (int k = 0; k <= m_order; k++)
- {
- c = Math.Cos(k * theta);
- s = Math.Sin(k * theta);
- sac += c * m_aCoeff[k];
- sas += s * m_aCoeff[k];
- sbc += c * m_bCoeff[k];
- sbs += s * m_bCoeff[k];
- }
-
- g[i] = sc * (float)Math.Log((Sqr(sac) + Sqr(sas)) / (Sqr(sbc) + Sqr(sbs)));
- gMax = Math.Max(gMax, g[i]);
- }
-
- // Normalize to 0 dB maximum gain
- for (int i = 0; i < freqPoints; i++)
- g[i] -= gMax;
-
- // Normalize numerator (a) coefficients
- float normFactor = (float)Math.Pow(10.0, -0.05 * gMax);
-
- for (int i = 0; i <= m_order; i++)
- m_aCoeff[i] *= normFactor;
-
- return g;
- }
- }
-}
diff --git a/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/PitchDsp.cs b/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/PitchDsp.cs
deleted file mode 100644
index 3fc22ee6..00000000
--- a/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/PitchDsp.cs
+++ /dev/null
@@ -1,561 +0,0 @@
-using System;
-
-namespace Vocaluxe.Lib.Sound.Record.PitchTracker.Pitch
-{
- ///
- /// Pitch related DSP
- ///
- public class PitchDsp
- {
- public static readonly double InverseLog2 = 1.0 / Math.Log10(2.0);
-
- private const int kCourseOctaveSteps = 96;
- private const int kScanHiSize = 31;
- private const float kScanHiFreqStep = 1.005f;
- private const int kMinMidiNote = 21; // A0
- private const int kMaxMidiNote = 108; // C8
-
- private float m_minPitch;
- private float m_maxPitch;
- private int m_minNote;
- private int m_maxNote;
- private int m_blockLen14; // 1/4 block len
- private int m_blockLen24; // 2/4 block len
- private int m_blockLen34; // 3/4 block len
- private int m_blockLen44; // 4/4 block len
- private double m_sampleRate;
-
- private int m_numCourseSteps;
- private float[] m_pCourseFreqOffset;
- private float[] m_pCourseFreq;
- private float[] m_scanHiOffset = new float[kScanHiSize];
- private float[] m_peakBuf = new float[kScanHiSize];
- private int m_prevPitchIdx;
- private float[] m_detectCurve;
-
- ///
- /// Constructor
- ///
- ///
- ///
- ///
- ///
- public PitchDsp(double sampleRate, float minPitch, float maxPitch)
- {
- m_sampleRate = sampleRate;
- m_minPitch = minPitch;
- m_maxPitch = maxPitch;
-
- m_minNote = (int)(PitchToMidiNote(m_minPitch) + 0.5f) + 2;
- m_maxNote = (int)(PitchToMidiNote(m_maxPitch) + 0.5f) - 2;
-
- m_blockLen44 = (int)(m_sampleRate / m_minPitch + 0.5f);
- m_blockLen34 = (m_blockLen44 * 3) / 4;
- m_blockLen24 = m_blockLen44 / 2;
- m_blockLen14 = m_blockLen44 / 4;
-
- m_numCourseSteps = (int)((Math.Log((double)m_maxPitch / (double)m_minPitch) / Math.Log(2.0)) * kCourseOctaveSteps + 0.5) + 3;
-
- m_pCourseFreqOffset = new float[m_numCourseSteps + 10000];
- m_pCourseFreq = new float[m_numCourseSteps + 10000];
-
- m_detectCurve = new float[m_numCourseSteps];
-
- double freqStep = 1.0 / Math.Pow(2.0, 1.0 / kCourseOctaveSteps);
- double curFreq = m_maxPitch / freqStep;
-
- // frequency is stored from high to low
- for (int idx = 0; idx < m_numCourseSteps; idx++)
- {
- m_pCourseFreq[idx] = (float)curFreq;
- m_pCourseFreqOffset[idx] = (float)(m_sampleRate / curFreq);
- curFreq *= freqStep;
- }
-
- for (int idx = 0; idx < kScanHiSize; idx++)
- m_scanHiOffset[idx] = (float)Math.Pow(kScanHiFreqStep, (kScanHiSize / 2) - idx);
- }
-
- ///
- /// Get the max detected pitch
- ///
- public float MaxPitch
- {
- get { return m_maxPitch; }
- }
-
- ///
- /// Get the min detected pitch
- ///
- public float MinPitch
- {
- get { return m_minPitch; }
- }
-
- ///
- /// Get the max note
- ///
- public int MaxNote
- {
- get { return m_maxNote; }
- }
-
- ///
- /// Get the min note
- ///
- public int MinNote
- {
- get { return m_minNote; }
- }
-
- ///
- /// Detect the pitch
- ///
- public float DetectPitch(float[] samplesLo, float[] samplesHi)
- {
- return DetectPitchLo(samplesLo, samplesHi);
- }
-
- ///
- /// Low resolution pitch detection
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- private float DetectPitchLo(float[] samplesLo, float[] samplesHi)
- {
- m_detectCurve.Clear();
-
- const int skipSize = 8;
- const int peakScanSize = 23;
- const int peakScanSizeHalf = peakScanSize / 2;
-
- float peakThresh1 = 200.0f;
- float peakThresh2 = 600.0f;
- bool bufferSwitched = false;
-
- for (int idx = 0; idx < m_numCourseSteps; idx += skipSize)
- {
- int blockLen = Math.Min(m_blockLen44, (int)m_pCourseFreqOffset[idx] * 2);
- float[] curSamples = null;
-
- // 258 is at 250 Hz, which is the switchover frequency for the two filters
- bool loBuffer = idx >= 258;
-
- if (loBuffer)
- {
- if (!bufferSwitched)
- {
- m_detectCurve.Clear(258 - peakScanSizeHalf, 258 + peakScanSizeHalf);
- bufferSwitched = true;
- }
-
- curSamples = samplesLo;
- }
- else
- curSamples = samplesHi;
-
- int stepSizeLoRes = blockLen / 10;
- int stepSizeHiRes = Math.Max(1, Math.Min(5, idx * 5 / m_numCourseSteps));
-
- float fValue = RatioAbsDiffLinear(curSamples, idx, blockLen, stepSizeLoRes, false);
-
- if (fValue > peakThresh1)
- {
- // Do a closer search for the peak
- int peakIdx = -1;
- float peakVal = 0.0f;
- float prevVal = 0.0f;
- int dir = 4; // start going forward
- int curPos = idx; // start at center of the scan range
- int begSearch = Math.Max(idx - peakScanSizeHalf, 0);
- int endSearch = Math.Min(idx + peakScanSizeHalf, m_numCourseSteps - 1);
-
- while (curPos >= begSearch && curPos < endSearch)
- {
- float curVal = RatioAbsDiffLinear(curSamples, curPos, blockLen, stepSizeHiRes, true);
-
- if (peakVal < curVal)
- {
- peakVal = curVal;
- peakIdx = curPos;
- }
-
- if (prevVal > curVal)
- {
- dir = -dir >> 1;
-
- if (dir == 0)
- {
- if (peakVal > peakThresh2 && peakIdx >= 6 && peakIdx <= m_numCourseSteps - 7)
- {
- float fValL = RatioAbsDiffLinear(curSamples, peakIdx - 5, blockLen, stepSizeHiRes, true);
- float fValR = RatioAbsDiffLinear(curSamples, peakIdx + 5, blockLen, stepSizeHiRes, true);
- float fPointy = peakVal / (fValL + fValR) * 2.0f;
-
- float minPointy = (m_prevPitchIdx > 0 && Math.Abs(m_prevPitchIdx - peakIdx) < 10) ? 1.2f : 1.5f;
-
- if (fPointy > minPointy)
- {
- float pitchHi = DetectPitchHi(curSamples, peakIdx);
-
- if (pitchHi > 1.0f)
- {
- m_prevPitchIdx = peakIdx;
- return pitchHi;
- }
- }
- }
-
- break;
- }
- }
-
- prevVal = curVal;
- curPos += dir;
- }
- }
- }
-
- m_prevPitchIdx = 0;
- return 0.0f;
- }
-
- ///
- /// High resolution pitch detection
- ///
- ///
- ///
- ///
- private float DetectPitchHi(float[] samples, int lowFreqIdx)
- {
- int peakIdx = -1;
- float prevVal = 0.0f;
- int dir = 4; // start going forward
- int curPos = kScanHiSize >> 1; // start at center of the scan range
-
- m_peakBuf.Clear();
-
- float offset = m_pCourseFreqOffset[lowFreqIdx];
-
- while (curPos >= 0 && curPos < kScanHiSize)
- {
- if (m_peakBuf[curPos] == 0.0f)
- m_peakBuf[curPos] = SumAbsDiffHermite(samples, offset * m_scanHiOffset[curPos], m_blockLen44, 1);
-
- if (peakIdx < 0 || m_peakBuf[peakIdx] < m_peakBuf[curPos])
- peakIdx = curPos;
-
- if (prevVal > m_peakBuf[curPos])
- {
- dir = -dir >> 1;
-
- if (dir == 0)
- {
- // found the peak
- float minVal = Math.Min(m_peakBuf[peakIdx - 1], m_peakBuf[peakIdx + 1]);
-
- minVal -= minVal * (1.0f / 32.0f);
-
- var y1 = (float)Math.Log10(m_peakBuf[peakIdx - 1] - minVal);
- var y2 = (float)Math.Log10(m_peakBuf[peakIdx] - minVal);
- var y3 = (float)Math.Log10(m_peakBuf[peakIdx + 1] - minVal);
-
- float fIdx = (float)peakIdx + (y3 - y1) / (2.0f * (2.0f * y2 - y1 - y3));
-
- return (float)Math.Pow(kScanHiFreqStep, fIdx - (kScanHiSize / 2)) * m_pCourseFreq[lowFreqIdx];
- }
- }
-
- prevVal = m_peakBuf[curPos];
- curPos += dir;
- }
-
- return 0.0f;
- }
-
- ///
- /// Create a sine wave with the specified frequency, amplitude and starting angle.
- /// Returns the updated angle.
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- public static double CreateSineWave(float[] buffer, int numSamples, float sampleRate,
- float freq, float amplitude, double startAngle)
- {
- double angleStep = freq / sampleRate * Math.PI * 2.0;
- double curAngle = startAngle;
-
- for (int idx = 0; idx < numSamples; idx++)
- {
- buffer[idx] = (float)Math.Sin(curAngle) * amplitude;
-
- curAngle += angleStep;
-
- while (curAngle > Math.PI)
- curAngle -= Math.PI * 2.0;
- }
-
- return curAngle;
- }
-
- ///
- /// Returns true if the level is above the specified value
- ///
- ///
- ///
- ///
- ///
- ///
- public bool LevelIsAbove(float[] buffer, int len, float level)
- {
- if (buffer == null || buffer.Length == 0)
- return false;
-
- int endIdx = Math.Min(buffer.Length, len);
-
- for (int idx = 0; idx < endIdx; idx++)
- {
- if (Math.Abs(buffer[idx]) >= level)
- return true;
- }
-
- return false;
- }
-
- ///
- /// Copy the data from the source to the destination buffer
- ///
- ///
- ///
- ///
- ///
- public static void CopyBuffer(T[] source, int srcStart, T[] destination, int dstStart, int length)
- {
- if (length < 0)
- throw new ArgumentOutOfRangeException("length");
-
- if (source == null || source.Length < srcStart + length)
- throw new Exception("Source buffer is null or not large enough");
-
- if (destination == null || destination.Length < dstStart + length)
- throw new Exception("Destination buffer is null or not large enough");
-
- int srcIdx = srcStart;
- int dstIdx = dstStart;
-
- for (int idx = 0; idx < length; idx++)
- destination[dstIdx++] = source[srcIdx++];
- }
-
- ///
- /// // 4-point, 3rd-order Hermite (x-form)
- ///
- private float InterpolateHermite(float fY0, float fY1, float fY2, float fY3, float frac)
- {
- float c1 = 0.5f * (fY2 - fY0);
- float c3 = 1.5f * (fY1 - fY2) + 0.5f * (fY3 - fY0);
- float c2 = fY0 - fY1 + c1 - c3;
-
- return ((c3 * frac + c2) * frac + c1) * frac + fY1;
- }
-
- ///
- /// Linear interpolation
- /// nFrac is based on 1.0 = 256
- ///
- private float InterpolateLinear(float y0, float y1, float frac)
- {
- return y0 * (1.0f - frac) + y1 * frac;
- }
-
- ///
- /// Medium Low res SumAbsDiff
- ///
- private float RatioAbsDiffLinear(float[] samples, int freqIdx, int blockLen, int stepSize, bool hiRes)
- {
- if (hiRes && m_detectCurve[freqIdx] > 0.0f)
- return m_detectCurve[freqIdx];
-
- var offsetInt = (int)m_pCourseFreqOffset[freqIdx];
- float offsetFrac = m_pCourseFreqOffset[freqIdx] - offsetInt;
- float rect = 0.0f;
- float absDiff = 0.01f; // prevent divide by zero
- int count = 0;
- float interp;
- float sample;
-
- // Do a scan using linear interpolation and the specified step size
- for (int idx = 0; idx < blockLen; idx += stepSize, count++)
- {
- sample = samples[idx];
- interp = InterpolateLinear(samples[offsetInt + idx], samples[offsetInt + idx + 1], offsetFrac);
- absDiff += Math.Abs(sample - interp);
- rect += Math.Abs(sample) + Math.Abs(interp);
- }
-
- float finalVal = rect / absDiff * 100.0f;
-
- if (hiRes)
- m_detectCurve[freqIdx] = finalVal;
-
- return finalVal;
- }
-
- ///
- /// Medium High res SumAbsDiff
- ///
- private float SumAbsDiffHermite(float[] samples, float fOffset, int blockLen, int stepSize)
- {
- var offsetInt = (int)fOffset;
- float offsetFrac = fOffset - offsetInt;
- float value = 0.001f; // prevent divide by zero
- int count = 0;
-
- // do a scan using linear interpolation and the specified step size
- for (int idx = 0; idx < blockLen; idx += stepSize, count++)
- {
- int offsetIdx = offsetInt + idx;
-
- value += Math.Abs(samples[idx] - InterpolateHermite(samples[offsetIdx - 1],
- samples[offsetIdx],
- samples[offsetIdx + 1],
- samples[offsetIdx + 2],
- offsetFrac));
- }
-
- return count / value;
- }
-
- ///
- /// Get the MIDI note and cents of the pitch
- ///
- ///
- ///
- ///
- ///
- public static bool PitchToMidiNote(float pitch, out int note, out int cents)
- {
- if (pitch < 20.0f)
- {
- note = 0;
- cents = 0;
- return false;
- }
-
- float fNote = (float)((12.0 * Math.Log10(pitch / 55.0) * InverseLog2)) + 33.0f;
- note = (int)(fNote + 0.5f);
- cents = (int)((note - fNote) * 100);
- return true;
- }
-
- ///
- /// Get the pitch from the MIDI note
- ///
- ///
- ///
- public static float PitchToMidiNote(float pitch)
- {
- if (pitch < 20.0f)
- return 0.0f;
-
- return (float)(12.0 * Math.Log10(pitch / 55.0) * InverseLog2) + 33.0f;
- }
-
- ///
- /// Get the pitch from the MIDI note
- ///
- ///
- ///
- public float MidiNoteToPitch(float note)
- {
- if (note < 33.0f)
- return 0.0f;
-
- float pitch = (float)Math.Pow(10.0, (note - 33.0f) / InverseLog2 / 12.0f) * 55.0f;
- return pitch <= m_maxPitch ? pitch : 0.0f;
- }
-
- ///
- /// Format a midi note to text
- ///
- ///
- ///
- ///
- ///
- public static string GetNoteName(int note, bool sharps, bool showOctave)
- {
- if (note < kMinMidiNote || note > kMaxMidiNote)
- return null;
-
- note -= kMinMidiNote;
-
- int octave = (note + 9) / 12;
- note = note % 12;
- string noteText = null;
-
- switch (note)
- {
- case 0:
- noteText = "A";
- break;
-
- case 1:
- noteText = sharps ? "A#" : "Bb";
- break;
-
- case 2:
- noteText = "B";
- break;
-
- case 3:
- noteText = "C";
- break;
-
- case 4:
- noteText = sharps ? "C#" : "Db";
- break;
-
- case 5:
- noteText = "D";
- break;
-
- case 6:
- noteText = sharps ? "D#" : "Eb";
- break;
-
- case 7:
- noteText = "E";
- break;
-
- case 8:
- noteText = "F";
- break;
-
- case 9:
- noteText = sharps ? "F#" : "Gb";
- break;
-
- case 10:
- noteText = "G";
- break;
-
- case 11:
- noteText = sharps ? "G#" : "Ab";
- break;
- }
-
- if (showOctave)
- noteText += " " + octave.ToString();
-
- return noteText;
- }
- }
-}
\ No newline at end of file
diff --git a/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/PitchTracker.cs b/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/PitchTracker.cs
deleted file mode 100644
index 59522197..00000000
--- a/Vocaluxe/Lib/Sound/Record/PitchTracker/Pitch/PitchTracker.cs
+++ /dev/null
@@ -1,431 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections;
-
-namespace Vocaluxe.Lib.Sound.Record.PitchTracker.Pitch
-{
- ///
- /// Tracks pitch
- ///
- // ReSharper disable InconsistentNaming
- public class PitchTracker
- {
- private const int kOctaveSteps = 96;
- private const int kStepOverlap = 4;
- private const float kMinFreq = 50.0f; // A1, Midi note 33, 55.0Hz
- private const float kMaxFreq = 1800.0f; // A#6. Midi note 92
- private const int kStartCircular = 40; // how far into the sample buffer do we start checking (allow for filter settling)
- private const float kDetectOverlapSec = 0.005f;
- private const float kMaxOctaveSecRate = 10.0f;
-
- private const float kAvgOffset = 0.005f; // time offset between pitch averaging values
- private const int kAvgCount = 1; // number of average pitch samples to take
- private const float kCircularBufSaveTime = 1.0f; // Amount of samples to store in the history buffer
-
- private PitchDsp m_dsp;
- private CircularBuffer m_circularBufferLo;
- private CircularBuffer m_circularBufferHi;
- private double m_sampleRate;
- private float m_detectLevelThreshold = 0.01f; // -40dB
- private int m_pitchRecordsPerSecond = 50; // default is 50, or one record every 20ms
-
- private float[] m_pitchBufLo;
- private float[] m_pitchBufHi;
- private int m_pitchBufSize;
- private int m_samplesPerPitchBlock;
- private int m_curPitchIndex;
- private long m_curPitchSamplePos;
-
- private int m_detectOverlapSamples;
- private float m_maxOverlapDiff;
-
- private bool m_recordPitchRecords;
- private int m_pitchRecordHistorySize;
- private List m_pitchRecords = new List();
- private PitchRecord m_curPitchRecord = new PitchRecord();
-
- private IIRFilter m_iirFilterLoLo;
- private IIRFilter m_iirFilterLoHi;
- private IIRFilter m_iirFilterHiLo;
- private IIRFilter m_iirFilterHiHi;
-
- public float LastMaxVol = 0;
-
- public delegate void PitchDetectedHandler(PitchTracker sender, PitchRecord pitchRecord);
-
- public event PitchDetectedHandler PitchDetected;
-
- ///
- /// Constructor
- ///
- public PitchTracker() {}
-
- ///
- /// Set the sample rate
- ///
- public double SampleRate
- {
- set
- {
- if (m_sampleRate == value)
- return;
-
- m_sampleRate = value;
- Setup();
- }
- }
-
- ///
- /// Set the detect level threshold, The value must be between 0.0001f and 1.0f (-80 dB to 0 dB)
- ///
- public float DetectLevelThreshold
- {
- set
- {
- float newValue = Math.Max(0.0001f, Math.Min(1.0f, value));
-
- if (m_detectLevelThreshold == newValue)
- return;
-
- m_detectLevelThreshold = newValue;
- //Setup();
- }
- get { return m_detectLevelThreshold; }
- }
-
- ///
- /// Return the samples per pitch block
- ///
- public int SamplesPerPitchBlock
- {
- get { return m_samplesPerPitchBlock; }
- }
-
- ///
- /// Get or set the number of pitch records per second (default is 50, or one record every 20ms)
- ///
- public int PitchRecordsPerSecond
- {
- get { return m_pitchRecordsPerSecond; }
- set
- {
- m_pitchRecordsPerSecond = Math.Max(1, Math.Min(100, value));
- Setup();
- }
- }
-
- ///
- /// Get or set whether pitch records should be recorded into a history buffer
- ///
- public bool RecordPitchRecords
- {
- get { return m_recordPitchRecords; }
- set
- {
- if (m_recordPitchRecords == value)
- return;
-
- m_recordPitchRecords = value;
-
- if (!m_recordPitchRecords)
- m_pitchRecords = new List();
- }
- }
-
- ///
- /// Get or set the max number of pitch records to keep. A value of 0 means no limit.
- /// Don't leave this at 0 when RecordPitchRecords is true and this is used in a realtime
- /// application since the buffer will grow indefinately!
- ///
- public int PitchRecordHistorySize
- {
- get { return m_pitchRecordHistorySize; }
- set
- {
- m_pitchRecordHistorySize = value;
-
- m_pitchRecords.Capacity = m_pitchRecordHistorySize;
- }
- }
-
- ///
- /// Get the current pitch records
- ///
- public IList PitchRecords
- {
- get { return m_pitchRecords.AsReadOnly(); }
- }
-
- ///
- /// Get the latest pitch record
- ///
- public PitchRecord CurrentPitchRecord
- {
- get { return m_curPitchRecord; }
- }
-
- ///
- /// Get the current pitch position
- ///
- public long CurrentPitchSamplePosition
- {
- get { return m_curPitchSamplePos; }
- }
-
- ///
- /// Get the minimum frequency that can be detected
- ///
- public static float MinDetectFrequency
- {
- get { return kMinFreq; }
- }
-
- ///
- /// Get the maximum frequency that can be detected
- ///
- public static float MaxDetectFrequency
- {
- get { return kMaxFreq; }
- }
-
- ///
- /// Get the frequency step
- ///
- public static double FrequencyStep
- {
- get { return Math.Pow(2.0, 1.0 / kOctaveSteps); }
- }
-
- ///
- /// Get the number of samples that the detected pitch is offset from the input buffer.
- /// This is just an estimate to sync up the samples and detected pitch
- ///
- public int DetectSampleOffset
- {
- get { return (m_pitchBufSize + m_detectOverlapSamples) / 2; }
- }
-
- ///
- /// Reset the pitch tracker. Call this when the sample position is
- /// not consecutive from the previous position
- ///
- public void Reset()
- {
- m_curPitchIndex = 0;
- m_curPitchSamplePos = 0;
- m_pitchRecords.Clear();
- m_iirFilterLoLo.Reset();
- m_iirFilterLoHi.Reset();
- m_iirFilterHiLo.Reset();
- m_iirFilterHiHi.Reset();
- m_circularBufferLo.Reset();
- m_circularBufferLo.Clear();
- m_circularBufferHi.Reset();
- m_circularBufferHi.Clear();
- m_pitchBufLo.Clear();
- m_pitchBufHi.Clear();
-
- m_circularBufferLo.StartPosition = -m_detectOverlapSamples;
- m_circularBufferLo.Available = m_detectOverlapSamples;
- m_circularBufferHi.StartPosition = -m_detectOverlapSamples;
- m_circularBufferHi.Available = m_detectOverlapSamples;
- }
-
- ///
- /// Process the passed in buffer of data. During this call, the PitchDetected event will
- /// be fired zero or more times, depending how many pitch records will fit in the new
- /// and previously cached buffer.
- ///
- /// This means that there is no size restriction on the buffer that is passed into ProcessBuffer.
- /// For instance, ProcessBuffer can be called with one very large buffer that contains all of the
- /// audio to be processed (many PitchDetected events will be fired), or just a small buffer at
- /// a time which is more typical for realtime applications. In the latter case, the PitchDetected
- /// event might not be fired at all since additional calls must first be made to accumulate enough
- /// data do another pitch detect operation.
- ///
- /// Input buffer. Samples must be in the range -1.0 to 1.0
- ///
- /// Number of samples to process. Zero means all samples in the buffer
- public void ProcessBuffer(float[] inBuffer, int sampleCount = 0)
- {
- if (inBuffer == null)
- throw new ArgumentNullException("inBuffer", "Input buffer cannot be null");
-
- int samplesProcessed = 0;
- int srcLength = sampleCount == 0 ? inBuffer.Length : Math.Min(sampleCount, inBuffer.Length);
-
- float maxVolume = LastMaxVol * 0.85f;
-
- while (samplesProcessed < srcLength)
- {
- int frameCount = Math.Min(srcLength - samplesProcessed, m_pitchBufSize + m_detectOverlapSamples);
-
- m_iirFilterLoLo.FilterBuffer(inBuffer, samplesProcessed, m_pitchBufLo, 0, frameCount);
- m_iirFilterLoHi.FilterBuffer(m_pitchBufLo, 0, m_pitchBufLo, 0, frameCount);
-
- m_iirFilterHiLo.FilterBuffer(inBuffer, samplesProcessed, m_pitchBufHi, 0, frameCount);
- m_iirFilterHiHi.FilterBuffer(m_pitchBufHi, 0, m_pitchBufHi, 0, frameCount);
-
- m_circularBufferLo.WriteBuffer(m_pitchBufLo, frameCount);
- m_circularBufferHi.WriteBuffer(m_pitchBufHi, frameCount);
-
- // Loop while there is enough samples in the circular buffer
- while (m_circularBufferLo.ReadBuffer(m_pitchBufLo, m_curPitchSamplePos, m_pitchBufSize + m_detectOverlapSamples))
- {
- float pitch1;
- float pitch2;
- float detectedPitch = 0.0f;
-
- m_circularBufferHi.ReadBuffer(m_pitchBufHi, m_curPitchSamplePos, m_pitchBufSize + m_detectOverlapSamples);
-
- maxVolume = 0f;
- for (int i = 0; i < (m_pitchBufSize + m_detectOverlapSamples) / 2; i++)
- {
- if (maxVolume < m_pitchBufHi[i])
- maxVolume = m_pitchBufHi[i];
- if (maxVolume < m_pitchBufLo[i])
- maxVolume = m_pitchBufLo[i];
- }
-
- pitch1 = (maxVolume >= m_detectLevelThreshold) ? m_dsp.DetectPitch(m_pitchBufLo, m_pitchBufHi) : 0f;
-
- if (pitch1 > 0.0f)
- {
- // Shift the buffers left by the overlapping amount
- m_pitchBufLo.Copy(m_pitchBufLo, m_detectOverlapSamples - 1, 0, m_pitchBufSize);
- m_pitchBufHi.Copy(m_pitchBufHi, m_detectOverlapSamples - 1, 0, m_pitchBufSize);
-
- pitch2 = m_dsp.DetectPitch(m_pitchBufLo, m_pitchBufHi);
-
- if (pitch2 > 0.0f)
- {
- float fDiff = Math.Max(pitch1, pitch2) / Math.Min(pitch1, pitch2) - 1.0f;
-
- if (fDiff < m_maxOverlapDiff)
- detectedPitch = (pitch1 + pitch2) * 0.5f;
- }
- }
-
- // Log the pitch record
- AddPitchRecord(detectedPitch);
-
- m_curPitchSamplePos += m_samplesPerPitchBlock;
- m_curPitchIndex++;
- }
-
- samplesProcessed += frameCount;
- }
- LastMaxVol = maxVolume;
- }
-
- ///
- /// Setup
- ///
- private void Setup()
- {
- if (m_sampleRate < 1.0f)
- return;
-
- m_dsp = new PitchDsp(m_sampleRate, kMinFreq, kMaxFreq);
-
- m_iirFilterLoLo = new IIRFilter();
- m_iirFilterLoLo.Proto = IIRFilter.ProtoType.Butterworth;
- m_iirFilterLoLo.Type = IIRFilter.FilterType.HP;
- m_iirFilterLoLo.Order = 5;
- m_iirFilterLoLo.FreqLow = 45.0f;
- m_iirFilterLoLo.SampleRate = (float)m_sampleRate;
-
- m_iirFilterLoHi = new IIRFilter();
- m_iirFilterLoHi.Proto = IIRFilter.ProtoType.Butterworth;
- m_iirFilterLoHi.Type = IIRFilter.FilterType.LP;
- m_iirFilterLoHi.Order = 5;
- m_iirFilterLoHi.FreqHigh = 280.0f;
- m_iirFilterLoHi.SampleRate = (float)m_sampleRate;
-
- m_iirFilterHiLo = new IIRFilter();
- m_iirFilterHiLo.Proto = IIRFilter.ProtoType.Butterworth;
- m_iirFilterHiLo.Type = IIRFilter.FilterType.HP;
- m_iirFilterHiLo.Order = 5;
- m_iirFilterHiLo.FreqLow = 45.0f;
- m_iirFilterHiLo.SampleRate = (float)m_sampleRate;
-
- m_iirFilterHiHi = new IIRFilter();
- m_iirFilterHiHi.Proto = IIRFilter.ProtoType.Butterworth;
- m_iirFilterHiHi.Type = IIRFilter.FilterType.LP;
- m_iirFilterHiHi.Order = 5;
- m_iirFilterHiHi.FreqHigh = 2000.0f;
- m_iirFilterHiHi.SampleRate = (float)m_sampleRate;
-
- m_detectOverlapSamples = (int)(kDetectOverlapSec * m_sampleRate);
- m_maxOverlapDiff = kMaxOctaveSecRate * kDetectOverlapSec;
-
- m_pitchBufSize = (int)(((1.0f / (float)kMinFreq) * 2.0f + ((kAvgCount - 1) * kAvgOffset)) * m_sampleRate) + 16;
- m_pitchBufLo = new float[m_pitchBufSize + m_detectOverlapSamples];
- m_pitchBufHi = new float[m_pitchBufSize + m_detectOverlapSamples];
- m_samplesPerPitchBlock = (int)Math.Round(m_sampleRate / m_pitchRecordsPerSecond);
-
- m_circularBufferLo = new CircularBuffer((int)(kCircularBufSaveTime * m_sampleRate + 0.5f) + 10000);
- m_circularBufferHi = new CircularBuffer((int)(kCircularBufSaveTime * m_sampleRate + 0.5f) + 10000);
- }
-
- ///
- /// The pitch was detected - add the record
- ///
- ///
- private void AddPitchRecord(float pitch)
- {
- int midiNote = 0;
- int midiCents = 0;
-
- PitchDsp.PitchToMidiNote(pitch, out midiNote, out midiCents);
-
- var record = new PitchRecord();
-
- record.RecordIndex = m_curPitchIndex;
- record.Pitch = pitch;
- record.MidiNote = midiNote;
- record.MidiCents = midiCents;
-
- m_curPitchRecord = record;
-
- if (m_recordPitchRecords)
- {
- if (m_pitchRecordHistorySize > 0 && m_pitchRecords.Count >= m_pitchRecordHistorySize)
- m_pitchRecords.RemoveAt(0);
-
- m_pitchRecords.Add(record);
- }
-
- if (this.PitchDetected != null)
- this.PitchDetected(this, record);
- }
-
- ///
- /// Stores one record
- ///
- public struct PitchRecord
- {
- ///
- /// The index of the pitch record since the last Reset call
- ///
- public int RecordIndex { get; set; }
-
- ///
- /// The detected pitch
- ///
- public float Pitch { get; set; }
-
- ///
- /// The detected MIDI note, or 0 for no pitch
- ///
- public int MidiNote { get; set; }
-
- ///
- /// The offset from the detected MIDI note in cents, from -50 to +50.
- ///
- public int MidiCents { get; set; }
- }
- }
-
- // ReSharper restore InconsistentNaming
-}
\ No newline at end of file
diff --git a/Vocaluxe/Vocaluxe.csproj b/Vocaluxe/Vocaluxe.csproj
index 02af3467..0c0d6aac 100644
--- a/Vocaluxe/Vocaluxe.csproj
+++ b/Vocaluxe/Vocaluxe.csproj
@@ -292,13 +292,7 @@
-
-
-
-
-
-