diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/DataService/AudioServiceImpl.cs b/Correlator/DataService/AudioServiceImpl.cs index 9227651..f5dbe51 100644 --- a/Correlator/DataService/AudioServiceImpl.cs +++ b/Correlator/DataService/AudioServiceImpl.cs @@ -1,5 +1,4 @@ using System; -using Correlator.SensorHubTag; using Correlator.Util; using NAudio.Wave; @@ -12,18 +11,19 @@ private BufferedWaveProvider _waveProvider; private readonly WaveFormat _waveFormat = new WaveFormat(7500, 24, 1); + public WaveOutEvent Wave { get; set; } = new WaveOutEvent(); + public void Start(string deviceCode) { _isStopped = false; _waveProvider = new BufferedWaveProvider(_waveFormat); - var waveOut = new WaveOut(); - waveOut.Init(_waveProvider); + Wave.Init(_waveProvider); string fileName; var audioDir = DirectoryManager.GetAudioDir(); var time = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - if (deviceCode == DevCode.Dev1) + if (deviceCode == RuntimeCache.Dev1) { //红色传感器听音 fileName = $"{audioDir}/听音_红_{time}.wav"; @@ -36,7 +36,7 @@ _waveFileWriter = new WaveFileWriter(fileName, _waveFormat); - waveOut.Play(); + Wave.Play(); } //缓存声波数据已经是后台线程了(处于线程池中) @@ -47,18 +47,23 @@ return; } - _waveProvider?.AddSamples(pcm, 0, pcm.Length); - _waveFileWriter?.Write(pcm, 0, pcm.Length); + try + { + _waveProvider?.AddSamples(pcm, 0, pcm.Length); + _waveFileWriter?.Write(pcm, 0, pcm.Length); + } + catch (InvalidOperationException) + { + _waveProvider?.ClearBuffer(); + } } public void Stop() { _isStopped = true; - + Wave.Stop(); _waveProvider.ClearBuffer(); _waveFileWriter.Dispose(); } - - // public AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/DataService/AudioServiceImpl.cs b/Correlator/DataService/AudioServiceImpl.cs index 9227651..f5dbe51 100644 --- a/Correlator/DataService/AudioServiceImpl.cs +++ b/Correlator/DataService/AudioServiceImpl.cs @@ -1,5 +1,4 @@ using System; -using Correlator.SensorHubTag; using Correlator.Util; using NAudio.Wave; @@ -12,18 +11,19 @@ private BufferedWaveProvider _waveProvider; private readonly WaveFormat _waveFormat = new WaveFormat(7500, 24, 1); + public WaveOutEvent Wave { get; set; } = new WaveOutEvent(); + public void Start(string deviceCode) { _isStopped = false; _waveProvider = new BufferedWaveProvider(_waveFormat); - var waveOut = new WaveOut(); - waveOut.Init(_waveProvider); + Wave.Init(_waveProvider); string fileName; var audioDir = DirectoryManager.GetAudioDir(); var time = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - if (deviceCode == DevCode.Dev1) + if (deviceCode == RuntimeCache.Dev1) { //红色传感器听音 fileName = $"{audioDir}/听音_红_{time}.wav"; @@ -36,7 +36,7 @@ _waveFileWriter = new WaveFileWriter(fileName, _waveFormat); - waveOut.Play(); + Wave.Play(); } //缓存声波数据已经是后台线程了(处于线程池中) @@ -47,18 +47,23 @@ return; } - _waveProvider?.AddSamples(pcm, 0, pcm.Length); - _waveFileWriter?.Write(pcm, 0, pcm.Length); + try + { + _waveProvider?.AddSamples(pcm, 0, pcm.Length); + _waveFileWriter?.Write(pcm, 0, pcm.Length); + } + catch (InvalidOperationException) + { + _waveProvider?.ClearBuffer(); + } } public void Stop() { _isStopped = true; - + Wave.Stop(); _waveProvider.ClearBuffer(); _waveFileWriter.Dispose(); } - - // public AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/IAudioService.cs b/Correlator/DataService/IAudioService.cs index 83609b2..f6e157a 100644 --- a/Correlator/DataService/IAudioService.cs +++ b/Correlator/DataService/IAudioService.cs @@ -1,7 +1,11 @@ -namespace Correlator.DataService +using NAudio.Wave; + +namespace Correlator.DataService { public interface IAudioService { + WaveOutEvent Wave { get; set; } + /// /// 开始听音 /// @@ -18,7 +22,5 @@ /// 结束听音 /// void Stop(); - - // AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/DataService/AudioServiceImpl.cs b/Correlator/DataService/AudioServiceImpl.cs index 9227651..f5dbe51 100644 --- a/Correlator/DataService/AudioServiceImpl.cs +++ b/Correlator/DataService/AudioServiceImpl.cs @@ -1,5 +1,4 @@ using System; -using Correlator.SensorHubTag; using Correlator.Util; using NAudio.Wave; @@ -12,18 +11,19 @@ private BufferedWaveProvider _waveProvider; private readonly WaveFormat _waveFormat = new WaveFormat(7500, 24, 1); + public WaveOutEvent Wave { get; set; } = new WaveOutEvent(); + public void Start(string deviceCode) { _isStopped = false; _waveProvider = new BufferedWaveProvider(_waveFormat); - var waveOut = new WaveOut(); - waveOut.Init(_waveProvider); + Wave.Init(_waveProvider); string fileName; var audioDir = DirectoryManager.GetAudioDir(); var time = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - if (deviceCode == DevCode.Dev1) + if (deviceCode == RuntimeCache.Dev1) { //红色传感器听音 fileName = $"{audioDir}/听音_红_{time}.wav"; @@ -36,7 +36,7 @@ _waveFileWriter = new WaveFileWriter(fileName, _waveFormat); - waveOut.Play(); + Wave.Play(); } //缓存声波数据已经是后台线程了(处于线程池中) @@ -47,18 +47,23 @@ return; } - _waveProvider?.AddSamples(pcm, 0, pcm.Length); - _waveFileWriter?.Write(pcm, 0, pcm.Length); + try + { + _waveProvider?.AddSamples(pcm, 0, pcm.Length); + _waveFileWriter?.Write(pcm, 0, pcm.Length); + } + catch (InvalidOperationException) + { + _waveProvider?.ClearBuffer(); + } } public void Stop() { _isStopped = true; - + Wave.Stop(); _waveProvider.ClearBuffer(); _waveFileWriter.Dispose(); } - - // public AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/IAudioService.cs b/Correlator/DataService/IAudioService.cs index 83609b2..f6e157a 100644 --- a/Correlator/DataService/IAudioService.cs +++ b/Correlator/DataService/IAudioService.cs @@ -1,7 +1,11 @@ -namespace Correlator.DataService +using NAudio.Wave; + +namespace Correlator.DataService { public interface IAudioService { + WaveOutEvent Wave { get; set; } + /// /// 开始听音 /// @@ -18,7 +22,5 @@ /// 结束听音 /// void Stop(); - - // AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/SerialPortServiceImpl.cs b/Correlator/DataService/SerialPortServiceImpl.cs index 0a7e32f..824eccb 100644 --- a/Correlator/DataService/SerialPortServiceImpl.cs +++ b/Correlator/DataService/SerialPortServiceImpl.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO.Ports; -using System.Text; using System.Threading; using System.Windows; using Correlator.Events; @@ -131,7 +130,7 @@ } //发送消息更新界面 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { _eventAggregator.GetEvent().Publish(_devStatus); } @@ -173,7 +172,7 @@ var response = BitConverter.ToString(receivedData).Replace("-", ""); //收集数据 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { //原始数据 RuntimeCache.RedSensorOriginalResp.Add(index, response); @@ -218,7 +217,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { //接收到数据之后时间重新赋值 _dataModel.LeftReceiveDataTime = DateTime.Now; @@ -271,16 +270,6 @@ //将pcm数据写入缓存 _audioService.Write(pcm); - - //波形图数据 - var length = pcm.Length / 4; - var spectrumData = new double[length]; - for (var i = 0; i < length; i++) - { - spectrumData[i] = BitConverter.ToSingle(pcm, i * 4); - } - - // _audioService.AudioVisualizer.PushSampleData(spectrumData); } } @@ -310,7 +299,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { _dataModel.LeftDeviceDataArray = doubleArrays.ToOneDimensionalArray(); } diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/DataService/AudioServiceImpl.cs b/Correlator/DataService/AudioServiceImpl.cs index 9227651..f5dbe51 100644 --- a/Correlator/DataService/AudioServiceImpl.cs +++ b/Correlator/DataService/AudioServiceImpl.cs @@ -1,5 +1,4 @@ using System; -using Correlator.SensorHubTag; using Correlator.Util; using NAudio.Wave; @@ -12,18 +11,19 @@ private BufferedWaveProvider _waveProvider; private readonly WaveFormat _waveFormat = new WaveFormat(7500, 24, 1); + public WaveOutEvent Wave { get; set; } = new WaveOutEvent(); + public void Start(string deviceCode) { _isStopped = false; _waveProvider = new BufferedWaveProvider(_waveFormat); - var waveOut = new WaveOut(); - waveOut.Init(_waveProvider); + Wave.Init(_waveProvider); string fileName; var audioDir = DirectoryManager.GetAudioDir(); var time = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - if (deviceCode == DevCode.Dev1) + if (deviceCode == RuntimeCache.Dev1) { //红色传感器听音 fileName = $"{audioDir}/听音_红_{time}.wav"; @@ -36,7 +36,7 @@ _waveFileWriter = new WaveFileWriter(fileName, _waveFormat); - waveOut.Play(); + Wave.Play(); } //缓存声波数据已经是后台线程了(处于线程池中) @@ -47,18 +47,23 @@ return; } - _waveProvider?.AddSamples(pcm, 0, pcm.Length); - _waveFileWriter?.Write(pcm, 0, pcm.Length); + try + { + _waveProvider?.AddSamples(pcm, 0, pcm.Length); + _waveFileWriter?.Write(pcm, 0, pcm.Length); + } + catch (InvalidOperationException) + { + _waveProvider?.ClearBuffer(); + } } public void Stop() { _isStopped = true; - + Wave.Stop(); _waveProvider.ClearBuffer(); _waveFileWriter.Dispose(); } - - // public AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/IAudioService.cs b/Correlator/DataService/IAudioService.cs index 83609b2..f6e157a 100644 --- a/Correlator/DataService/IAudioService.cs +++ b/Correlator/DataService/IAudioService.cs @@ -1,7 +1,11 @@ -namespace Correlator.DataService +using NAudio.Wave; + +namespace Correlator.DataService { public interface IAudioService { + WaveOutEvent Wave { get; set; } + /// /// 开始听音 /// @@ -18,7 +22,5 @@ /// 结束听音 /// void Stop(); - - // AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/SerialPortServiceImpl.cs b/Correlator/DataService/SerialPortServiceImpl.cs index 0a7e32f..824eccb 100644 --- a/Correlator/DataService/SerialPortServiceImpl.cs +++ b/Correlator/DataService/SerialPortServiceImpl.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO.Ports; -using System.Text; using System.Threading; using System.Windows; using Correlator.Events; @@ -131,7 +130,7 @@ } //发送消息更新界面 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { _eventAggregator.GetEvent().Publish(_devStatus); } @@ -173,7 +172,7 @@ var response = BitConverter.ToString(receivedData).Replace("-", ""); //收集数据 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { //原始数据 RuntimeCache.RedSensorOriginalResp.Add(index, response); @@ -218,7 +217,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { //接收到数据之后时间重新赋值 _dataModel.LeftReceiveDataTime = DateTime.Now; @@ -271,16 +270,6 @@ //将pcm数据写入缓存 _audioService.Write(pcm); - - //波形图数据 - var length = pcm.Length / 4; - var spectrumData = new double[length]; - for (var i = 0; i < length; i++) - { - spectrumData[i] = BitConverter.ToSingle(pcm, i * 4); - } - - // _audioService.AudioVisualizer.PushSampleData(spectrumData); } } @@ -310,7 +299,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { _dataModel.LeftDeviceDataArray = doubleArrays.ToOneDimensionalArray(); } diff --git a/Correlator/Dialog/CheckResponseDialog.xaml.cs b/Correlator/Dialog/CheckResponseDialog.xaml.cs index 43f84fd..91441a2 100644 --- a/Correlator/Dialog/CheckResponseDialog.xaml.cs +++ b/Correlator/Dialog/CheckResponseDialog.xaml.cs @@ -231,7 +231,7 @@ if (RedSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev1); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev1); _redResponseTimer.Start(); ReCheckButton.IsEnabled = true; @@ -239,11 +239,11 @@ else if (RedSensorStepBar.StepIndex == 2) { //下发数据全部正常指令 - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev1}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev1}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.RedSensorOriginalResp orderby pair.Key select pair; @@ -266,7 +266,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev1, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev1, tags); #endregion } @@ -315,18 +315,18 @@ if (BlueSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev2); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev2); _blueResponseTimer.Start(); ReCheckButton.IsEnabled = true; } else if (BlueSensorStepBar.StepIndex == 2) { - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev2}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev2}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.BlueSensorOriginalResp orderby pair.Key select pair; @@ -349,7 +349,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev2, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev2, tags); #endregion } @@ -396,7 +396,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, redIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, redIndexArray); } else { @@ -417,7 +417,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, blueIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, blueIndexArray); } }; } diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/DataService/AudioServiceImpl.cs b/Correlator/DataService/AudioServiceImpl.cs index 9227651..f5dbe51 100644 --- a/Correlator/DataService/AudioServiceImpl.cs +++ b/Correlator/DataService/AudioServiceImpl.cs @@ -1,5 +1,4 @@ using System; -using Correlator.SensorHubTag; using Correlator.Util; using NAudio.Wave; @@ -12,18 +11,19 @@ private BufferedWaveProvider _waveProvider; private readonly WaveFormat _waveFormat = new WaveFormat(7500, 24, 1); + public WaveOutEvent Wave { get; set; } = new WaveOutEvent(); + public void Start(string deviceCode) { _isStopped = false; _waveProvider = new BufferedWaveProvider(_waveFormat); - var waveOut = new WaveOut(); - waveOut.Init(_waveProvider); + Wave.Init(_waveProvider); string fileName; var audioDir = DirectoryManager.GetAudioDir(); var time = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - if (deviceCode == DevCode.Dev1) + if (deviceCode == RuntimeCache.Dev1) { //红色传感器听音 fileName = $"{audioDir}/听音_红_{time}.wav"; @@ -36,7 +36,7 @@ _waveFileWriter = new WaveFileWriter(fileName, _waveFormat); - waveOut.Play(); + Wave.Play(); } //缓存声波数据已经是后台线程了(处于线程池中) @@ -47,18 +47,23 @@ return; } - _waveProvider?.AddSamples(pcm, 0, pcm.Length); - _waveFileWriter?.Write(pcm, 0, pcm.Length); + try + { + _waveProvider?.AddSamples(pcm, 0, pcm.Length); + _waveFileWriter?.Write(pcm, 0, pcm.Length); + } + catch (InvalidOperationException) + { + _waveProvider?.ClearBuffer(); + } } public void Stop() { _isStopped = true; - + Wave.Stop(); _waveProvider.ClearBuffer(); _waveFileWriter.Dispose(); } - - // public AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/IAudioService.cs b/Correlator/DataService/IAudioService.cs index 83609b2..f6e157a 100644 --- a/Correlator/DataService/IAudioService.cs +++ b/Correlator/DataService/IAudioService.cs @@ -1,7 +1,11 @@ -namespace Correlator.DataService +using NAudio.Wave; + +namespace Correlator.DataService { public interface IAudioService { + WaveOutEvent Wave { get; set; } + /// /// 开始听音 /// @@ -18,7 +22,5 @@ /// 结束听音 /// void Stop(); - - // AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/SerialPortServiceImpl.cs b/Correlator/DataService/SerialPortServiceImpl.cs index 0a7e32f..824eccb 100644 --- a/Correlator/DataService/SerialPortServiceImpl.cs +++ b/Correlator/DataService/SerialPortServiceImpl.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO.Ports; -using System.Text; using System.Threading; using System.Windows; using Correlator.Events; @@ -131,7 +130,7 @@ } //发送消息更新界面 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { _eventAggregator.GetEvent().Publish(_devStatus); } @@ -173,7 +172,7 @@ var response = BitConverter.ToString(receivedData).Replace("-", ""); //收集数据 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { //原始数据 RuntimeCache.RedSensorOriginalResp.Add(index, response); @@ -218,7 +217,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { //接收到数据之后时间重新赋值 _dataModel.LeftReceiveDataTime = DateTime.Now; @@ -271,16 +270,6 @@ //将pcm数据写入缓存 _audioService.Write(pcm); - - //波形图数据 - var length = pcm.Length / 4; - var spectrumData = new double[length]; - for (var i = 0; i < length; i++) - { - spectrumData[i] = BitConverter.ToSingle(pcm, i * 4); - } - - // _audioService.AudioVisualizer.PushSampleData(spectrumData); } } @@ -310,7 +299,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { _dataModel.LeftDeviceDataArray = doubleArrays.ToOneDimensionalArray(); } diff --git a/Correlator/Dialog/CheckResponseDialog.xaml.cs b/Correlator/Dialog/CheckResponseDialog.xaml.cs index 43f84fd..91441a2 100644 --- a/Correlator/Dialog/CheckResponseDialog.xaml.cs +++ b/Correlator/Dialog/CheckResponseDialog.xaml.cs @@ -231,7 +231,7 @@ if (RedSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev1); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev1); _redResponseTimer.Start(); ReCheckButton.IsEnabled = true; @@ -239,11 +239,11 @@ else if (RedSensorStepBar.StepIndex == 2) { //下发数据全部正常指令 - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev1}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev1}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.RedSensorOriginalResp orderby pair.Key select pair; @@ -266,7 +266,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev1, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev1, tags); #endregion } @@ -315,18 +315,18 @@ if (BlueSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev2); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev2); _blueResponseTimer.Start(); ReCheckButton.IsEnabled = true; } else if (BlueSensorStepBar.StepIndex == 2) { - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev2}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev2}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.BlueSensorOriginalResp orderby pair.Key select pair; @@ -349,7 +349,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev2, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev2, tags); #endregion } @@ -396,7 +396,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, redIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, redIndexArray); } else { @@ -417,7 +417,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, blueIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, blueIndexArray); } }; } diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml b/Correlator/Dialog/SimplyAuditionDialog.xaml index 5fd8124..cd03b74 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml @@ -9,7 +9,7 @@ xmlns:prism="http://prismlibrary.com/" xmlns:vm="clr-namespace:Correlator.ViewModels" Width="600" - Height="400" + Height="480" d:DataContext="{d:DesignInstance Type=vm:SimplyAuditionDialogViewModel}" Loaded="SimplyAuditionDialog_OnLoaded" Unloaded="SimplyAuditionDialog_OnUnloaded" @@ -187,10 +187,15 @@ - + Background="{StaticResource MainThemeColor}"> + + + + + diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/DataService/AudioServiceImpl.cs b/Correlator/DataService/AudioServiceImpl.cs index 9227651..f5dbe51 100644 --- a/Correlator/DataService/AudioServiceImpl.cs +++ b/Correlator/DataService/AudioServiceImpl.cs @@ -1,5 +1,4 @@ using System; -using Correlator.SensorHubTag; using Correlator.Util; using NAudio.Wave; @@ -12,18 +11,19 @@ private BufferedWaveProvider _waveProvider; private readonly WaveFormat _waveFormat = new WaveFormat(7500, 24, 1); + public WaveOutEvent Wave { get; set; } = new WaveOutEvent(); + public void Start(string deviceCode) { _isStopped = false; _waveProvider = new BufferedWaveProvider(_waveFormat); - var waveOut = new WaveOut(); - waveOut.Init(_waveProvider); + Wave.Init(_waveProvider); string fileName; var audioDir = DirectoryManager.GetAudioDir(); var time = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - if (deviceCode == DevCode.Dev1) + if (deviceCode == RuntimeCache.Dev1) { //红色传感器听音 fileName = $"{audioDir}/听音_红_{time}.wav"; @@ -36,7 +36,7 @@ _waveFileWriter = new WaveFileWriter(fileName, _waveFormat); - waveOut.Play(); + Wave.Play(); } //缓存声波数据已经是后台线程了(处于线程池中) @@ -47,18 +47,23 @@ return; } - _waveProvider?.AddSamples(pcm, 0, pcm.Length); - _waveFileWriter?.Write(pcm, 0, pcm.Length); + try + { + _waveProvider?.AddSamples(pcm, 0, pcm.Length); + _waveFileWriter?.Write(pcm, 0, pcm.Length); + } + catch (InvalidOperationException) + { + _waveProvider?.ClearBuffer(); + } } public void Stop() { _isStopped = true; - + Wave.Stop(); _waveProvider.ClearBuffer(); _waveFileWriter.Dispose(); } - - // public AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/IAudioService.cs b/Correlator/DataService/IAudioService.cs index 83609b2..f6e157a 100644 --- a/Correlator/DataService/IAudioService.cs +++ b/Correlator/DataService/IAudioService.cs @@ -1,7 +1,11 @@ -namespace Correlator.DataService +using NAudio.Wave; + +namespace Correlator.DataService { public interface IAudioService { + WaveOutEvent Wave { get; set; } + /// /// 开始听音 /// @@ -18,7 +22,5 @@ /// 结束听音 /// void Stop(); - - // AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/SerialPortServiceImpl.cs b/Correlator/DataService/SerialPortServiceImpl.cs index 0a7e32f..824eccb 100644 --- a/Correlator/DataService/SerialPortServiceImpl.cs +++ b/Correlator/DataService/SerialPortServiceImpl.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO.Ports; -using System.Text; using System.Threading; using System.Windows; using Correlator.Events; @@ -131,7 +130,7 @@ } //发送消息更新界面 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { _eventAggregator.GetEvent().Publish(_devStatus); } @@ -173,7 +172,7 @@ var response = BitConverter.ToString(receivedData).Replace("-", ""); //收集数据 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { //原始数据 RuntimeCache.RedSensorOriginalResp.Add(index, response); @@ -218,7 +217,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { //接收到数据之后时间重新赋值 _dataModel.LeftReceiveDataTime = DateTime.Now; @@ -271,16 +270,6 @@ //将pcm数据写入缓存 _audioService.Write(pcm); - - //波形图数据 - var length = pcm.Length / 4; - var spectrumData = new double[length]; - for (var i = 0; i < length; i++) - { - spectrumData[i] = BitConverter.ToSingle(pcm, i * 4); - } - - // _audioService.AudioVisualizer.PushSampleData(spectrumData); } } @@ -310,7 +299,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { _dataModel.LeftDeviceDataArray = doubleArrays.ToOneDimensionalArray(); } diff --git a/Correlator/Dialog/CheckResponseDialog.xaml.cs b/Correlator/Dialog/CheckResponseDialog.xaml.cs index 43f84fd..91441a2 100644 --- a/Correlator/Dialog/CheckResponseDialog.xaml.cs +++ b/Correlator/Dialog/CheckResponseDialog.xaml.cs @@ -231,7 +231,7 @@ if (RedSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev1); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev1); _redResponseTimer.Start(); ReCheckButton.IsEnabled = true; @@ -239,11 +239,11 @@ else if (RedSensorStepBar.StepIndex == 2) { //下发数据全部正常指令 - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev1}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev1}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.RedSensorOriginalResp orderby pair.Key select pair; @@ -266,7 +266,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev1, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev1, tags); #endregion } @@ -315,18 +315,18 @@ if (BlueSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev2); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev2); _blueResponseTimer.Start(); ReCheckButton.IsEnabled = true; } else if (BlueSensorStepBar.StepIndex == 2) { - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev2}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev2}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.BlueSensorOriginalResp orderby pair.Key select pair; @@ -349,7 +349,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev2, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev2, tags); #endregion } @@ -396,7 +396,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, redIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, redIndexArray); } else { @@ -417,7 +417,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, blueIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, blueIndexArray); } }; } diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml b/Correlator/Dialog/SimplyAuditionDialog.xaml index 5fd8124..cd03b74 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml @@ -9,7 +9,7 @@ xmlns:prism="http://prismlibrary.com/" xmlns:vm="clr-namespace:Correlator.ViewModels" Width="600" - Height="400" + Height="480" d:DataContext="{d:DesignInstance Type=vm:SimplyAuditionDialogViewModel}" Loaded="SimplyAuditionDialog_OnLoaded" Unloaded="SimplyAuditionDialog_OnUnloaded" @@ -187,10 +187,15 @@ - + Background="{StaticResource MainThemeColor}"> + + + + + diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs index 3747ce0..41cb280 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -6,6 +7,8 @@ using System.Windows.Threading; using Correlator.DataService; using Correlator.Util; +using NAudio.CoreAudioApi; +using NAudio.Wave; namespace Correlator.Dialog { @@ -16,6 +19,7 @@ { private readonly AudioVisualizer _visualizer; // 可视化 private double[] _spectrumData; // 频谱数据 + private readonly WasapiCapture _capture; // 音频捕获 private int _colorIndex; private readonly Color[] _allColors; @@ -29,29 +33,44 @@ Interval = new TimeSpan(0, 0, 0, 0, 30) }; - public SimplyAuditionDialog(IApplicationDataService dataService, IAudioService audioService) + public SimplyAuditionDialog(IApplicationDataService dataService) { InitializeComponent(); - // _visualizer = dataService.GetAudioVisualizer(256); - // _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) - // - // audioService.AudioVisualizer = _visualizer; - // - // _dataTimer.Tick += DataTimer_Tick; - // _drawingTimer.Tick += DrawingTimer_Tick; + _capture = new WasapiLoopbackCapture(); // 捕获电脑发出的声音 + _visualizer = dataService.GetAudioVisualizer(512); + _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) + + _capture.WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(7500, 1); + _capture.DataAvailable += delegate(object o, WaveInEventArgs args) + { + var length = args.BytesRecorded / 4; // 采样的数量 (每一个采样是 4 字节) + var result = new double[length]; + + for (var i = 0; i < length; i++) + { + result[i] = BitConverter.ToSingle(args.Buffer, i * 4); // 取出采样值 + } + + _visualizer.PushSampleData(result); // 将新的采样存储到 可视化器 中 + }; + + _dataTimer.Tick += DataTimer_Tick; + _drawingTimer.Tick += DrawingTimer_Tick; } private void SimplyAuditionDialog_OnLoaded(object sender, RoutedEventArgs e) { - // _dataTimer.Start(); - // _drawingTimer.Start(); + _capture.StartRecording(); + _dataTimer.Start(); + _drawingTimer.Start(); } private void SimplyAuditionDialog_OnUnloaded(object sender, RoutedEventArgs e) { - // _drawingTimer.Stop(); - // _dataTimer.Stop(); + _drawingTimer.Stop(); + _dataTimer.Stop(); + _capture.StopRecording(); } /// @@ -62,7 +81,7 @@ private void DataTimer_Tick(object sender, EventArgs e) { var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据 - newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 + newSpectrumData = AudioDataHub.Get.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去 { @@ -92,80 +111,90 @@ 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 * 200 + var bassArea = AudioDataHub.Get.TakeSpectrumOfFrequency( + _spectrumData, RuntimeCache.AudioSampleRate, 250 + ); + var bassScale = bassArea.Average() * 100; //低音区 + + //波形曲线 + var curveBrush = new SolidColorBrush(color1); + DrawCurve( + SampleWavePath, curveBrush, + _visualizer.SampleData, _visualizer.SampleData.Length, + SampleWavePanel.ActualWidth, 0, SampleWavePanel.ActualHeight / 2, + Math.Min(SampleWavePanel.ActualHeight / 2, 50) + ); + + //四周边框 + DrawGradientBorder( + TopBorder, BottomBorder, LeftBorder, RightBorder, + Color.FromArgb(0, color1.R, color1.G, color1.B), color2, + SampleWavePanel.ActualWidth / 3, bassScale ); } /// - /// 绘制渐变的条形 + /// 画曲线 /// - /// 绘图目标 - /// 下方颜色 - /// 上方颜色 - /// 频谱数据 - /// 条形的数量 - /// 绘图的宽度 - /// 绘图的起始 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 + /// + /// + /// + /// + /// + /// + /// + /// 控制波形图波峰高度和波谷深度 + private void DrawCurve( + Path wavePath, Brush brush, double[] spectrumData, int pointCount, double drawingWidth, + double xOffset, double yOffset, double scale ) { - //竖条宽度 - var stripWidth = (drawingWidth - spacing * stripCount) / stripCount; - var pointArray = new Point[stripCount]; - - for (var i = 0; i < stripCount; i++) + var pointArray = new Point[pointCount]; + for (var i = 0; i < pointCount; i++) { - var x = stripWidth * i + spacing * i + xOffset; - var y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height - //给所有频谱位置赋值 + var x = i * drawingWidth / pointCount + xOffset; + var y = spectrumData[i * spectrumData.Length / pointCount] * scale + yOffset; pointArray[i] = new Point(x, y); } - //生成一系列频谱竖条 - var geometry = new GeometryGroup(); - foreach (var point in pointArray) + var figure = new PathFigure { - var height = point.Y; + StartPoint = pointArray[0] + }; + figure.Segments.Add(new PolyLineSegment(pointArray, true)); - if (height < 0) - { - height = -height; - } + wavePath.Data = new PathGeometry { Figures = { figure } }; + wavePath.Stroke = brush; + } - //每根竖条的四个角坐标 - 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) //右下角 - }; + /// + /// 画四周渐变边框 + /// + /// + /// + /// + /// + /// + /// + /// 画图宽度 + /// 高低音转化比例 + private void DrawGradientBorder( + Rectangle topBorder, Rectangle bottomBorder, Rectangle leftBorder, + Rectangle rightBorder, Color inner, Color outer, double width, double bassScale + ) + { + //边框粗细根据音频高低音变化 + var thickness = (int)(width * bassScale); - var figure = new PathFigure - { - StartPoint = endPoints[0] - }; + topBorder.Height = thickness; + bottomBorder.Height = thickness; + leftBorder.Width = thickness; + rightBorder.Width = thickness; - 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; + topBorder.Fill = new LinearGradientBrush(outer, inner, 90); + bottomBorder.Fill = new LinearGradientBrush(inner, outer, 90); + leftBorder.Fill = new LinearGradientBrush(outer, inner, 0); + rightBorder.Fill = new LinearGradientBrush(inner, outer, 0); } } } \ No newline at end of file diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/DataService/AudioServiceImpl.cs b/Correlator/DataService/AudioServiceImpl.cs index 9227651..f5dbe51 100644 --- a/Correlator/DataService/AudioServiceImpl.cs +++ b/Correlator/DataService/AudioServiceImpl.cs @@ -1,5 +1,4 @@ using System; -using Correlator.SensorHubTag; using Correlator.Util; using NAudio.Wave; @@ -12,18 +11,19 @@ private BufferedWaveProvider _waveProvider; private readonly WaveFormat _waveFormat = new WaveFormat(7500, 24, 1); + public WaveOutEvent Wave { get; set; } = new WaveOutEvent(); + public void Start(string deviceCode) { _isStopped = false; _waveProvider = new BufferedWaveProvider(_waveFormat); - var waveOut = new WaveOut(); - waveOut.Init(_waveProvider); + Wave.Init(_waveProvider); string fileName; var audioDir = DirectoryManager.GetAudioDir(); var time = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - if (deviceCode == DevCode.Dev1) + if (deviceCode == RuntimeCache.Dev1) { //红色传感器听音 fileName = $"{audioDir}/听音_红_{time}.wav"; @@ -36,7 +36,7 @@ _waveFileWriter = new WaveFileWriter(fileName, _waveFormat); - waveOut.Play(); + Wave.Play(); } //缓存声波数据已经是后台线程了(处于线程池中) @@ -47,18 +47,23 @@ return; } - _waveProvider?.AddSamples(pcm, 0, pcm.Length); - _waveFileWriter?.Write(pcm, 0, pcm.Length); + try + { + _waveProvider?.AddSamples(pcm, 0, pcm.Length); + _waveFileWriter?.Write(pcm, 0, pcm.Length); + } + catch (InvalidOperationException) + { + _waveProvider?.ClearBuffer(); + } } public void Stop() { _isStopped = true; - + Wave.Stop(); _waveProvider.ClearBuffer(); _waveFileWriter.Dispose(); } - - // public AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/IAudioService.cs b/Correlator/DataService/IAudioService.cs index 83609b2..f6e157a 100644 --- a/Correlator/DataService/IAudioService.cs +++ b/Correlator/DataService/IAudioService.cs @@ -1,7 +1,11 @@ -namespace Correlator.DataService +using NAudio.Wave; + +namespace Correlator.DataService { public interface IAudioService { + WaveOutEvent Wave { get; set; } + /// /// 开始听音 /// @@ -18,7 +22,5 @@ /// 结束听音 /// void Stop(); - - // AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/SerialPortServiceImpl.cs b/Correlator/DataService/SerialPortServiceImpl.cs index 0a7e32f..824eccb 100644 --- a/Correlator/DataService/SerialPortServiceImpl.cs +++ b/Correlator/DataService/SerialPortServiceImpl.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO.Ports; -using System.Text; using System.Threading; using System.Windows; using Correlator.Events; @@ -131,7 +130,7 @@ } //发送消息更新界面 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { _eventAggregator.GetEvent().Publish(_devStatus); } @@ -173,7 +172,7 @@ var response = BitConverter.ToString(receivedData).Replace("-", ""); //收集数据 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { //原始数据 RuntimeCache.RedSensorOriginalResp.Add(index, response); @@ -218,7 +217,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { //接收到数据之后时间重新赋值 _dataModel.LeftReceiveDataTime = DateTime.Now; @@ -271,16 +270,6 @@ //将pcm数据写入缓存 _audioService.Write(pcm); - - //波形图数据 - var length = pcm.Length / 4; - var spectrumData = new double[length]; - for (var i = 0; i < length; i++) - { - spectrumData[i] = BitConverter.ToSingle(pcm, i * 4); - } - - // _audioService.AudioVisualizer.PushSampleData(spectrumData); } } @@ -310,7 +299,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { _dataModel.LeftDeviceDataArray = doubleArrays.ToOneDimensionalArray(); } diff --git a/Correlator/Dialog/CheckResponseDialog.xaml.cs b/Correlator/Dialog/CheckResponseDialog.xaml.cs index 43f84fd..91441a2 100644 --- a/Correlator/Dialog/CheckResponseDialog.xaml.cs +++ b/Correlator/Dialog/CheckResponseDialog.xaml.cs @@ -231,7 +231,7 @@ if (RedSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev1); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev1); _redResponseTimer.Start(); ReCheckButton.IsEnabled = true; @@ -239,11 +239,11 @@ else if (RedSensorStepBar.StepIndex == 2) { //下发数据全部正常指令 - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev1}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev1}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.RedSensorOriginalResp orderby pair.Key select pair; @@ -266,7 +266,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev1, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev1, tags); #endregion } @@ -315,18 +315,18 @@ if (BlueSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev2); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev2); _blueResponseTimer.Start(); ReCheckButton.IsEnabled = true; } else if (BlueSensorStepBar.StepIndex == 2) { - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev2}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev2}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.BlueSensorOriginalResp orderby pair.Key select pair; @@ -349,7 +349,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev2, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev2, tags); #endregion } @@ -396,7 +396,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, redIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, redIndexArray); } else { @@ -417,7 +417,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, blueIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, blueIndexArray); } }; } diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml b/Correlator/Dialog/SimplyAuditionDialog.xaml index 5fd8124..cd03b74 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml @@ -9,7 +9,7 @@ xmlns:prism="http://prismlibrary.com/" xmlns:vm="clr-namespace:Correlator.ViewModels" Width="600" - Height="400" + Height="480" d:DataContext="{d:DesignInstance Type=vm:SimplyAuditionDialogViewModel}" Loaded="SimplyAuditionDialog_OnLoaded" Unloaded="SimplyAuditionDialog_OnUnloaded" @@ -187,10 +187,15 @@ - + Background="{StaticResource MainThemeColor}"> + + + + + diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs index 3747ce0..41cb280 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -6,6 +7,8 @@ using System.Windows.Threading; using Correlator.DataService; using Correlator.Util; +using NAudio.CoreAudioApi; +using NAudio.Wave; namespace Correlator.Dialog { @@ -16,6 +19,7 @@ { private readonly AudioVisualizer _visualizer; // 可视化 private double[] _spectrumData; // 频谱数据 + private readonly WasapiCapture _capture; // 音频捕获 private int _colorIndex; private readonly Color[] _allColors; @@ -29,29 +33,44 @@ Interval = new TimeSpan(0, 0, 0, 0, 30) }; - public SimplyAuditionDialog(IApplicationDataService dataService, IAudioService audioService) + public SimplyAuditionDialog(IApplicationDataService dataService) { InitializeComponent(); - // _visualizer = dataService.GetAudioVisualizer(256); - // _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) - // - // audioService.AudioVisualizer = _visualizer; - // - // _dataTimer.Tick += DataTimer_Tick; - // _drawingTimer.Tick += DrawingTimer_Tick; + _capture = new WasapiLoopbackCapture(); // 捕获电脑发出的声音 + _visualizer = dataService.GetAudioVisualizer(512); + _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) + + _capture.WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(7500, 1); + _capture.DataAvailable += delegate(object o, WaveInEventArgs args) + { + var length = args.BytesRecorded / 4; // 采样的数量 (每一个采样是 4 字节) + var result = new double[length]; + + for (var i = 0; i < length; i++) + { + result[i] = BitConverter.ToSingle(args.Buffer, i * 4); // 取出采样值 + } + + _visualizer.PushSampleData(result); // 将新的采样存储到 可视化器 中 + }; + + _dataTimer.Tick += DataTimer_Tick; + _drawingTimer.Tick += DrawingTimer_Tick; } private void SimplyAuditionDialog_OnLoaded(object sender, RoutedEventArgs e) { - // _dataTimer.Start(); - // _drawingTimer.Start(); + _capture.StartRecording(); + _dataTimer.Start(); + _drawingTimer.Start(); } private void SimplyAuditionDialog_OnUnloaded(object sender, RoutedEventArgs e) { - // _drawingTimer.Stop(); - // _dataTimer.Stop(); + _drawingTimer.Stop(); + _dataTimer.Stop(); + _capture.StopRecording(); } /// @@ -62,7 +81,7 @@ private void DataTimer_Tick(object sender, EventArgs e) { var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据 - newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 + newSpectrumData = AudioDataHub.Get.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去 { @@ -92,80 +111,90 @@ 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 * 200 + var bassArea = AudioDataHub.Get.TakeSpectrumOfFrequency( + _spectrumData, RuntimeCache.AudioSampleRate, 250 + ); + var bassScale = bassArea.Average() * 100; //低音区 + + //波形曲线 + var curveBrush = new SolidColorBrush(color1); + DrawCurve( + SampleWavePath, curveBrush, + _visualizer.SampleData, _visualizer.SampleData.Length, + SampleWavePanel.ActualWidth, 0, SampleWavePanel.ActualHeight / 2, + Math.Min(SampleWavePanel.ActualHeight / 2, 50) + ); + + //四周边框 + DrawGradientBorder( + TopBorder, BottomBorder, LeftBorder, RightBorder, + Color.FromArgb(0, color1.R, color1.G, color1.B), color2, + SampleWavePanel.ActualWidth / 3, bassScale ); } /// - /// 绘制渐变的条形 + /// 画曲线 /// - /// 绘图目标 - /// 下方颜色 - /// 上方颜色 - /// 频谱数据 - /// 条形的数量 - /// 绘图的宽度 - /// 绘图的起始 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 + /// + /// + /// + /// + /// + /// + /// + /// 控制波形图波峰高度和波谷深度 + private void DrawCurve( + Path wavePath, Brush brush, double[] spectrumData, int pointCount, double drawingWidth, + double xOffset, double yOffset, double scale ) { - //竖条宽度 - var stripWidth = (drawingWidth - spacing * stripCount) / stripCount; - var pointArray = new Point[stripCount]; - - for (var i = 0; i < stripCount; i++) + var pointArray = new Point[pointCount]; + for (var i = 0; i < pointCount; i++) { - var x = stripWidth * i + spacing * i + xOffset; - var y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height - //给所有频谱位置赋值 + var x = i * drawingWidth / pointCount + xOffset; + var y = spectrumData[i * spectrumData.Length / pointCount] * scale + yOffset; pointArray[i] = new Point(x, y); } - //生成一系列频谱竖条 - var geometry = new GeometryGroup(); - foreach (var point in pointArray) + var figure = new PathFigure { - var height = point.Y; + StartPoint = pointArray[0] + }; + figure.Segments.Add(new PolyLineSegment(pointArray, true)); - if (height < 0) - { - height = -height; - } + wavePath.Data = new PathGeometry { Figures = { figure } }; + wavePath.Stroke = brush; + } - //每根竖条的四个角坐标 - 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) //右下角 - }; + /// + /// 画四周渐变边框 + /// + /// + /// + /// + /// + /// + /// + /// 画图宽度 + /// 高低音转化比例 + private void DrawGradientBorder( + Rectangle topBorder, Rectangle bottomBorder, Rectangle leftBorder, + Rectangle rightBorder, Color inner, Color outer, double width, double bassScale + ) + { + //边框粗细根据音频高低音变化 + var thickness = (int)(width * bassScale); - var figure = new PathFigure - { - StartPoint = endPoints[0] - }; + topBorder.Height = thickness; + bottomBorder.Height = thickness; + leftBorder.Width = thickness; + rightBorder.Width = thickness; - 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; + topBorder.Fill = new LinearGradientBrush(outer, inner, 90); + bottomBorder.Fill = new LinearGradientBrush(inner, outer, 90); + leftBorder.Fill = new LinearGradientBrush(outer, inner, 0); + rightBorder.Fill = new LinearGradientBrush(inner, outer, 0); } } } \ No newline at end of file diff --git a/Correlator/SensorHubTag/DevCode.cs b/Correlator/SensorHubTag/DevCode.cs deleted file mode 100644 index afd5e8f..0000000 --- a/Correlator/SensorHubTag/DevCode.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Correlator.SensorHubTag -{ - public static class DevCode - { - public static string Dev1 => "211700082201"; - - public static string Dev2 => "211700082202"; - } -} \ No newline at end of file diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/DataService/AudioServiceImpl.cs b/Correlator/DataService/AudioServiceImpl.cs index 9227651..f5dbe51 100644 --- a/Correlator/DataService/AudioServiceImpl.cs +++ b/Correlator/DataService/AudioServiceImpl.cs @@ -1,5 +1,4 @@ using System; -using Correlator.SensorHubTag; using Correlator.Util; using NAudio.Wave; @@ -12,18 +11,19 @@ private BufferedWaveProvider _waveProvider; private readonly WaveFormat _waveFormat = new WaveFormat(7500, 24, 1); + public WaveOutEvent Wave { get; set; } = new WaveOutEvent(); + public void Start(string deviceCode) { _isStopped = false; _waveProvider = new BufferedWaveProvider(_waveFormat); - var waveOut = new WaveOut(); - waveOut.Init(_waveProvider); + Wave.Init(_waveProvider); string fileName; var audioDir = DirectoryManager.GetAudioDir(); var time = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - if (deviceCode == DevCode.Dev1) + if (deviceCode == RuntimeCache.Dev1) { //红色传感器听音 fileName = $"{audioDir}/听音_红_{time}.wav"; @@ -36,7 +36,7 @@ _waveFileWriter = new WaveFileWriter(fileName, _waveFormat); - waveOut.Play(); + Wave.Play(); } //缓存声波数据已经是后台线程了(处于线程池中) @@ -47,18 +47,23 @@ return; } - _waveProvider?.AddSamples(pcm, 0, pcm.Length); - _waveFileWriter?.Write(pcm, 0, pcm.Length); + try + { + _waveProvider?.AddSamples(pcm, 0, pcm.Length); + _waveFileWriter?.Write(pcm, 0, pcm.Length); + } + catch (InvalidOperationException) + { + _waveProvider?.ClearBuffer(); + } } public void Stop() { _isStopped = true; - + Wave.Stop(); _waveProvider.ClearBuffer(); _waveFileWriter.Dispose(); } - - // public AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/IAudioService.cs b/Correlator/DataService/IAudioService.cs index 83609b2..f6e157a 100644 --- a/Correlator/DataService/IAudioService.cs +++ b/Correlator/DataService/IAudioService.cs @@ -1,7 +1,11 @@ -namespace Correlator.DataService +using NAudio.Wave; + +namespace Correlator.DataService { public interface IAudioService { + WaveOutEvent Wave { get; set; } + /// /// 开始听音 /// @@ -18,7 +22,5 @@ /// 结束听音 /// void Stop(); - - // AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/SerialPortServiceImpl.cs b/Correlator/DataService/SerialPortServiceImpl.cs index 0a7e32f..824eccb 100644 --- a/Correlator/DataService/SerialPortServiceImpl.cs +++ b/Correlator/DataService/SerialPortServiceImpl.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO.Ports; -using System.Text; using System.Threading; using System.Windows; using Correlator.Events; @@ -131,7 +130,7 @@ } //发送消息更新界面 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { _eventAggregator.GetEvent().Publish(_devStatus); } @@ -173,7 +172,7 @@ var response = BitConverter.ToString(receivedData).Replace("-", ""); //收集数据 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { //原始数据 RuntimeCache.RedSensorOriginalResp.Add(index, response); @@ -218,7 +217,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { //接收到数据之后时间重新赋值 _dataModel.LeftReceiveDataTime = DateTime.Now; @@ -271,16 +270,6 @@ //将pcm数据写入缓存 _audioService.Write(pcm); - - //波形图数据 - var length = pcm.Length / 4; - var spectrumData = new double[length]; - for (var i = 0; i < length; i++) - { - spectrumData[i] = BitConverter.ToSingle(pcm, i * 4); - } - - // _audioService.AudioVisualizer.PushSampleData(spectrumData); } } @@ -310,7 +299,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { _dataModel.LeftDeviceDataArray = doubleArrays.ToOneDimensionalArray(); } diff --git a/Correlator/Dialog/CheckResponseDialog.xaml.cs b/Correlator/Dialog/CheckResponseDialog.xaml.cs index 43f84fd..91441a2 100644 --- a/Correlator/Dialog/CheckResponseDialog.xaml.cs +++ b/Correlator/Dialog/CheckResponseDialog.xaml.cs @@ -231,7 +231,7 @@ if (RedSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev1); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev1); _redResponseTimer.Start(); ReCheckButton.IsEnabled = true; @@ -239,11 +239,11 @@ else if (RedSensorStepBar.StepIndex == 2) { //下发数据全部正常指令 - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev1}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev1}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.RedSensorOriginalResp orderby pair.Key select pair; @@ -266,7 +266,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev1, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev1, tags); #endregion } @@ -315,18 +315,18 @@ if (BlueSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev2); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev2); _blueResponseTimer.Start(); ReCheckButton.IsEnabled = true; } else if (BlueSensorStepBar.StepIndex == 2) { - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev2}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev2}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.BlueSensorOriginalResp orderby pair.Key select pair; @@ -349,7 +349,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev2, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev2, tags); #endregion } @@ -396,7 +396,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, redIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, redIndexArray); } else { @@ -417,7 +417,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, blueIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, blueIndexArray); } }; } diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml b/Correlator/Dialog/SimplyAuditionDialog.xaml index 5fd8124..cd03b74 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml @@ -9,7 +9,7 @@ xmlns:prism="http://prismlibrary.com/" xmlns:vm="clr-namespace:Correlator.ViewModels" Width="600" - Height="400" + Height="480" d:DataContext="{d:DesignInstance Type=vm:SimplyAuditionDialogViewModel}" Loaded="SimplyAuditionDialog_OnLoaded" Unloaded="SimplyAuditionDialog_OnUnloaded" @@ -187,10 +187,15 @@ - + Background="{StaticResource MainThemeColor}"> + + + + + diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs index 3747ce0..41cb280 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -6,6 +7,8 @@ using System.Windows.Threading; using Correlator.DataService; using Correlator.Util; +using NAudio.CoreAudioApi; +using NAudio.Wave; namespace Correlator.Dialog { @@ -16,6 +19,7 @@ { private readonly AudioVisualizer _visualizer; // 可视化 private double[] _spectrumData; // 频谱数据 + private readonly WasapiCapture _capture; // 音频捕获 private int _colorIndex; private readonly Color[] _allColors; @@ -29,29 +33,44 @@ Interval = new TimeSpan(0, 0, 0, 0, 30) }; - public SimplyAuditionDialog(IApplicationDataService dataService, IAudioService audioService) + public SimplyAuditionDialog(IApplicationDataService dataService) { InitializeComponent(); - // _visualizer = dataService.GetAudioVisualizer(256); - // _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) - // - // audioService.AudioVisualizer = _visualizer; - // - // _dataTimer.Tick += DataTimer_Tick; - // _drawingTimer.Tick += DrawingTimer_Tick; + _capture = new WasapiLoopbackCapture(); // 捕获电脑发出的声音 + _visualizer = dataService.GetAudioVisualizer(512); + _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) + + _capture.WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(7500, 1); + _capture.DataAvailable += delegate(object o, WaveInEventArgs args) + { + var length = args.BytesRecorded / 4; // 采样的数量 (每一个采样是 4 字节) + var result = new double[length]; + + for (var i = 0; i < length; i++) + { + result[i] = BitConverter.ToSingle(args.Buffer, i * 4); // 取出采样值 + } + + _visualizer.PushSampleData(result); // 将新的采样存储到 可视化器 中 + }; + + _dataTimer.Tick += DataTimer_Tick; + _drawingTimer.Tick += DrawingTimer_Tick; } private void SimplyAuditionDialog_OnLoaded(object sender, RoutedEventArgs e) { - // _dataTimer.Start(); - // _drawingTimer.Start(); + _capture.StartRecording(); + _dataTimer.Start(); + _drawingTimer.Start(); } private void SimplyAuditionDialog_OnUnloaded(object sender, RoutedEventArgs e) { - // _drawingTimer.Stop(); - // _dataTimer.Stop(); + _drawingTimer.Stop(); + _dataTimer.Stop(); + _capture.StopRecording(); } /// @@ -62,7 +81,7 @@ private void DataTimer_Tick(object sender, EventArgs e) { var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据 - newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 + newSpectrumData = AudioDataHub.Get.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去 { @@ -92,80 +111,90 @@ 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 * 200 + var bassArea = AudioDataHub.Get.TakeSpectrumOfFrequency( + _spectrumData, RuntimeCache.AudioSampleRate, 250 + ); + var bassScale = bassArea.Average() * 100; //低音区 + + //波形曲线 + var curveBrush = new SolidColorBrush(color1); + DrawCurve( + SampleWavePath, curveBrush, + _visualizer.SampleData, _visualizer.SampleData.Length, + SampleWavePanel.ActualWidth, 0, SampleWavePanel.ActualHeight / 2, + Math.Min(SampleWavePanel.ActualHeight / 2, 50) + ); + + //四周边框 + DrawGradientBorder( + TopBorder, BottomBorder, LeftBorder, RightBorder, + Color.FromArgb(0, color1.R, color1.G, color1.B), color2, + SampleWavePanel.ActualWidth / 3, bassScale ); } /// - /// 绘制渐变的条形 + /// 画曲线 /// - /// 绘图目标 - /// 下方颜色 - /// 上方颜色 - /// 频谱数据 - /// 条形的数量 - /// 绘图的宽度 - /// 绘图的起始 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 + /// + /// + /// + /// + /// + /// + /// + /// 控制波形图波峰高度和波谷深度 + private void DrawCurve( + Path wavePath, Brush brush, double[] spectrumData, int pointCount, double drawingWidth, + double xOffset, double yOffset, double scale ) { - //竖条宽度 - var stripWidth = (drawingWidth - spacing * stripCount) / stripCount; - var pointArray = new Point[stripCount]; - - for (var i = 0; i < stripCount; i++) + var pointArray = new Point[pointCount]; + for (var i = 0; i < pointCount; i++) { - var x = stripWidth * i + spacing * i + xOffset; - var y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height - //给所有频谱位置赋值 + var x = i * drawingWidth / pointCount + xOffset; + var y = spectrumData[i * spectrumData.Length / pointCount] * scale + yOffset; pointArray[i] = new Point(x, y); } - //生成一系列频谱竖条 - var geometry = new GeometryGroup(); - foreach (var point in pointArray) + var figure = new PathFigure { - var height = point.Y; + StartPoint = pointArray[0] + }; + figure.Segments.Add(new PolyLineSegment(pointArray, true)); - if (height < 0) - { - height = -height; - } + wavePath.Data = new PathGeometry { Figures = { figure } }; + wavePath.Stroke = brush; + } - //每根竖条的四个角坐标 - 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) //右下角 - }; + /// + /// 画四周渐变边框 + /// + /// + /// + /// + /// + /// + /// + /// 画图宽度 + /// 高低音转化比例 + private void DrawGradientBorder( + Rectangle topBorder, Rectangle bottomBorder, Rectangle leftBorder, + Rectangle rightBorder, Color inner, Color outer, double width, double bassScale + ) + { + //边框粗细根据音频高低音变化 + var thickness = (int)(width * bassScale); - var figure = new PathFigure - { - StartPoint = endPoints[0] - }; + topBorder.Height = thickness; + bottomBorder.Height = thickness; + leftBorder.Width = thickness; + rightBorder.Width = thickness; - 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; + topBorder.Fill = new LinearGradientBrush(outer, inner, 90); + bottomBorder.Fill = new LinearGradientBrush(inner, outer, 90); + leftBorder.Fill = new LinearGradientBrush(outer, inner, 0); + rightBorder.Fill = new LinearGradientBrush(inner, outer, 0); } } } \ No newline at end of file diff --git a/Correlator/SensorHubTag/DevCode.cs b/Correlator/SensorHubTag/DevCode.cs deleted file mode 100644 index afd5e8f..0000000 --- a/Correlator/SensorHubTag/DevCode.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Correlator.SensorHubTag -{ - public static class DevCode - { - public static string Dev1 => "211700082201"; - - public static string Dev2 => "211700082202"; - } -} \ No newline at end of file diff --git a/Correlator/Util/AudioDataHub.cs b/Correlator/Util/AudioDataHub.cs new file mode 100644 index 0000000..72d62ea --- /dev/null +++ b/Correlator/Util/AudioDataHub.cs @@ -0,0 +1,135 @@ +using System; +using System.Linq; + +namespace Correlator.Util +{ + /// + /// 音频可视化数据处理 + /// + public class AudioDataHub + { + #region 懒汉单例模式 + + private static readonly Lazy Lazy = new Lazy(() => new AudioDataHub()); + + public static AudioDataHub Get => Lazy.Value; + + + private AudioDataHub() + { + } + + #endregion + + private double[] _smoothResult; + + public double[] TakeSpectrumOfFrequency(double[] spectrum, double sampleRate, double frequency) + { + var frequencyPerSample = sampleRate / spectrum.Length; + + var lengthInNeed = (int)Math.Min(frequency / frequencyPerSample, spectrum.Length); + var result = new double[lengthInNeed]; + Array.Copy(spectrum, 0, result, 0, lengthInNeed); + return result; + } + + /// + /// 简单的数据模糊 + /// + /// 数据 + /// 模糊半径 + /// 结果 + public double[] MakeSmooth(double[] data, int radius) + { + var weights = GetWeights(radius); + var buffer = new double[1 + radius * 2]; + + _smoothResult = new double[data.Length]; + if (data.Length < radius) + { + data.Average(); + _smoothResult.SetValue(data, 0); + return _smoothResult; + } + + for (var i = 0; i < radius; i++) + { + for (var j = 0; j < radius; j++) // + { + buffer[radius + 1 + j] = data[i + j]; + } + + ApplyWeights(buffer, weights); + _smoothResult[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); + _smoothResult[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); + _smoothResult[i] = buffer.Sum(); + } + + return _smoothResult; + } + + private 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 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/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/DataService/AudioServiceImpl.cs b/Correlator/DataService/AudioServiceImpl.cs index 9227651..f5dbe51 100644 --- a/Correlator/DataService/AudioServiceImpl.cs +++ b/Correlator/DataService/AudioServiceImpl.cs @@ -1,5 +1,4 @@ using System; -using Correlator.SensorHubTag; using Correlator.Util; using NAudio.Wave; @@ -12,18 +11,19 @@ private BufferedWaveProvider _waveProvider; private readonly WaveFormat _waveFormat = new WaveFormat(7500, 24, 1); + public WaveOutEvent Wave { get; set; } = new WaveOutEvent(); + public void Start(string deviceCode) { _isStopped = false; _waveProvider = new BufferedWaveProvider(_waveFormat); - var waveOut = new WaveOut(); - waveOut.Init(_waveProvider); + Wave.Init(_waveProvider); string fileName; var audioDir = DirectoryManager.GetAudioDir(); var time = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - if (deviceCode == DevCode.Dev1) + if (deviceCode == RuntimeCache.Dev1) { //红色传感器听音 fileName = $"{audioDir}/听音_红_{time}.wav"; @@ -36,7 +36,7 @@ _waveFileWriter = new WaveFileWriter(fileName, _waveFormat); - waveOut.Play(); + Wave.Play(); } //缓存声波数据已经是后台线程了(处于线程池中) @@ -47,18 +47,23 @@ return; } - _waveProvider?.AddSamples(pcm, 0, pcm.Length); - _waveFileWriter?.Write(pcm, 0, pcm.Length); + try + { + _waveProvider?.AddSamples(pcm, 0, pcm.Length); + _waveFileWriter?.Write(pcm, 0, pcm.Length); + } + catch (InvalidOperationException) + { + _waveProvider?.ClearBuffer(); + } } public void Stop() { _isStopped = true; - + Wave.Stop(); _waveProvider.ClearBuffer(); _waveFileWriter.Dispose(); } - - // public AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/IAudioService.cs b/Correlator/DataService/IAudioService.cs index 83609b2..f6e157a 100644 --- a/Correlator/DataService/IAudioService.cs +++ b/Correlator/DataService/IAudioService.cs @@ -1,7 +1,11 @@ -namespace Correlator.DataService +using NAudio.Wave; + +namespace Correlator.DataService { public interface IAudioService { + WaveOutEvent Wave { get; set; } + /// /// 开始听音 /// @@ -18,7 +22,5 @@ /// 结束听音 /// void Stop(); - - // AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/SerialPortServiceImpl.cs b/Correlator/DataService/SerialPortServiceImpl.cs index 0a7e32f..824eccb 100644 --- a/Correlator/DataService/SerialPortServiceImpl.cs +++ b/Correlator/DataService/SerialPortServiceImpl.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO.Ports; -using System.Text; using System.Threading; using System.Windows; using Correlator.Events; @@ -131,7 +130,7 @@ } //发送消息更新界面 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { _eventAggregator.GetEvent().Publish(_devStatus); } @@ -173,7 +172,7 @@ var response = BitConverter.ToString(receivedData).Replace("-", ""); //收集数据 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { //原始数据 RuntimeCache.RedSensorOriginalResp.Add(index, response); @@ -218,7 +217,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { //接收到数据之后时间重新赋值 _dataModel.LeftReceiveDataTime = DateTime.Now; @@ -271,16 +270,6 @@ //将pcm数据写入缓存 _audioService.Write(pcm); - - //波形图数据 - var length = pcm.Length / 4; - var spectrumData = new double[length]; - for (var i = 0; i < length; i++) - { - spectrumData[i] = BitConverter.ToSingle(pcm, i * 4); - } - - // _audioService.AudioVisualizer.PushSampleData(spectrumData); } } @@ -310,7 +299,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { _dataModel.LeftDeviceDataArray = doubleArrays.ToOneDimensionalArray(); } diff --git a/Correlator/Dialog/CheckResponseDialog.xaml.cs b/Correlator/Dialog/CheckResponseDialog.xaml.cs index 43f84fd..91441a2 100644 --- a/Correlator/Dialog/CheckResponseDialog.xaml.cs +++ b/Correlator/Dialog/CheckResponseDialog.xaml.cs @@ -231,7 +231,7 @@ if (RedSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev1); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev1); _redResponseTimer.Start(); ReCheckButton.IsEnabled = true; @@ -239,11 +239,11 @@ else if (RedSensorStepBar.StepIndex == 2) { //下发数据全部正常指令 - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev1}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev1}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.RedSensorOriginalResp orderby pair.Key select pair; @@ -266,7 +266,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev1, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev1, tags); #endregion } @@ -315,18 +315,18 @@ if (BlueSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev2); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev2); _blueResponseTimer.Start(); ReCheckButton.IsEnabled = true; } else if (BlueSensorStepBar.StepIndex == 2) { - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev2}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev2}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.BlueSensorOriginalResp orderby pair.Key select pair; @@ -349,7 +349,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev2, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev2, tags); #endregion } @@ -396,7 +396,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, redIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, redIndexArray); } else { @@ -417,7 +417,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, blueIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, blueIndexArray); } }; } diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml b/Correlator/Dialog/SimplyAuditionDialog.xaml index 5fd8124..cd03b74 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml @@ -9,7 +9,7 @@ xmlns:prism="http://prismlibrary.com/" xmlns:vm="clr-namespace:Correlator.ViewModels" Width="600" - Height="400" + Height="480" d:DataContext="{d:DesignInstance Type=vm:SimplyAuditionDialogViewModel}" Loaded="SimplyAuditionDialog_OnLoaded" Unloaded="SimplyAuditionDialog_OnUnloaded" @@ -187,10 +187,15 @@ - + Background="{StaticResource MainThemeColor}"> + + + + + diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs index 3747ce0..41cb280 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -6,6 +7,8 @@ using System.Windows.Threading; using Correlator.DataService; using Correlator.Util; +using NAudio.CoreAudioApi; +using NAudio.Wave; namespace Correlator.Dialog { @@ -16,6 +19,7 @@ { private readonly AudioVisualizer _visualizer; // 可视化 private double[] _spectrumData; // 频谱数据 + private readonly WasapiCapture _capture; // 音频捕获 private int _colorIndex; private readonly Color[] _allColors; @@ -29,29 +33,44 @@ Interval = new TimeSpan(0, 0, 0, 0, 30) }; - public SimplyAuditionDialog(IApplicationDataService dataService, IAudioService audioService) + public SimplyAuditionDialog(IApplicationDataService dataService) { InitializeComponent(); - // _visualizer = dataService.GetAudioVisualizer(256); - // _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) - // - // audioService.AudioVisualizer = _visualizer; - // - // _dataTimer.Tick += DataTimer_Tick; - // _drawingTimer.Tick += DrawingTimer_Tick; + _capture = new WasapiLoopbackCapture(); // 捕获电脑发出的声音 + _visualizer = dataService.GetAudioVisualizer(512); + _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) + + _capture.WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(7500, 1); + _capture.DataAvailable += delegate(object o, WaveInEventArgs args) + { + var length = args.BytesRecorded / 4; // 采样的数量 (每一个采样是 4 字节) + var result = new double[length]; + + for (var i = 0; i < length; i++) + { + result[i] = BitConverter.ToSingle(args.Buffer, i * 4); // 取出采样值 + } + + _visualizer.PushSampleData(result); // 将新的采样存储到 可视化器 中 + }; + + _dataTimer.Tick += DataTimer_Tick; + _drawingTimer.Tick += DrawingTimer_Tick; } private void SimplyAuditionDialog_OnLoaded(object sender, RoutedEventArgs e) { - // _dataTimer.Start(); - // _drawingTimer.Start(); + _capture.StartRecording(); + _dataTimer.Start(); + _drawingTimer.Start(); } private void SimplyAuditionDialog_OnUnloaded(object sender, RoutedEventArgs e) { - // _drawingTimer.Stop(); - // _dataTimer.Stop(); + _drawingTimer.Stop(); + _dataTimer.Stop(); + _capture.StopRecording(); } /// @@ -62,7 +81,7 @@ private void DataTimer_Tick(object sender, EventArgs e) { var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据 - newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 + newSpectrumData = AudioDataHub.Get.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去 { @@ -92,80 +111,90 @@ 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 * 200 + var bassArea = AudioDataHub.Get.TakeSpectrumOfFrequency( + _spectrumData, RuntimeCache.AudioSampleRate, 250 + ); + var bassScale = bassArea.Average() * 100; //低音区 + + //波形曲线 + var curveBrush = new SolidColorBrush(color1); + DrawCurve( + SampleWavePath, curveBrush, + _visualizer.SampleData, _visualizer.SampleData.Length, + SampleWavePanel.ActualWidth, 0, SampleWavePanel.ActualHeight / 2, + Math.Min(SampleWavePanel.ActualHeight / 2, 50) + ); + + //四周边框 + DrawGradientBorder( + TopBorder, BottomBorder, LeftBorder, RightBorder, + Color.FromArgb(0, color1.R, color1.G, color1.B), color2, + SampleWavePanel.ActualWidth / 3, bassScale ); } /// - /// 绘制渐变的条形 + /// 画曲线 /// - /// 绘图目标 - /// 下方颜色 - /// 上方颜色 - /// 频谱数据 - /// 条形的数量 - /// 绘图的宽度 - /// 绘图的起始 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 + /// + /// + /// + /// + /// + /// + /// + /// 控制波形图波峰高度和波谷深度 + private void DrawCurve( + Path wavePath, Brush brush, double[] spectrumData, int pointCount, double drawingWidth, + double xOffset, double yOffset, double scale ) { - //竖条宽度 - var stripWidth = (drawingWidth - spacing * stripCount) / stripCount; - var pointArray = new Point[stripCount]; - - for (var i = 0; i < stripCount; i++) + var pointArray = new Point[pointCount]; + for (var i = 0; i < pointCount; i++) { - var x = stripWidth * i + spacing * i + xOffset; - var y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height - //给所有频谱位置赋值 + var x = i * drawingWidth / pointCount + xOffset; + var y = spectrumData[i * spectrumData.Length / pointCount] * scale + yOffset; pointArray[i] = new Point(x, y); } - //生成一系列频谱竖条 - var geometry = new GeometryGroup(); - foreach (var point in pointArray) + var figure = new PathFigure { - var height = point.Y; + StartPoint = pointArray[0] + }; + figure.Segments.Add(new PolyLineSegment(pointArray, true)); - if (height < 0) - { - height = -height; - } + wavePath.Data = new PathGeometry { Figures = { figure } }; + wavePath.Stroke = brush; + } - //每根竖条的四个角坐标 - 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) //右下角 - }; + /// + /// 画四周渐变边框 + /// + /// + /// + /// + /// + /// + /// + /// 画图宽度 + /// 高低音转化比例 + private void DrawGradientBorder( + Rectangle topBorder, Rectangle bottomBorder, Rectangle leftBorder, + Rectangle rightBorder, Color inner, Color outer, double width, double bassScale + ) + { + //边框粗细根据音频高低音变化 + var thickness = (int)(width * bassScale); - var figure = new PathFigure - { - StartPoint = endPoints[0] - }; + topBorder.Height = thickness; + bottomBorder.Height = thickness; + leftBorder.Width = thickness; + rightBorder.Width = thickness; - 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; + topBorder.Fill = new LinearGradientBrush(outer, inner, 90); + bottomBorder.Fill = new LinearGradientBrush(inner, outer, 90); + leftBorder.Fill = new LinearGradientBrush(outer, inner, 0); + rightBorder.Fill = new LinearGradientBrush(inner, outer, 0); } } } \ No newline at end of file diff --git a/Correlator/SensorHubTag/DevCode.cs b/Correlator/SensorHubTag/DevCode.cs deleted file mode 100644 index afd5e8f..0000000 --- a/Correlator/SensorHubTag/DevCode.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Correlator.SensorHubTag -{ - public static class DevCode - { - public static string Dev1 => "211700082201"; - - public static string Dev2 => "211700082202"; - } -} \ No newline at end of file diff --git a/Correlator/Util/AudioDataHub.cs b/Correlator/Util/AudioDataHub.cs new file mode 100644 index 0000000..72d62ea --- /dev/null +++ b/Correlator/Util/AudioDataHub.cs @@ -0,0 +1,135 @@ +using System; +using System.Linq; + +namespace Correlator.Util +{ + /// + /// 音频可视化数据处理 + /// + public class AudioDataHub + { + #region 懒汉单例模式 + + private static readonly Lazy Lazy = new Lazy(() => new AudioDataHub()); + + public static AudioDataHub Get => Lazy.Value; + + + private AudioDataHub() + { + } + + #endregion + + private double[] _smoothResult; + + public double[] TakeSpectrumOfFrequency(double[] spectrum, double sampleRate, double frequency) + { + var frequencyPerSample = sampleRate / spectrum.Length; + + var lengthInNeed = (int)Math.Min(frequency / frequencyPerSample, spectrum.Length); + var result = new double[lengthInNeed]; + Array.Copy(spectrum, 0, result, 0, lengthInNeed); + return result; + } + + /// + /// 简单的数据模糊 + /// + /// 数据 + /// 模糊半径 + /// 结果 + public double[] MakeSmooth(double[] data, int radius) + { + var weights = GetWeights(radius); + var buffer = new double[1 + radius * 2]; + + _smoothResult = new double[data.Length]; + if (data.Length < radius) + { + data.Average(); + _smoothResult.SetValue(data, 0); + return _smoothResult; + } + + for (var i = 0; i < radius; i++) + { + for (var j = 0; j < radius; j++) // + { + buffer[radius + 1 + j] = data[i + j]; + } + + ApplyWeights(buffer, weights); + _smoothResult[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); + _smoothResult[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); + _smoothResult[i] = buffer.Sum(); + } + + return _smoothResult; + } + + private 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 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/Util/AudioVisualizer.cs b/Correlator/Util/AudioVisualizer.cs index 9a888f5..393f7df 100644 --- a/Correlator/Util/AudioVisualizer.cs +++ b/Correlator/Util/AudioVisualizer.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using FftSharp; using FftSharp.Windows; using Complex = System.Numerics.Complex; @@ -13,6 +12,8 @@ /// public double[] SampleData { get; } + private Complex[] _data; + /// /// /// @@ -63,126 +64,27 @@ public double[] GetSpectrumData() { var len = SampleData.Length; - var data = new Complex[len]; - + _data = new Complex[len]; + for (var i = 0; i < len; i++) { - data[i] = new Complex(SampleData[i], 0); + _data[i] = new Complex(SampleData[i], 0); } - - FFT.Forward(data); - + + FFT.Forward(_data); + var halfLen = len / 2; var result = new double[halfLen]; // 傅里叶变换结果左右对称, 只需要取一半 for (var i = 0; i < halfLen; i++) { - result[i] = data[i].Magnitude / len; + 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/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/DataService/AudioServiceImpl.cs b/Correlator/DataService/AudioServiceImpl.cs index 9227651..f5dbe51 100644 --- a/Correlator/DataService/AudioServiceImpl.cs +++ b/Correlator/DataService/AudioServiceImpl.cs @@ -1,5 +1,4 @@ using System; -using Correlator.SensorHubTag; using Correlator.Util; using NAudio.Wave; @@ -12,18 +11,19 @@ private BufferedWaveProvider _waveProvider; private readonly WaveFormat _waveFormat = new WaveFormat(7500, 24, 1); + public WaveOutEvent Wave { get; set; } = new WaveOutEvent(); + public void Start(string deviceCode) { _isStopped = false; _waveProvider = new BufferedWaveProvider(_waveFormat); - var waveOut = new WaveOut(); - waveOut.Init(_waveProvider); + Wave.Init(_waveProvider); string fileName; var audioDir = DirectoryManager.GetAudioDir(); var time = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - if (deviceCode == DevCode.Dev1) + if (deviceCode == RuntimeCache.Dev1) { //红色传感器听音 fileName = $"{audioDir}/听音_红_{time}.wav"; @@ -36,7 +36,7 @@ _waveFileWriter = new WaveFileWriter(fileName, _waveFormat); - waveOut.Play(); + Wave.Play(); } //缓存声波数据已经是后台线程了(处于线程池中) @@ -47,18 +47,23 @@ return; } - _waveProvider?.AddSamples(pcm, 0, pcm.Length); - _waveFileWriter?.Write(pcm, 0, pcm.Length); + try + { + _waveProvider?.AddSamples(pcm, 0, pcm.Length); + _waveFileWriter?.Write(pcm, 0, pcm.Length); + } + catch (InvalidOperationException) + { + _waveProvider?.ClearBuffer(); + } } public void Stop() { _isStopped = true; - + Wave.Stop(); _waveProvider.ClearBuffer(); _waveFileWriter.Dispose(); } - - // public AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/IAudioService.cs b/Correlator/DataService/IAudioService.cs index 83609b2..f6e157a 100644 --- a/Correlator/DataService/IAudioService.cs +++ b/Correlator/DataService/IAudioService.cs @@ -1,7 +1,11 @@ -namespace Correlator.DataService +using NAudio.Wave; + +namespace Correlator.DataService { public interface IAudioService { + WaveOutEvent Wave { get; set; } + /// /// 开始听音 /// @@ -18,7 +22,5 @@ /// 结束听音 /// void Stop(); - - // AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/SerialPortServiceImpl.cs b/Correlator/DataService/SerialPortServiceImpl.cs index 0a7e32f..824eccb 100644 --- a/Correlator/DataService/SerialPortServiceImpl.cs +++ b/Correlator/DataService/SerialPortServiceImpl.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO.Ports; -using System.Text; using System.Threading; using System.Windows; using Correlator.Events; @@ -131,7 +130,7 @@ } //发送消息更新界面 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { _eventAggregator.GetEvent().Publish(_devStatus); } @@ -173,7 +172,7 @@ var response = BitConverter.ToString(receivedData).Replace("-", ""); //收集数据 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { //原始数据 RuntimeCache.RedSensorOriginalResp.Add(index, response); @@ -218,7 +217,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { //接收到数据之后时间重新赋值 _dataModel.LeftReceiveDataTime = DateTime.Now; @@ -271,16 +270,6 @@ //将pcm数据写入缓存 _audioService.Write(pcm); - - //波形图数据 - var length = pcm.Length / 4; - var spectrumData = new double[length]; - for (var i = 0; i < length; i++) - { - spectrumData[i] = BitConverter.ToSingle(pcm, i * 4); - } - - // _audioService.AudioVisualizer.PushSampleData(spectrumData); } } @@ -310,7 +299,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { _dataModel.LeftDeviceDataArray = doubleArrays.ToOneDimensionalArray(); } diff --git a/Correlator/Dialog/CheckResponseDialog.xaml.cs b/Correlator/Dialog/CheckResponseDialog.xaml.cs index 43f84fd..91441a2 100644 --- a/Correlator/Dialog/CheckResponseDialog.xaml.cs +++ b/Correlator/Dialog/CheckResponseDialog.xaml.cs @@ -231,7 +231,7 @@ if (RedSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev1); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev1); _redResponseTimer.Start(); ReCheckButton.IsEnabled = true; @@ -239,11 +239,11 @@ else if (RedSensorStepBar.StepIndex == 2) { //下发数据全部正常指令 - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev1}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev1}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.RedSensorOriginalResp orderby pair.Key select pair; @@ -266,7 +266,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev1, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev1, tags); #endregion } @@ -315,18 +315,18 @@ if (BlueSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev2); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev2); _blueResponseTimer.Start(); ReCheckButton.IsEnabled = true; } else if (BlueSensorStepBar.StepIndex == 2) { - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev2}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev2}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.BlueSensorOriginalResp orderby pair.Key select pair; @@ -349,7 +349,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev2, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev2, tags); #endregion } @@ -396,7 +396,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, redIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, redIndexArray); } else { @@ -417,7 +417,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, blueIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, blueIndexArray); } }; } diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml b/Correlator/Dialog/SimplyAuditionDialog.xaml index 5fd8124..cd03b74 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml @@ -9,7 +9,7 @@ xmlns:prism="http://prismlibrary.com/" xmlns:vm="clr-namespace:Correlator.ViewModels" Width="600" - Height="400" + Height="480" d:DataContext="{d:DesignInstance Type=vm:SimplyAuditionDialogViewModel}" Loaded="SimplyAuditionDialog_OnLoaded" Unloaded="SimplyAuditionDialog_OnUnloaded" @@ -187,10 +187,15 @@ - + Background="{StaticResource MainThemeColor}"> + + + + + diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs index 3747ce0..41cb280 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -6,6 +7,8 @@ using System.Windows.Threading; using Correlator.DataService; using Correlator.Util; +using NAudio.CoreAudioApi; +using NAudio.Wave; namespace Correlator.Dialog { @@ -16,6 +19,7 @@ { private readonly AudioVisualizer _visualizer; // 可视化 private double[] _spectrumData; // 频谱数据 + private readonly WasapiCapture _capture; // 音频捕获 private int _colorIndex; private readonly Color[] _allColors; @@ -29,29 +33,44 @@ Interval = new TimeSpan(0, 0, 0, 0, 30) }; - public SimplyAuditionDialog(IApplicationDataService dataService, IAudioService audioService) + public SimplyAuditionDialog(IApplicationDataService dataService) { InitializeComponent(); - // _visualizer = dataService.GetAudioVisualizer(256); - // _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) - // - // audioService.AudioVisualizer = _visualizer; - // - // _dataTimer.Tick += DataTimer_Tick; - // _drawingTimer.Tick += DrawingTimer_Tick; + _capture = new WasapiLoopbackCapture(); // 捕获电脑发出的声音 + _visualizer = dataService.GetAudioVisualizer(512); + _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) + + _capture.WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(7500, 1); + _capture.DataAvailable += delegate(object o, WaveInEventArgs args) + { + var length = args.BytesRecorded / 4; // 采样的数量 (每一个采样是 4 字节) + var result = new double[length]; + + for (var i = 0; i < length; i++) + { + result[i] = BitConverter.ToSingle(args.Buffer, i * 4); // 取出采样值 + } + + _visualizer.PushSampleData(result); // 将新的采样存储到 可视化器 中 + }; + + _dataTimer.Tick += DataTimer_Tick; + _drawingTimer.Tick += DrawingTimer_Tick; } private void SimplyAuditionDialog_OnLoaded(object sender, RoutedEventArgs e) { - // _dataTimer.Start(); - // _drawingTimer.Start(); + _capture.StartRecording(); + _dataTimer.Start(); + _drawingTimer.Start(); } private void SimplyAuditionDialog_OnUnloaded(object sender, RoutedEventArgs e) { - // _drawingTimer.Stop(); - // _dataTimer.Stop(); + _drawingTimer.Stop(); + _dataTimer.Stop(); + _capture.StopRecording(); } /// @@ -62,7 +81,7 @@ private void DataTimer_Tick(object sender, EventArgs e) { var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据 - newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 + newSpectrumData = AudioDataHub.Get.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去 { @@ -92,80 +111,90 @@ 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 * 200 + var bassArea = AudioDataHub.Get.TakeSpectrumOfFrequency( + _spectrumData, RuntimeCache.AudioSampleRate, 250 + ); + var bassScale = bassArea.Average() * 100; //低音区 + + //波形曲线 + var curveBrush = new SolidColorBrush(color1); + DrawCurve( + SampleWavePath, curveBrush, + _visualizer.SampleData, _visualizer.SampleData.Length, + SampleWavePanel.ActualWidth, 0, SampleWavePanel.ActualHeight / 2, + Math.Min(SampleWavePanel.ActualHeight / 2, 50) + ); + + //四周边框 + DrawGradientBorder( + TopBorder, BottomBorder, LeftBorder, RightBorder, + Color.FromArgb(0, color1.R, color1.G, color1.B), color2, + SampleWavePanel.ActualWidth / 3, bassScale ); } /// - /// 绘制渐变的条形 + /// 画曲线 /// - /// 绘图目标 - /// 下方颜色 - /// 上方颜色 - /// 频谱数据 - /// 条形的数量 - /// 绘图的宽度 - /// 绘图的起始 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 + /// + /// + /// + /// + /// + /// + /// + /// 控制波形图波峰高度和波谷深度 + private void DrawCurve( + Path wavePath, Brush brush, double[] spectrumData, int pointCount, double drawingWidth, + double xOffset, double yOffset, double scale ) { - //竖条宽度 - var stripWidth = (drawingWidth - spacing * stripCount) / stripCount; - var pointArray = new Point[stripCount]; - - for (var i = 0; i < stripCount; i++) + var pointArray = new Point[pointCount]; + for (var i = 0; i < pointCount; i++) { - var x = stripWidth * i + spacing * i + xOffset; - var y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height - //给所有频谱位置赋值 + var x = i * drawingWidth / pointCount + xOffset; + var y = spectrumData[i * spectrumData.Length / pointCount] * scale + yOffset; pointArray[i] = new Point(x, y); } - //生成一系列频谱竖条 - var geometry = new GeometryGroup(); - foreach (var point in pointArray) + var figure = new PathFigure { - var height = point.Y; + StartPoint = pointArray[0] + }; + figure.Segments.Add(new PolyLineSegment(pointArray, true)); - if (height < 0) - { - height = -height; - } + wavePath.Data = new PathGeometry { Figures = { figure } }; + wavePath.Stroke = brush; + } - //每根竖条的四个角坐标 - 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) //右下角 - }; + /// + /// 画四周渐变边框 + /// + /// + /// + /// + /// + /// + /// + /// 画图宽度 + /// 高低音转化比例 + private void DrawGradientBorder( + Rectangle topBorder, Rectangle bottomBorder, Rectangle leftBorder, + Rectangle rightBorder, Color inner, Color outer, double width, double bassScale + ) + { + //边框粗细根据音频高低音变化 + var thickness = (int)(width * bassScale); - var figure = new PathFigure - { - StartPoint = endPoints[0] - }; + topBorder.Height = thickness; + bottomBorder.Height = thickness; + leftBorder.Width = thickness; + rightBorder.Width = thickness; - 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; + topBorder.Fill = new LinearGradientBrush(outer, inner, 90); + bottomBorder.Fill = new LinearGradientBrush(inner, outer, 90); + leftBorder.Fill = new LinearGradientBrush(outer, inner, 0); + rightBorder.Fill = new LinearGradientBrush(inner, outer, 0); } } } \ No newline at end of file diff --git a/Correlator/SensorHubTag/DevCode.cs b/Correlator/SensorHubTag/DevCode.cs deleted file mode 100644 index afd5e8f..0000000 --- a/Correlator/SensorHubTag/DevCode.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Correlator.SensorHubTag -{ - public static class DevCode - { - public static string Dev1 => "211700082201"; - - public static string Dev2 => "211700082202"; - } -} \ No newline at end of file diff --git a/Correlator/Util/AudioDataHub.cs b/Correlator/Util/AudioDataHub.cs new file mode 100644 index 0000000..72d62ea --- /dev/null +++ b/Correlator/Util/AudioDataHub.cs @@ -0,0 +1,135 @@ +using System; +using System.Linq; + +namespace Correlator.Util +{ + /// + /// 音频可视化数据处理 + /// + public class AudioDataHub + { + #region 懒汉单例模式 + + private static readonly Lazy Lazy = new Lazy(() => new AudioDataHub()); + + public static AudioDataHub Get => Lazy.Value; + + + private AudioDataHub() + { + } + + #endregion + + private double[] _smoothResult; + + public double[] TakeSpectrumOfFrequency(double[] spectrum, double sampleRate, double frequency) + { + var frequencyPerSample = sampleRate / spectrum.Length; + + var lengthInNeed = (int)Math.Min(frequency / frequencyPerSample, spectrum.Length); + var result = new double[lengthInNeed]; + Array.Copy(spectrum, 0, result, 0, lengthInNeed); + return result; + } + + /// + /// 简单的数据模糊 + /// + /// 数据 + /// 模糊半径 + /// 结果 + public double[] MakeSmooth(double[] data, int radius) + { + var weights = GetWeights(radius); + var buffer = new double[1 + radius * 2]; + + _smoothResult = new double[data.Length]; + if (data.Length < radius) + { + data.Average(); + _smoothResult.SetValue(data, 0); + return _smoothResult; + } + + for (var i = 0; i < radius; i++) + { + for (var j = 0; j < radius; j++) // + { + buffer[radius + 1 + j] = data[i + j]; + } + + ApplyWeights(buffer, weights); + _smoothResult[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); + _smoothResult[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); + _smoothResult[i] = buffer.Sum(); + } + + return _smoothResult; + } + + private 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 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/Util/AudioVisualizer.cs b/Correlator/Util/AudioVisualizer.cs index 9a888f5..393f7df 100644 --- a/Correlator/Util/AudioVisualizer.cs +++ b/Correlator/Util/AudioVisualizer.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using FftSharp; using FftSharp.Windows; using Complex = System.Numerics.Complex; @@ -13,6 +12,8 @@ /// public double[] SampleData { get; } + private Complex[] _data; + /// /// /// @@ -63,126 +64,27 @@ public double[] GetSpectrumData() { var len = SampleData.Length; - var data = new Complex[len]; - + _data = new Complex[len]; + for (var i = 0; i < len; i++) { - data[i] = new Complex(SampleData[i], 0); + _data[i] = new Complex(SampleData[i], 0); } - - FFT.Forward(data); - + + FFT.Forward(_data); + var halfLen = len / 2; var result = new double[halfLen]; // 傅里叶变换结果左右对称, 只需要取一半 for (var i = 0; i < halfLen; i++) { - result[i] = data[i].Magnitude / len; + 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/Util/RuntimeCache.cs b/Correlator/Util/RuntimeCache.cs index 468ca7f..4a1e94e 100644 --- a/Correlator/Util/RuntimeCache.cs +++ b/Correlator/Util/RuntimeCache.cs @@ -86,5 +86,15 @@ /// 采样率 /// public const int AudioSampleRate = 7500; + + /// + /// 设备1(红色的) + /// + public static string Dev1 => "211700082201"; + + /// + /// 设备2(蓝色的) + /// + public static string Dev2 => "211700082202"; } } \ No newline at end of file diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/DataService/AudioServiceImpl.cs b/Correlator/DataService/AudioServiceImpl.cs index 9227651..f5dbe51 100644 --- a/Correlator/DataService/AudioServiceImpl.cs +++ b/Correlator/DataService/AudioServiceImpl.cs @@ -1,5 +1,4 @@ using System; -using Correlator.SensorHubTag; using Correlator.Util; using NAudio.Wave; @@ -12,18 +11,19 @@ private BufferedWaveProvider _waveProvider; private readonly WaveFormat _waveFormat = new WaveFormat(7500, 24, 1); + public WaveOutEvent Wave { get; set; } = new WaveOutEvent(); + public void Start(string deviceCode) { _isStopped = false; _waveProvider = new BufferedWaveProvider(_waveFormat); - var waveOut = new WaveOut(); - waveOut.Init(_waveProvider); + Wave.Init(_waveProvider); string fileName; var audioDir = DirectoryManager.GetAudioDir(); var time = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - if (deviceCode == DevCode.Dev1) + if (deviceCode == RuntimeCache.Dev1) { //红色传感器听音 fileName = $"{audioDir}/听音_红_{time}.wav"; @@ -36,7 +36,7 @@ _waveFileWriter = new WaveFileWriter(fileName, _waveFormat); - waveOut.Play(); + Wave.Play(); } //缓存声波数据已经是后台线程了(处于线程池中) @@ -47,18 +47,23 @@ return; } - _waveProvider?.AddSamples(pcm, 0, pcm.Length); - _waveFileWriter?.Write(pcm, 0, pcm.Length); + try + { + _waveProvider?.AddSamples(pcm, 0, pcm.Length); + _waveFileWriter?.Write(pcm, 0, pcm.Length); + } + catch (InvalidOperationException) + { + _waveProvider?.ClearBuffer(); + } } public void Stop() { _isStopped = true; - + Wave.Stop(); _waveProvider.ClearBuffer(); _waveFileWriter.Dispose(); } - - // public AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/IAudioService.cs b/Correlator/DataService/IAudioService.cs index 83609b2..f6e157a 100644 --- a/Correlator/DataService/IAudioService.cs +++ b/Correlator/DataService/IAudioService.cs @@ -1,7 +1,11 @@ -namespace Correlator.DataService +using NAudio.Wave; + +namespace Correlator.DataService { public interface IAudioService { + WaveOutEvent Wave { get; set; } + /// /// 开始听音 /// @@ -18,7 +22,5 @@ /// 结束听音 /// void Stop(); - - // AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/SerialPortServiceImpl.cs b/Correlator/DataService/SerialPortServiceImpl.cs index 0a7e32f..824eccb 100644 --- a/Correlator/DataService/SerialPortServiceImpl.cs +++ b/Correlator/DataService/SerialPortServiceImpl.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO.Ports; -using System.Text; using System.Threading; using System.Windows; using Correlator.Events; @@ -131,7 +130,7 @@ } //发送消息更新界面 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { _eventAggregator.GetEvent().Publish(_devStatus); } @@ -173,7 +172,7 @@ var response = BitConverter.ToString(receivedData).Replace("-", ""); //收集数据 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { //原始数据 RuntimeCache.RedSensorOriginalResp.Add(index, response); @@ -218,7 +217,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { //接收到数据之后时间重新赋值 _dataModel.LeftReceiveDataTime = DateTime.Now; @@ -271,16 +270,6 @@ //将pcm数据写入缓存 _audioService.Write(pcm); - - //波形图数据 - var length = pcm.Length / 4; - var spectrumData = new double[length]; - for (var i = 0; i < length; i++) - { - spectrumData[i] = BitConverter.ToSingle(pcm, i * 4); - } - - // _audioService.AudioVisualizer.PushSampleData(spectrumData); } } @@ -310,7 +299,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { _dataModel.LeftDeviceDataArray = doubleArrays.ToOneDimensionalArray(); } diff --git a/Correlator/Dialog/CheckResponseDialog.xaml.cs b/Correlator/Dialog/CheckResponseDialog.xaml.cs index 43f84fd..91441a2 100644 --- a/Correlator/Dialog/CheckResponseDialog.xaml.cs +++ b/Correlator/Dialog/CheckResponseDialog.xaml.cs @@ -231,7 +231,7 @@ if (RedSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev1); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev1); _redResponseTimer.Start(); ReCheckButton.IsEnabled = true; @@ -239,11 +239,11 @@ else if (RedSensorStepBar.StepIndex == 2) { //下发数据全部正常指令 - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev1}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev1}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.RedSensorOriginalResp orderby pair.Key select pair; @@ -266,7 +266,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev1, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev1, tags); #endregion } @@ -315,18 +315,18 @@ if (BlueSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev2); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev2); _blueResponseTimer.Start(); ReCheckButton.IsEnabled = true; } else if (BlueSensorStepBar.StepIndex == 2) { - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev2}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev2}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.BlueSensorOriginalResp orderby pair.Key select pair; @@ -349,7 +349,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev2, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev2, tags); #endregion } @@ -396,7 +396,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, redIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, redIndexArray); } else { @@ -417,7 +417,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, blueIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, blueIndexArray); } }; } diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml b/Correlator/Dialog/SimplyAuditionDialog.xaml index 5fd8124..cd03b74 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml @@ -9,7 +9,7 @@ xmlns:prism="http://prismlibrary.com/" xmlns:vm="clr-namespace:Correlator.ViewModels" Width="600" - Height="400" + Height="480" d:DataContext="{d:DesignInstance Type=vm:SimplyAuditionDialogViewModel}" Loaded="SimplyAuditionDialog_OnLoaded" Unloaded="SimplyAuditionDialog_OnUnloaded" @@ -187,10 +187,15 @@ - + Background="{StaticResource MainThemeColor}"> + + + + + diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs index 3747ce0..41cb280 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -6,6 +7,8 @@ using System.Windows.Threading; using Correlator.DataService; using Correlator.Util; +using NAudio.CoreAudioApi; +using NAudio.Wave; namespace Correlator.Dialog { @@ -16,6 +19,7 @@ { private readonly AudioVisualizer _visualizer; // 可视化 private double[] _spectrumData; // 频谱数据 + private readonly WasapiCapture _capture; // 音频捕获 private int _colorIndex; private readonly Color[] _allColors; @@ -29,29 +33,44 @@ Interval = new TimeSpan(0, 0, 0, 0, 30) }; - public SimplyAuditionDialog(IApplicationDataService dataService, IAudioService audioService) + public SimplyAuditionDialog(IApplicationDataService dataService) { InitializeComponent(); - // _visualizer = dataService.GetAudioVisualizer(256); - // _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) - // - // audioService.AudioVisualizer = _visualizer; - // - // _dataTimer.Tick += DataTimer_Tick; - // _drawingTimer.Tick += DrawingTimer_Tick; + _capture = new WasapiLoopbackCapture(); // 捕获电脑发出的声音 + _visualizer = dataService.GetAudioVisualizer(512); + _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) + + _capture.WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(7500, 1); + _capture.DataAvailable += delegate(object o, WaveInEventArgs args) + { + var length = args.BytesRecorded / 4; // 采样的数量 (每一个采样是 4 字节) + var result = new double[length]; + + for (var i = 0; i < length; i++) + { + result[i] = BitConverter.ToSingle(args.Buffer, i * 4); // 取出采样值 + } + + _visualizer.PushSampleData(result); // 将新的采样存储到 可视化器 中 + }; + + _dataTimer.Tick += DataTimer_Tick; + _drawingTimer.Tick += DrawingTimer_Tick; } private void SimplyAuditionDialog_OnLoaded(object sender, RoutedEventArgs e) { - // _dataTimer.Start(); - // _drawingTimer.Start(); + _capture.StartRecording(); + _dataTimer.Start(); + _drawingTimer.Start(); } private void SimplyAuditionDialog_OnUnloaded(object sender, RoutedEventArgs e) { - // _drawingTimer.Stop(); - // _dataTimer.Stop(); + _drawingTimer.Stop(); + _dataTimer.Stop(); + _capture.StopRecording(); } /// @@ -62,7 +81,7 @@ private void DataTimer_Tick(object sender, EventArgs e) { var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据 - newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 + newSpectrumData = AudioDataHub.Get.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去 { @@ -92,80 +111,90 @@ 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 * 200 + var bassArea = AudioDataHub.Get.TakeSpectrumOfFrequency( + _spectrumData, RuntimeCache.AudioSampleRate, 250 + ); + var bassScale = bassArea.Average() * 100; //低音区 + + //波形曲线 + var curveBrush = new SolidColorBrush(color1); + DrawCurve( + SampleWavePath, curveBrush, + _visualizer.SampleData, _visualizer.SampleData.Length, + SampleWavePanel.ActualWidth, 0, SampleWavePanel.ActualHeight / 2, + Math.Min(SampleWavePanel.ActualHeight / 2, 50) + ); + + //四周边框 + DrawGradientBorder( + TopBorder, BottomBorder, LeftBorder, RightBorder, + Color.FromArgb(0, color1.R, color1.G, color1.B), color2, + SampleWavePanel.ActualWidth / 3, bassScale ); } /// - /// 绘制渐变的条形 + /// 画曲线 /// - /// 绘图目标 - /// 下方颜色 - /// 上方颜色 - /// 频谱数据 - /// 条形的数量 - /// 绘图的宽度 - /// 绘图的起始 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 + /// + /// + /// + /// + /// + /// + /// + /// 控制波形图波峰高度和波谷深度 + private void DrawCurve( + Path wavePath, Brush brush, double[] spectrumData, int pointCount, double drawingWidth, + double xOffset, double yOffset, double scale ) { - //竖条宽度 - var stripWidth = (drawingWidth - spacing * stripCount) / stripCount; - var pointArray = new Point[stripCount]; - - for (var i = 0; i < stripCount; i++) + var pointArray = new Point[pointCount]; + for (var i = 0; i < pointCount; i++) { - var x = stripWidth * i + spacing * i + xOffset; - var y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height - //给所有频谱位置赋值 + var x = i * drawingWidth / pointCount + xOffset; + var y = spectrumData[i * spectrumData.Length / pointCount] * scale + yOffset; pointArray[i] = new Point(x, y); } - //生成一系列频谱竖条 - var geometry = new GeometryGroup(); - foreach (var point in pointArray) + var figure = new PathFigure { - var height = point.Y; + StartPoint = pointArray[0] + }; + figure.Segments.Add(new PolyLineSegment(pointArray, true)); - if (height < 0) - { - height = -height; - } + wavePath.Data = new PathGeometry { Figures = { figure } }; + wavePath.Stroke = brush; + } - //每根竖条的四个角坐标 - 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) //右下角 - }; + /// + /// 画四周渐变边框 + /// + /// + /// + /// + /// + /// + /// + /// 画图宽度 + /// 高低音转化比例 + private void DrawGradientBorder( + Rectangle topBorder, Rectangle bottomBorder, Rectangle leftBorder, + Rectangle rightBorder, Color inner, Color outer, double width, double bassScale + ) + { + //边框粗细根据音频高低音变化 + var thickness = (int)(width * bassScale); - var figure = new PathFigure - { - StartPoint = endPoints[0] - }; + topBorder.Height = thickness; + bottomBorder.Height = thickness; + leftBorder.Width = thickness; + rightBorder.Width = thickness; - 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; + topBorder.Fill = new LinearGradientBrush(outer, inner, 90); + bottomBorder.Fill = new LinearGradientBrush(inner, outer, 90); + leftBorder.Fill = new LinearGradientBrush(outer, inner, 0); + rightBorder.Fill = new LinearGradientBrush(inner, outer, 0); } } } \ No newline at end of file diff --git a/Correlator/SensorHubTag/DevCode.cs b/Correlator/SensorHubTag/DevCode.cs deleted file mode 100644 index afd5e8f..0000000 --- a/Correlator/SensorHubTag/DevCode.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Correlator.SensorHubTag -{ - public static class DevCode - { - public static string Dev1 => "211700082201"; - - public static string Dev2 => "211700082202"; - } -} \ No newline at end of file diff --git a/Correlator/Util/AudioDataHub.cs b/Correlator/Util/AudioDataHub.cs new file mode 100644 index 0000000..72d62ea --- /dev/null +++ b/Correlator/Util/AudioDataHub.cs @@ -0,0 +1,135 @@ +using System; +using System.Linq; + +namespace Correlator.Util +{ + /// + /// 音频可视化数据处理 + /// + public class AudioDataHub + { + #region 懒汉单例模式 + + private static readonly Lazy Lazy = new Lazy(() => new AudioDataHub()); + + public static AudioDataHub Get => Lazy.Value; + + + private AudioDataHub() + { + } + + #endregion + + private double[] _smoothResult; + + public double[] TakeSpectrumOfFrequency(double[] spectrum, double sampleRate, double frequency) + { + var frequencyPerSample = sampleRate / spectrum.Length; + + var lengthInNeed = (int)Math.Min(frequency / frequencyPerSample, spectrum.Length); + var result = new double[lengthInNeed]; + Array.Copy(spectrum, 0, result, 0, lengthInNeed); + return result; + } + + /// + /// 简单的数据模糊 + /// + /// 数据 + /// 模糊半径 + /// 结果 + public double[] MakeSmooth(double[] data, int radius) + { + var weights = GetWeights(radius); + var buffer = new double[1 + radius * 2]; + + _smoothResult = new double[data.Length]; + if (data.Length < radius) + { + data.Average(); + _smoothResult.SetValue(data, 0); + return _smoothResult; + } + + for (var i = 0; i < radius; i++) + { + for (var j = 0; j < radius; j++) // + { + buffer[radius + 1 + j] = data[i + j]; + } + + ApplyWeights(buffer, weights); + _smoothResult[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); + _smoothResult[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); + _smoothResult[i] = buffer.Sum(); + } + + return _smoothResult; + } + + private 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 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/Util/AudioVisualizer.cs b/Correlator/Util/AudioVisualizer.cs index 9a888f5..393f7df 100644 --- a/Correlator/Util/AudioVisualizer.cs +++ b/Correlator/Util/AudioVisualizer.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using FftSharp; using FftSharp.Windows; using Complex = System.Numerics.Complex; @@ -13,6 +12,8 @@ /// public double[] SampleData { get; } + private Complex[] _data; + /// /// /// @@ -63,126 +64,27 @@ public double[] GetSpectrumData() { var len = SampleData.Length; - var data = new Complex[len]; - + _data = new Complex[len]; + for (var i = 0; i < len; i++) { - data[i] = new Complex(SampleData[i], 0); + _data[i] = new Complex(SampleData[i], 0); } - - FFT.Forward(data); - + + FFT.Forward(_data); + var halfLen = len / 2; var result = new double[halfLen]; // 傅里叶变换结果左右对称, 只需要取一半 for (var i = 0; i < halfLen; i++) { - result[i] = data[i].Magnitude / len; + 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/Util/RuntimeCache.cs b/Correlator/Util/RuntimeCache.cs index 468ca7f..4a1e94e 100644 --- a/Correlator/Util/RuntimeCache.cs +++ b/Correlator/Util/RuntimeCache.cs @@ -86,5 +86,15 @@ /// 采样率 /// public const int AudioSampleRate = 7500; + + /// + /// 设备1(红色的) + /// + public static string Dev1 => "211700082201"; + + /// + /// 设备2(蓝色的) + /// + public static string Dev2 => "211700082202"; } } \ No newline at end of file diff --git a/Correlator/ViewModels/ImportResponseDialogViewModel.cs b/Correlator/ViewModels/ImportResponseDialogViewModel.cs index 5b6c1f3..af9c398 100644 --- a/Correlator/ViewModels/ImportResponseDialogViewModel.cs +++ b/Correlator/ViewModels/ImportResponseDialogViewModel.cs @@ -286,7 +286,7 @@ Thread.Sleep(10); } - _dataModel.DevCode = DevCode.Dev1; + _dataModel.DevCode = RuntimeCache.Dev1; _dataModel.LeftReceiveDataTime = DateTime.Now; _dataModel.LeftDeviceDataArray = totalData.ToArray(); } @@ -312,7 +312,7 @@ Thread.Sleep(10); } - _dataModel.DevCode = DevCode.Dev2; + _dataModel.DevCode = RuntimeCache.Dev2; _dataModel.RightReceiveDataTime = DateTime.Now; _dataModel.RightDeviceDataArray = totalData.ToArray(); } diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/DataService/AudioServiceImpl.cs b/Correlator/DataService/AudioServiceImpl.cs index 9227651..f5dbe51 100644 --- a/Correlator/DataService/AudioServiceImpl.cs +++ b/Correlator/DataService/AudioServiceImpl.cs @@ -1,5 +1,4 @@ using System; -using Correlator.SensorHubTag; using Correlator.Util; using NAudio.Wave; @@ -12,18 +11,19 @@ private BufferedWaveProvider _waveProvider; private readonly WaveFormat _waveFormat = new WaveFormat(7500, 24, 1); + public WaveOutEvent Wave { get; set; } = new WaveOutEvent(); + public void Start(string deviceCode) { _isStopped = false; _waveProvider = new BufferedWaveProvider(_waveFormat); - var waveOut = new WaveOut(); - waveOut.Init(_waveProvider); + Wave.Init(_waveProvider); string fileName; var audioDir = DirectoryManager.GetAudioDir(); var time = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - if (deviceCode == DevCode.Dev1) + if (deviceCode == RuntimeCache.Dev1) { //红色传感器听音 fileName = $"{audioDir}/听音_红_{time}.wav"; @@ -36,7 +36,7 @@ _waveFileWriter = new WaveFileWriter(fileName, _waveFormat); - waveOut.Play(); + Wave.Play(); } //缓存声波数据已经是后台线程了(处于线程池中) @@ -47,18 +47,23 @@ return; } - _waveProvider?.AddSamples(pcm, 0, pcm.Length); - _waveFileWriter?.Write(pcm, 0, pcm.Length); + try + { + _waveProvider?.AddSamples(pcm, 0, pcm.Length); + _waveFileWriter?.Write(pcm, 0, pcm.Length); + } + catch (InvalidOperationException) + { + _waveProvider?.ClearBuffer(); + } } public void Stop() { _isStopped = true; - + Wave.Stop(); _waveProvider.ClearBuffer(); _waveFileWriter.Dispose(); } - - // public AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/IAudioService.cs b/Correlator/DataService/IAudioService.cs index 83609b2..f6e157a 100644 --- a/Correlator/DataService/IAudioService.cs +++ b/Correlator/DataService/IAudioService.cs @@ -1,7 +1,11 @@ -namespace Correlator.DataService +using NAudio.Wave; + +namespace Correlator.DataService { public interface IAudioService { + WaveOutEvent Wave { get; set; } + /// /// 开始听音 /// @@ -18,7 +22,5 @@ /// 结束听音 /// void Stop(); - - // AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/SerialPortServiceImpl.cs b/Correlator/DataService/SerialPortServiceImpl.cs index 0a7e32f..824eccb 100644 --- a/Correlator/DataService/SerialPortServiceImpl.cs +++ b/Correlator/DataService/SerialPortServiceImpl.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO.Ports; -using System.Text; using System.Threading; using System.Windows; using Correlator.Events; @@ -131,7 +130,7 @@ } //发送消息更新界面 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { _eventAggregator.GetEvent().Publish(_devStatus); } @@ -173,7 +172,7 @@ var response = BitConverter.ToString(receivedData).Replace("-", ""); //收集数据 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { //原始数据 RuntimeCache.RedSensorOriginalResp.Add(index, response); @@ -218,7 +217,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { //接收到数据之后时间重新赋值 _dataModel.LeftReceiveDataTime = DateTime.Now; @@ -271,16 +270,6 @@ //将pcm数据写入缓存 _audioService.Write(pcm); - - //波形图数据 - var length = pcm.Length / 4; - var spectrumData = new double[length]; - for (var i = 0; i < length; i++) - { - spectrumData[i] = BitConverter.ToSingle(pcm, i * 4); - } - - // _audioService.AudioVisualizer.PushSampleData(spectrumData); } } @@ -310,7 +299,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { _dataModel.LeftDeviceDataArray = doubleArrays.ToOneDimensionalArray(); } diff --git a/Correlator/Dialog/CheckResponseDialog.xaml.cs b/Correlator/Dialog/CheckResponseDialog.xaml.cs index 43f84fd..91441a2 100644 --- a/Correlator/Dialog/CheckResponseDialog.xaml.cs +++ b/Correlator/Dialog/CheckResponseDialog.xaml.cs @@ -231,7 +231,7 @@ if (RedSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev1); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev1); _redResponseTimer.Start(); ReCheckButton.IsEnabled = true; @@ -239,11 +239,11 @@ else if (RedSensorStepBar.StepIndex == 2) { //下发数据全部正常指令 - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev1}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev1}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.RedSensorOriginalResp orderby pair.Key select pair; @@ -266,7 +266,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev1, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev1, tags); #endregion } @@ -315,18 +315,18 @@ if (BlueSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev2); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev2); _blueResponseTimer.Start(); ReCheckButton.IsEnabled = true; } else if (BlueSensorStepBar.StepIndex == 2) { - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev2}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev2}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.BlueSensorOriginalResp orderby pair.Key select pair; @@ -349,7 +349,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev2, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev2, tags); #endregion } @@ -396,7 +396,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, redIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, redIndexArray); } else { @@ -417,7 +417,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, blueIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, blueIndexArray); } }; } diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml b/Correlator/Dialog/SimplyAuditionDialog.xaml index 5fd8124..cd03b74 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml @@ -9,7 +9,7 @@ xmlns:prism="http://prismlibrary.com/" xmlns:vm="clr-namespace:Correlator.ViewModels" Width="600" - Height="400" + Height="480" d:DataContext="{d:DesignInstance Type=vm:SimplyAuditionDialogViewModel}" Loaded="SimplyAuditionDialog_OnLoaded" Unloaded="SimplyAuditionDialog_OnUnloaded" @@ -187,10 +187,15 @@ - + Background="{StaticResource MainThemeColor}"> + + + + + diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs index 3747ce0..41cb280 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -6,6 +7,8 @@ using System.Windows.Threading; using Correlator.DataService; using Correlator.Util; +using NAudio.CoreAudioApi; +using NAudio.Wave; namespace Correlator.Dialog { @@ -16,6 +19,7 @@ { private readonly AudioVisualizer _visualizer; // 可视化 private double[] _spectrumData; // 频谱数据 + private readonly WasapiCapture _capture; // 音频捕获 private int _colorIndex; private readonly Color[] _allColors; @@ -29,29 +33,44 @@ Interval = new TimeSpan(0, 0, 0, 0, 30) }; - public SimplyAuditionDialog(IApplicationDataService dataService, IAudioService audioService) + public SimplyAuditionDialog(IApplicationDataService dataService) { InitializeComponent(); - // _visualizer = dataService.GetAudioVisualizer(256); - // _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) - // - // audioService.AudioVisualizer = _visualizer; - // - // _dataTimer.Tick += DataTimer_Tick; - // _drawingTimer.Tick += DrawingTimer_Tick; + _capture = new WasapiLoopbackCapture(); // 捕获电脑发出的声音 + _visualizer = dataService.GetAudioVisualizer(512); + _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) + + _capture.WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(7500, 1); + _capture.DataAvailable += delegate(object o, WaveInEventArgs args) + { + var length = args.BytesRecorded / 4; // 采样的数量 (每一个采样是 4 字节) + var result = new double[length]; + + for (var i = 0; i < length; i++) + { + result[i] = BitConverter.ToSingle(args.Buffer, i * 4); // 取出采样值 + } + + _visualizer.PushSampleData(result); // 将新的采样存储到 可视化器 中 + }; + + _dataTimer.Tick += DataTimer_Tick; + _drawingTimer.Tick += DrawingTimer_Tick; } private void SimplyAuditionDialog_OnLoaded(object sender, RoutedEventArgs e) { - // _dataTimer.Start(); - // _drawingTimer.Start(); + _capture.StartRecording(); + _dataTimer.Start(); + _drawingTimer.Start(); } private void SimplyAuditionDialog_OnUnloaded(object sender, RoutedEventArgs e) { - // _drawingTimer.Stop(); - // _dataTimer.Stop(); + _drawingTimer.Stop(); + _dataTimer.Stop(); + _capture.StopRecording(); } /// @@ -62,7 +81,7 @@ private void DataTimer_Tick(object sender, EventArgs e) { var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据 - newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 + newSpectrumData = AudioDataHub.Get.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去 { @@ -92,80 +111,90 @@ 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 * 200 + var bassArea = AudioDataHub.Get.TakeSpectrumOfFrequency( + _spectrumData, RuntimeCache.AudioSampleRate, 250 + ); + var bassScale = bassArea.Average() * 100; //低音区 + + //波形曲线 + var curveBrush = new SolidColorBrush(color1); + DrawCurve( + SampleWavePath, curveBrush, + _visualizer.SampleData, _visualizer.SampleData.Length, + SampleWavePanel.ActualWidth, 0, SampleWavePanel.ActualHeight / 2, + Math.Min(SampleWavePanel.ActualHeight / 2, 50) + ); + + //四周边框 + DrawGradientBorder( + TopBorder, BottomBorder, LeftBorder, RightBorder, + Color.FromArgb(0, color1.R, color1.G, color1.B), color2, + SampleWavePanel.ActualWidth / 3, bassScale ); } /// - /// 绘制渐变的条形 + /// 画曲线 /// - /// 绘图目标 - /// 下方颜色 - /// 上方颜色 - /// 频谱数据 - /// 条形的数量 - /// 绘图的宽度 - /// 绘图的起始 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 + /// + /// + /// + /// + /// + /// + /// + /// 控制波形图波峰高度和波谷深度 + private void DrawCurve( + Path wavePath, Brush brush, double[] spectrumData, int pointCount, double drawingWidth, + double xOffset, double yOffset, double scale ) { - //竖条宽度 - var stripWidth = (drawingWidth - spacing * stripCount) / stripCount; - var pointArray = new Point[stripCount]; - - for (var i = 0; i < stripCount; i++) + var pointArray = new Point[pointCount]; + for (var i = 0; i < pointCount; i++) { - var x = stripWidth * i + spacing * i + xOffset; - var y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height - //给所有频谱位置赋值 + var x = i * drawingWidth / pointCount + xOffset; + var y = spectrumData[i * spectrumData.Length / pointCount] * scale + yOffset; pointArray[i] = new Point(x, y); } - //生成一系列频谱竖条 - var geometry = new GeometryGroup(); - foreach (var point in pointArray) + var figure = new PathFigure { - var height = point.Y; + StartPoint = pointArray[0] + }; + figure.Segments.Add(new PolyLineSegment(pointArray, true)); - if (height < 0) - { - height = -height; - } + wavePath.Data = new PathGeometry { Figures = { figure } }; + wavePath.Stroke = brush; + } - //每根竖条的四个角坐标 - 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) //右下角 - }; + /// + /// 画四周渐变边框 + /// + /// + /// + /// + /// + /// + /// + /// 画图宽度 + /// 高低音转化比例 + private void DrawGradientBorder( + Rectangle topBorder, Rectangle bottomBorder, Rectangle leftBorder, + Rectangle rightBorder, Color inner, Color outer, double width, double bassScale + ) + { + //边框粗细根据音频高低音变化 + var thickness = (int)(width * bassScale); - var figure = new PathFigure - { - StartPoint = endPoints[0] - }; + topBorder.Height = thickness; + bottomBorder.Height = thickness; + leftBorder.Width = thickness; + rightBorder.Width = thickness; - 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; + topBorder.Fill = new LinearGradientBrush(outer, inner, 90); + bottomBorder.Fill = new LinearGradientBrush(inner, outer, 90); + leftBorder.Fill = new LinearGradientBrush(outer, inner, 0); + rightBorder.Fill = new LinearGradientBrush(inner, outer, 0); } } } \ No newline at end of file diff --git a/Correlator/SensorHubTag/DevCode.cs b/Correlator/SensorHubTag/DevCode.cs deleted file mode 100644 index afd5e8f..0000000 --- a/Correlator/SensorHubTag/DevCode.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Correlator.SensorHubTag -{ - public static class DevCode - { - public static string Dev1 => "211700082201"; - - public static string Dev2 => "211700082202"; - } -} \ No newline at end of file diff --git a/Correlator/Util/AudioDataHub.cs b/Correlator/Util/AudioDataHub.cs new file mode 100644 index 0000000..72d62ea --- /dev/null +++ b/Correlator/Util/AudioDataHub.cs @@ -0,0 +1,135 @@ +using System; +using System.Linq; + +namespace Correlator.Util +{ + /// + /// 音频可视化数据处理 + /// + public class AudioDataHub + { + #region 懒汉单例模式 + + private static readonly Lazy Lazy = new Lazy(() => new AudioDataHub()); + + public static AudioDataHub Get => Lazy.Value; + + + private AudioDataHub() + { + } + + #endregion + + private double[] _smoothResult; + + public double[] TakeSpectrumOfFrequency(double[] spectrum, double sampleRate, double frequency) + { + var frequencyPerSample = sampleRate / spectrum.Length; + + var lengthInNeed = (int)Math.Min(frequency / frequencyPerSample, spectrum.Length); + var result = new double[lengthInNeed]; + Array.Copy(spectrum, 0, result, 0, lengthInNeed); + return result; + } + + /// + /// 简单的数据模糊 + /// + /// 数据 + /// 模糊半径 + /// 结果 + public double[] MakeSmooth(double[] data, int radius) + { + var weights = GetWeights(radius); + var buffer = new double[1 + radius * 2]; + + _smoothResult = new double[data.Length]; + if (data.Length < radius) + { + data.Average(); + _smoothResult.SetValue(data, 0); + return _smoothResult; + } + + for (var i = 0; i < radius; i++) + { + for (var j = 0; j < radius; j++) // + { + buffer[radius + 1 + j] = data[i + j]; + } + + ApplyWeights(buffer, weights); + _smoothResult[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); + _smoothResult[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); + _smoothResult[i] = buffer.Sum(); + } + + return _smoothResult; + } + + private 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 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/Util/AudioVisualizer.cs b/Correlator/Util/AudioVisualizer.cs index 9a888f5..393f7df 100644 --- a/Correlator/Util/AudioVisualizer.cs +++ b/Correlator/Util/AudioVisualizer.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using FftSharp; using FftSharp.Windows; using Complex = System.Numerics.Complex; @@ -13,6 +12,8 @@ /// public double[] SampleData { get; } + private Complex[] _data; + /// /// /// @@ -63,126 +64,27 @@ public double[] GetSpectrumData() { var len = SampleData.Length; - var data = new Complex[len]; - + _data = new Complex[len]; + for (var i = 0; i < len; i++) { - data[i] = new Complex(SampleData[i], 0); + _data[i] = new Complex(SampleData[i], 0); } - - FFT.Forward(data); - + + FFT.Forward(_data); + var halfLen = len / 2; var result = new double[halfLen]; // 傅里叶变换结果左右对称, 只需要取一半 for (var i = 0; i < halfLen; i++) { - result[i] = data[i].Magnitude / len; + 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/Util/RuntimeCache.cs b/Correlator/Util/RuntimeCache.cs index 468ca7f..4a1e94e 100644 --- a/Correlator/Util/RuntimeCache.cs +++ b/Correlator/Util/RuntimeCache.cs @@ -86,5 +86,15 @@ /// 采样率 /// public const int AudioSampleRate = 7500; + + /// + /// 设备1(红色的) + /// + public static string Dev1 => "211700082201"; + + /// + /// 设备2(蓝色的) + /// + public static string Dev2 => "211700082202"; } } \ No newline at end of file diff --git a/Correlator/ViewModels/ImportResponseDialogViewModel.cs b/Correlator/ViewModels/ImportResponseDialogViewModel.cs index 5b6c1f3..af9c398 100644 --- a/Correlator/ViewModels/ImportResponseDialogViewModel.cs +++ b/Correlator/ViewModels/ImportResponseDialogViewModel.cs @@ -286,7 +286,7 @@ Thread.Sleep(10); } - _dataModel.DevCode = DevCode.Dev1; + _dataModel.DevCode = RuntimeCache.Dev1; _dataModel.LeftReceiveDataTime = DateTime.Now; _dataModel.LeftDeviceDataArray = totalData.ToArray(); } @@ -312,7 +312,7 @@ Thread.Sleep(10); } - _dataModel.DevCode = DevCode.Dev2; + _dataModel.DevCode = RuntimeCache.Dev2; _dataModel.RightReceiveDataTime = DateTime.Now; _dataModel.RightDeviceDataArray = totalData.ToArray(); } diff --git a/Correlator/ViewModels/SimplyAuditionDialogViewModel.cs b/Correlator/ViewModels/SimplyAuditionDialogViewModel.cs index d1f6f4c..9322765 100644 --- a/Correlator/ViewModels/SimplyAuditionDialogViewModel.cs +++ b/Correlator/ViewModels/SimplyAuditionDialogViewModel.cs @@ -129,8 +129,8 @@ } else { - CommandSender.SendSoundCollectCmd(serialPortService.Sp, DevCode.Dev1); - audioService.Start(DevCode.Dev1); + CommandSender.SendSoundCollectCmd(serialPortService.Sp, RuntimeCache.Dev1); + audioService.Start(RuntimeCache.Dev1); IsRedRecording = true; } }); @@ -178,8 +178,8 @@ } else { - CommandSender.SendSoundCollectCmd(serialPortService.Sp, DevCode.Dev2); - audioService.Start(DevCode.Dev2); + CommandSender.SendSoundCollectCmd(serialPortService.Sp, RuntimeCache.Dev2); + audioService.Start(RuntimeCache.Dev2); IsBlueRecording = true; } }); @@ -192,7 +192,7 @@ /// private void StopRedSensor(ISerialPortService serialPortService, IAudioService audioService) { - CommandSender.SendSoundStopCmd(serialPortService.Sp, DevCode.Dev1); + CommandSender.SendSoundStopCmd(serialPortService.Sp, RuntimeCache.Dev1); audioService.Stop(); IsRedRecording = false; RuntimeCache.SoundCaches.SaveSoundData(); @@ -205,7 +205,7 @@ /// private void StopBlueSensor(ISerialPortService serialPortService, IAudioService audioService) { - CommandSender.SendSoundStopCmd(serialPortService.Sp, DevCode.Dev2); + CommandSender.SendSoundStopCmd(serialPortService.Sp, RuntimeCache.Dev2); audioService.Stop(); IsBlueRecording = false; RuntimeCache.SoundCaches.SaveSoundData(); diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/DataService/AudioServiceImpl.cs b/Correlator/DataService/AudioServiceImpl.cs index 9227651..f5dbe51 100644 --- a/Correlator/DataService/AudioServiceImpl.cs +++ b/Correlator/DataService/AudioServiceImpl.cs @@ -1,5 +1,4 @@ using System; -using Correlator.SensorHubTag; using Correlator.Util; using NAudio.Wave; @@ -12,18 +11,19 @@ private BufferedWaveProvider _waveProvider; private readonly WaveFormat _waveFormat = new WaveFormat(7500, 24, 1); + public WaveOutEvent Wave { get; set; } = new WaveOutEvent(); + public void Start(string deviceCode) { _isStopped = false; _waveProvider = new BufferedWaveProvider(_waveFormat); - var waveOut = new WaveOut(); - waveOut.Init(_waveProvider); + Wave.Init(_waveProvider); string fileName; var audioDir = DirectoryManager.GetAudioDir(); var time = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - if (deviceCode == DevCode.Dev1) + if (deviceCode == RuntimeCache.Dev1) { //红色传感器听音 fileName = $"{audioDir}/听音_红_{time}.wav"; @@ -36,7 +36,7 @@ _waveFileWriter = new WaveFileWriter(fileName, _waveFormat); - waveOut.Play(); + Wave.Play(); } //缓存声波数据已经是后台线程了(处于线程池中) @@ -47,18 +47,23 @@ return; } - _waveProvider?.AddSamples(pcm, 0, pcm.Length); - _waveFileWriter?.Write(pcm, 0, pcm.Length); + try + { + _waveProvider?.AddSamples(pcm, 0, pcm.Length); + _waveFileWriter?.Write(pcm, 0, pcm.Length); + } + catch (InvalidOperationException) + { + _waveProvider?.ClearBuffer(); + } } public void Stop() { _isStopped = true; - + Wave.Stop(); _waveProvider.ClearBuffer(); _waveFileWriter.Dispose(); } - - // public AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/IAudioService.cs b/Correlator/DataService/IAudioService.cs index 83609b2..f6e157a 100644 --- a/Correlator/DataService/IAudioService.cs +++ b/Correlator/DataService/IAudioService.cs @@ -1,7 +1,11 @@ -namespace Correlator.DataService +using NAudio.Wave; + +namespace Correlator.DataService { public interface IAudioService { + WaveOutEvent Wave { get; set; } + /// /// 开始听音 /// @@ -18,7 +22,5 @@ /// 结束听音 /// void Stop(); - - // AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/SerialPortServiceImpl.cs b/Correlator/DataService/SerialPortServiceImpl.cs index 0a7e32f..824eccb 100644 --- a/Correlator/DataService/SerialPortServiceImpl.cs +++ b/Correlator/DataService/SerialPortServiceImpl.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO.Ports; -using System.Text; using System.Threading; using System.Windows; using Correlator.Events; @@ -131,7 +130,7 @@ } //发送消息更新界面 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { _eventAggregator.GetEvent().Publish(_devStatus); } @@ -173,7 +172,7 @@ var response = BitConverter.ToString(receivedData).Replace("-", ""); //收集数据 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { //原始数据 RuntimeCache.RedSensorOriginalResp.Add(index, response); @@ -218,7 +217,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { //接收到数据之后时间重新赋值 _dataModel.LeftReceiveDataTime = DateTime.Now; @@ -271,16 +270,6 @@ //将pcm数据写入缓存 _audioService.Write(pcm); - - //波形图数据 - var length = pcm.Length / 4; - var spectrumData = new double[length]; - for (var i = 0; i < length; i++) - { - spectrumData[i] = BitConverter.ToSingle(pcm, i * 4); - } - - // _audioService.AudioVisualizer.PushSampleData(spectrumData); } } @@ -310,7 +299,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { _dataModel.LeftDeviceDataArray = doubleArrays.ToOneDimensionalArray(); } diff --git a/Correlator/Dialog/CheckResponseDialog.xaml.cs b/Correlator/Dialog/CheckResponseDialog.xaml.cs index 43f84fd..91441a2 100644 --- a/Correlator/Dialog/CheckResponseDialog.xaml.cs +++ b/Correlator/Dialog/CheckResponseDialog.xaml.cs @@ -231,7 +231,7 @@ if (RedSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev1); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev1); _redResponseTimer.Start(); ReCheckButton.IsEnabled = true; @@ -239,11 +239,11 @@ else if (RedSensorStepBar.StepIndex == 2) { //下发数据全部正常指令 - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev1}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev1}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.RedSensorOriginalResp orderby pair.Key select pair; @@ -266,7 +266,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev1, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev1, tags); #endregion } @@ -315,18 +315,18 @@ if (BlueSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev2); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev2); _blueResponseTimer.Start(); ReCheckButton.IsEnabled = true; } else if (BlueSensorStepBar.StepIndex == 2) { - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev2}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev2}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.BlueSensorOriginalResp orderby pair.Key select pair; @@ -349,7 +349,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev2, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev2, tags); #endregion } @@ -396,7 +396,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, redIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, redIndexArray); } else { @@ -417,7 +417,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, blueIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, blueIndexArray); } }; } diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml b/Correlator/Dialog/SimplyAuditionDialog.xaml index 5fd8124..cd03b74 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml @@ -9,7 +9,7 @@ xmlns:prism="http://prismlibrary.com/" xmlns:vm="clr-namespace:Correlator.ViewModels" Width="600" - Height="400" + Height="480" d:DataContext="{d:DesignInstance Type=vm:SimplyAuditionDialogViewModel}" Loaded="SimplyAuditionDialog_OnLoaded" Unloaded="SimplyAuditionDialog_OnUnloaded" @@ -187,10 +187,15 @@ - + Background="{StaticResource MainThemeColor}"> + + + + + diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs index 3747ce0..41cb280 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -6,6 +7,8 @@ using System.Windows.Threading; using Correlator.DataService; using Correlator.Util; +using NAudio.CoreAudioApi; +using NAudio.Wave; namespace Correlator.Dialog { @@ -16,6 +19,7 @@ { private readonly AudioVisualizer _visualizer; // 可视化 private double[] _spectrumData; // 频谱数据 + private readonly WasapiCapture _capture; // 音频捕获 private int _colorIndex; private readonly Color[] _allColors; @@ -29,29 +33,44 @@ Interval = new TimeSpan(0, 0, 0, 0, 30) }; - public SimplyAuditionDialog(IApplicationDataService dataService, IAudioService audioService) + public SimplyAuditionDialog(IApplicationDataService dataService) { InitializeComponent(); - // _visualizer = dataService.GetAudioVisualizer(256); - // _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) - // - // audioService.AudioVisualizer = _visualizer; - // - // _dataTimer.Tick += DataTimer_Tick; - // _drawingTimer.Tick += DrawingTimer_Tick; + _capture = new WasapiLoopbackCapture(); // 捕获电脑发出的声音 + _visualizer = dataService.GetAudioVisualizer(512); + _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) + + _capture.WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(7500, 1); + _capture.DataAvailable += delegate(object o, WaveInEventArgs args) + { + var length = args.BytesRecorded / 4; // 采样的数量 (每一个采样是 4 字节) + var result = new double[length]; + + for (var i = 0; i < length; i++) + { + result[i] = BitConverter.ToSingle(args.Buffer, i * 4); // 取出采样值 + } + + _visualizer.PushSampleData(result); // 将新的采样存储到 可视化器 中 + }; + + _dataTimer.Tick += DataTimer_Tick; + _drawingTimer.Tick += DrawingTimer_Tick; } private void SimplyAuditionDialog_OnLoaded(object sender, RoutedEventArgs e) { - // _dataTimer.Start(); - // _drawingTimer.Start(); + _capture.StartRecording(); + _dataTimer.Start(); + _drawingTimer.Start(); } private void SimplyAuditionDialog_OnUnloaded(object sender, RoutedEventArgs e) { - // _drawingTimer.Stop(); - // _dataTimer.Stop(); + _drawingTimer.Stop(); + _dataTimer.Stop(); + _capture.StopRecording(); } /// @@ -62,7 +81,7 @@ private void DataTimer_Tick(object sender, EventArgs e) { var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据 - newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 + newSpectrumData = AudioDataHub.Get.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去 { @@ -92,80 +111,90 @@ 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 * 200 + var bassArea = AudioDataHub.Get.TakeSpectrumOfFrequency( + _spectrumData, RuntimeCache.AudioSampleRate, 250 + ); + var bassScale = bassArea.Average() * 100; //低音区 + + //波形曲线 + var curveBrush = new SolidColorBrush(color1); + DrawCurve( + SampleWavePath, curveBrush, + _visualizer.SampleData, _visualizer.SampleData.Length, + SampleWavePanel.ActualWidth, 0, SampleWavePanel.ActualHeight / 2, + Math.Min(SampleWavePanel.ActualHeight / 2, 50) + ); + + //四周边框 + DrawGradientBorder( + TopBorder, BottomBorder, LeftBorder, RightBorder, + Color.FromArgb(0, color1.R, color1.G, color1.B), color2, + SampleWavePanel.ActualWidth / 3, bassScale ); } /// - /// 绘制渐变的条形 + /// 画曲线 /// - /// 绘图目标 - /// 下方颜色 - /// 上方颜色 - /// 频谱数据 - /// 条形的数量 - /// 绘图的宽度 - /// 绘图的起始 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 + /// + /// + /// + /// + /// + /// + /// + /// 控制波形图波峰高度和波谷深度 + private void DrawCurve( + Path wavePath, Brush brush, double[] spectrumData, int pointCount, double drawingWidth, + double xOffset, double yOffset, double scale ) { - //竖条宽度 - var stripWidth = (drawingWidth - spacing * stripCount) / stripCount; - var pointArray = new Point[stripCount]; - - for (var i = 0; i < stripCount; i++) + var pointArray = new Point[pointCount]; + for (var i = 0; i < pointCount; i++) { - var x = stripWidth * i + spacing * i + xOffset; - var y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height - //给所有频谱位置赋值 + var x = i * drawingWidth / pointCount + xOffset; + var y = spectrumData[i * spectrumData.Length / pointCount] * scale + yOffset; pointArray[i] = new Point(x, y); } - //生成一系列频谱竖条 - var geometry = new GeometryGroup(); - foreach (var point in pointArray) + var figure = new PathFigure { - var height = point.Y; + StartPoint = pointArray[0] + }; + figure.Segments.Add(new PolyLineSegment(pointArray, true)); - if (height < 0) - { - height = -height; - } + wavePath.Data = new PathGeometry { Figures = { figure } }; + wavePath.Stroke = brush; + } - //每根竖条的四个角坐标 - 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) //右下角 - }; + /// + /// 画四周渐变边框 + /// + /// + /// + /// + /// + /// + /// + /// 画图宽度 + /// 高低音转化比例 + private void DrawGradientBorder( + Rectangle topBorder, Rectangle bottomBorder, Rectangle leftBorder, + Rectangle rightBorder, Color inner, Color outer, double width, double bassScale + ) + { + //边框粗细根据音频高低音变化 + var thickness = (int)(width * bassScale); - var figure = new PathFigure - { - StartPoint = endPoints[0] - }; + topBorder.Height = thickness; + bottomBorder.Height = thickness; + leftBorder.Width = thickness; + rightBorder.Width = thickness; - 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; + topBorder.Fill = new LinearGradientBrush(outer, inner, 90); + bottomBorder.Fill = new LinearGradientBrush(inner, outer, 90); + leftBorder.Fill = new LinearGradientBrush(outer, inner, 0); + rightBorder.Fill = new LinearGradientBrush(inner, outer, 0); } } } \ No newline at end of file diff --git a/Correlator/SensorHubTag/DevCode.cs b/Correlator/SensorHubTag/DevCode.cs deleted file mode 100644 index afd5e8f..0000000 --- a/Correlator/SensorHubTag/DevCode.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Correlator.SensorHubTag -{ - public static class DevCode - { - public static string Dev1 => "211700082201"; - - public static string Dev2 => "211700082202"; - } -} \ No newline at end of file diff --git a/Correlator/Util/AudioDataHub.cs b/Correlator/Util/AudioDataHub.cs new file mode 100644 index 0000000..72d62ea --- /dev/null +++ b/Correlator/Util/AudioDataHub.cs @@ -0,0 +1,135 @@ +using System; +using System.Linq; + +namespace Correlator.Util +{ + /// + /// 音频可视化数据处理 + /// + public class AudioDataHub + { + #region 懒汉单例模式 + + private static readonly Lazy Lazy = new Lazy(() => new AudioDataHub()); + + public static AudioDataHub Get => Lazy.Value; + + + private AudioDataHub() + { + } + + #endregion + + private double[] _smoothResult; + + public double[] TakeSpectrumOfFrequency(double[] spectrum, double sampleRate, double frequency) + { + var frequencyPerSample = sampleRate / spectrum.Length; + + var lengthInNeed = (int)Math.Min(frequency / frequencyPerSample, spectrum.Length); + var result = new double[lengthInNeed]; + Array.Copy(spectrum, 0, result, 0, lengthInNeed); + return result; + } + + /// + /// 简单的数据模糊 + /// + /// 数据 + /// 模糊半径 + /// 结果 + public double[] MakeSmooth(double[] data, int radius) + { + var weights = GetWeights(radius); + var buffer = new double[1 + radius * 2]; + + _smoothResult = new double[data.Length]; + if (data.Length < radius) + { + data.Average(); + _smoothResult.SetValue(data, 0); + return _smoothResult; + } + + for (var i = 0; i < radius; i++) + { + for (var j = 0; j < radius; j++) // + { + buffer[radius + 1 + j] = data[i + j]; + } + + ApplyWeights(buffer, weights); + _smoothResult[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); + _smoothResult[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); + _smoothResult[i] = buffer.Sum(); + } + + return _smoothResult; + } + + private 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 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/Util/AudioVisualizer.cs b/Correlator/Util/AudioVisualizer.cs index 9a888f5..393f7df 100644 --- a/Correlator/Util/AudioVisualizer.cs +++ b/Correlator/Util/AudioVisualizer.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using FftSharp; using FftSharp.Windows; using Complex = System.Numerics.Complex; @@ -13,6 +12,8 @@ /// public double[] SampleData { get; } + private Complex[] _data; + /// /// /// @@ -63,126 +64,27 @@ public double[] GetSpectrumData() { var len = SampleData.Length; - var data = new Complex[len]; - + _data = new Complex[len]; + for (var i = 0; i < len; i++) { - data[i] = new Complex(SampleData[i], 0); + _data[i] = new Complex(SampleData[i], 0); } - - FFT.Forward(data); - + + FFT.Forward(_data); + var halfLen = len / 2; var result = new double[halfLen]; // 傅里叶变换结果左右对称, 只需要取一半 for (var i = 0; i < halfLen; i++) { - result[i] = data[i].Magnitude / len; + 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/Util/RuntimeCache.cs b/Correlator/Util/RuntimeCache.cs index 468ca7f..4a1e94e 100644 --- a/Correlator/Util/RuntimeCache.cs +++ b/Correlator/Util/RuntimeCache.cs @@ -86,5 +86,15 @@ /// 采样率 /// public const int AudioSampleRate = 7500; + + /// + /// 设备1(红色的) + /// + public static string Dev1 => "211700082201"; + + /// + /// 设备2(蓝色的) + /// + public static string Dev2 => "211700082202"; } } \ No newline at end of file diff --git a/Correlator/ViewModels/ImportResponseDialogViewModel.cs b/Correlator/ViewModels/ImportResponseDialogViewModel.cs index 5b6c1f3..af9c398 100644 --- a/Correlator/ViewModels/ImportResponseDialogViewModel.cs +++ b/Correlator/ViewModels/ImportResponseDialogViewModel.cs @@ -286,7 +286,7 @@ Thread.Sleep(10); } - _dataModel.DevCode = DevCode.Dev1; + _dataModel.DevCode = RuntimeCache.Dev1; _dataModel.LeftReceiveDataTime = DateTime.Now; _dataModel.LeftDeviceDataArray = totalData.ToArray(); } @@ -312,7 +312,7 @@ Thread.Sleep(10); } - _dataModel.DevCode = DevCode.Dev2; + _dataModel.DevCode = RuntimeCache.Dev2; _dataModel.RightReceiveDataTime = DateTime.Now; _dataModel.RightDeviceDataArray = totalData.ToArray(); } diff --git a/Correlator/ViewModels/SimplyAuditionDialogViewModel.cs b/Correlator/ViewModels/SimplyAuditionDialogViewModel.cs index d1f6f4c..9322765 100644 --- a/Correlator/ViewModels/SimplyAuditionDialogViewModel.cs +++ b/Correlator/ViewModels/SimplyAuditionDialogViewModel.cs @@ -129,8 +129,8 @@ } else { - CommandSender.SendSoundCollectCmd(serialPortService.Sp, DevCode.Dev1); - audioService.Start(DevCode.Dev1); + CommandSender.SendSoundCollectCmd(serialPortService.Sp, RuntimeCache.Dev1); + audioService.Start(RuntimeCache.Dev1); IsRedRecording = true; } }); @@ -178,8 +178,8 @@ } else { - CommandSender.SendSoundCollectCmd(serialPortService.Sp, DevCode.Dev2); - audioService.Start(DevCode.Dev2); + CommandSender.SendSoundCollectCmd(serialPortService.Sp, RuntimeCache.Dev2); + audioService.Start(RuntimeCache.Dev2); IsBlueRecording = true; } }); @@ -192,7 +192,7 @@ /// private void StopRedSensor(ISerialPortService serialPortService, IAudioService audioService) { - CommandSender.SendSoundStopCmd(serialPortService.Sp, DevCode.Dev1); + CommandSender.SendSoundStopCmd(serialPortService.Sp, RuntimeCache.Dev1); audioService.Stop(); IsRedRecording = false; RuntimeCache.SoundCaches.SaveSoundData(); @@ -205,7 +205,7 @@ /// private void StopBlueSensor(ISerialPortService serialPortService, IAudioService audioService) { - CommandSender.SendSoundStopCmd(serialPortService.Sp, DevCode.Dev2); + CommandSender.SendSoundStopCmd(serialPortService.Sp, RuntimeCache.Dev2); audioService.Stop(); IsBlueRecording = false; RuntimeCache.SoundCaches.SaveSoundData(); diff --git a/Correlator/Views/AudioFileView.xaml.cs b/Correlator/Views/AudioFileView.xaml.cs index 76e7f1b..b59a84f 100644 --- a/Correlator/Views/AudioFileView.xaml.cs +++ b/Correlator/Views/AudioFileView.xaml.cs @@ -77,7 +77,7 @@ private void DataTimer_Tick(object sender, EventArgs e) { var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据 - newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 + newSpectrumData = AudioDataHub.Get.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去 { diff --git a/Correlator/Correlator.csproj b/Correlator/Correlator.csproj index b4a4553..8163935 100644 --- a/Correlator/Correlator.csproj +++ b/Correlator/Correlator.csproj @@ -251,7 +251,6 @@ - @@ -262,6 +261,7 @@ + diff --git a/Correlator/DataService/AudioServiceImpl.cs b/Correlator/DataService/AudioServiceImpl.cs index 9227651..f5dbe51 100644 --- a/Correlator/DataService/AudioServiceImpl.cs +++ b/Correlator/DataService/AudioServiceImpl.cs @@ -1,5 +1,4 @@ using System; -using Correlator.SensorHubTag; using Correlator.Util; using NAudio.Wave; @@ -12,18 +11,19 @@ private BufferedWaveProvider _waveProvider; private readonly WaveFormat _waveFormat = new WaveFormat(7500, 24, 1); + public WaveOutEvent Wave { get; set; } = new WaveOutEvent(); + public void Start(string deviceCode) { _isStopped = false; _waveProvider = new BufferedWaveProvider(_waveFormat); - var waveOut = new WaveOut(); - waveOut.Init(_waveProvider); + Wave.Init(_waveProvider); string fileName; var audioDir = DirectoryManager.GetAudioDir(); var time = DateTime.Now.ToString("yyyyMMdd_HHmmss"); - if (deviceCode == DevCode.Dev1) + if (deviceCode == RuntimeCache.Dev1) { //红色传感器听音 fileName = $"{audioDir}/听音_红_{time}.wav"; @@ -36,7 +36,7 @@ _waveFileWriter = new WaveFileWriter(fileName, _waveFormat); - waveOut.Play(); + Wave.Play(); } //缓存声波数据已经是后台线程了(处于线程池中) @@ -47,18 +47,23 @@ return; } - _waveProvider?.AddSamples(pcm, 0, pcm.Length); - _waveFileWriter?.Write(pcm, 0, pcm.Length); + try + { + _waveProvider?.AddSamples(pcm, 0, pcm.Length); + _waveFileWriter?.Write(pcm, 0, pcm.Length); + } + catch (InvalidOperationException) + { + _waveProvider?.ClearBuffer(); + } } public void Stop() { _isStopped = true; - + Wave.Stop(); _waveProvider.ClearBuffer(); _waveFileWriter.Dispose(); } - - // public AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/IAudioService.cs b/Correlator/DataService/IAudioService.cs index 83609b2..f6e157a 100644 --- a/Correlator/DataService/IAudioService.cs +++ b/Correlator/DataService/IAudioService.cs @@ -1,7 +1,11 @@ -namespace Correlator.DataService +using NAudio.Wave; + +namespace Correlator.DataService { public interface IAudioService { + WaveOutEvent Wave { get; set; } + /// /// 开始听音 /// @@ -18,7 +22,5 @@ /// 结束听音 /// void Stop(); - - // AudioVisualizer AudioVisualizer { get; set; } } } \ No newline at end of file diff --git a/Correlator/DataService/SerialPortServiceImpl.cs b/Correlator/DataService/SerialPortServiceImpl.cs index 0a7e32f..824eccb 100644 --- a/Correlator/DataService/SerialPortServiceImpl.cs +++ b/Correlator/DataService/SerialPortServiceImpl.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.IO.Ports; -using System.Text; using System.Threading; using System.Windows; using Correlator.Events; @@ -131,7 +130,7 @@ } //发送消息更新界面 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { _eventAggregator.GetEvent().Publish(_devStatus); } @@ -173,7 +172,7 @@ var response = BitConverter.ToString(receivedData).Replace("-", ""); //收集数据 - if (deviceId.Equals(DevCode.Dev1)) + if (deviceId.Equals(RuntimeCache.Dev1)) { //原始数据 RuntimeCache.RedSensorOriginalResp.Add(index, response); @@ -218,7 +217,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { //接收到数据之后时间重新赋值 _dataModel.LeftReceiveDataTime = DateTime.Now; @@ -271,16 +270,6 @@ //将pcm数据写入缓存 _audioService.Write(pcm); - - //波形图数据 - var length = pcm.Length / 4; - var spectrumData = new double[length]; - for (var i = 0; i < length; i++) - { - spectrumData[i] = BitConverter.ToSingle(pcm, i * 4); - } - - // _audioService.AudioVisualizer.PushSampleData(spectrumData); } } @@ -310,7 +299,7 @@ } _dataModel.DevCode = devCode; - if (devCode.Equals(DevCode.Dev1)) + if (devCode.Equals(RuntimeCache.Dev1)) { _dataModel.LeftDeviceDataArray = doubleArrays.ToOneDimensionalArray(); } diff --git a/Correlator/Dialog/CheckResponseDialog.xaml.cs b/Correlator/Dialog/CheckResponseDialog.xaml.cs index 43f84fd..91441a2 100644 --- a/Correlator/Dialog/CheckResponseDialog.xaml.cs +++ b/Correlator/Dialog/CheckResponseDialog.xaml.cs @@ -231,7 +231,7 @@ if (RedSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev1); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev1); _redResponseTimer.Start(); ReCheckButton.IsEnabled = true; @@ -239,11 +239,11 @@ else if (RedSensorStepBar.StepIndex == 2) { //下发数据全部正常指令 - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev1}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev1}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.RedSensorOriginalResp orderby pair.Key select pair; @@ -266,7 +266,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev1, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev1, tags); #endregion } @@ -315,18 +315,18 @@ if (BlueSensorStepBar.StepIndex == 1) { RuntimeCache.SeqCaches.Clear(); - CommandSender.StartCheckResponse(_serialPortService.Sp, DevCode.Dev2); + CommandSender.StartCheckResponse(_serialPortService.Sp, RuntimeCache.Dev2); _blueResponseTimer.Start(); ReCheckButton.IsEnabled = true; } else if (BlueSensorStepBar.StepIndex == 2) { - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, new List()); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, new List()); #region 保存原始数据 - var fileName = $"{locateDataDir}\\原始数据.{DevCode.Dev2}.txt"; + var fileName = $"{locateDataDir}\\原始数据.{RuntimeCache.Dev2}.txt"; //将Dictionary按照index排序 var sortResult = from pair in RuntimeCache.BlueSensorOriginalResp orderby pair.Key select pair; @@ -349,7 +349,7 @@ tags.Add(noiseTag); } - _serialPortService.HandleHydrophoneData(DevCode.Dev2, tags); + _serialPortService.HandleHydrophoneData(RuntimeCache.Dev2, tags); #endregion } @@ -396,7 +396,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev1, redIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev1, redIndexArray); } else { @@ -417,7 +417,7 @@ } } - CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, DevCode.Dev2, blueIndexArray); + CommandSender.SendDataCheckResultCmd(_serialPortService.Sp, RuntimeCache.Dev2, blueIndexArray); } }; } diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml b/Correlator/Dialog/SimplyAuditionDialog.xaml index 5fd8124..cd03b74 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml @@ -9,7 +9,7 @@ xmlns:prism="http://prismlibrary.com/" xmlns:vm="clr-namespace:Correlator.ViewModels" Width="600" - Height="400" + Height="480" d:DataContext="{d:DesignInstance Type=vm:SimplyAuditionDialogViewModel}" Loaded="SimplyAuditionDialog_OnLoaded" Unloaded="SimplyAuditionDialog_OnUnloaded" @@ -187,10 +187,15 @@ - + Background="{StaticResource MainThemeColor}"> + + + + + diff --git a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs index 3747ce0..41cb280 100644 --- a/Correlator/Dialog/SimplyAuditionDialog.xaml.cs +++ b/Correlator/Dialog/SimplyAuditionDialog.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -6,6 +7,8 @@ using System.Windows.Threading; using Correlator.DataService; using Correlator.Util; +using NAudio.CoreAudioApi; +using NAudio.Wave; namespace Correlator.Dialog { @@ -16,6 +19,7 @@ { private readonly AudioVisualizer _visualizer; // 可视化 private double[] _spectrumData; // 频谱数据 + private readonly WasapiCapture _capture; // 音频捕获 private int _colorIndex; private readonly Color[] _allColors; @@ -29,29 +33,44 @@ Interval = new TimeSpan(0, 0, 0, 0, 30) }; - public SimplyAuditionDialog(IApplicationDataService dataService, IAudioService audioService) + public SimplyAuditionDialog(IApplicationDataService dataService) { InitializeComponent(); - // _visualizer = dataService.GetAudioVisualizer(256); - // _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) - // - // audioService.AudioVisualizer = _visualizer; - // - // _dataTimer.Tick += DataTimer_Tick; - // _drawingTimer.Tick += DrawingTimer_Tick; + _capture = new WasapiLoopbackCapture(); // 捕获电脑发出的声音 + _visualizer = dataService.GetAudioVisualizer(512); + _allColors = dataService.GetAllHsvColors(); // 获取所有的渐变颜色 (HSV 颜色) + + _capture.WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(7500, 1); + _capture.DataAvailable += delegate(object o, WaveInEventArgs args) + { + var length = args.BytesRecorded / 4; // 采样的数量 (每一个采样是 4 字节) + var result = new double[length]; + + for (var i = 0; i < length; i++) + { + result[i] = BitConverter.ToSingle(args.Buffer, i * 4); // 取出采样值 + } + + _visualizer.PushSampleData(result); // 将新的采样存储到 可视化器 中 + }; + + _dataTimer.Tick += DataTimer_Tick; + _drawingTimer.Tick += DrawingTimer_Tick; } private void SimplyAuditionDialog_OnLoaded(object sender, RoutedEventArgs e) { - // _dataTimer.Start(); - // _drawingTimer.Start(); + _capture.StartRecording(); + _dataTimer.Start(); + _drawingTimer.Start(); } private void SimplyAuditionDialog_OnUnloaded(object sender, RoutedEventArgs e) { - // _drawingTimer.Stop(); - // _dataTimer.Stop(); + _drawingTimer.Stop(); + _dataTimer.Stop(); + _capture.StopRecording(); } /// @@ -62,7 +81,7 @@ private void DataTimer_Tick(object sender, EventArgs e) { var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据 - newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 + newSpectrumData = AudioDataHub.Get.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去 { @@ -92,80 +111,90 @@ 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 * 200 + var bassArea = AudioDataHub.Get.TakeSpectrumOfFrequency( + _spectrumData, RuntimeCache.AudioSampleRate, 250 + ); + var bassScale = bassArea.Average() * 100; //低音区 + + //波形曲线 + var curveBrush = new SolidColorBrush(color1); + DrawCurve( + SampleWavePath, curveBrush, + _visualizer.SampleData, _visualizer.SampleData.Length, + SampleWavePanel.ActualWidth, 0, SampleWavePanel.ActualHeight / 2, + Math.Min(SampleWavePanel.ActualHeight / 2, 50) + ); + + //四周边框 + DrawGradientBorder( + TopBorder, BottomBorder, LeftBorder, RightBorder, + Color.FromArgb(0, color1.R, color1.G, color1.B), color2, + SampleWavePanel.ActualWidth / 3, bassScale ); } /// - /// 绘制渐变的条形 + /// 画曲线 /// - /// 绘图目标 - /// 下方颜色 - /// 上方颜色 - /// 频谱数据 - /// 条形的数量 - /// 绘图的宽度 - /// 绘图的起始 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 + /// + /// + /// + /// + /// + /// + /// + /// 控制波形图波峰高度和波谷深度 + private void DrawCurve( + Path wavePath, Brush brush, double[] spectrumData, int pointCount, double drawingWidth, + double xOffset, double yOffset, double scale ) { - //竖条宽度 - var stripWidth = (drawingWidth - spacing * stripCount) / stripCount; - var pointArray = new Point[stripCount]; - - for (var i = 0; i < stripCount; i++) + var pointArray = new Point[pointCount]; + for (var i = 0; i < pointCount; i++) { - var x = stripWidth * i + spacing * i + xOffset; - var y = spectrumData[i * spectrumData.Length / stripCount] * scale; // height - //给所有频谱位置赋值 + var x = i * drawingWidth / pointCount + xOffset; + var y = spectrumData[i * spectrumData.Length / pointCount] * scale + yOffset; pointArray[i] = new Point(x, y); } - //生成一系列频谱竖条 - var geometry = new GeometryGroup(); - foreach (var point in pointArray) + var figure = new PathFigure { - var height = point.Y; + StartPoint = pointArray[0] + }; + figure.Segments.Add(new PolyLineSegment(pointArray, true)); - if (height < 0) - { - height = -height; - } + wavePath.Data = new PathGeometry { Figures = { figure } }; + wavePath.Stroke = brush; + } - //每根竖条的四个角坐标 - 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) //右下角 - }; + /// + /// 画四周渐变边框 + /// + /// + /// + /// + /// + /// + /// + /// 画图宽度 + /// 高低音转化比例 + private void DrawGradientBorder( + Rectangle topBorder, Rectangle bottomBorder, Rectangle leftBorder, + Rectangle rightBorder, Color inner, Color outer, double width, double bassScale + ) + { + //边框粗细根据音频高低音变化 + var thickness = (int)(width * bassScale); - var figure = new PathFigure - { - StartPoint = endPoints[0] - }; + topBorder.Height = thickness; + bottomBorder.Height = thickness; + leftBorder.Width = thickness; + rightBorder.Width = thickness; - 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; + topBorder.Fill = new LinearGradientBrush(outer, inner, 90); + bottomBorder.Fill = new LinearGradientBrush(inner, outer, 90); + leftBorder.Fill = new LinearGradientBrush(outer, inner, 0); + rightBorder.Fill = new LinearGradientBrush(inner, outer, 0); } } } \ No newline at end of file diff --git a/Correlator/SensorHubTag/DevCode.cs b/Correlator/SensorHubTag/DevCode.cs deleted file mode 100644 index afd5e8f..0000000 --- a/Correlator/SensorHubTag/DevCode.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Correlator.SensorHubTag -{ - public static class DevCode - { - public static string Dev1 => "211700082201"; - - public static string Dev2 => "211700082202"; - } -} \ No newline at end of file diff --git a/Correlator/Util/AudioDataHub.cs b/Correlator/Util/AudioDataHub.cs new file mode 100644 index 0000000..72d62ea --- /dev/null +++ b/Correlator/Util/AudioDataHub.cs @@ -0,0 +1,135 @@ +using System; +using System.Linq; + +namespace Correlator.Util +{ + /// + /// 音频可视化数据处理 + /// + public class AudioDataHub + { + #region 懒汉单例模式 + + private static readonly Lazy Lazy = new Lazy(() => new AudioDataHub()); + + public static AudioDataHub Get => Lazy.Value; + + + private AudioDataHub() + { + } + + #endregion + + private double[] _smoothResult; + + public double[] TakeSpectrumOfFrequency(double[] spectrum, double sampleRate, double frequency) + { + var frequencyPerSample = sampleRate / spectrum.Length; + + var lengthInNeed = (int)Math.Min(frequency / frequencyPerSample, spectrum.Length); + var result = new double[lengthInNeed]; + Array.Copy(spectrum, 0, result, 0, lengthInNeed); + return result; + } + + /// + /// 简单的数据模糊 + /// + /// 数据 + /// 模糊半径 + /// 结果 + public double[] MakeSmooth(double[] data, int radius) + { + var weights = GetWeights(radius); + var buffer = new double[1 + radius * 2]; + + _smoothResult = new double[data.Length]; + if (data.Length < radius) + { + data.Average(); + _smoothResult.SetValue(data, 0); + return _smoothResult; + } + + for (var i = 0; i < radius; i++) + { + for (var j = 0; j < radius; j++) // + { + buffer[radius + 1 + j] = data[i + j]; + } + + ApplyWeights(buffer, weights); + _smoothResult[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); + _smoothResult[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); + _smoothResult[i] = buffer.Sum(); + } + + return _smoothResult; + } + + private 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 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/Util/AudioVisualizer.cs b/Correlator/Util/AudioVisualizer.cs index 9a888f5..393f7df 100644 --- a/Correlator/Util/AudioVisualizer.cs +++ b/Correlator/Util/AudioVisualizer.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using FftSharp; using FftSharp.Windows; using Complex = System.Numerics.Complex; @@ -13,6 +12,8 @@ /// public double[] SampleData { get; } + private Complex[] _data; + /// /// /// @@ -63,126 +64,27 @@ public double[] GetSpectrumData() { var len = SampleData.Length; - var data = new Complex[len]; - + _data = new Complex[len]; + for (var i = 0; i < len; i++) { - data[i] = new Complex(SampleData[i], 0); + _data[i] = new Complex(SampleData[i], 0); } - - FFT.Forward(data); - + + FFT.Forward(_data); + var halfLen = len / 2; var result = new double[halfLen]; // 傅里叶变换结果左右对称, 只需要取一半 for (var i = 0; i < halfLen; i++) { - result[i] = data[i].Magnitude / len; + 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/Util/RuntimeCache.cs b/Correlator/Util/RuntimeCache.cs index 468ca7f..4a1e94e 100644 --- a/Correlator/Util/RuntimeCache.cs +++ b/Correlator/Util/RuntimeCache.cs @@ -86,5 +86,15 @@ /// 采样率 /// public const int AudioSampleRate = 7500; + + /// + /// 设备1(红色的) + /// + public static string Dev1 => "211700082201"; + + /// + /// 设备2(蓝色的) + /// + public static string Dev2 => "211700082202"; } } \ No newline at end of file diff --git a/Correlator/ViewModels/ImportResponseDialogViewModel.cs b/Correlator/ViewModels/ImportResponseDialogViewModel.cs index 5b6c1f3..af9c398 100644 --- a/Correlator/ViewModels/ImportResponseDialogViewModel.cs +++ b/Correlator/ViewModels/ImportResponseDialogViewModel.cs @@ -286,7 +286,7 @@ Thread.Sleep(10); } - _dataModel.DevCode = DevCode.Dev1; + _dataModel.DevCode = RuntimeCache.Dev1; _dataModel.LeftReceiveDataTime = DateTime.Now; _dataModel.LeftDeviceDataArray = totalData.ToArray(); } @@ -312,7 +312,7 @@ Thread.Sleep(10); } - _dataModel.DevCode = DevCode.Dev2; + _dataModel.DevCode = RuntimeCache.Dev2; _dataModel.RightReceiveDataTime = DateTime.Now; _dataModel.RightDeviceDataArray = totalData.ToArray(); } diff --git a/Correlator/ViewModels/SimplyAuditionDialogViewModel.cs b/Correlator/ViewModels/SimplyAuditionDialogViewModel.cs index d1f6f4c..9322765 100644 --- a/Correlator/ViewModels/SimplyAuditionDialogViewModel.cs +++ b/Correlator/ViewModels/SimplyAuditionDialogViewModel.cs @@ -129,8 +129,8 @@ } else { - CommandSender.SendSoundCollectCmd(serialPortService.Sp, DevCode.Dev1); - audioService.Start(DevCode.Dev1); + CommandSender.SendSoundCollectCmd(serialPortService.Sp, RuntimeCache.Dev1); + audioService.Start(RuntimeCache.Dev1); IsRedRecording = true; } }); @@ -178,8 +178,8 @@ } else { - CommandSender.SendSoundCollectCmd(serialPortService.Sp, DevCode.Dev2); - audioService.Start(DevCode.Dev2); + CommandSender.SendSoundCollectCmd(serialPortService.Sp, RuntimeCache.Dev2); + audioService.Start(RuntimeCache.Dev2); IsBlueRecording = true; } }); @@ -192,7 +192,7 @@ /// private void StopRedSensor(ISerialPortService serialPortService, IAudioService audioService) { - CommandSender.SendSoundStopCmd(serialPortService.Sp, DevCode.Dev1); + CommandSender.SendSoundStopCmd(serialPortService.Sp, RuntimeCache.Dev1); audioService.Stop(); IsRedRecording = false; RuntimeCache.SoundCaches.SaveSoundData(); @@ -205,7 +205,7 @@ /// private void StopBlueSensor(ISerialPortService serialPortService, IAudioService audioService) { - CommandSender.SendSoundStopCmd(serialPortService.Sp, DevCode.Dev2); + CommandSender.SendSoundStopCmd(serialPortService.Sp, RuntimeCache.Dev2); audioService.Stop(); IsBlueRecording = false; RuntimeCache.SoundCaches.SaveSoundData(); diff --git a/Correlator/Views/AudioFileView.xaml.cs b/Correlator/Views/AudioFileView.xaml.cs index 76e7f1b..b59a84f 100644 --- a/Correlator/Views/AudioFileView.xaml.cs +++ b/Correlator/Views/AudioFileView.xaml.cs @@ -77,7 +77,7 @@ private void DataTimer_Tick(object sender, EventArgs e) { var newSpectrumData = _visualizer.GetSpectrumData(); // 从可视化器中获取频谱数据 - newSpectrumData = AudioVisualizer.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 + newSpectrumData = AudioDataHub.Get.MakeSmooth(newSpectrumData, 2); // 平滑频谱数据 if (_spectrumData == null) // 如果已经存储的频谱数据为空, 则把新的频谱数据直接赋值上去 { diff --git a/Correlator/Views/MainWindow.xaml b/Correlator/Views/MainWindow.xaml index 683db0a..8aa9c1e 100644 --- a/Correlator/Views/MainWindow.xaml +++ b/Correlator/Views/MainWindow.xaml @@ -863,7 +863,6 @@ Text="管道材料" /> -