1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Fixed audio layer CPU usage

This commit is contained in:
SpoinkyNL 2016-12-08 14:46:55 +01:00
parent 56c5a41033
commit 04a13050dc
4 changed files with 167 additions and 98 deletions

View File

@ -431,6 +431,7 @@
<Compile Include="Profiles\Layers\Types\AmbientLight\ScreenCapturing\DX9ScreenCapture.cs" />
<Compile Include="Profiles\Layers\Types\AmbientLight\ScreenCapturing\IScreenCapture.cs" />
<Compile Include="Profiles\Layers\Types\AmbientLight\ScreenCapturing\ScreenCaptureManager.cs" />
<Compile Include="Profiles\Layers\Types\Audio\AudioCapturing\AudioCaptureManager.cs" />
<Compile Include="Profiles\Layers\Types\Audio\AudioPropertiesModel.cs" />
<Compile Include="Profiles\Layers\Types\Audio\AudioPropertiesView.xaml.cs">
<DependentUpon>AudioPropertiesView.xaml</DependentUpon>

View File

@ -3,6 +3,7 @@ using Artemis.Profiles.Layers.Conditions;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Types.AmbientLight;
using Artemis.Profiles.Layers.Types.Audio;
using Artemis.Profiles.Layers.Types.Audio.AudioCapturing;
using Artemis.Profiles.Layers.Types.Folder;
using Artemis.Profiles.Layers.Types.Generic;
using Artemis.Profiles.Layers.Types.Headset;
@ -48,6 +49,9 @@ namespace Artemis.InjectionModules
Bind<KeyPressType>().ToSelf();
Bind<AudioType>().ToSelf();
Bind<AmbientLightType>().ToSelf();
// Type helpers
Bind<AudioCaptureManager>().ToSelf().InSingletonScope();
}
}
}

View File

@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Artemis.Modules.Effects.AudioVisualizer.Utilities;
using NAudio.CoreAudioApi;
using NAudio.Dsp;
using NAudio.Wave;
using Ninject.Extensions.Logging;
namespace Artemis.Profiles.Layers.Types.Audio.AudioCapturing
{
public class AudioCaptureManager
{
private readonly SampleAggregator _sampleAggregator = new SampleAggregator(1024);
private readonly WasapiLoopbackCapture _waveIn;
private Complex[] _fft;
private DateTime _lastAudioUpdate;
private DateTime _lastRequest;
public AudioCaptureManager(ILogger logger)
{
Logger = logger;
Device = new MMDeviceEnumerator().EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active).FirstOrDefault();
_sampleAggregator.FftCalculated += FftCalculated;
_sampleAggregator.PerformFFT = true;
// Start listening for sound data
_waveIn = new WasapiLoopbackCapture();
_waveIn.DataAvailable += OnDataAvailable;
}
public ILogger Logger { get; set; }
public MMDevice Device { get; set; }
public bool Running { get; set; }
public void Start()
{
if (Running)
return;
try
{
_waveIn.StartRecording();
Running = true;
}
catch (Exception e)
{
Logger.Warn(e, "Failed to start WASAPI audio capture");
}
}
public void Stop()
{
if (!Running)
return;
try
{
_waveIn.StopRecording();
Running = false;
}
catch (Exception e)
{
Logger.Warn(e, "Failed to start WASAPI audio capture");
}
}
private void FftCalculated(object sender, FftEventArgs e)
{
_fft = e.Result;
}
private void OnDataAvailable(object sender, WaveInEventArgs e)
{
if (DateTime.Now - _lastAudioUpdate < TimeSpan.FromMilliseconds(40))
return;
if (DateTime.Now - _lastRequest > TimeSpan.FromSeconds(5))
{
Stop();
return;
}
_lastAudioUpdate = DateTime.Now;
var buffer = e.Buffer;
var bytesRecorded = e.BytesRecorded;
var bufferIncrement = _waveIn.WaveFormat.BlockAlign;
for (var index = 0; index < bytesRecorded; index += bufferIncrement)
{
var sample32 = BitConverter.ToSingle(buffer, index);
_sampleAggregator.Add(sample32);
}
}
public List<byte> GetSpectrumData(int lines)
{
_lastRequest = DateTime.Now;
if (!Running)
Start();
var spectrumData = new List<byte>();
if (_fft == null)
return spectrumData;
int x;
var b0 = 0;
for (x = 0; x < lines; x++)
{
float peak = 0;
var b1 = (int) Math.Pow(2, x*10.0/(lines - 1));
if (b1 > 1023)
b1 = 1023;
if (b1 <= b0)
b1 = b0 + 1;
for (; b0 < b1; b0++)
if (peak < _fft[1 + b0].X)
peak = _fft[1 + b0].X;
var y = (int) (Math.Sqrt(peak)*3*255 - 4);
if (y > 255)
y = 255;
if (y < 0)
y = 0;
spectrumData.Add((byte) y);
}
return spectrumData;
}
}
}

View File

@ -4,60 +4,35 @@ using System.Linq;
using System.Windows;
using System.Windows.Media;
using Artemis.Models.Interfaces;
using Artemis.Modules.Effects.AudioVisualizer.Utilities;
using Artemis.Profiles.Layers.Abstract;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
using Artemis.Profiles.Layers.Types.Audio.AudioCapturing;
using Artemis.Properties;
using Artemis.Utilities;
using Artemis.ViewModels.Profiles;
using NAudio.CoreAudioApi;
using NAudio.Wave;
using Newtonsoft.Json;
using Ninject;
using NLog;
namespace Artemis.Profiles.Layers.Types.Audio
{
internal class AudioType : ILayerType
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly List<LayerModel> _audioLayers = new List<LayerModel>();
private readonly MMDevice _device;
private readonly IKernel _kernel;
private readonly SampleAggregator _sampleAggregator = new SampleAggregator(1024);
private readonly WasapiLoopbackCapture _waveIn;
private DateTime _lastAudioUpdate;
private DateTime _lastUpdate;
private int _lines;
private string _previousSettings;
public AudioType(IKernel kernel)
public AudioType(IKernel kernel, AudioCaptureManager audioCaptureManager)
{
_kernel = kernel;
_device = new MMDeviceEnumerator()
.EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active).FirstOrDefault();
_sampleAggregator.FftCalculated += FftCalculated;
_sampleAggregator.PerformFFT = true;
// Start listening for sound data
_waveIn = new WasapiLoopbackCapture();
_waveIn.DataAvailable += OnDataAvailable;
try
{
_waveIn.StartRecording();
}
catch (Exception e)
{
Logger.Warn(e, "Failed to start WASAPI audio capture");
throw;
}
AudioCaptureManager = audioCaptureManager;
}
[JsonIgnore]
public List<byte> SpectrumData { get; set; } = new List<byte>();
public AudioCaptureManager AudioCaptureManager { get; set; }
public string Name => "Keyboard - Audio visualization";
public bool ShowInEdtor => true;
@ -78,7 +53,7 @@ namespace Artemis.Profiles.Layers.Types.Audio
public void Draw(LayerModel layerModel, DrawingContext c)
{
lock (SpectrumData)
lock (_audioLayers)
{
foreach (var audioLayer in _audioLayers)
{
@ -104,21 +79,28 @@ namespace Artemis.Profiles.Layers.Types.Audio
public void Update(LayerModel layerModel, IDataModel dataModel, bool isPreview = false)
{
if ((_device == null) || isPreview)
layerModel.ApplyProperties(true);
if (isPreview)
return;
lock (SpectrumData)
lock (_audioLayers)
{
SetupLayers(layerModel);
var spectrumData = AudioCaptureManager.GetSpectrumData(_lines);
if (!spectrumData.Any())
return;
if (SpectrumData.Any())
var settings = (AudioPropertiesModel) layerModel.Properties;
switch (settings.Direction)
{
var settings = (AudioPropertiesModel) layerModel.Properties;
if ((settings.Direction == Direction.TopToBottom) || (settings.Direction == Direction.BottomToTop))
ApplyVertical(settings);
else if ((settings.Direction == Direction.LeftToRight) ||
(settings.Direction == Direction.RightToLeft))
ApplyHorizontal(settings);
case Direction.TopToBottom:
case Direction.BottomToTop:
ApplyVertical(spectrumData, settings);
break;
case Direction.LeftToRight:
case Direction.RightToLeft:
ApplyHorizontal(spectrumData, settings);
break;
}
}
}
@ -143,14 +125,14 @@ namespace Artemis.Profiles.Layers.Types.Audio
return new AudioPropertiesViewModel(layerEditorViewModel);
}
private void ApplyVertical(AudioPropertiesModel settings)
private void ApplyVertical(List<byte> spectrumData, AudioPropertiesModel settings)
{
var index = 0;
foreach (var audioLayer in _audioLayers)
{
int height;
if (SpectrumData.Count > index)
height = (int) Math.Round(SpectrumData[index]/2.55);
if (spectrumData.Count > index)
height = (int) Math.Round(spectrumData[index]/2.55);
else
height = 0;
@ -174,14 +156,14 @@ namespace Artemis.Profiles.Layers.Types.Audio
}
}
private void ApplyHorizontal(AudioPropertiesModel settings)
private void ApplyHorizontal(List<byte> spectrumData, AudioPropertiesModel settings)
{
var index = 0;
foreach (var audioLayer in _audioLayers)
{
int width;
if (SpectrumData.Count > index)
width = (int) Math.Round(SpectrumData[index]/2.55);
if (spectrumData.Count > index)
width = (int) Math.Round(spectrumData[index]/2.55);
else
width = 0;
@ -308,57 +290,5 @@ namespace Artemis.Profiles.Layers.Types.Audio
layer.Update(null, false, true);
}
}
private void FftCalculated(object sender, FftEventArgs e)
{
if (_lines == 0)
return;
lock (SpectrumData)
{
int x;
var b0 = 0;
SpectrumData.Clear();
for (x = 0; x < _lines; x++)
{
float peak = 0;
var b1 = (int) Math.Pow(2, x*10.0/(_lines - 1));
if (b1 > 1023)
b1 = 1023;
if (b1 <= b0)
b1 = b0 + 1;
for (; b0 < b1; b0++)
if (peak < e.Result[1 + b0].X)
peak = e.Result[1 + b0].X;
var y = (int) (Math.Sqrt(peak)*3*255 - 4);
if (y > 255)
y = 255;
if (y < 0)
y = 0;
SpectrumData.Add((byte) y);
}
}
}
// TODO: Check how often this is called
private void OnDataAvailable(object sender, WaveInEventArgs e)
{
if (DateTime.Now - _lastAudioUpdate < TimeSpan.FromMilliseconds(40))
return;
_lastAudioUpdate = DateTime.Now;
var buffer = e.Buffer;
var bytesRecorded = e.BytesRecorded;
var bufferIncrement = _waveIn.WaveFormat.BlockAlign;
for (var index = 0; index < bytesRecorded; index += bufferIncrement)
{
var sample32 = BitConverter.ToSingle(buffer, index);
_sampleAggregator.Add(sample32);
}
}
}
}