diff --git a/Correlator/App.config b/Correlator/App.config
index a673178..30cf21c 100644
--- a/Correlator/App.config
+++ b/Correlator/App.config
@@ -133,6 +133,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Correlator/App.config b/Correlator/App.config
index a673178..30cf21c 100644
--- a/Correlator/App.config
+++ b/Correlator/App.config
@@ -133,6 +133,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj
index 1dc857e..f593d28 100644
--- a/Correlator/Correlator.csproj
+++ b/Correlator/Correlator.csproj
@@ -65,6 +65,9 @@
..\packages\DryIoc.dll.4.7.7\lib\net45\DryIoc.dll
+
+ ..\packages\FftSharp.2.1.0\lib\netstandard2.0\FftSharp.dll
+
..\packages\HandyControl.3.3.0\lib\net48\HandyControl.dll
@@ -144,8 +147,8 @@
..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.4\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll
-
- ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
@@ -155,15 +158,15 @@
..\packages\System.Drawing.Common.4.7.2\lib\net461\System.Drawing.Common.dll
-
- ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
+
+ ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
@@ -232,7 +235,6 @@
SoundSpeedDialog.xaml
-
@@ -261,6 +263,7 @@
+
diff --git a/Correlator/App.config b/Correlator/App.config
index a673178..30cf21c 100644
--- a/Correlator/App.config
+++ b/Correlator/App.config
@@ -133,6 +133,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj
index 1dc857e..f593d28 100644
--- a/Correlator/Correlator.csproj
+++ b/Correlator/Correlator.csproj
@@ -65,6 +65,9 @@
..\packages\DryIoc.dll.4.7.7\lib\net45\DryIoc.dll
+
+ ..\packages\FftSharp.2.1.0\lib\netstandard2.0\FftSharp.dll
+
..\packages\HandyControl.3.3.0\lib\net48\HandyControl.dll
@@ -144,8 +147,8 @@
..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.4\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll
-
- ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
@@ -155,15 +158,15 @@
..\packages\System.Drawing.Common.4.7.2\lib\net461\System.Drawing.Common.dll
-
- ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
+
+ ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
@@ -232,7 +235,6 @@
SoundSpeedDialog.xaml
-
@@ -261,6 +263,7 @@
+
diff --git a/Correlator/DataService/ApplicationDataServiceImpl.cs b/Correlator/DataService/ApplicationDataServiceImpl.cs
index 3da8760..1b830bb 100644
--- a/Correlator/DataService/ApplicationDataServiceImpl.cs
+++ b/Correlator/DataService/ApplicationDataServiceImpl.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Windows.Media;
using Correlator.Model;
using Correlator.Util;
using Newtonsoft.Json;
@@ -98,5 +99,42 @@
return 0;
}
}
+
+ public Color[] GetAllHsvColors()
+ {
+ var result = new Color[256 * 6];
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[i] = Color.FromArgb(255, 255, (byte)i, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[256 + i] = Color.FromArgb(255, (byte)(255 - i), 255, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[512 + i] = Color.FromArgb(255, 0, 255, (byte)i);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[768 + i] = Color.FromArgb(255, 0, (byte)(255 - i), 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1024 + i] = Color.FromArgb(255, (byte)i, 0, 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1280 + i] = Color.FromArgb(255, 255, 0, (byte)(255 - i));
+ }
+
+ return result;
+ }
}
}
\ No newline at end of file
diff --git a/Correlator/App.config b/Correlator/App.config
index a673178..30cf21c 100644
--- a/Correlator/App.config
+++ b/Correlator/App.config
@@ -133,6 +133,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj
index 1dc857e..f593d28 100644
--- a/Correlator/Correlator.csproj
+++ b/Correlator/Correlator.csproj
@@ -65,6 +65,9 @@
..\packages\DryIoc.dll.4.7.7\lib\net45\DryIoc.dll
+
+ ..\packages\FftSharp.2.1.0\lib\netstandard2.0\FftSharp.dll
+
..\packages\HandyControl.3.3.0\lib\net48\HandyControl.dll
@@ -144,8 +147,8 @@
..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.4\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll
-
- ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
@@ -155,15 +158,15 @@
..\packages\System.Drawing.Common.4.7.2\lib\net461\System.Drawing.Common.dll
-
- ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
+
+ ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
@@ -232,7 +235,6 @@
SoundSpeedDialog.xaml
-
@@ -261,6 +263,7 @@
+
diff --git a/Correlator/DataService/ApplicationDataServiceImpl.cs b/Correlator/DataService/ApplicationDataServiceImpl.cs
index 3da8760..1b830bb 100644
--- a/Correlator/DataService/ApplicationDataServiceImpl.cs
+++ b/Correlator/DataService/ApplicationDataServiceImpl.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Windows.Media;
using Correlator.Model;
using Correlator.Util;
using Newtonsoft.Json;
@@ -98,5 +99,42 @@
return 0;
}
}
+
+ public Color[] GetAllHsvColors()
+ {
+ var result = new Color[256 * 6];
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[i] = Color.FromArgb(255, 255, (byte)i, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[256 + i] = Color.FromArgb(255, (byte)(255 - i), 255, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[512 + i] = Color.FromArgb(255, 0, 255, (byte)i);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[768 + i] = Color.FromArgb(255, 0, (byte)(255 - i), 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1024 + i] = Color.FromArgb(255, (byte)i, 0, 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1280 + i] = Color.FromArgb(255, 255, 0, (byte)(255 - i));
+ }
+
+ return result;
+ }
}
}
\ No newline at end of file
diff --git a/Correlator/DataService/IApplicationDataService.cs b/Correlator/DataService/IApplicationDataService.cs
index fd9fb5a..0dc0b5a 100644
--- a/Correlator/DataService/IApplicationDataService.cs
+++ b/Correlator/DataService/IApplicationDataService.cs
@@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
+using System.Windows.Media;
using Correlator.Model;
namespace Correlator.DataService
@@ -22,5 +23,11 @@
///
///
int GetSoundVelocity(string material, int pipeDiameter);
+
+ ///
+ /// 获取 HSV 中所有的基础颜色 (饱和度和明度均为最大值)
+ ///
+ /// 所有的 HSV 基础颜色(共 256 * 6 个, 并且随着索引增加, 颜色也会渐变)
+ Color[] GetAllHsvColors();
}
}
\ No newline at end of file
diff --git a/Correlator/App.config b/Correlator/App.config
index a673178..30cf21c 100644
--- a/Correlator/App.config
+++ b/Correlator/App.config
@@ -133,6 +133,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj
index 1dc857e..f593d28 100644
--- a/Correlator/Correlator.csproj
+++ b/Correlator/Correlator.csproj
@@ -65,6 +65,9 @@
..\packages\DryIoc.dll.4.7.7\lib\net45\DryIoc.dll
+
+ ..\packages\FftSharp.2.1.0\lib\netstandard2.0\FftSharp.dll
+
..\packages\HandyControl.3.3.0\lib\net48\HandyControl.dll
@@ -144,8 +147,8 @@
..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.4\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll
-
- ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
@@ -155,15 +158,15 @@
..\packages\System.Drawing.Common.4.7.2\lib\net461\System.Drawing.Common.dll
-
- ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
+
+ ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
@@ -232,7 +235,6 @@
SoundSpeedDialog.xaml
-
@@ -261,6 +263,7 @@
+
diff --git a/Correlator/DataService/ApplicationDataServiceImpl.cs b/Correlator/DataService/ApplicationDataServiceImpl.cs
index 3da8760..1b830bb 100644
--- a/Correlator/DataService/ApplicationDataServiceImpl.cs
+++ b/Correlator/DataService/ApplicationDataServiceImpl.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Windows.Media;
using Correlator.Model;
using Correlator.Util;
using Newtonsoft.Json;
@@ -98,5 +99,42 @@
return 0;
}
}
+
+ public Color[] GetAllHsvColors()
+ {
+ var result = new Color[256 * 6];
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[i] = Color.FromArgb(255, 255, (byte)i, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[256 + i] = Color.FromArgb(255, (byte)(255 - i), 255, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[512 + i] = Color.FromArgb(255, 0, 255, (byte)i);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[768 + i] = Color.FromArgb(255, 0, (byte)(255 - i), 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1024 + i] = Color.FromArgb(255, (byte)i, 0, 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1280 + i] = Color.FromArgb(255, 255, 0, (byte)(255 - i));
+ }
+
+ return result;
+ }
}
}
\ No newline at end of file
diff --git a/Correlator/DataService/IApplicationDataService.cs b/Correlator/DataService/IApplicationDataService.cs
index fd9fb5a..0dc0b5a 100644
--- a/Correlator/DataService/IApplicationDataService.cs
+++ b/Correlator/DataService/IApplicationDataService.cs
@@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
+using System.Windows.Media;
using Correlator.Model;
namespace Correlator.DataService
@@ -22,5 +23,11 @@
///
///
int GetSoundVelocity(string material, int pipeDiameter);
+
+ ///
+ /// 获取 HSV 中所有的基础颜色 (饱和度和明度均为最大值)
+ ///
+ /// 所有的 HSV 基础颜色(共 256 * 6 个, 并且随着索引增加, 颜色也会渐变)
+ Color[] GetAllHsvColors();
}
}
\ No newline at end of file
diff --git a/Correlator/Events/AudioSampleEvent.cs b/Correlator/Events/AudioSampleEvent.cs
deleted file mode 100644
index 2309da1..0000000
--- a/Correlator/Events/AudioSampleEvent.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Prism.Events;
-
-namespace Correlator.Events
-{
- public class AudioSampleEvent : PubSubEvent
- {
-
- }
-}
\ No newline at end of file
diff --git a/Correlator/App.config b/Correlator/App.config
index a673178..30cf21c 100644
--- a/Correlator/App.config
+++ b/Correlator/App.config
@@ -133,6 +133,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj
index 1dc857e..f593d28 100644
--- a/Correlator/Correlator.csproj
+++ b/Correlator/Correlator.csproj
@@ -65,6 +65,9 @@
..\packages\DryIoc.dll.4.7.7\lib\net45\DryIoc.dll
+
+ ..\packages\FftSharp.2.1.0\lib\netstandard2.0\FftSharp.dll
+
..\packages\HandyControl.3.3.0\lib\net48\HandyControl.dll
@@ -144,8 +147,8 @@
..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.4\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll
-
- ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
@@ -155,15 +158,15 @@
..\packages\System.Drawing.Common.4.7.2\lib\net461\System.Drawing.Common.dll
-
- ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
+
+ ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
@@ -232,7 +235,6 @@
SoundSpeedDialog.xaml
-
@@ -261,6 +263,7 @@
+
diff --git a/Correlator/DataService/ApplicationDataServiceImpl.cs b/Correlator/DataService/ApplicationDataServiceImpl.cs
index 3da8760..1b830bb 100644
--- a/Correlator/DataService/ApplicationDataServiceImpl.cs
+++ b/Correlator/DataService/ApplicationDataServiceImpl.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Windows.Media;
using Correlator.Model;
using Correlator.Util;
using Newtonsoft.Json;
@@ -98,5 +99,42 @@
return 0;
}
}
+
+ public Color[] GetAllHsvColors()
+ {
+ var result = new Color[256 * 6];
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[i] = Color.FromArgb(255, 255, (byte)i, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[256 + i] = Color.FromArgb(255, (byte)(255 - i), 255, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[512 + i] = Color.FromArgb(255, 0, 255, (byte)i);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[768 + i] = Color.FromArgb(255, 0, (byte)(255 - i), 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1024 + i] = Color.FromArgb(255, (byte)i, 0, 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1280 + i] = Color.FromArgb(255, 255, 0, (byte)(255 - i));
+ }
+
+ return result;
+ }
}
}
\ No newline at end of file
diff --git a/Correlator/DataService/IApplicationDataService.cs b/Correlator/DataService/IApplicationDataService.cs
index fd9fb5a..0dc0b5a 100644
--- a/Correlator/DataService/IApplicationDataService.cs
+++ b/Correlator/DataService/IApplicationDataService.cs
@@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
+using System.Windows.Media;
using Correlator.Model;
namespace Correlator.DataService
@@ -22,5 +23,11 @@
///
///
int GetSoundVelocity(string material, int pipeDiameter);
+
+ ///
+ /// 获取 HSV 中所有的基础颜色 (饱和度和明度均为最大值)
+ ///
+ /// 所有的 HSV 基础颜色(共 256 * 6 个, 并且随着索引增加, 颜色也会渐变)
+ Color[] GetAllHsvColors();
}
}
\ No newline at end of file
diff --git a/Correlator/Events/AudioSampleEvent.cs b/Correlator/Events/AudioSampleEvent.cs
deleted file mode 100644
index 2309da1..0000000
--- a/Correlator/Events/AudioSampleEvent.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Prism.Events;
-
-namespace Correlator.Events
-{
- public class AudioSampleEvent : PubSubEvent
- {
-
- }
-}
\ No newline at end of file
diff --git a/Correlator/Util/AudioVisualizer.cs b/Correlator/Util/AudioVisualizer.cs
new file mode 100644
index 0000000..c4b1f45
--- /dev/null
+++ b/Correlator/Util/AudioVisualizer.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Linq;
+using FftSharp;
+using FftSharp.Windows;
+
+namespace Correlator.Util
+{
+ public class AudioVisualizer
+ {
+ ///
+ /// 采样数据
+ ///
+ public double[] SampleData { get; }
+
+ ///
+ ///
+ ///
+ /// 控制频谱数量,数量越多,界面显示波动的频谱越多,建议256就好
+ ///
+ public AudioVisualizer(int waveDataSize)
+ {
+ if (!Get2Flag(waveDataSize))
+ {
+ throw new ArgumentException("长度必须是 2 的 n 次幂");
+ }
+
+ SampleData = new double[waveDataSize];
+ }
+
+ ///
+ /// 判断是否是 2 的整数次幂
+ ///
+ ///
+ ///
+ private bool Get2Flag(int num)
+ {
+ if (num < 1)
+ {
+ return false;
+ }
+
+ return (num & num - 1) == 0;
+ }
+
+ public void PushSampleData(double[] waveData)
+ {
+ if (waveData.Length > SampleData.Length)
+ {
+ Array.Copy(waveData, waveData.Length - SampleData.Length, SampleData, 0, SampleData.Length);
+ }
+ else
+ {
+ Array.Copy(SampleData, waveData.Length, SampleData, 0, SampleData.Length - waveData.Length);
+ Array.Copy(waveData, 0, SampleData, SampleData.Length - waveData.Length, waveData.Length);
+ }
+ }
+
+ ///
+ /// 获取频谱数据 (数据已经删去共轭部分)
+ ///
+ ///
+ public double[] GetSpectrumData()
+ {
+ var len = SampleData.Length;
+ var data = new Complex[len];
+
+ for (var i = 0; i < len; i++)
+ {
+ data[i] = new Complex(SampleData[i], 0);
+ }
+
+ Transform.FFT(data);
+
+ var halfLen = len / 2;
+ var result = new double[halfLen]; // 傅里叶变换结果左右对称, 只需要取一半
+ for (var i = 0; i < halfLen; i++)
+ {
+ result[i] = data[i].Magnitude / len;
+ }
+
+ var window = new Bartlett();
+ window.Create(halfLen);
+ window.ApplyInPlace(result);
+
+ return result;
+ }
+
+ ///
+ /// 简单的数据模糊
+ ///
+ /// 数据
+ /// 模糊半径
+ /// 结果
+ public static double[] MakeSmooth(double[] data, int radius)
+ {
+ var weights = GetWeights(radius);
+ var buffer = new double[1 + radius * 2];
+
+ var result = new double[data.Length];
+ if (data.Length < radius)
+ {
+ data.Average();
+ result.SetValue(data, 0);
+ return result;
+ }
+
+ for (var i = 0; i < radius; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + 1 + j] = data[i + j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ for (var i = radius; i < data.Length - radius; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[j] = data[i - j];
+ }
+
+ buffer[radius] = data[i];
+
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + j + 1] = data[i + j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ for (var i = data.Length - radius; i < data.Length; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + 1 + j] = data[i - j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ return result;
+ }
+
+ private static double[] GetWeights(int radius)
+ {
+ double Gaussian(double x) => Math.Pow(Math.E, -4 * x * x); // 高斯函数
+
+ var len = 1 + radius * 2; // 长度
+ var end = len - 1; // 最后的索引
+ var radiusF = (double)radius; // 半径浮点数
+ var weights = new double[len]; // 权重
+
+ for (var i = 0; i <= radius; i++) // 先把右边的权重算出来
+ {
+ weights[radius + i] = Gaussian(i / radiusF);
+ }
+
+ for (var i = 0; i < radius; i++) // 把右边的权重拷贝到左边
+ {
+ weights[i] = weights[end - i];
+ }
+
+ var total = weights.Sum();
+ for (var i = 0; i < len; i++) // 使权重合为 0
+ {
+ weights[i] /= total;
+ }
+
+ return weights;
+ }
+
+ private static void ApplyWeights(double[] buffer, double[] weights)
+ {
+ var len = buffer.Length;
+ for (var i = 0; i < len; i++)
+ {
+ buffer[i] *= weights[i];
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Correlator/App.config b/Correlator/App.config
index a673178..30cf21c 100644
--- a/Correlator/App.config
+++ b/Correlator/App.config
@@ -133,6 +133,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj
index 1dc857e..f593d28 100644
--- a/Correlator/Correlator.csproj
+++ b/Correlator/Correlator.csproj
@@ -65,6 +65,9 @@
..\packages\DryIoc.dll.4.7.7\lib\net45\DryIoc.dll
+
+ ..\packages\FftSharp.2.1.0\lib\netstandard2.0\FftSharp.dll
+
..\packages\HandyControl.3.3.0\lib\net48\HandyControl.dll
@@ -144,8 +147,8 @@
..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.4\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll
-
- ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
@@ -155,15 +158,15 @@
..\packages\System.Drawing.Common.4.7.2\lib\net461\System.Drawing.Common.dll
-
- ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
+
+ ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
@@ -232,7 +235,6 @@
SoundSpeedDialog.xaml
-
@@ -261,6 +263,7 @@
+
diff --git a/Correlator/DataService/ApplicationDataServiceImpl.cs b/Correlator/DataService/ApplicationDataServiceImpl.cs
index 3da8760..1b830bb 100644
--- a/Correlator/DataService/ApplicationDataServiceImpl.cs
+++ b/Correlator/DataService/ApplicationDataServiceImpl.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Windows.Media;
using Correlator.Model;
using Correlator.Util;
using Newtonsoft.Json;
@@ -98,5 +99,42 @@
return 0;
}
}
+
+ public Color[] GetAllHsvColors()
+ {
+ var result = new Color[256 * 6];
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[i] = Color.FromArgb(255, 255, (byte)i, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[256 + i] = Color.FromArgb(255, (byte)(255 - i), 255, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[512 + i] = Color.FromArgb(255, 0, 255, (byte)i);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[768 + i] = Color.FromArgb(255, 0, (byte)(255 - i), 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1024 + i] = Color.FromArgb(255, (byte)i, 0, 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1280 + i] = Color.FromArgb(255, 255, 0, (byte)(255 - i));
+ }
+
+ return result;
+ }
}
}
\ No newline at end of file
diff --git a/Correlator/DataService/IApplicationDataService.cs b/Correlator/DataService/IApplicationDataService.cs
index fd9fb5a..0dc0b5a 100644
--- a/Correlator/DataService/IApplicationDataService.cs
+++ b/Correlator/DataService/IApplicationDataService.cs
@@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
+using System.Windows.Media;
using Correlator.Model;
namespace Correlator.DataService
@@ -22,5 +23,11 @@
///
///
int GetSoundVelocity(string material, int pipeDiameter);
+
+ ///
+ /// 获取 HSV 中所有的基础颜色 (饱和度和明度均为最大值)
+ ///
+ /// 所有的 HSV 基础颜色(共 256 * 6 个, 并且随着索引增加, 颜色也会渐变)
+ Color[] GetAllHsvColors();
}
}
\ No newline at end of file
diff --git a/Correlator/Events/AudioSampleEvent.cs b/Correlator/Events/AudioSampleEvent.cs
deleted file mode 100644
index 2309da1..0000000
--- a/Correlator/Events/AudioSampleEvent.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Prism.Events;
-
-namespace Correlator.Events
-{
- public class AudioSampleEvent : PubSubEvent
- {
-
- }
-}
\ No newline at end of file
diff --git a/Correlator/Util/AudioVisualizer.cs b/Correlator/Util/AudioVisualizer.cs
new file mode 100644
index 0000000..c4b1f45
--- /dev/null
+++ b/Correlator/Util/AudioVisualizer.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Linq;
+using FftSharp;
+using FftSharp.Windows;
+
+namespace Correlator.Util
+{
+ public class AudioVisualizer
+ {
+ ///
+ /// 采样数据
+ ///
+ public double[] SampleData { get; }
+
+ ///
+ ///
+ ///
+ /// 控制频谱数量,数量越多,界面显示波动的频谱越多,建议256就好
+ ///
+ public AudioVisualizer(int waveDataSize)
+ {
+ if (!Get2Flag(waveDataSize))
+ {
+ throw new ArgumentException("长度必须是 2 的 n 次幂");
+ }
+
+ SampleData = new double[waveDataSize];
+ }
+
+ ///
+ /// 判断是否是 2 的整数次幂
+ ///
+ ///
+ ///
+ private bool Get2Flag(int num)
+ {
+ if (num < 1)
+ {
+ return false;
+ }
+
+ return (num & num - 1) == 0;
+ }
+
+ public void PushSampleData(double[] waveData)
+ {
+ if (waveData.Length > SampleData.Length)
+ {
+ Array.Copy(waveData, waveData.Length - SampleData.Length, SampleData, 0, SampleData.Length);
+ }
+ else
+ {
+ Array.Copy(SampleData, waveData.Length, SampleData, 0, SampleData.Length - waveData.Length);
+ Array.Copy(waveData, 0, SampleData, SampleData.Length - waveData.Length, waveData.Length);
+ }
+ }
+
+ ///
+ /// 获取频谱数据 (数据已经删去共轭部分)
+ ///
+ ///
+ public double[] GetSpectrumData()
+ {
+ var len = SampleData.Length;
+ var data = new Complex[len];
+
+ for (var i = 0; i < len; i++)
+ {
+ data[i] = new Complex(SampleData[i], 0);
+ }
+
+ Transform.FFT(data);
+
+ var halfLen = len / 2;
+ var result = new double[halfLen]; // 傅里叶变换结果左右对称, 只需要取一半
+ for (var i = 0; i < halfLen; i++)
+ {
+ result[i] = data[i].Magnitude / len;
+ }
+
+ var window = new Bartlett();
+ window.Create(halfLen);
+ window.ApplyInPlace(result);
+
+ return result;
+ }
+
+ ///
+ /// 简单的数据模糊
+ ///
+ /// 数据
+ /// 模糊半径
+ /// 结果
+ public static double[] MakeSmooth(double[] data, int radius)
+ {
+ var weights = GetWeights(radius);
+ var buffer = new double[1 + radius * 2];
+
+ var result = new double[data.Length];
+ if (data.Length < radius)
+ {
+ data.Average();
+ result.SetValue(data, 0);
+ return result;
+ }
+
+ for (var i = 0; i < radius; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + 1 + j] = data[i + j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ for (var i = radius; i < data.Length - radius; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[j] = data[i - j];
+ }
+
+ buffer[radius] = data[i];
+
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + j + 1] = data[i + j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ for (var i = data.Length - radius; i < data.Length; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + 1 + j] = data[i - j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ return result;
+ }
+
+ private static double[] GetWeights(int radius)
+ {
+ double Gaussian(double x) => Math.Pow(Math.E, -4 * x * x); // 高斯函数
+
+ var len = 1 + radius * 2; // 长度
+ var end = len - 1; // 最后的索引
+ var radiusF = (double)radius; // 半径浮点数
+ var weights = new double[len]; // 权重
+
+ for (var i = 0; i <= radius; i++) // 先把右边的权重算出来
+ {
+ weights[radius + i] = Gaussian(i / radiusF);
+ }
+
+ for (var i = 0; i < radius; i++) // 把右边的权重拷贝到左边
+ {
+ weights[i] = weights[end - i];
+ }
+
+ var total = weights.Sum();
+ for (var i = 0; i < len; i++) // 使权重合为 0
+ {
+ weights[i] /= total;
+ }
+
+ return weights;
+ }
+
+ private static void ApplyWeights(double[] buffer, double[] weights)
+ {
+ var len = buffer.Length;
+ for (var i = 0; i < len; i++)
+ {
+ buffer[i] *= weights[i];
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Correlator/ViewModels/AudioFileViewModel.cs b/Correlator/ViewModels/AudioFileViewModel.cs
index a9579a8..8366c70 100644
--- a/Correlator/ViewModels/AudioFileViewModel.cs
+++ b/Correlator/ViewModels/AudioFileViewModel.cs
@@ -4,7 +4,6 @@
using System.Linq;
using System.Windows.Controls;
using System.Windows.Threading;
-using Correlator.Events;
using Correlator.Model;
using Correlator.Util;
using HandyControl.Controls;
@@ -134,13 +133,6 @@
}
CurrentValue = _audioFileReader.CurrentTime.Seconds;
-
- var buffer = new float[1000];
- var samplesRead = _audioFileReader.Read(buffer, 0, buffer.Length);
- var samples = buffer.Take(samplesRead).Select(x => (double)Math.Abs(x));
- var array = samples.ToArray();
-
- eventAggregator.GetEvent().Publish(array);
};
GoBackCommand = new DelegateCommand(delegate
diff --git a/Correlator/App.config b/Correlator/App.config
index a673178..30cf21c 100644
--- a/Correlator/App.config
+++ b/Correlator/App.config
@@ -133,6 +133,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj
index 1dc857e..f593d28 100644
--- a/Correlator/Correlator.csproj
+++ b/Correlator/Correlator.csproj
@@ -65,6 +65,9 @@
..\packages\DryIoc.dll.4.7.7\lib\net45\DryIoc.dll
+
+ ..\packages\FftSharp.2.1.0\lib\netstandard2.0\FftSharp.dll
+
..\packages\HandyControl.3.3.0\lib\net48\HandyControl.dll
@@ -144,8 +147,8 @@
..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.4\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll
-
- ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
@@ -155,15 +158,15 @@
..\packages\System.Drawing.Common.4.7.2\lib\net461\System.Drawing.Common.dll
-
- ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
+
+ ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
@@ -232,7 +235,6 @@
SoundSpeedDialog.xaml
-
@@ -261,6 +263,7 @@
+
diff --git a/Correlator/DataService/ApplicationDataServiceImpl.cs b/Correlator/DataService/ApplicationDataServiceImpl.cs
index 3da8760..1b830bb 100644
--- a/Correlator/DataService/ApplicationDataServiceImpl.cs
+++ b/Correlator/DataService/ApplicationDataServiceImpl.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Windows.Media;
using Correlator.Model;
using Correlator.Util;
using Newtonsoft.Json;
@@ -98,5 +99,42 @@
return 0;
}
}
+
+ public Color[] GetAllHsvColors()
+ {
+ var result = new Color[256 * 6];
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[i] = Color.FromArgb(255, 255, (byte)i, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[256 + i] = Color.FromArgb(255, (byte)(255 - i), 255, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[512 + i] = Color.FromArgb(255, 0, 255, (byte)i);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[768 + i] = Color.FromArgb(255, 0, (byte)(255 - i), 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1024 + i] = Color.FromArgb(255, (byte)i, 0, 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1280 + i] = Color.FromArgb(255, 255, 0, (byte)(255 - i));
+ }
+
+ return result;
+ }
}
}
\ No newline at end of file
diff --git a/Correlator/DataService/IApplicationDataService.cs b/Correlator/DataService/IApplicationDataService.cs
index fd9fb5a..0dc0b5a 100644
--- a/Correlator/DataService/IApplicationDataService.cs
+++ b/Correlator/DataService/IApplicationDataService.cs
@@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
+using System.Windows.Media;
using Correlator.Model;
namespace Correlator.DataService
@@ -22,5 +23,11 @@
///
///
int GetSoundVelocity(string material, int pipeDiameter);
+
+ ///
+ /// 获取 HSV 中所有的基础颜色 (饱和度和明度均为最大值)
+ ///
+ /// 所有的 HSV 基础颜色(共 256 * 6 个, 并且随着索引增加, 颜色也会渐变)
+ Color[] GetAllHsvColors();
}
}
\ No newline at end of file
diff --git a/Correlator/Events/AudioSampleEvent.cs b/Correlator/Events/AudioSampleEvent.cs
deleted file mode 100644
index 2309da1..0000000
--- a/Correlator/Events/AudioSampleEvent.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Prism.Events;
-
-namespace Correlator.Events
-{
- public class AudioSampleEvent : PubSubEvent
- {
-
- }
-}
\ No newline at end of file
diff --git a/Correlator/Util/AudioVisualizer.cs b/Correlator/Util/AudioVisualizer.cs
new file mode 100644
index 0000000..c4b1f45
--- /dev/null
+++ b/Correlator/Util/AudioVisualizer.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Linq;
+using FftSharp;
+using FftSharp.Windows;
+
+namespace Correlator.Util
+{
+ public class AudioVisualizer
+ {
+ ///
+ /// 采样数据
+ ///
+ public double[] SampleData { get; }
+
+ ///
+ ///
+ ///
+ /// 控制频谱数量,数量越多,界面显示波动的频谱越多,建议256就好
+ ///
+ public AudioVisualizer(int waveDataSize)
+ {
+ if (!Get2Flag(waveDataSize))
+ {
+ throw new ArgumentException("长度必须是 2 的 n 次幂");
+ }
+
+ SampleData = new double[waveDataSize];
+ }
+
+ ///
+ /// 判断是否是 2 的整数次幂
+ ///
+ ///
+ ///
+ private bool Get2Flag(int num)
+ {
+ if (num < 1)
+ {
+ return false;
+ }
+
+ return (num & num - 1) == 0;
+ }
+
+ public void PushSampleData(double[] waveData)
+ {
+ if (waveData.Length > SampleData.Length)
+ {
+ Array.Copy(waveData, waveData.Length - SampleData.Length, SampleData, 0, SampleData.Length);
+ }
+ else
+ {
+ Array.Copy(SampleData, waveData.Length, SampleData, 0, SampleData.Length - waveData.Length);
+ Array.Copy(waveData, 0, SampleData, SampleData.Length - waveData.Length, waveData.Length);
+ }
+ }
+
+ ///
+ /// 获取频谱数据 (数据已经删去共轭部分)
+ ///
+ ///
+ public double[] GetSpectrumData()
+ {
+ var len = SampleData.Length;
+ var data = new Complex[len];
+
+ for (var i = 0; i < len; i++)
+ {
+ data[i] = new Complex(SampleData[i], 0);
+ }
+
+ Transform.FFT(data);
+
+ var halfLen = len / 2;
+ var result = new double[halfLen]; // 傅里叶变换结果左右对称, 只需要取一半
+ for (var i = 0; i < halfLen; i++)
+ {
+ result[i] = data[i].Magnitude / len;
+ }
+
+ var window = new Bartlett();
+ window.Create(halfLen);
+ window.ApplyInPlace(result);
+
+ return result;
+ }
+
+ ///
+ /// 简单的数据模糊
+ ///
+ /// 数据
+ /// 模糊半径
+ /// 结果
+ public static double[] MakeSmooth(double[] data, int radius)
+ {
+ var weights = GetWeights(radius);
+ var buffer = new double[1 + radius * 2];
+
+ var result = new double[data.Length];
+ if (data.Length < radius)
+ {
+ data.Average();
+ result.SetValue(data, 0);
+ return result;
+ }
+
+ for (var i = 0; i < radius; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + 1 + j] = data[i + j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ for (var i = radius; i < data.Length - radius; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[j] = data[i - j];
+ }
+
+ buffer[radius] = data[i];
+
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + j + 1] = data[i + j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ for (var i = data.Length - radius; i < data.Length; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + 1 + j] = data[i - j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ return result;
+ }
+
+ private static double[] GetWeights(int radius)
+ {
+ double Gaussian(double x) => Math.Pow(Math.E, -4 * x * x); // 高斯函数
+
+ var len = 1 + radius * 2; // 长度
+ var end = len - 1; // 最后的索引
+ var radiusF = (double)radius; // 半径浮点数
+ var weights = new double[len]; // 权重
+
+ for (var i = 0; i <= radius; i++) // 先把右边的权重算出来
+ {
+ weights[radius + i] = Gaussian(i / radiusF);
+ }
+
+ for (var i = 0; i < radius; i++) // 把右边的权重拷贝到左边
+ {
+ weights[i] = weights[end - i];
+ }
+
+ var total = weights.Sum();
+ for (var i = 0; i < len; i++) // 使权重合为 0
+ {
+ weights[i] /= total;
+ }
+
+ return weights;
+ }
+
+ private static void ApplyWeights(double[] buffer, double[] weights)
+ {
+ var len = buffer.Length;
+ for (var i = 0; i < len; i++)
+ {
+ buffer[i] *= weights[i];
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Correlator/ViewModels/AudioFileViewModel.cs b/Correlator/ViewModels/AudioFileViewModel.cs
index a9579a8..8366c70 100644
--- a/Correlator/ViewModels/AudioFileViewModel.cs
+++ b/Correlator/ViewModels/AudioFileViewModel.cs
@@ -4,7 +4,6 @@
using System.Linq;
using System.Windows.Controls;
using System.Windows.Threading;
-using Correlator.Events;
using Correlator.Model;
using Correlator.Util;
using HandyControl.Controls;
@@ -134,13 +133,6 @@
}
CurrentValue = _audioFileReader.CurrentTime.Seconds;
-
- var buffer = new float[1000];
- var samplesRead = _audioFileReader.Read(buffer, 0, buffer.Length);
- var samples = buffer.Take(samplesRead).Select(x => (double)Math.Abs(x));
- var array = samples.ToArray();
-
- eventAggregator.GetEvent().Publish(array);
};
GoBackCommand = new DelegateCommand(delegate
diff --git a/Correlator/Views/AudioFileView.xaml b/Correlator/Views/AudioFileView.xaml
index ac2cfb8..cf6531e 100644
--- a/Correlator/Views/AudioFileView.xaml
+++ b/Correlator/Views/AudioFileView.xaml
@@ -11,6 +11,8 @@
d:DataContext="{d:DesignInstance Type=vm:AudioFileViewModel}"
d:DesignHeight="1080"
d:DesignWidth="1920"
+ Loaded="AudioFileView_OnLoaded"
+ Unloaded="AudioFileView_OnUnloaded"
mc:Ignorable="d">
@@ -36,7 +38,7 @@
-
+
-
+ Margin="50,0">
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj
index 1dc857e..f593d28 100644
--- a/Correlator/Correlator.csproj
+++ b/Correlator/Correlator.csproj
@@ -65,6 +65,9 @@
..\packages\DryIoc.dll.4.7.7\lib\net45\DryIoc.dll
+
+ ..\packages\FftSharp.2.1.0\lib\netstandard2.0\FftSharp.dll
+
..\packages\HandyControl.3.3.0\lib\net48\HandyControl.dll
@@ -144,8 +147,8 @@
..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.4\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll
-
- ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
@@ -155,15 +158,15 @@
..\packages\System.Drawing.Common.4.7.2\lib\net461\System.Drawing.Common.dll
-
- ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
+
+ ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
@@ -232,7 +235,6 @@
SoundSpeedDialog.xaml
-
@@ -261,6 +263,7 @@
+
diff --git a/Correlator/DataService/ApplicationDataServiceImpl.cs b/Correlator/DataService/ApplicationDataServiceImpl.cs
index 3da8760..1b830bb 100644
--- a/Correlator/DataService/ApplicationDataServiceImpl.cs
+++ b/Correlator/DataService/ApplicationDataServiceImpl.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Windows.Media;
using Correlator.Model;
using Correlator.Util;
using Newtonsoft.Json;
@@ -98,5 +99,42 @@
return 0;
}
}
+
+ public Color[] GetAllHsvColors()
+ {
+ var result = new Color[256 * 6];
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[i] = Color.FromArgb(255, 255, (byte)i, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[256 + i] = Color.FromArgb(255, (byte)(255 - i), 255, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[512 + i] = Color.FromArgb(255, 0, 255, (byte)i);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[768 + i] = Color.FromArgb(255, 0, (byte)(255 - i), 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1024 + i] = Color.FromArgb(255, (byte)i, 0, 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1280 + i] = Color.FromArgb(255, 255, 0, (byte)(255 - i));
+ }
+
+ return result;
+ }
}
}
\ No newline at end of file
diff --git a/Correlator/DataService/IApplicationDataService.cs b/Correlator/DataService/IApplicationDataService.cs
index fd9fb5a..0dc0b5a 100644
--- a/Correlator/DataService/IApplicationDataService.cs
+++ b/Correlator/DataService/IApplicationDataService.cs
@@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
+using System.Windows.Media;
using Correlator.Model;
namespace Correlator.DataService
@@ -22,5 +23,11 @@
///
///
int GetSoundVelocity(string material, int pipeDiameter);
+
+ ///
+ /// 获取 HSV 中所有的基础颜色 (饱和度和明度均为最大值)
+ ///
+ /// 所有的 HSV 基础颜色(共 256 * 6 个, 并且随着索引增加, 颜色也会渐变)
+ Color[] GetAllHsvColors();
}
}
\ No newline at end of file
diff --git a/Correlator/Events/AudioSampleEvent.cs b/Correlator/Events/AudioSampleEvent.cs
deleted file mode 100644
index 2309da1..0000000
--- a/Correlator/Events/AudioSampleEvent.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Prism.Events;
-
-namespace Correlator.Events
-{
- public class AudioSampleEvent : PubSubEvent
- {
-
- }
-}
\ No newline at end of file
diff --git a/Correlator/Util/AudioVisualizer.cs b/Correlator/Util/AudioVisualizer.cs
new file mode 100644
index 0000000..c4b1f45
--- /dev/null
+++ b/Correlator/Util/AudioVisualizer.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Linq;
+using FftSharp;
+using FftSharp.Windows;
+
+namespace Correlator.Util
+{
+ public class AudioVisualizer
+ {
+ ///
+ /// 采样数据
+ ///
+ public double[] SampleData { get; }
+
+ ///
+ ///
+ ///
+ /// 控制频谱数量,数量越多,界面显示波动的频谱越多,建议256就好
+ ///
+ public AudioVisualizer(int waveDataSize)
+ {
+ if (!Get2Flag(waveDataSize))
+ {
+ throw new ArgumentException("长度必须是 2 的 n 次幂");
+ }
+
+ SampleData = new double[waveDataSize];
+ }
+
+ ///
+ /// 判断是否是 2 的整数次幂
+ ///
+ ///
+ ///
+ private bool Get2Flag(int num)
+ {
+ if (num < 1)
+ {
+ return false;
+ }
+
+ return (num & num - 1) == 0;
+ }
+
+ public void PushSampleData(double[] waveData)
+ {
+ if (waveData.Length > SampleData.Length)
+ {
+ Array.Copy(waveData, waveData.Length - SampleData.Length, SampleData, 0, SampleData.Length);
+ }
+ else
+ {
+ Array.Copy(SampleData, waveData.Length, SampleData, 0, SampleData.Length - waveData.Length);
+ Array.Copy(waveData, 0, SampleData, SampleData.Length - waveData.Length, waveData.Length);
+ }
+ }
+
+ ///
+ /// 获取频谱数据 (数据已经删去共轭部分)
+ ///
+ ///
+ public double[] GetSpectrumData()
+ {
+ var len = SampleData.Length;
+ var data = new Complex[len];
+
+ for (var i = 0; i < len; i++)
+ {
+ data[i] = new Complex(SampleData[i], 0);
+ }
+
+ Transform.FFT(data);
+
+ var halfLen = len / 2;
+ var result = new double[halfLen]; // 傅里叶变换结果左右对称, 只需要取一半
+ for (var i = 0; i < halfLen; i++)
+ {
+ result[i] = data[i].Magnitude / len;
+ }
+
+ var window = new Bartlett();
+ window.Create(halfLen);
+ window.ApplyInPlace(result);
+
+ return result;
+ }
+
+ ///
+ /// 简单的数据模糊
+ ///
+ /// 数据
+ /// 模糊半径
+ /// 结果
+ public static double[] MakeSmooth(double[] data, int radius)
+ {
+ var weights = GetWeights(radius);
+ var buffer = new double[1 + radius * 2];
+
+ var result = new double[data.Length];
+ if (data.Length < radius)
+ {
+ data.Average();
+ result.SetValue(data, 0);
+ return result;
+ }
+
+ for (var i = 0; i < radius; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + 1 + j] = data[i + j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ for (var i = radius; i < data.Length - radius; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[j] = data[i - j];
+ }
+
+ buffer[radius] = data[i];
+
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + j + 1] = data[i + j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ for (var i = data.Length - radius; i < data.Length; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + 1 + j] = data[i - j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ return result;
+ }
+
+ private static double[] GetWeights(int radius)
+ {
+ double Gaussian(double x) => Math.Pow(Math.E, -4 * x * x); // 高斯函数
+
+ var len = 1 + radius * 2; // 长度
+ var end = len - 1; // 最后的索引
+ var radiusF = (double)radius; // 半径浮点数
+ var weights = new double[len]; // 权重
+
+ for (var i = 0; i <= radius; i++) // 先把右边的权重算出来
+ {
+ weights[radius + i] = Gaussian(i / radiusF);
+ }
+
+ for (var i = 0; i < radius; i++) // 把右边的权重拷贝到左边
+ {
+ weights[i] = weights[end - i];
+ }
+
+ var total = weights.Sum();
+ for (var i = 0; i < len; i++) // 使权重合为 0
+ {
+ weights[i] /= total;
+ }
+
+ return weights;
+ }
+
+ private static void ApplyWeights(double[] buffer, double[] weights)
+ {
+ var len = buffer.Length;
+ for (var i = 0; i < len; i++)
+ {
+ buffer[i] *= weights[i];
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Correlator/ViewModels/AudioFileViewModel.cs b/Correlator/ViewModels/AudioFileViewModel.cs
index a9579a8..8366c70 100644
--- a/Correlator/ViewModels/AudioFileViewModel.cs
+++ b/Correlator/ViewModels/AudioFileViewModel.cs
@@ -4,7 +4,6 @@
using System.Linq;
using System.Windows.Controls;
using System.Windows.Threading;
-using Correlator.Events;
using Correlator.Model;
using Correlator.Util;
using HandyControl.Controls;
@@ -134,13 +133,6 @@
}
CurrentValue = _audioFileReader.CurrentTime.Seconds;
-
- var buffer = new float[1000];
- var samplesRead = _audioFileReader.Read(buffer, 0, buffer.Length);
- var samples = buffer.Take(samplesRead).Select(x => (double)Math.Abs(x));
- var array = samples.ToArray();
-
- eventAggregator.GetEvent().Publish(array);
};
GoBackCommand = new DelegateCommand(delegate
diff --git a/Correlator/Views/AudioFileView.xaml b/Correlator/Views/AudioFileView.xaml
index ac2cfb8..cf6531e 100644
--- a/Correlator/Views/AudioFileView.xaml
+++ b/Correlator/Views/AudioFileView.xaml
@@ -11,6 +11,8 @@
d:DataContext="{d:DesignInstance Type=vm:AudioFileViewModel}"
d:DesignHeight="1080"
d:DesignWidth="1920"
+ Loaded="AudioFileView_OnLoaded"
+ Unloaded="AudioFileView_OnUnloaded"
mc:Ignorable="d">
@@ -36,7 +38,7 @@
-
+
-
+ Margin="50,0">
+
+
().Subscribe(delegate(double[] doubles)
+ _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色)
+
+ _capture.WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(7500, 1);
+ _capture.DataAvailable += delegate(object o, WaveInEventArgs args)
{
- Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(delegate
+ var length = args.BytesRecorded / 4; // 采样的数量 (每一个采样是 4 字节)
+ var result = new double[length]; // 声明结果
+
+ for (var i = 0; i < length; i++)
{
- if (doubles.Any())
- {
- AudioWaveView.Plot.Clear();
- AudioWaveView.Plot.AddSignal(doubles, color: Color.FromArgb(255, 49, 151, 36));
- AudioWaveView.Refresh();
- }
- }));
- });
+ result[i] = BitConverter.ToSingle(args.Buffer, i * 4); // 取出采样值
+ }
+
+ _visualizer.PushSampleData(result); // 将新的采样存储到 可视化器 中
+ };
+
+ _dataTimer.Tick += DataTimer_Tick;
+ _drawingTimer.Tick += DrawingTimer_Tick;
+ }
+
+ private void AudioFileView_OnLoaded(object sender, RoutedEventArgs e)
+ {
+ _capture.StartRecording();
+ _dataTimer.Start();
+ _drawingTimer.Start();
+ }
+
+ private void AudioFileView_OnUnloaded(object sender, RoutedEventArgs e)
+ {
+ _drawingTimer.Stop();
+ _dataTimer.Stop();
+ _capture.StopRecording();
+ }
+
+ ///
+ /// 刷新频谱数据以及实现频谱数据缓动
+ ///
+ ///
+ ///
+ private void DataTimer_Tick(object sender, EventArgs e)
+ {
+ var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据
+ newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据
+
+ if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去
+ {
+ _spectrumData = newSpectrumData;
+ return;
+ }
+
+ for (var i = 0; i < newSpectrumData.Length; i++) // 计算旧频谱数据和新频谱数据之间的 "中间值"
+ {
+ var oldData = _spectrumData[i];
+ var newData = newSpectrumData[i];
+ // 每一次执行, 频谱值会向目标值移动 20% (如果太大, 缓动效果不明显, 如果太小, 频谱会有延迟的感觉)
+ var lerpData = oldData + (newData - oldData) * .2f;
+ _spectrumData[i] = lerpData;
+ }
+ }
+
+ private void DrawingTimer_Tick(object sender, EventArgs e)
+ {
+ if (_spectrumData == null)
+ {
+ return;
+ }
+
+ _colorIndex++;
+
+ var color1 = _allColors[_colorIndex % _allColors.Length];
+ var color2 = _allColors[(_colorIndex + 200) % _allColors.Length];
+
+ DrawGradientStrips(
+ StripsPath, color1, color2,
+ _spectrumData, _spectrumData.Length,
+ StripsPath.ActualWidth, 0, StripsPath.ActualHeight,
+ 2, -StripsPath.ActualHeight * 50
+ );
+ }
+
+ ///
+ /// 绘制渐变的条形
+ ///
+ /// 绘图目标
+ /// 下方颜色
+ /// 上方颜色
+ /// 频谱数据
+ /// 条形的数量
+ /// 绘图的宽度
+ /// 绘图的起始 X 坐标
+ /// 绘图的起始 Y 坐标
+ /// 条形与条形之间的间隔(像素)
+ /// 控制波形图波峰高度
+ private void DrawGradientStrips(Path stripsPath, Color bottomColor, Color topColor, double[] spectrumData,
+ int stripCount, double drawingWidth, double xOffset, double yOffset, double spacing, double scale)
+ {
+ //竖条宽度
+ var stripWidth = (drawingWidth - spacing * stripCount) / stripCount;
+ var pointArray = new Point[stripCount];
+
+ for (var i = 0; i < stripCount; i++)
+ {
+ var x = stripWidth * i + spacing * i + xOffset;
+ var y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height
+ //给所有频谱位置赋值
+ pointArray[i] = new Point(x, y);
+ }
+
+ //生成一系列频谱竖条
+ var geometry = new GeometryGroup();
+ foreach (var point in pointArray)
+ {
+ var height = point.Y;
+
+ if (height < 0)
+ {
+ height = -height;
+ }
+
+ //每根竖条的四个角坐标
+ var endPoints = new[]
+ {
+ new Point(point.X, point.Y + yOffset), //左下角
+ new Point(point.X, point.Y + height + yOffset), //左上角
+ new Point(point.X + stripWidth, point.Y + height + yOffset), //右上角
+ new Point(point.X + stripWidth, point.Y + yOffset) //右下角
+ };
+
+ var figure = new PathFigure
+ {
+ StartPoint = endPoints[0]
+ };
+
+ figure.Segments.Add(new PolyLineSegment(endPoints, false));
+ geometry.Children.Add(new PathGeometry { Figures = { figure } });
+ }
+
+ stripsPath.Data = geometry;
+
+ //设置频谱竖条的渐变色
+ var linearGradientBrush = new LinearGradientBrush(
+ bottomColor, topColor, new Point(0, 0), new Point(0, 1)
+ );
+ stripsPath.Fill = linearGradientBrush;
}
}
}
\ No newline at end of file
diff --git a/Correlator/App.config b/Correlator/App.config
index a673178..30cf21c 100644
--- a/Correlator/App.config
+++ b/Correlator/App.config
@@ -133,6 +133,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj
index 1dc857e..f593d28 100644
--- a/Correlator/Correlator.csproj
+++ b/Correlator/Correlator.csproj
@@ -65,6 +65,9 @@
..\packages\DryIoc.dll.4.7.7\lib\net45\DryIoc.dll
+
+ ..\packages\FftSharp.2.1.0\lib\netstandard2.0\FftSharp.dll
+
..\packages\HandyControl.3.3.0\lib\net48\HandyControl.dll
@@ -144,8 +147,8 @@
..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.4\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll
-
- ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
@@ -155,15 +158,15 @@
..\packages\System.Drawing.Common.4.7.2\lib\net461\System.Drawing.Common.dll
-
- ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
+
+ ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
@@ -232,7 +235,6 @@
SoundSpeedDialog.xaml
-
@@ -261,6 +263,7 @@
+
diff --git a/Correlator/DataService/ApplicationDataServiceImpl.cs b/Correlator/DataService/ApplicationDataServiceImpl.cs
index 3da8760..1b830bb 100644
--- a/Correlator/DataService/ApplicationDataServiceImpl.cs
+++ b/Correlator/DataService/ApplicationDataServiceImpl.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Windows.Media;
using Correlator.Model;
using Correlator.Util;
using Newtonsoft.Json;
@@ -98,5 +99,42 @@
return 0;
}
}
+
+ public Color[] GetAllHsvColors()
+ {
+ var result = new Color[256 * 6];
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[i] = Color.FromArgb(255, 255, (byte)i, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[256 + i] = Color.FromArgb(255, (byte)(255 - i), 255, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[512 + i] = Color.FromArgb(255, 0, 255, (byte)i);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[768 + i] = Color.FromArgb(255, 0, (byte)(255 - i), 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1024 + i] = Color.FromArgb(255, (byte)i, 0, 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1280 + i] = Color.FromArgb(255, 255, 0, (byte)(255 - i));
+ }
+
+ return result;
+ }
}
}
\ No newline at end of file
diff --git a/Correlator/DataService/IApplicationDataService.cs b/Correlator/DataService/IApplicationDataService.cs
index fd9fb5a..0dc0b5a 100644
--- a/Correlator/DataService/IApplicationDataService.cs
+++ b/Correlator/DataService/IApplicationDataService.cs
@@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
+using System.Windows.Media;
using Correlator.Model;
namespace Correlator.DataService
@@ -22,5 +23,11 @@
///
///
int GetSoundVelocity(string material, int pipeDiameter);
+
+ ///
+ /// 获取 HSV 中所有的基础颜色 (饱和度和明度均为最大值)
+ ///
+ /// 所有的 HSV 基础颜色(共 256 * 6 个, 并且随着索引增加, 颜色也会渐变)
+ Color[] GetAllHsvColors();
}
}
\ No newline at end of file
diff --git a/Correlator/Events/AudioSampleEvent.cs b/Correlator/Events/AudioSampleEvent.cs
deleted file mode 100644
index 2309da1..0000000
--- a/Correlator/Events/AudioSampleEvent.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Prism.Events;
-
-namespace Correlator.Events
-{
- public class AudioSampleEvent : PubSubEvent
- {
-
- }
-}
\ No newline at end of file
diff --git a/Correlator/Util/AudioVisualizer.cs b/Correlator/Util/AudioVisualizer.cs
new file mode 100644
index 0000000..c4b1f45
--- /dev/null
+++ b/Correlator/Util/AudioVisualizer.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Linq;
+using FftSharp;
+using FftSharp.Windows;
+
+namespace Correlator.Util
+{
+ public class AudioVisualizer
+ {
+ ///
+ /// 采样数据
+ ///
+ public double[] SampleData { get; }
+
+ ///
+ ///
+ ///
+ /// 控制频谱数量,数量越多,界面显示波动的频谱越多,建议256就好
+ ///
+ public AudioVisualizer(int waveDataSize)
+ {
+ if (!Get2Flag(waveDataSize))
+ {
+ throw new ArgumentException("长度必须是 2 的 n 次幂");
+ }
+
+ SampleData = new double[waveDataSize];
+ }
+
+ ///
+ /// 判断是否是 2 的整数次幂
+ ///
+ ///
+ ///
+ private bool Get2Flag(int num)
+ {
+ if (num < 1)
+ {
+ return false;
+ }
+
+ return (num & num - 1) == 0;
+ }
+
+ public void PushSampleData(double[] waveData)
+ {
+ if (waveData.Length > SampleData.Length)
+ {
+ Array.Copy(waveData, waveData.Length - SampleData.Length, SampleData, 0, SampleData.Length);
+ }
+ else
+ {
+ Array.Copy(SampleData, waveData.Length, SampleData, 0, SampleData.Length - waveData.Length);
+ Array.Copy(waveData, 0, SampleData, SampleData.Length - waveData.Length, waveData.Length);
+ }
+ }
+
+ ///
+ /// 获取频谱数据 (数据已经删去共轭部分)
+ ///
+ ///
+ public double[] GetSpectrumData()
+ {
+ var len = SampleData.Length;
+ var data = new Complex[len];
+
+ for (var i = 0; i < len; i++)
+ {
+ data[i] = new Complex(SampleData[i], 0);
+ }
+
+ Transform.FFT(data);
+
+ var halfLen = len / 2;
+ var result = new double[halfLen]; // 傅里叶变换结果左右对称, 只需要取一半
+ for (var i = 0; i < halfLen; i++)
+ {
+ result[i] = data[i].Magnitude / len;
+ }
+
+ var window = new Bartlett();
+ window.Create(halfLen);
+ window.ApplyInPlace(result);
+
+ return result;
+ }
+
+ ///
+ /// 简单的数据模糊
+ ///
+ /// 数据
+ /// 模糊半径
+ /// 结果
+ public static double[] MakeSmooth(double[] data, int radius)
+ {
+ var weights = GetWeights(radius);
+ var buffer = new double[1 + radius * 2];
+
+ var result = new double[data.Length];
+ if (data.Length < radius)
+ {
+ data.Average();
+ result.SetValue(data, 0);
+ return result;
+ }
+
+ for (var i = 0; i < radius; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + 1 + j] = data[i + j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ for (var i = radius; i < data.Length - radius; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[j] = data[i - j];
+ }
+
+ buffer[radius] = data[i];
+
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + j + 1] = data[i + j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ for (var i = data.Length - radius; i < data.Length; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + 1 + j] = data[i - j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ return result;
+ }
+
+ private static double[] GetWeights(int radius)
+ {
+ double Gaussian(double x) => Math.Pow(Math.E, -4 * x * x); // 高斯函数
+
+ var len = 1 + radius * 2; // 长度
+ var end = len - 1; // 最后的索引
+ var radiusF = (double)radius; // 半径浮点数
+ var weights = new double[len]; // 权重
+
+ for (var i = 0; i <= radius; i++) // 先把右边的权重算出来
+ {
+ weights[radius + i] = Gaussian(i / radiusF);
+ }
+
+ for (var i = 0; i < radius; i++) // 把右边的权重拷贝到左边
+ {
+ weights[i] = weights[end - i];
+ }
+
+ var total = weights.Sum();
+ for (var i = 0; i < len; i++) // 使权重合为 0
+ {
+ weights[i] /= total;
+ }
+
+ return weights;
+ }
+
+ private static void ApplyWeights(double[] buffer, double[] weights)
+ {
+ var len = buffer.Length;
+ for (var i = 0; i < len; i++)
+ {
+ buffer[i] *= weights[i];
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Correlator/ViewModels/AudioFileViewModel.cs b/Correlator/ViewModels/AudioFileViewModel.cs
index a9579a8..8366c70 100644
--- a/Correlator/ViewModels/AudioFileViewModel.cs
+++ b/Correlator/ViewModels/AudioFileViewModel.cs
@@ -4,7 +4,6 @@
using System.Linq;
using System.Windows.Controls;
using System.Windows.Threading;
-using Correlator.Events;
using Correlator.Model;
using Correlator.Util;
using HandyControl.Controls;
@@ -134,13 +133,6 @@
}
CurrentValue = _audioFileReader.CurrentTime.Seconds;
-
- var buffer = new float[1000];
- var samplesRead = _audioFileReader.Read(buffer, 0, buffer.Length);
- var samples = buffer.Take(samplesRead).Select(x => (double)Math.Abs(x));
- var array = samples.ToArray();
-
- eventAggregator.GetEvent().Publish(array);
};
GoBackCommand = new DelegateCommand(delegate
diff --git a/Correlator/Views/AudioFileView.xaml b/Correlator/Views/AudioFileView.xaml
index ac2cfb8..cf6531e 100644
--- a/Correlator/Views/AudioFileView.xaml
+++ b/Correlator/Views/AudioFileView.xaml
@@ -11,6 +11,8 @@
d:DataContext="{d:DesignInstance Type=vm:AudioFileViewModel}"
d:DesignHeight="1080"
d:DesignWidth="1920"
+ Loaded="AudioFileView_OnLoaded"
+ Unloaded="AudioFileView_OnUnloaded"
mc:Ignorable="d">
@@ -36,7 +38,7 @@
-
+
-
+ Margin="50,0">
+
+
().Subscribe(delegate(double[] doubles)
+ _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色)
+
+ _capture.WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(7500, 1);
+ _capture.DataAvailable += delegate(object o, WaveInEventArgs args)
{
- Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(delegate
+ var length = args.BytesRecorded / 4; // 采样的数量 (每一个采样是 4 字节)
+ var result = new double[length]; // 声明结果
+
+ for (var i = 0; i < length; i++)
{
- if (doubles.Any())
- {
- AudioWaveView.Plot.Clear();
- AudioWaveView.Plot.AddSignal(doubles, color: Color.FromArgb(255, 49, 151, 36));
- AudioWaveView.Refresh();
- }
- }));
- });
+ result[i] = BitConverter.ToSingle(args.Buffer, i * 4); // 取出采样值
+ }
+
+ _visualizer.PushSampleData(result); // 将新的采样存储到 可视化器 中
+ };
+
+ _dataTimer.Tick += DataTimer_Tick;
+ _drawingTimer.Tick += DrawingTimer_Tick;
+ }
+
+ private void AudioFileView_OnLoaded(object sender, RoutedEventArgs e)
+ {
+ _capture.StartRecording();
+ _dataTimer.Start();
+ _drawingTimer.Start();
+ }
+
+ private void AudioFileView_OnUnloaded(object sender, RoutedEventArgs e)
+ {
+ _drawingTimer.Stop();
+ _dataTimer.Stop();
+ _capture.StopRecording();
+ }
+
+ ///
+ /// 刷新频谱数据以及实现频谱数据缓动
+ ///
+ ///
+ ///
+ private void DataTimer_Tick(object sender, EventArgs e)
+ {
+ var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据
+ newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据
+
+ if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去
+ {
+ _spectrumData = newSpectrumData;
+ return;
+ }
+
+ for (var i = 0; i < newSpectrumData.Length; i++) // 计算旧频谱数据和新频谱数据之间的 "中间值"
+ {
+ var oldData = _spectrumData[i];
+ var newData = newSpectrumData[i];
+ // 每一次执行, 频谱值会向目标值移动 20% (如果太大, 缓动效果不明显, 如果太小, 频谱会有延迟的感觉)
+ var lerpData = oldData + (newData - oldData) * .2f;
+ _spectrumData[i] = lerpData;
+ }
+ }
+
+ private void DrawingTimer_Tick(object sender, EventArgs e)
+ {
+ if (_spectrumData == null)
+ {
+ return;
+ }
+
+ _colorIndex++;
+
+ var color1 = _allColors[_colorIndex % _allColors.Length];
+ var color2 = _allColors[(_colorIndex + 200) % _allColors.Length];
+
+ DrawGradientStrips(
+ StripsPath, color1, color2,
+ _spectrumData, _spectrumData.Length,
+ StripsPath.ActualWidth, 0, StripsPath.ActualHeight,
+ 2, -StripsPath.ActualHeight * 50
+ );
+ }
+
+ ///
+ /// 绘制渐变的条形
+ ///
+ /// 绘图目标
+ /// 下方颜色
+ /// 上方颜色
+ /// 频谱数据
+ /// 条形的数量
+ /// 绘图的宽度
+ /// 绘图的起始 X 坐标
+ /// 绘图的起始 Y 坐标
+ /// 条形与条形之间的间隔(像素)
+ /// 控制波形图波峰高度
+ private void DrawGradientStrips(Path stripsPath, Color bottomColor, Color topColor, double[] spectrumData,
+ int stripCount, double drawingWidth, double xOffset, double yOffset, double spacing, double scale)
+ {
+ //竖条宽度
+ var stripWidth = (drawingWidth - spacing * stripCount) / stripCount;
+ var pointArray = new Point[stripCount];
+
+ for (var i = 0; i < stripCount; i++)
+ {
+ var x = stripWidth * i + spacing * i + xOffset;
+ var y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height
+ //给所有频谱位置赋值
+ pointArray[i] = new Point(x, y);
+ }
+
+ //生成一系列频谱竖条
+ var geometry = new GeometryGroup();
+ foreach (var point in pointArray)
+ {
+ var height = point.Y;
+
+ if (height < 0)
+ {
+ height = -height;
+ }
+
+ //每根竖条的四个角坐标
+ var endPoints = new[]
+ {
+ new Point(point.X, point.Y + yOffset), //左下角
+ new Point(point.X, point.Y + height + yOffset), //左上角
+ new Point(point.X + stripWidth, point.Y + height + yOffset), //右上角
+ new Point(point.X + stripWidth, point.Y + yOffset) //右下角
+ };
+
+ var figure = new PathFigure
+ {
+ StartPoint = endPoints[0]
+ };
+
+ figure.Segments.Add(new PolyLineSegment(endPoints, false));
+ geometry.Children.Add(new PathGeometry { Figures = { figure } });
+ }
+
+ stripsPath.Data = geometry;
+
+ //设置频谱竖条的渐变色
+ var linearGradientBrush = new LinearGradientBrush(
+ bottomColor, topColor, new Point(0, 0), new Point(0, 1)
+ );
+ stripsPath.Fill = linearGradientBrush;
}
}
}
\ No newline at end of file
diff --git a/Correlator/Views/StartupWindow.xaml b/Correlator/Views/StartupWindow.xaml
index c64484f..b2c9824 100644
--- a/Correlator/Views/StartupWindow.xaml
+++ b/Correlator/Views/StartupWindow.xaml
@@ -36,7 +36,7 @@
+ Maximum="150" />
\ No newline at end of file
diff --git a/Correlator/App.config b/Correlator/App.config
index a673178..30cf21c 100644
--- a/Correlator/App.config
+++ b/Correlator/App.config
@@ -133,6 +133,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj
index 1dc857e..f593d28 100644
--- a/Correlator/Correlator.csproj
+++ b/Correlator/Correlator.csproj
@@ -65,6 +65,9 @@
..\packages\DryIoc.dll.4.7.7\lib\net45\DryIoc.dll
+
+ ..\packages\FftSharp.2.1.0\lib\netstandard2.0\FftSharp.dll
+
..\packages\HandyControl.3.3.0\lib\net48\HandyControl.dll
@@ -144,8 +147,8 @@
..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.4\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll
-
- ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
@@ -155,15 +158,15 @@
..\packages\System.Drawing.Common.4.7.2\lib\net461\System.Drawing.Common.dll
-
- ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
+
+ ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
@@ -232,7 +235,6 @@
SoundSpeedDialog.xaml
-
@@ -261,6 +263,7 @@
+
diff --git a/Correlator/DataService/ApplicationDataServiceImpl.cs b/Correlator/DataService/ApplicationDataServiceImpl.cs
index 3da8760..1b830bb 100644
--- a/Correlator/DataService/ApplicationDataServiceImpl.cs
+++ b/Correlator/DataService/ApplicationDataServiceImpl.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Windows.Media;
using Correlator.Model;
using Correlator.Util;
using Newtonsoft.Json;
@@ -98,5 +99,42 @@
return 0;
}
}
+
+ public Color[] GetAllHsvColors()
+ {
+ var result = new Color[256 * 6];
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[i] = Color.FromArgb(255, 255, (byte)i, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[256 + i] = Color.FromArgb(255, (byte)(255 - i), 255, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[512 + i] = Color.FromArgb(255, 0, 255, (byte)i);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[768 + i] = Color.FromArgb(255, 0, (byte)(255 - i), 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1024 + i] = Color.FromArgb(255, (byte)i, 0, 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1280 + i] = Color.FromArgb(255, 255, 0, (byte)(255 - i));
+ }
+
+ return result;
+ }
}
}
\ No newline at end of file
diff --git a/Correlator/DataService/IApplicationDataService.cs b/Correlator/DataService/IApplicationDataService.cs
index fd9fb5a..0dc0b5a 100644
--- a/Correlator/DataService/IApplicationDataService.cs
+++ b/Correlator/DataService/IApplicationDataService.cs
@@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
+using System.Windows.Media;
using Correlator.Model;
namespace Correlator.DataService
@@ -22,5 +23,11 @@
///
///
int GetSoundVelocity(string material, int pipeDiameter);
+
+ ///
+ /// 获取 HSV 中所有的基础颜色 (饱和度和明度均为最大值)
+ ///
+ /// 所有的 HSV 基础颜色(共 256 * 6 个, 并且随着索引增加, 颜色也会渐变)
+ Color[] GetAllHsvColors();
}
}
\ No newline at end of file
diff --git a/Correlator/Events/AudioSampleEvent.cs b/Correlator/Events/AudioSampleEvent.cs
deleted file mode 100644
index 2309da1..0000000
--- a/Correlator/Events/AudioSampleEvent.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Prism.Events;
-
-namespace Correlator.Events
-{
- public class AudioSampleEvent : PubSubEvent
- {
-
- }
-}
\ No newline at end of file
diff --git a/Correlator/Util/AudioVisualizer.cs b/Correlator/Util/AudioVisualizer.cs
new file mode 100644
index 0000000..c4b1f45
--- /dev/null
+++ b/Correlator/Util/AudioVisualizer.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Linq;
+using FftSharp;
+using FftSharp.Windows;
+
+namespace Correlator.Util
+{
+ public class AudioVisualizer
+ {
+ ///
+ /// 采样数据
+ ///
+ public double[] SampleData { get; }
+
+ ///
+ ///
+ ///
+ /// 控制频谱数量,数量越多,界面显示波动的频谱越多,建议256就好
+ ///
+ public AudioVisualizer(int waveDataSize)
+ {
+ if (!Get2Flag(waveDataSize))
+ {
+ throw new ArgumentException("长度必须是 2 的 n 次幂");
+ }
+
+ SampleData = new double[waveDataSize];
+ }
+
+ ///
+ /// 判断是否是 2 的整数次幂
+ ///
+ ///
+ ///
+ private bool Get2Flag(int num)
+ {
+ if (num < 1)
+ {
+ return false;
+ }
+
+ return (num & num - 1) == 0;
+ }
+
+ public void PushSampleData(double[] waveData)
+ {
+ if (waveData.Length > SampleData.Length)
+ {
+ Array.Copy(waveData, waveData.Length - SampleData.Length, SampleData, 0, SampleData.Length);
+ }
+ else
+ {
+ Array.Copy(SampleData, waveData.Length, SampleData, 0, SampleData.Length - waveData.Length);
+ Array.Copy(waveData, 0, SampleData, SampleData.Length - waveData.Length, waveData.Length);
+ }
+ }
+
+ ///
+ /// 获取频谱数据 (数据已经删去共轭部分)
+ ///
+ ///
+ public double[] GetSpectrumData()
+ {
+ var len = SampleData.Length;
+ var data = new Complex[len];
+
+ for (var i = 0; i < len; i++)
+ {
+ data[i] = new Complex(SampleData[i], 0);
+ }
+
+ Transform.FFT(data);
+
+ var halfLen = len / 2;
+ var result = new double[halfLen]; // 傅里叶变换结果左右对称, 只需要取一半
+ for (var i = 0; i < halfLen; i++)
+ {
+ result[i] = data[i].Magnitude / len;
+ }
+
+ var window = new Bartlett();
+ window.Create(halfLen);
+ window.ApplyInPlace(result);
+
+ return result;
+ }
+
+ ///
+ /// 简单的数据模糊
+ ///
+ /// 数据
+ /// 模糊半径
+ /// 结果
+ public static double[] MakeSmooth(double[] data, int radius)
+ {
+ var weights = GetWeights(radius);
+ var buffer = new double[1 + radius * 2];
+
+ var result = new double[data.Length];
+ if (data.Length < radius)
+ {
+ data.Average();
+ result.SetValue(data, 0);
+ return result;
+ }
+
+ for (var i = 0; i < radius; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + 1 + j] = data[i + j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ for (var i = radius; i < data.Length - radius; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[j] = data[i - j];
+ }
+
+ buffer[radius] = data[i];
+
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + j + 1] = data[i + j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ for (var i = data.Length - radius; i < data.Length; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + 1 + j] = data[i - j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ return result;
+ }
+
+ private static double[] GetWeights(int radius)
+ {
+ double Gaussian(double x) => Math.Pow(Math.E, -4 * x * x); // 高斯函数
+
+ var len = 1 + radius * 2; // 长度
+ var end = len - 1; // 最后的索引
+ var radiusF = (double)radius; // 半径浮点数
+ var weights = new double[len]; // 权重
+
+ for (var i = 0; i <= radius; i++) // 先把右边的权重算出来
+ {
+ weights[radius + i] = Gaussian(i / radiusF);
+ }
+
+ for (var i = 0; i < radius; i++) // 把右边的权重拷贝到左边
+ {
+ weights[i] = weights[end - i];
+ }
+
+ var total = weights.Sum();
+ for (var i = 0; i < len; i++) // 使权重合为 0
+ {
+ weights[i] /= total;
+ }
+
+ return weights;
+ }
+
+ private static void ApplyWeights(double[] buffer, double[] weights)
+ {
+ var len = buffer.Length;
+ for (var i = 0; i < len; i++)
+ {
+ buffer[i] *= weights[i];
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Correlator/ViewModels/AudioFileViewModel.cs b/Correlator/ViewModels/AudioFileViewModel.cs
index a9579a8..8366c70 100644
--- a/Correlator/ViewModels/AudioFileViewModel.cs
+++ b/Correlator/ViewModels/AudioFileViewModel.cs
@@ -4,7 +4,6 @@
using System.Linq;
using System.Windows.Controls;
using System.Windows.Threading;
-using Correlator.Events;
using Correlator.Model;
using Correlator.Util;
using HandyControl.Controls;
@@ -134,13 +133,6 @@
}
CurrentValue = _audioFileReader.CurrentTime.Seconds;
-
- var buffer = new float[1000];
- var samplesRead = _audioFileReader.Read(buffer, 0, buffer.Length);
- var samples = buffer.Take(samplesRead).Select(x => (double)Math.Abs(x));
- var array = samples.ToArray();
-
- eventAggregator.GetEvent().Publish(array);
};
GoBackCommand = new DelegateCommand(delegate
diff --git a/Correlator/Views/AudioFileView.xaml b/Correlator/Views/AudioFileView.xaml
index ac2cfb8..cf6531e 100644
--- a/Correlator/Views/AudioFileView.xaml
+++ b/Correlator/Views/AudioFileView.xaml
@@ -11,6 +11,8 @@
d:DataContext="{d:DesignInstance Type=vm:AudioFileViewModel}"
d:DesignHeight="1080"
d:DesignWidth="1920"
+ Loaded="AudioFileView_OnLoaded"
+ Unloaded="AudioFileView_OnUnloaded"
mc:Ignorable="d">
@@ -36,7 +38,7 @@
-
+
-
+ Margin="50,0">
+
+
().Subscribe(delegate(double[] doubles)
+ _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色)
+
+ _capture.WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(7500, 1);
+ _capture.DataAvailable += delegate(object o, WaveInEventArgs args)
{
- Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(delegate
+ var length = args.BytesRecorded / 4; // 采样的数量 (每一个采样是 4 字节)
+ var result = new double[length]; // 声明结果
+
+ for (var i = 0; i < length; i++)
{
- if (doubles.Any())
- {
- AudioWaveView.Plot.Clear();
- AudioWaveView.Plot.AddSignal(doubles, color: Color.FromArgb(255, 49, 151, 36));
- AudioWaveView.Refresh();
- }
- }));
- });
+ result[i] = BitConverter.ToSingle(args.Buffer, i * 4); // 取出采样值
+ }
+
+ _visualizer.PushSampleData(result); // 将新的采样存储到 可视化器 中
+ };
+
+ _dataTimer.Tick += DataTimer_Tick;
+ _drawingTimer.Tick += DrawingTimer_Tick;
+ }
+
+ private void AudioFileView_OnLoaded(object sender, RoutedEventArgs e)
+ {
+ _capture.StartRecording();
+ _dataTimer.Start();
+ _drawingTimer.Start();
+ }
+
+ private void AudioFileView_OnUnloaded(object sender, RoutedEventArgs e)
+ {
+ _drawingTimer.Stop();
+ _dataTimer.Stop();
+ _capture.StopRecording();
+ }
+
+ ///
+ /// 刷新频谱数据以及实现频谱数据缓动
+ ///
+ ///
+ ///
+ private void DataTimer_Tick(object sender, EventArgs e)
+ {
+ var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据
+ newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据
+
+ if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去
+ {
+ _spectrumData = newSpectrumData;
+ return;
+ }
+
+ for (var i = 0; i < newSpectrumData.Length; i++) // 计算旧频谱数据和新频谱数据之间的 "中间值"
+ {
+ var oldData = _spectrumData[i];
+ var newData = newSpectrumData[i];
+ // 每一次执行, 频谱值会向目标值移动 20% (如果太大, 缓动效果不明显, 如果太小, 频谱会有延迟的感觉)
+ var lerpData = oldData + (newData - oldData) * .2f;
+ _spectrumData[i] = lerpData;
+ }
+ }
+
+ private void DrawingTimer_Tick(object sender, EventArgs e)
+ {
+ if (_spectrumData == null)
+ {
+ return;
+ }
+
+ _colorIndex++;
+
+ var color1 = _allColors[_colorIndex % _allColors.Length];
+ var color2 = _allColors[(_colorIndex + 200) % _allColors.Length];
+
+ DrawGradientStrips(
+ StripsPath, color1, color2,
+ _spectrumData, _spectrumData.Length,
+ StripsPath.ActualWidth, 0, StripsPath.ActualHeight,
+ 2, -StripsPath.ActualHeight * 50
+ );
+ }
+
+ ///
+ /// 绘制渐变的条形
+ ///
+ /// 绘图目标
+ /// 下方颜色
+ /// 上方颜色
+ /// 频谱数据
+ /// 条形的数量
+ /// 绘图的宽度
+ /// 绘图的起始 X 坐标
+ /// 绘图的起始 Y 坐标
+ /// 条形与条形之间的间隔(像素)
+ /// 控制波形图波峰高度
+ private void DrawGradientStrips(Path stripsPath, Color bottomColor, Color topColor, double[] spectrumData,
+ int stripCount, double drawingWidth, double xOffset, double yOffset, double spacing, double scale)
+ {
+ //竖条宽度
+ var stripWidth = (drawingWidth - spacing * stripCount) / stripCount;
+ var pointArray = new Point[stripCount];
+
+ for (var i = 0; i < stripCount; i++)
+ {
+ var x = stripWidth * i + spacing * i + xOffset;
+ var y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height
+ //给所有频谱位置赋值
+ pointArray[i] = new Point(x, y);
+ }
+
+ //生成一系列频谱竖条
+ var geometry = new GeometryGroup();
+ foreach (var point in pointArray)
+ {
+ var height = point.Y;
+
+ if (height < 0)
+ {
+ height = -height;
+ }
+
+ //每根竖条的四个角坐标
+ var endPoints = new[]
+ {
+ new Point(point.X, point.Y + yOffset), //左下角
+ new Point(point.X, point.Y + height + yOffset), //左上角
+ new Point(point.X + stripWidth, point.Y + height + yOffset), //右上角
+ new Point(point.X + stripWidth, point.Y + yOffset) //右下角
+ };
+
+ var figure = new PathFigure
+ {
+ StartPoint = endPoints[0]
+ };
+
+ figure.Segments.Add(new PolyLineSegment(endPoints, false));
+ geometry.Children.Add(new PathGeometry { Figures = { figure } });
+ }
+
+ stripsPath.Data = geometry;
+
+ //设置频谱竖条的渐变色
+ var linearGradientBrush = new LinearGradientBrush(
+ bottomColor, topColor, new Point(0, 0), new Point(0, 1)
+ );
+ stripsPath.Fill = linearGradientBrush;
}
}
}
\ No newline at end of file
diff --git a/Correlator/Views/StartupWindow.xaml b/Correlator/Views/StartupWindow.xaml
index c64484f..b2c9824 100644
--- a/Correlator/Views/StartupWindow.xaml
+++ b/Correlator/Views/StartupWindow.xaml
@@ -36,7 +36,7 @@
+ Maximum="150" />
\ No newline at end of file
diff --git a/Correlator/Views/StartupWindow.xaml.cs b/Correlator/Views/StartupWindow.xaml.cs
index 9c943a8..edc3dc5 100644
--- a/Correlator/Views/StartupWindow.xaml.cs
+++ b/Correlator/Views/StartupWindow.xaml.cs
@@ -13,7 +13,7 @@
Interval = new TimeSpan(0, 0, 0,0,1)
};
- private int _counterTime = 200;
+ private int _counterTime = 150;
public StartupWindow()
{
diff --git a/Correlator/App.config b/Correlator/App.config
index a673178..30cf21c 100644
--- a/Correlator/App.config
+++ b/Correlator/App.config
@@ -133,6 +133,14 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj
index 1dc857e..f593d28 100644
--- a/Correlator/Correlator.csproj
+++ b/Correlator/Correlator.csproj
@@ -65,6 +65,9 @@
..\packages\DryIoc.dll.4.7.7\lib\net45\DryIoc.dll
+
+ ..\packages\FftSharp.2.1.0\lib\netstandard2.0\FftSharp.dll
+
..\packages\HandyControl.3.3.0\lib\net48\HandyControl.dll
@@ -144,8 +147,8 @@
..\packages\SQLitePCLRaw.provider.dynamic_cdecl.2.0.4\lib\netstandard2.0\SQLitePCLRaw.provider.dynamic_cdecl.dll
-
- ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
@@ -155,15 +158,15 @@
..\packages\System.Drawing.Common.4.7.2\lib\net461\System.Drawing.Common.dll
-
- ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
+
+ ..\packages\System.Memory.4.5.5\lib\net461\System.Memory.dll
..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
- ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll
+ ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
@@ -232,7 +235,6 @@
SoundSpeedDialog.xaml
-
@@ -261,6 +263,7 @@
+
diff --git a/Correlator/DataService/ApplicationDataServiceImpl.cs b/Correlator/DataService/ApplicationDataServiceImpl.cs
index 3da8760..1b830bb 100644
--- a/Correlator/DataService/ApplicationDataServiceImpl.cs
+++ b/Correlator/DataService/ApplicationDataServiceImpl.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
+using System.Windows.Media;
using Correlator.Model;
using Correlator.Util;
using Newtonsoft.Json;
@@ -98,5 +99,42 @@
return 0;
}
}
+
+ public Color[] GetAllHsvColors()
+ {
+ var result = new Color[256 * 6];
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[i] = Color.FromArgb(255, 255, (byte)i, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[256 + i] = Color.FromArgb(255, (byte)(255 - i), 255, 0);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[512 + i] = Color.FromArgb(255, 0, 255, (byte)i);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[768 + i] = Color.FromArgb(255, 0, (byte)(255 - i), 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1024 + i] = Color.FromArgb(255, (byte)i, 0, 255);
+ }
+
+ for (var i = 0; i <= 255; i++)
+ {
+ result[1280 + i] = Color.FromArgb(255, 255, 0, (byte)(255 - i));
+ }
+
+ return result;
+ }
}
}
\ No newline at end of file
diff --git a/Correlator/DataService/IApplicationDataService.cs b/Correlator/DataService/IApplicationDataService.cs
index fd9fb5a..0dc0b5a 100644
--- a/Correlator/DataService/IApplicationDataService.cs
+++ b/Correlator/DataService/IApplicationDataService.cs
@@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
+using System.Windows.Media;
using Correlator.Model;
namespace Correlator.DataService
@@ -22,5 +23,11 @@
///
///
int GetSoundVelocity(string material, int pipeDiameter);
+
+ ///
+ /// 获取 HSV 中所有的基础颜色 (饱和度和明度均为最大值)
+ ///
+ /// 所有的 HSV 基础颜色(共 256 * 6 个, 并且随着索引增加, 颜色也会渐变)
+ Color[] GetAllHsvColors();
}
}
\ No newline at end of file
diff --git a/Correlator/Events/AudioSampleEvent.cs b/Correlator/Events/AudioSampleEvent.cs
deleted file mode 100644
index 2309da1..0000000
--- a/Correlator/Events/AudioSampleEvent.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using Prism.Events;
-
-namespace Correlator.Events
-{
- public class AudioSampleEvent : PubSubEvent
- {
-
- }
-}
\ No newline at end of file
diff --git a/Correlator/Util/AudioVisualizer.cs b/Correlator/Util/AudioVisualizer.cs
new file mode 100644
index 0000000..c4b1f45
--- /dev/null
+++ b/Correlator/Util/AudioVisualizer.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Linq;
+using FftSharp;
+using FftSharp.Windows;
+
+namespace Correlator.Util
+{
+ public class AudioVisualizer
+ {
+ ///
+ /// 采样数据
+ ///
+ public double[] SampleData { get; }
+
+ ///
+ ///
+ ///
+ /// 控制频谱数量,数量越多,界面显示波动的频谱越多,建议256就好
+ ///
+ public AudioVisualizer(int waveDataSize)
+ {
+ if (!Get2Flag(waveDataSize))
+ {
+ throw new ArgumentException("长度必须是 2 的 n 次幂");
+ }
+
+ SampleData = new double[waveDataSize];
+ }
+
+ ///
+ /// 判断是否是 2 的整数次幂
+ ///
+ ///
+ ///
+ private bool Get2Flag(int num)
+ {
+ if (num < 1)
+ {
+ return false;
+ }
+
+ return (num & num - 1) == 0;
+ }
+
+ public void PushSampleData(double[] waveData)
+ {
+ if (waveData.Length > SampleData.Length)
+ {
+ Array.Copy(waveData, waveData.Length - SampleData.Length, SampleData, 0, SampleData.Length);
+ }
+ else
+ {
+ Array.Copy(SampleData, waveData.Length, SampleData, 0, SampleData.Length - waveData.Length);
+ Array.Copy(waveData, 0, SampleData, SampleData.Length - waveData.Length, waveData.Length);
+ }
+ }
+
+ ///
+ /// 获取频谱数据 (数据已经删去共轭部分)
+ ///
+ ///
+ public double[] GetSpectrumData()
+ {
+ var len = SampleData.Length;
+ var data = new Complex[len];
+
+ for (var i = 0; i < len; i++)
+ {
+ data[i] = new Complex(SampleData[i], 0);
+ }
+
+ Transform.FFT(data);
+
+ var halfLen = len / 2;
+ var result = new double[halfLen]; // 傅里叶变换结果左右对称, 只需要取一半
+ for (var i = 0; i < halfLen; i++)
+ {
+ result[i] = data[i].Magnitude / len;
+ }
+
+ var window = new Bartlett();
+ window.Create(halfLen);
+ window.ApplyInPlace(result);
+
+ return result;
+ }
+
+ ///
+ /// 简单的数据模糊
+ ///
+ /// 数据
+ /// 模糊半径
+ /// 结果
+ public static double[] MakeSmooth(double[] data, int radius)
+ {
+ var weights = GetWeights(radius);
+ var buffer = new double[1 + radius * 2];
+
+ var result = new double[data.Length];
+ if (data.Length < radius)
+ {
+ data.Average();
+ result.SetValue(data, 0);
+ return result;
+ }
+
+ for (var i = 0; i < radius; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + 1 + j] = data[i + j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ for (var i = radius; i < data.Length - radius; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[j] = data[i - j];
+ }
+
+ buffer[radius] = data[i];
+
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + j + 1] = data[i + j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ for (var i = data.Length - radius; i < data.Length; i++)
+ {
+ for (var j = 0; j < radius; j++) //
+ {
+ buffer[radius + 1 + j] = data[i - j];
+ }
+
+ ApplyWeights(buffer, weights);
+ result[i] = buffer.Sum();
+ }
+
+ return result;
+ }
+
+ private static double[] GetWeights(int radius)
+ {
+ double Gaussian(double x) => Math.Pow(Math.E, -4 * x * x); // 高斯函数
+
+ var len = 1 + radius * 2; // 长度
+ var end = len - 1; // 最后的索引
+ var radiusF = (double)radius; // 半径浮点数
+ var weights = new double[len]; // 权重
+
+ for (var i = 0; i <= radius; i++) // 先把右边的权重算出来
+ {
+ weights[radius + i] = Gaussian(i / radiusF);
+ }
+
+ for (var i = 0; i < radius; i++) // 把右边的权重拷贝到左边
+ {
+ weights[i] = weights[end - i];
+ }
+
+ var total = weights.Sum();
+ for (var i = 0; i < len; i++) // 使权重合为 0
+ {
+ weights[i] /= total;
+ }
+
+ return weights;
+ }
+
+ private static void ApplyWeights(double[] buffer, double[] weights)
+ {
+ var len = buffer.Length;
+ for (var i = 0; i < len; i++)
+ {
+ buffer[i] *= weights[i];
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Correlator/ViewModels/AudioFileViewModel.cs b/Correlator/ViewModels/AudioFileViewModel.cs
index a9579a8..8366c70 100644
--- a/Correlator/ViewModels/AudioFileViewModel.cs
+++ b/Correlator/ViewModels/AudioFileViewModel.cs
@@ -4,7 +4,6 @@
using System.Linq;
using System.Windows.Controls;
using System.Windows.Threading;
-using Correlator.Events;
using Correlator.Model;
using Correlator.Util;
using HandyControl.Controls;
@@ -134,13 +133,6 @@
}
CurrentValue = _audioFileReader.CurrentTime.Seconds;
-
- var buffer = new float[1000];
- var samplesRead = _audioFileReader.Read(buffer, 0, buffer.Length);
- var samples = buffer.Take(samplesRead).Select(x => (double)Math.Abs(x));
- var array = samples.ToArray();
-
- eventAggregator.GetEvent().Publish(array);
};
GoBackCommand = new DelegateCommand(delegate
diff --git a/Correlator/Views/AudioFileView.xaml b/Correlator/Views/AudioFileView.xaml
index ac2cfb8..cf6531e 100644
--- a/Correlator/Views/AudioFileView.xaml
+++ b/Correlator/Views/AudioFileView.xaml
@@ -11,6 +11,8 @@
d:DataContext="{d:DesignInstance Type=vm:AudioFileViewModel}"
d:DesignHeight="1080"
d:DesignWidth="1920"
+ Loaded="AudioFileView_OnLoaded"
+ Unloaded="AudioFileView_OnUnloaded"
mc:Ignorable="d">
@@ -36,7 +38,7 @@
-
+
-
+ Margin="50,0">
+
+
().Subscribe(delegate(double[] doubles)
+ _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色)
+
+ _capture.WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(7500, 1);
+ _capture.DataAvailable += delegate(object o, WaveInEventArgs args)
{
- Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(delegate
+ var length = args.BytesRecorded / 4; // 采样的数量 (每一个采样是 4 字节)
+ var result = new double[length]; // 声明结果
+
+ for (var i = 0; i < length; i++)
{
- if (doubles.Any())
- {
- AudioWaveView.Plot.Clear();
- AudioWaveView.Plot.AddSignal(doubles, color: Color.FromArgb(255, 49, 151, 36));
- AudioWaveView.Refresh();
- }
- }));
- });
+ result[i] = BitConverter.ToSingle(args.Buffer, i * 4); // 取出采样值
+ }
+
+ _visualizer.PushSampleData(result); // 将新的采样存储到 可视化器 中
+ };
+
+ _dataTimer.Tick += DataTimer_Tick;
+ _drawingTimer.Tick += DrawingTimer_Tick;
+ }
+
+ private void AudioFileView_OnLoaded(object sender, RoutedEventArgs e)
+ {
+ _capture.StartRecording();
+ _dataTimer.Start();
+ _drawingTimer.Start();
+ }
+
+ private void AudioFileView_OnUnloaded(object sender, RoutedEventArgs e)
+ {
+ _drawingTimer.Stop();
+ _dataTimer.Stop();
+ _capture.StopRecording();
+ }
+
+ ///
+ /// 刷新频谱数据以及实现频谱数据缓动
+ ///
+ ///
+ ///
+ private void DataTimer_Tick(object sender, EventArgs e)
+ {
+ var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据
+ newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据
+
+ if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去
+ {
+ _spectrumData = newSpectrumData;
+ return;
+ }
+
+ for (var i = 0; i < newSpectrumData.Length; i++) // 计算旧频谱数据和新频谱数据之间的 "中间值"
+ {
+ var oldData = _spectrumData[i];
+ var newData = newSpectrumData[i];
+ // 每一次执行, 频谱值会向目标值移动 20% (如果太大, 缓动效果不明显, 如果太小, 频谱会有延迟的感觉)
+ var lerpData = oldData + (newData - oldData) * .2f;
+ _spectrumData[i] = lerpData;
+ }
+ }
+
+ private void DrawingTimer_Tick(object sender, EventArgs e)
+ {
+ if (_spectrumData == null)
+ {
+ return;
+ }
+
+ _colorIndex++;
+
+ var color1 = _allColors[_colorIndex % _allColors.Length];
+ var color2 = _allColors[(_colorIndex + 200) % _allColors.Length];
+
+ DrawGradientStrips(
+ StripsPath, color1, color2,
+ _spectrumData, _spectrumData.Length,
+ StripsPath.ActualWidth, 0, StripsPath.ActualHeight,
+ 2, -StripsPath.ActualHeight * 50
+ );
+ }
+
+ ///
+ /// 绘制渐变的条形
+ ///
+ /// 绘图目标
+ /// 下方颜色
+ /// 上方颜色
+ /// 频谱数据
+ /// 条形的数量
+ /// 绘图的宽度
+ /// 绘图的起始 X 坐标
+ /// 绘图的起始 Y 坐标
+ /// 条形与条形之间的间隔(像素)
+ /// 控制波形图波峰高度
+ private void DrawGradientStrips(Path stripsPath, Color bottomColor, Color topColor, double[] spectrumData,
+ int stripCount, double drawingWidth, double xOffset, double yOffset, double spacing, double scale)
+ {
+ //竖条宽度
+ var stripWidth = (drawingWidth - spacing * stripCount) / stripCount;
+ var pointArray = new Point[stripCount];
+
+ for (var i = 0; i < stripCount; i++)
+ {
+ var x = stripWidth * i + spacing * i + xOffset;
+ var y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height
+ //给所有频谱位置赋值
+ pointArray[i] = new Point(x, y);
+ }
+
+ //生成一系列频谱竖条
+ var geometry = new GeometryGroup();
+ foreach (var point in pointArray)
+ {
+ var height = point.Y;
+
+ if (height < 0)
+ {
+ height = -height;
+ }
+
+ //每根竖条的四个角坐标
+ var endPoints = new[]
+ {
+ new Point(point.X, point.Y + yOffset), //左下角
+ new Point(point.X, point.Y + height + yOffset), //左上角
+ new Point(point.X + stripWidth, point.Y + height + yOffset), //右上角
+ new Point(point.X + stripWidth, point.Y + yOffset) //右下角
+ };
+
+ var figure = new PathFigure
+ {
+ StartPoint = endPoints[0]
+ };
+
+ figure.Segments.Add(new PolyLineSegment(endPoints, false));
+ geometry.Children.Add(new PathGeometry { Figures = { figure } });
+ }
+
+ stripsPath.Data = geometry;
+
+ //设置频谱竖条的渐变色
+ var linearGradientBrush = new LinearGradientBrush(
+ bottomColor, topColor, new Point(0, 0), new Point(0, 1)
+ );
+ stripsPath.Fill = linearGradientBrush;
}
}
}
\ No newline at end of file
diff --git a/Correlator/Views/StartupWindow.xaml b/Correlator/Views/StartupWindow.xaml
index c64484f..b2c9824 100644
--- a/Correlator/Views/StartupWindow.xaml
+++ b/Correlator/Views/StartupWindow.xaml
@@ -36,7 +36,7 @@
+ Maximum="150" />
\ No newline at end of file
diff --git a/Correlator/Views/StartupWindow.xaml.cs b/Correlator/Views/StartupWindow.xaml.cs
index 9c943a8..edc3dc5 100644
--- a/Correlator/Views/StartupWindow.xaml.cs
+++ b/Correlator/Views/StartupWindow.xaml.cs
@@ -13,7 +13,7 @@
Interval = new TimeSpan(0, 0, 0,0,1)
};
- private int _counterTime = 200;
+ private int _counterTime = 150;
public StartupWindow()
{
diff --git a/Correlator/packages.config b/Correlator/packages.config
index d66552c..cd851a5 100644
--- a/Correlator/packages.config
+++ b/Correlator/packages.config
@@ -1,6 +1,7 @@
+
@@ -29,7 +30,7 @@
-
-
-
+
+
+
\ No newline at end of file