Split classes from CSound.cs to separate files (1 class/file) and move to Lib/Sound (where they belong)
This commit is contained in:
1 parent
10ecc361e2
commit
5270d570d5
5 files changed
+376
-361
No files matched your search
@@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Vocaluxe.Lib.Sound;
|
using Vocaluxe.Lib.Sound;
|
||||||
using VocaluxeLib;
|
using VocaluxeLib;
|
||||||
@@ -311,364 +310,4 @@ namespace Vocaluxe.Base
|
|||||||
}
|
}
|
||||||
#endregion Record
|
#endregion Record
|
||||||
}
|
}
|
||||||
|
|
||||||
class CBuffer : IDisposable
|
|
||||||
{
|
|
||||||
private const double _BaseToneFreq = 65.4064;
|
|
||||||
public const int NumHalfTones = 17;
|
|
||||||
|
|
||||||
private const int _AnalysisBufLen = 4096;
|
|
||||||
private const int _AnalysisByteBufLen = _AnalysisBufLen * 2;
|
|
||||||
|
|
||||||
private readonly Int16[] _AnalysisBuffer = new Int16[_AnalysisBufLen];
|
|
||||||
private readonly byte[] _AnalysisByteBuffer = new byte[_AnalysisByteBufLen]; //tmp buffer (stream->tmpBuffer->(Int16)AnalysisBuffer)
|
|
||||||
|
|
||||||
private static readonly int[] _SamplesPerPeriodPerTone = new int[NumHalfTones]; //Precalculated table holding sample# per period for each tone
|
|
||||||
private readonly float[] _TmpWeight = new float[NumHalfTones]; //tmp buffer for weights (gets copied to ToneWeight when checked)
|
|
||||||
|
|
||||||
private double _MaxVolume;
|
|
||||||
private bool _NewSamples;
|
|
||||||
|
|
||||||
private MemoryStream _Stream = new MemoryStream(); // full buffer
|
|
||||||
|
|
||||||
public CBuffer()
|
|
||||||
{
|
|
||||||
ToneWeigth = new float[NumHalfTones];
|
|
||||||
for (int i = 0; i < ToneWeigth.Length; i++)
|
|
||||||
ToneWeigth[i] = 0.99f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static CBuffer()
|
|
||||||
{
|
|
||||||
const double halftoneBase = 1.05946309436; // 2^(1/12) -> HalftoneBase^12 = 2 (one octave)
|
|
||||||
//Init Array to avoid costly calculations
|
|
||||||
for (int toneIndex = 0; toneIndex < NumHalfTones; toneIndex++)
|
|
||||||
{
|
|
||||||
double freq = _BaseToneFreq * Math.Pow(halftoneBase, toneIndex);
|
|
||||||
_SamplesPerPeriodPerTone[toneIndex] = (int)Math.Round(44100.0 / freq); // samples in one period
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ToneAbs { get; private set; }
|
|
||||||
|
|
||||||
public int Tone { get; set; }
|
|
||||||
|
|
||||||
public float MaxVolume
|
|
||||||
{
|
|
||||||
get { return (float)_MaxVolume; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ToneValid { get; private set; }
|
|
||||||
|
|
||||||
public float[] ToneWeigth { get; private set; }
|
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
lock (_Stream)
|
|
||||||
{
|
|
||||||
_Stream.SetLength(0L);
|
|
||||||
_NewSamples = false;
|
|
||||||
}
|
|
||||||
ToneValid = false;
|
|
||||||
ToneAbs = 0;
|
|
||||||
Tone = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void _Add(byte[] bytes)
|
|
||||||
{
|
|
||||||
_Stream.Write(bytes, 0, bytes.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ProcessNewBuffer(byte[] buffer)
|
|
||||||
{
|
|
||||||
// apply software boost
|
|
||||||
//BoostBuffer(Buffer, BufferSize);
|
|
||||||
|
|
||||||
// voice passthrough (send data to playback-device)
|
|
||||||
//if (assigned(fVoiceStream)) then
|
|
||||||
//fVoiceStream.WriteData(Buffer, BufferSize);
|
|
||||||
lock (_Stream)
|
|
||||||
{
|
|
||||||
_Add(buffer);
|
|
||||||
_NewSamples = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AnalyzeBuffer()
|
|
||||||
{
|
|
||||||
if (!_NewSamples)
|
|
||||||
return;
|
|
||||||
|
|
||||||
lock (_Stream)
|
|
||||||
{
|
|
||||||
if (_Stream.Length >= _AnalysisByteBufLen)
|
|
||||||
{
|
|
||||||
_Stream.Position -= _AnalysisByteBufLen;
|
|
||||||
_Stream.Read(_AnalysisByteBuffer, 0, _AnalysisByteBufLen);
|
|
||||||
}
|
|
||||||
_NewSamples = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < _AnalysisBufLen; i++)
|
|
||||||
_AnalysisBuffer[i] = BitConverter.ToInt16(_AnalysisByteBuffer, i * 2);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// find maximum volume
|
|
||||||
_FindMaxVolume();
|
|
||||||
|
|
||||||
if (MaxVolume >= 0.02)
|
|
||||||
_AnalyzeByAutocorrelation();
|
|
||||||
else
|
|
||||||
ToneValid = false;
|
|
||||||
}
|
|
||||||
catch (Exception) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void _FindMaxVolume()
|
|
||||||
{
|
|
||||||
short maxVolume = 0;
|
|
||||||
for (int i = 0; i < _AnalysisBuffer.Length / 4; i++)
|
|
||||||
{
|
|
||||||
short volume = _AnalysisBuffer[i];
|
|
||||||
if (volume < 0)
|
|
||||||
{
|
|
||||||
if (volume == Int16.MinValue)
|
|
||||||
{
|
|
||||||
maxVolume = Int16.MaxValue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
volume = (short)-volume;
|
|
||||||
}
|
|
||||||
if (volume > maxVolume)
|
|
||||||
maxVolume = volume;
|
|
||||||
}
|
|
||||||
_MaxVolume = (double)maxVolume / Int16.MaxValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void _AnalyzeByAutocorrelation()
|
|
||||||
{
|
|
||||||
// prepare to analyze
|
|
||||||
double maxWeight = -1.0;
|
|
||||||
double minWeight = 1.0;
|
|
||||||
int maxTone = -1;
|
|
||||||
|
|
||||||
// analyze halftones
|
|
||||||
// Note: at the lowest tone (~65Hz) and a buffer-size of 4096
|
|
||||||
// at 44.1 (or 48kHz) only 6 (or 5) samples are compared, this might be
|
|
||||||
// too few samples -> use a bigger buffer-size
|
|
||||||
for (int toneIndex = 0; toneIndex < NumHalfTones; toneIndex++)
|
|
||||||
{
|
|
||||||
double curWeight = _AnalyzeAutocorrelationTone(toneIndex);
|
|
||||||
|
|
||||||
if (curWeight > maxWeight)
|
|
||||||
{
|
|
||||||
maxWeight = curWeight;
|
|
||||||
maxTone = toneIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (curWeight < minWeight)
|
|
||||||
minWeight = curWeight;
|
|
||||||
|
|
||||||
_TmpWeight[toneIndex] = (float)curWeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxWeight - minWeight > 0.01)
|
|
||||||
{
|
|
||||||
Array.Copy(_TmpWeight, ToneWeigth, NumHalfTones);
|
|
||||||
|
|
||||||
ToneAbs = maxTone;
|
|
||||||
Tone = maxTone % 12;
|
|
||||||
ToneValid = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ToneValid = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private double _AnalyzeAutocorrelationTone(int tone)
|
|
||||||
{
|
|
||||||
int samplesPerPeriod = _SamplesPerPeriodPerTone[tone]; // samples in one period
|
|
||||||
|
|
||||||
int accumDist = 0; // accumulated distances
|
|
||||||
|
|
||||||
// compare correlating samples
|
|
||||||
int sampleIndex = 0; // index of sample to analyze
|
|
||||||
// Start value= index of sample one period ahead
|
|
||||||
for (int correlatingSampleIndex = sampleIndex + samplesPerPeriod; correlatingSampleIndex < _AnalysisBufLen; correlatingSampleIndex++, sampleIndex++)
|
|
||||||
{
|
|
||||||
// calc distance (correlation: 1-dist/IntMax) to corresponding sample in next period
|
|
||||||
// distance (0=equal .. IntMax=totally different) between correlated samples
|
|
||||||
int dist = Math.Abs(_AnalysisBuffer[sampleIndex] - _AnalysisBuffer[correlatingSampleIndex]);
|
|
||||||
accumDist += dist;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1.0 - (double)accumDist / Int16.MaxValue / _AnalysisBufLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
if (_Stream != null)
|
|
||||||
{
|
|
||||||
_Stream.Dispose();
|
|
||||||
_Stream = null;
|
|
||||||
}
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CSyncTimer
|
|
||||||
{
|
|
||||||
private readonly CPt1 _ExternTime;
|
|
||||||
private readonly Stopwatch _Timer;
|
|
||||||
private float _SetValue;
|
|
||||||
|
|
||||||
public float Time
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
double nanosecPerTick = (1000.0 * 1000.0 * 1000.0) / Stopwatch.Frequency;
|
|
||||||
long ticks = _Timer.ElapsedTicks;
|
|
||||||
float dt = _Timer.ElapsedMilliseconds / 1000f;
|
|
||||||
|
|
||||||
if (Stopwatch.IsHighResolution && ticks != 0)
|
|
||||||
dt = (float)(ticks * nanosecPerTick / 1000000000.0);
|
|
||||||
|
|
||||||
return _SetValue + dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_ExternTime.Time = value;
|
|
||||||
_SetValue = value;
|
|
||||||
_Timer.Reset();
|
|
||||||
_Timer.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public CSyncTimer(float currentTime, float k, float t)
|
|
||||||
{
|
|
||||||
_ExternTime = new CPt1(currentTime, k, t);
|
|
||||||
_Timer = new Stopwatch();
|
|
||||||
_SetValue = currentTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Update(float newTime)
|
|
||||||
{
|
|
||||||
float et = _ExternTime.Update(newTime);
|
|
||||||
|
|
||||||
float dt = Time;
|
|
||||||
|
|
||||||
float diff = et - dt;
|
|
||||||
if (Math.Abs(diff) > 0.05f)
|
|
||||||
{
|
|
||||||
_Timer.Reset();
|
|
||||||
_Timer.Start();
|
|
||||||
_SetValue = dt + diff;
|
|
||||||
dt = _SetValue;
|
|
||||||
//Console.WriteLine("DRIFTED!!! " + diff.ToString());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (diff > 0.01f)
|
|
||||||
_SetValue += 0.000025f;
|
|
||||||
|
|
||||||
if (diff < -0.01f)
|
|
||||||
_SetValue -= 0.000025f;
|
|
||||||
}
|
|
||||||
//Console.WriteLine(diff.ToString());
|
|
||||||
return dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Pause()
|
|
||||||
{
|
|
||||||
_ExternTime.Pause();
|
|
||||||
_Timer.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Resume()
|
|
||||||
{
|
|
||||||
_ExternTime.Resume();
|
|
||||||
_Timer.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CPt1
|
|
||||||
{
|
|
||||||
private float _CurrentTime;
|
|
||||||
private float _OldTime;
|
|
||||||
|
|
||||||
private readonly Stopwatch _Timer;
|
|
||||||
private readonly float _K;
|
|
||||||
private readonly float _T;
|
|
||||||
|
|
||||||
public float Time
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
double nanosecPerTick = (1000.0 * 1000.0 * 1000.0) / Stopwatch.Frequency;
|
|
||||||
long ticks = _Timer.ElapsedTicks;
|
|
||||||
float dt = _Timer.ElapsedMilliseconds / 1000f;
|
|
||||||
|
|
||||||
if (Stopwatch.IsHighResolution && ticks != 0)
|
|
||||||
dt = (float)(ticks * nanosecPerTick / 1000000000.0);
|
|
||||||
|
|
||||||
return _CurrentTime + dt;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value < 0f)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_CurrentTime = value;
|
|
||||||
_OldTime = value;
|
|
||||||
_Timer.Reset();
|
|
||||||
_Timer.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public CPt1(float currentTime, float k, float t)
|
|
||||||
{
|
|
||||||
_CurrentTime = currentTime;
|
|
||||||
_OldTime = currentTime;
|
|
||||||
|
|
||||||
_Timer = new Stopwatch();
|
|
||||||
_K = k;
|
|
||||||
_T = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Update(float newTime)
|
|
||||||
{
|
|
||||||
_Timer.Stop();
|
|
||||||
|
|
||||||
double nanosecPerTick = (1000.0 * 1000.0 * 1000.0) / Stopwatch.Frequency;
|
|
||||||
long ticks = _Timer.ElapsedTicks;
|
|
||||||
float dt = _Timer.ElapsedMilliseconds / 1000f;
|
|
||||||
|
|
||||||
if (Stopwatch.IsHighResolution && ticks != 0)
|
|
||||||
dt = (float)(ticks * nanosecPerTick / 1000000000.0);
|
|
||||||
|
|
||||||
float ts = 0f;
|
|
||||||
if (dt > 0)
|
|
||||||
ts = 1 / (_T / dt + 1);
|
|
||||||
|
|
||||||
_CurrentTime = ts * (_K * newTime - _OldTime) + _OldTime;
|
|
||||||
_OldTime = _CurrentTime;
|
|
||||||
|
|
||||||
_Timer.Reset();
|
|
||||||
_Timer.Start();
|
|
||||||
|
|
||||||
return _CurrentTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Pause()
|
|
||||||
{
|
|
||||||
_Timer.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Resume()
|
|
||||||
{
|
|
||||||
_Timer.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,209 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Vocaluxe.Lib.Sound
|
||||||
|
{
|
||||||
|
class CBuffer : IDisposable
|
||||||
|
{
|
||||||
|
private const double _BaseToneFreq = 65.4064;
|
||||||
|
public const int NumHalfTones = 17;
|
||||||
|
|
||||||
|
private const int _AnalysisBufLen = 4096;
|
||||||
|
private const int _AnalysisByteBufLen = _AnalysisBufLen * 2;
|
||||||
|
|
||||||
|
private readonly Int16[] _AnalysisBuffer = new Int16[_AnalysisBufLen];
|
||||||
|
private readonly byte[] _AnalysisByteBuffer = new byte[_AnalysisByteBufLen]; //tmp buffer (stream->tmpBuffer->(Int16)AnalysisBuffer)
|
||||||
|
|
||||||
|
private static readonly int[] _SamplesPerPeriodPerTone = new int[NumHalfTones]; //Precalculated table holding sample# per period for each tone
|
||||||
|
private readonly float[] _TmpWeight = new float[NumHalfTones]; //tmp buffer for weights (gets copied to ToneWeight when checked)
|
||||||
|
|
||||||
|
private double _MaxVolume;
|
||||||
|
private bool _NewSamples;
|
||||||
|
|
||||||
|
private MemoryStream _Stream = new MemoryStream(); // full buffer
|
||||||
|
|
||||||
|
public CBuffer()
|
||||||
|
{
|
||||||
|
ToneWeigth = new float[NumHalfTones];
|
||||||
|
for (int i = 0; i < ToneWeigth.Length; i++)
|
||||||
|
ToneWeigth[i] = 0.99f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static CBuffer()
|
||||||
|
{
|
||||||
|
const double halftoneBase = 1.05946309436; // 2^(1/12) -> HalftoneBase^12 = 2 (one octave)
|
||||||
|
//Init Array to avoid costly calculations
|
||||||
|
for (int toneIndex = 0; toneIndex < NumHalfTones; toneIndex++)
|
||||||
|
{
|
||||||
|
double freq = _BaseToneFreq * Math.Pow(halftoneBase, toneIndex);
|
||||||
|
_SamplesPerPeriodPerTone[toneIndex] = (int)Math.Round(44100.0 / freq); // samples in one period
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ToneAbs { get; private set; }
|
||||||
|
|
||||||
|
public int Tone { get; set; }
|
||||||
|
|
||||||
|
public float MaxVolume
|
||||||
|
{
|
||||||
|
get { return (float)_MaxVolume; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ToneValid { get; private set; }
|
||||||
|
|
||||||
|
public float[] ToneWeigth { get; private set; }
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
lock (_Stream)
|
||||||
|
{
|
||||||
|
_Stream.SetLength(0L);
|
||||||
|
_NewSamples = false;
|
||||||
|
}
|
||||||
|
ToneValid = false;
|
||||||
|
ToneAbs = 0;
|
||||||
|
Tone = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _Add(byte[] bytes)
|
||||||
|
{
|
||||||
|
_Stream.Write(bytes, 0, bytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProcessNewBuffer(byte[] buffer)
|
||||||
|
{
|
||||||
|
// apply software boost
|
||||||
|
//BoostBuffer(Buffer, BufferSize);
|
||||||
|
|
||||||
|
// voice passthrough (send data to playback-device)
|
||||||
|
//if (assigned(fVoiceStream)) then
|
||||||
|
//fVoiceStream.WriteData(Buffer, BufferSize);
|
||||||
|
lock (_Stream)
|
||||||
|
{
|
||||||
|
_Add(buffer);
|
||||||
|
_NewSamples = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AnalyzeBuffer()
|
||||||
|
{
|
||||||
|
if (!_NewSamples)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock (_Stream)
|
||||||
|
{
|
||||||
|
if (_Stream.Length >= _AnalysisByteBufLen)
|
||||||
|
{
|
||||||
|
_Stream.Position -= _AnalysisByteBufLen;
|
||||||
|
_Stream.Read(_AnalysisByteBuffer, 0, _AnalysisByteBufLen);
|
||||||
|
}
|
||||||
|
_NewSamples = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < _AnalysisBufLen; i++)
|
||||||
|
_AnalysisBuffer[i] = BitConverter.ToInt16(_AnalysisByteBuffer, i * 2);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// find maximum volume
|
||||||
|
_FindMaxVolume();
|
||||||
|
|
||||||
|
if (MaxVolume >= 0.02)
|
||||||
|
_AnalyzeByAutocorrelation();
|
||||||
|
else
|
||||||
|
ToneValid = false;
|
||||||
|
}
|
||||||
|
catch (Exception) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _FindMaxVolume()
|
||||||
|
{
|
||||||
|
short maxVolume = 0;
|
||||||
|
for (int i = 0; i < _AnalysisBuffer.Length / 4; i++)
|
||||||
|
{
|
||||||
|
short volume = _AnalysisBuffer[i];
|
||||||
|
if (volume < 0)
|
||||||
|
{
|
||||||
|
if (volume == Int16.MinValue)
|
||||||
|
{
|
||||||
|
maxVolume = Int16.MaxValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
volume = (short)-volume;
|
||||||
|
}
|
||||||
|
if (volume > maxVolume)
|
||||||
|
maxVolume = volume;
|
||||||
|
}
|
||||||
|
_MaxVolume = (double)maxVolume / Int16.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _AnalyzeByAutocorrelation()
|
||||||
|
{
|
||||||
|
// prepare to analyze
|
||||||
|
double maxWeight = -1.0;
|
||||||
|
double minWeight = 1.0;
|
||||||
|
int maxTone = -1;
|
||||||
|
|
||||||
|
// analyze halftones
|
||||||
|
// Note: at the lowest tone (~65Hz) and a buffer-size of 4096
|
||||||
|
// at 44.1 (or 48kHz) only 6 (or 5) samples are compared, this might be
|
||||||
|
// too few samples -> use a bigger buffer-size
|
||||||
|
for (int toneIndex = 0; toneIndex < NumHalfTones; toneIndex++)
|
||||||
|
{
|
||||||
|
double curWeight = _AnalyzeAutocorrelationTone(toneIndex);
|
||||||
|
|
||||||
|
if (curWeight > maxWeight)
|
||||||
|
{
|
||||||
|
maxWeight = curWeight;
|
||||||
|
maxTone = toneIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curWeight < minWeight)
|
||||||
|
minWeight = curWeight;
|
||||||
|
|
||||||
|
_TmpWeight[toneIndex] = (float)curWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxWeight - minWeight > 0.01)
|
||||||
|
{
|
||||||
|
Array.Copy(_TmpWeight, ToneWeigth, NumHalfTones);
|
||||||
|
|
||||||
|
ToneAbs = maxTone;
|
||||||
|
Tone = maxTone % 12;
|
||||||
|
ToneValid = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ToneValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double _AnalyzeAutocorrelationTone(int tone)
|
||||||
|
{
|
||||||
|
int samplesPerPeriod = _SamplesPerPeriodPerTone[tone]; // samples in one period
|
||||||
|
|
||||||
|
int accumDist = 0; // accumulated distances
|
||||||
|
|
||||||
|
// compare correlating samples
|
||||||
|
int sampleIndex = 0; // index of sample to analyze
|
||||||
|
// Start value= index of sample one period ahead
|
||||||
|
for (int correlatingSampleIndex = sampleIndex + samplesPerPeriod; correlatingSampleIndex < _AnalysisBufLen; correlatingSampleIndex++, sampleIndex++)
|
||||||
|
{
|
||||||
|
// calc distance (correlation: 1-dist/IntMax) to corresponding sample in next period
|
||||||
|
// distance (0=equal .. IntMax=totally different) between correlated samples
|
||||||
|
int dist = Math.Abs(_AnalysisBuffer[sampleIndex] - _AnalysisBuffer[correlatingSampleIndex]);
|
||||||
|
accumDist += dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1.0 - (double)accumDist / Int16.MaxValue / _AnalysisBufLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (_Stream != null)
|
||||||
|
{
|
||||||
|
_Stream.Dispose();
|
||||||
|
_Stream = null;
|
||||||
|
}
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Vocaluxe.Lib.Sound
|
||||||
|
{
|
||||||
|
class CPt1
|
||||||
|
{
|
||||||
|
private float _CurrentTime;
|
||||||
|
private float _OldTime;
|
||||||
|
|
||||||
|
private readonly Stopwatch _Timer;
|
||||||
|
private readonly float _K;
|
||||||
|
private readonly float _T;
|
||||||
|
|
||||||
|
public float Time
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
double nanosecPerTick = (1000.0 * 1000.0 * 1000.0) / Stopwatch.Frequency;
|
||||||
|
long ticks = _Timer.ElapsedTicks;
|
||||||
|
float dt = _Timer.ElapsedMilliseconds / 1000f;
|
||||||
|
|
||||||
|
if (Stopwatch.IsHighResolution && ticks != 0)
|
||||||
|
dt = (float)(ticks * nanosecPerTick / 1000000000.0);
|
||||||
|
|
||||||
|
return _CurrentTime + dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value < 0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_CurrentTime = value;
|
||||||
|
_OldTime = value;
|
||||||
|
_Timer.Reset();
|
||||||
|
_Timer.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CPt1(float currentTime, float k, float t)
|
||||||
|
{
|
||||||
|
_CurrentTime = currentTime;
|
||||||
|
_OldTime = currentTime;
|
||||||
|
|
||||||
|
_Timer = new Stopwatch();
|
||||||
|
_K = k;
|
||||||
|
_T = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Update(float newTime)
|
||||||
|
{
|
||||||
|
_Timer.Stop();
|
||||||
|
|
||||||
|
double nanosecPerTick = (1000.0 * 1000.0 * 1000.0) / Stopwatch.Frequency;
|
||||||
|
long ticks = _Timer.ElapsedTicks;
|
||||||
|
float dt = _Timer.ElapsedMilliseconds / 1000f;
|
||||||
|
|
||||||
|
if (Stopwatch.IsHighResolution && ticks != 0)
|
||||||
|
dt = (float)(ticks * nanosecPerTick / 1000000000.0);
|
||||||
|
|
||||||
|
float ts = 0f;
|
||||||
|
if (dt > 0)
|
||||||
|
ts = 1 / (_T / dt + 1);
|
||||||
|
|
||||||
|
_CurrentTime = ts * (_K * newTime - _OldTime) + _OldTime;
|
||||||
|
_OldTime = _CurrentTime;
|
||||||
|
|
||||||
|
_Timer.Restart();
|
||||||
|
|
||||||
|
return _CurrentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Pause()
|
||||||
|
{
|
||||||
|
_Timer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resume()
|
||||||
|
{
|
||||||
|
_Timer.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
namespace Vocaluxe.Lib.Sound
|
||||||
|
{
|
||||||
|
class CSyncTimer
|
||||||
|
{
|
||||||
|
private readonly CPt1 _ExternTime;
|
||||||
|
private readonly Stopwatch _Timer;
|
||||||
|
private float _SetValue;
|
||||||
|
|
||||||
|
public float Time
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
double nanosecPerTick = (1000.0 * 1000.0 * 1000.0) / Stopwatch.Frequency;
|
||||||
|
long ticks = _Timer.ElapsedTicks;
|
||||||
|
float dt = _Timer.ElapsedMilliseconds / 1000f;
|
||||||
|
|
||||||
|
if (Stopwatch.IsHighResolution && ticks != 0)
|
||||||
|
dt = (float)(ticks * nanosecPerTick / 1000000000.0);
|
||||||
|
|
||||||
|
return _SetValue + dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_ExternTime.Time = value;
|
||||||
|
_SetValue = value;
|
||||||
|
_Timer.Reset();
|
||||||
|
_Timer.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CSyncTimer(float currentTime, float k, float t)
|
||||||
|
{
|
||||||
|
_ExternTime = new CPt1(currentTime, k, t);
|
||||||
|
_Timer = new Stopwatch();
|
||||||
|
_SetValue = currentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Update(float newTime)
|
||||||
|
{
|
||||||
|
float et = _ExternTime.Update(newTime);
|
||||||
|
|
||||||
|
float dt = Time;
|
||||||
|
|
||||||
|
float diff = et - dt;
|
||||||
|
if (Math.Abs(diff) > 0.05f)
|
||||||
|
{
|
||||||
|
_Timer.Reset();
|
||||||
|
_Timer.Start();
|
||||||
|
_SetValue = dt + diff;
|
||||||
|
dt = _SetValue;
|
||||||
|
//Console.WriteLine("DRIFTED!!! " + diff.ToString());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (diff > 0.01f)
|
||||||
|
_SetValue += 0.000025f;
|
||||||
|
|
||||||
|
if (diff < -0.01f)
|
||||||
|
_SetValue -= 0.000025f;
|
||||||
|
}
|
||||||
|
//Console.WriteLine(diff.ToString());
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Pause()
|
||||||
|
{
|
||||||
|
_ExternTime.Pause();
|
||||||
|
_Timer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resume()
|
||||||
|
{
|
||||||
|
_ExternTime.Resume();
|
||||||
|
_Timer.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -212,11 +212,14 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Base\CBackgroundMusic.cs" />
|
<Compile Include="Base\CBackgroundMusic.cs" />
|
||||||
|
<Compile Include="Lib\Sound\CBuffer.cs" />
|
||||||
<Compile Include="Base\CConfig.cs" />
|
<Compile Include="Base\CConfig.cs" />
|
||||||
<Compile Include="Base\CCover.cs" />
|
<Compile Include="Base\CCover.cs" />
|
||||||
<Compile Include="Base\CCursor.cs" />
|
<Compile Include="Base\CCursor.cs" />
|
||||||
<Compile Include="Base\CDataBase.cs" />
|
<Compile Include="Base\CDataBase.cs" />
|
||||||
<Compile Include="Base\CDraw.cs" />
|
<Compile Include="Base\CDraw.cs" />
|
||||||
|
<Compile Include="Lib\Sound\CPt1.cs" />
|
||||||
|
<Compile Include="Lib\Sound\CSyncTimer.cs" />
|
||||||
<Compile Include="Base\Fonts\CFont.cs" />
|
<Compile Include="Base\Fonts\CFont.cs" />
|
||||||
<Compile Include="Base\CGame.cs" />
|
<Compile Include="Base\CGame.cs" />
|
||||||
<Compile Include="Base\CController.cs" />
|
<Compile Include="Base\CController.cs" />
|
||||||
|
|||||||
Reference in new issue
Block a user