public static unsafe double CrossCorrelationOffset(byte[] x, byte[] y) { if (x.Length != y.Length) { throw new ArgumentException("interval lengths do not match"); } fixed(byte *xB = &x[0], yB = &y[0]) { float *xF = (float *)xB; float *yF = (float *)yB; int n = x.Length / sizeof(float); CrossCorrelation.Result ccr; return((1 - Math.Abs(CrossCorrelation.Calculate(xF, yF, n, out ccr)) / (n / 2d)) * ccr.AbsoluteMaxValue); } }
public void Execute() { Debug.WriteLine("window length: {0}s, interval length: {1}s, sample rate: {2}", windowLength.TotalSeconds, intervalLength.TotalSeconds, sampleRate); IProgressReporter reporter = progressMonitor.BeginTask("Analyzing alignment...", true); List <IAudioStream> streams = new List <IAudioStream>(audioTracks.Count); TimeSpan start = audioTracks.Start; TimeSpan end = audioTracks.End; foreach (AudioTrack audioTrack in audioTracks) { streams.Add(CrossCorrelation.PrepareStream(audioTrack.CreateAudioStream(), sampleRate)); } long[] streamOffsets = new long[audioTracks.Count]; for (int i = 0; i < audioTracks.Count; i++) { streamOffsets[i] = TimeUtil.TimeSpanToBytes(audioTracks[i].Offset - start, streams[0].Properties); } int windowLengthInBytes = (int)TimeUtil.TimeSpanToBytes(windowLength, streams[0].Properties); int windowLengthInSamples = windowLengthInBytes / streams[0].Properties.SampleBlockByteSize; long intervalLengthInBytes = TimeUtil.TimeSpanToBytes(intervalLength, streams[0].Properties); long analysisIntervalLength = TimeUtil.TimeSpanToBytes(end - start, streams[0].Properties); OnStarted(); byte[] x = new byte[windowLengthInBytes]; byte[] y = new byte[windowLengthInBytes]; long positionX; long positionY; double sumNegative = 0; double sumPositive = 0; int countNegative = 0; int countPositive = 0; double min = 0; double max = 0; for (long position = 0; position < analysisIntervalLength; position += intervalLengthInBytes) { double windowSumNegative = 0; double windowSumPositive = 0; int windowCountNegative = 0; int windowCountPositive = 0; double windowMin = 0; double windowMax = 0; Debug.WriteLine("Analyzing {0} @ {1} / {2}", intervalLengthInBytes, position, analysisIntervalLength); // at each position in the analysis interval, compare each stream with each other for (int i = 0; i < streams.Count; i++) { positionX = position - streamOffsets[i]; if (positionX >= 0 && positionX < streams[i].Length) { streams[i].Position = positionX; StreamUtil.ForceRead(streams[i], x, 0, windowLengthInBytes); for (int j = i + 1; j < streams.Count; j++) { positionY = position - streamOffsets[j]; if (positionY >= 0 && positionY < streams[j].Length) { streams[j].Position = positionY; StreamUtil.ForceRead(streams[j], y, 0, windowLengthInBytes); double val = analyzeSection(x, y); if (val > 0) { windowSumPositive += val; windowCountPositive++; } else { windowSumNegative += val; windowCountNegative++; } if (windowMin > val) { windowMin = val; } if (windowMax < val) { windowMax = val; } Debug.WriteLine("{0,2}->{1,2}: {2}", i, j, val); } } } } sumPositive += windowSumPositive; countPositive += windowCountPositive; sumNegative += windowSumNegative; countNegative += windowCountNegative; if (min > windowMin) { min = windowMin; } if (max < windowMax) { max = windowMax; } reporter.ReportProgress((double)position / analysisIntervalLength * 100); OnWindowAnalyzed(start + TimeUtil.BytesToTimeSpan(position, streams[0].Properties), windowCountPositive, windowCountNegative, windowMin, windowMax, windowSumPositive, windowSumNegative); } reporter.Finish(); Debug.WriteLine("Finished. sum: {0}, sum+: {1}, sum-: {2}, sumAbs: {3}, avg: {4}, avg+: {5}, avg-: {6}, avgAbs: {7}, min: {8}, max: {9}, points: {10}", sumPositive + sumNegative, sumPositive, sumNegative, sumPositive + (sumNegative * -1), (sumPositive + sumNegative) / (countPositive + countNegative), sumPositive / countPositive, sumNegative / countNegative, (sumPositive + (sumNegative * -1)) / (countPositive + countNegative), min, max, countPositive + countNegative); double score = (sumPositive + (sumNegative * -1)) / (countPositive + countNegative); Debug.WriteLine("Score: {0} => {1}%", score, Math.Round(score * 100)); OnFinished(countPositive, countNegative, min, max, sumPositive, sumNegative); streams.ForEach(s => s.Close()); }