mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-01-02 10:43:31 +00:00
WIP on new audio layers
This commit is contained in:
parent
52afde89ec
commit
1fa6063706
@ -151,6 +151,10 @@
|
|||||||
<HintPath>..\packages\Colore.5.1.0\lib\net35\Corale.Colore.dll</HintPath>
|
<HintPath>..\packages\Colore.5.1.0\lib\net35\Corale.Colore.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="CSCore, Version=1.1.5992.18249, Culture=neutral, PublicKeyToken=5a08f2b6f4415dea, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\CSCore.1.1.0\lib\net35-client\CSCore.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
<Reference Include="CUE.NET, Version=1.1.0.2, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="CUE.NET, Version=1.1.0.2, Culture=neutral, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\CUE.NET.1.1.0.2\lib\net45\CUE.NET.dll</HintPath>
|
<HintPath>..\packages\CUE.NET.1.1.0.2\lib\net45\CUE.NET.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
@ -211,10 +215,6 @@
|
|||||||
<HintPath>..\packages\MoonSharp.2.0.0.0\lib\net40-client\MoonSharp.Interpreter.dll</HintPath>
|
<HintPath>..\packages\MoonSharp.2.0.0.0\lib\net40-client\MoonSharp.Interpreter.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="NAudio, Version=1.7.3.0, Culture=neutral, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\NAudio.1.7.3\lib\net35\NAudio.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
@ -489,9 +489,12 @@
|
|||||||
<Compile Include="Profiles\Layers\Types\AmbientLight\ScreenCapturing\DX9ScreenCapture.cs" />
|
<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\IScreenCapture.cs" />
|
||||||
<Compile Include="Profiles\Layers\Types\AmbientLight\ScreenCapturing\ScreenCaptureManager.cs" />
|
<Compile Include="Profiles\Layers\Types\AmbientLight\ScreenCapturing\ScreenCaptureManager.cs" />
|
||||||
|
<Compile Include="Profiles\Layers\Types\Audio\AudioCapturing\AudioCapture.cs" />
|
||||||
<Compile Include="Profiles\Layers\Types\Audio\AudioCapturing\AudioCaptureManager.cs" />
|
<Compile Include="Profiles\Layers\Types\Audio\AudioCapturing\AudioCaptureManager.cs" />
|
||||||
<Compile Include="Profiles\Layers\Types\Audio\AudioCapturing\FftEventArgs.cs" />
|
<Compile Include="Profiles\Layers\Types\Audio\AudioCapturing\BaseSpectrumProvider.cs" />
|
||||||
<Compile Include="Profiles\Layers\Types\Audio\AudioCapturing\SampleAggregator.cs" />
|
<Compile Include="Profiles\Layers\Types\Audio\AudioCapturing\ISpectrumProvider.cs" />
|
||||||
|
<Compile Include="Profiles\Layers\Types\Audio\AudioCapturing\LineSpectrum.cs" />
|
||||||
|
<Compile Include="Profiles\Layers\Types\Audio\AudioCapturing\SpectrumBase.cs" />
|
||||||
<Compile Include="Profiles\Layers\Types\Audio\AudioPropertiesModel.cs" />
|
<Compile Include="Profiles\Layers\Types\Audio\AudioPropertiesModel.cs" />
|
||||||
<Compile Include="Profiles\Layers\Types\Audio\AudioPropertiesView.xaml.cs">
|
<Compile Include="Profiles\Layers\Types\Audio\AudioPropertiesView.xaml.cs">
|
||||||
<DependentUpon>AudioPropertiesView.xaml</DependentUpon>
|
<DependentUpon>AudioPropertiesView.xaml</DependentUpon>
|
||||||
|
|||||||
@ -99,6 +99,11 @@ namespace Artemis.Modules.Abstract
|
|||||||
|
|
||||||
ProfileModel = profileModel;
|
ProfileModel = profileModel;
|
||||||
ProfileModel?.Activate(_luaManager);
|
ProfileModel?.Activate(_luaManager);
|
||||||
|
if (ProfileModel != null)
|
||||||
|
{
|
||||||
|
Settings.LastProfile = ProfileModel.Name;
|
||||||
|
Settings.Save();
|
||||||
|
}
|
||||||
|
|
||||||
RaiseProfileChangedEvent(new ProfileChangedEventArgs(ProfileModel));
|
RaiseProfileChangedEvent(new ProfileChangedEventArgs(ProfileModel));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,17 +55,20 @@ namespace Artemis.Modules.Games.RocketLeague
|
|||||||
Updater.GetPointers();
|
Updater.GetPointers();
|
||||||
_pointer = SettingsProvider.Load<OffsetSettings>().RocketLeague;
|
_pointer = SettingsProvider.Load<OffsetSettings>().RocketLeague;
|
||||||
|
|
||||||
var tempProcess = MemoryHelpers.GetProcessIfRunning(ProcessName);
|
|
||||||
if (tempProcess == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_memory = new Memory(tempProcess);
|
|
||||||
|
|
||||||
base.Enable();
|
base.Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
|
if (_memory == null)
|
||||||
|
{
|
||||||
|
var tempProcess = MemoryHelpers.GetProcessIfRunning(ProcessName);
|
||||||
|
if (tempProcess == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_memory = new Memory(tempProcess);
|
||||||
|
}
|
||||||
|
|
||||||
if (ProfileModel == null || DataModel == null || _memory == null)
|
if (ProfileModel == null || DataModel == null || _memory == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@ -72,19 +72,17 @@ namespace Artemis.Modules.Games.WoW
|
|||||||
_process = null;
|
_process = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Enable()
|
|
||||||
{
|
|
||||||
var tempProcess = MemoryHelpers.GetProcessIfRunning(ProcessName);
|
|
||||||
if (tempProcess == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_process = new ProcessSharp(tempProcess, MemoryType.Remote);
|
|
||||||
|
|
||||||
base.Enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
|
if (_process == null)
|
||||||
|
{
|
||||||
|
var tempProcess = MemoryHelpers.GetProcessIfRunning(ProcessName);
|
||||||
|
if (tempProcess == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_process = new ProcessSharp(tempProcess, MemoryType.Remote);
|
||||||
|
}
|
||||||
|
|
||||||
if (ProfileModel == null || DataModel == null || _process == null)
|
if (ProfileModel == null || DataModel == null || _process == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,135 @@
|
|||||||
|
using System;
|
||||||
|
using System.Timers;
|
||||||
|
using CSCore;
|
||||||
|
using CSCore.CoreAudioAPI;
|
||||||
|
using CSCore.DSP;
|
||||||
|
using CSCore.SoundIn;
|
||||||
|
using CSCore.Streams;
|
||||||
|
using Ninject.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace Artemis.Profiles.Layers.Types.Audio.AudioCapturing
|
||||||
|
{
|
||||||
|
public class AudioCapture
|
||||||
|
{
|
||||||
|
private const FftSize FftSize = CSCore.DSP.FftSize.Fft4096;
|
||||||
|
private WasapiLoopbackCapture _soundIn;
|
||||||
|
private GainSource _source;
|
||||||
|
private BasicSpectrumProvider _spectrumProvider;
|
||||||
|
private GainSource _volume;
|
||||||
|
private Timer _timer;
|
||||||
|
|
||||||
|
public AudioCapture(ILogger logger, MMDevice device)
|
||||||
|
{
|
||||||
|
Logger = logger;
|
||||||
|
Device = device;
|
||||||
|
|
||||||
|
_timer = new Timer(1000);
|
||||||
|
_timer.Elapsed += TimerOnElapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TimerOnElapsed(object sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
// If MayStop is true for longer than a second, this will stop the audio capture
|
||||||
|
if (MayStop)
|
||||||
|
{
|
||||||
|
Stop();
|
||||||
|
MayStop = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
MayStop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MayStop { get; set; }
|
||||||
|
|
||||||
|
public ILogger Logger { get; }
|
||||||
|
|
||||||
|
public float Volume
|
||||||
|
{
|
||||||
|
get { return _volume.Volume; }
|
||||||
|
set { _volume.Volume = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public MMDevice Device { get; }
|
||||||
|
public bool Running { get; set; }
|
||||||
|
|
||||||
|
public LineSpectrum GetLineSpectrum(int barCount, int volume, ScalingStrategy scalingStrategy)
|
||||||
|
{
|
||||||
|
return new LineSpectrum(FftSize)
|
||||||
|
{
|
||||||
|
SpectrumProvider = _spectrumProvider,
|
||||||
|
UseAverage = true,
|
||||||
|
BarCount = barCount,
|
||||||
|
IsXLogScale = true,
|
||||||
|
ScalingStrategy = scalingStrategy
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
if (Running)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_soundIn = new WasapiLoopbackCapture();
|
||||||
|
_soundIn.Initialize();
|
||||||
|
// Not sure if this null check is needed but doesnt hurt
|
||||||
|
if (Device != null)
|
||||||
|
_soundIn.Device = Device;
|
||||||
|
|
||||||
|
var soundInSource = new SoundInSource(_soundIn);
|
||||||
|
_source = soundInSource.ToSampleSource().AppendSource(x => new GainSource(x), out _volume);
|
||||||
|
|
||||||
|
// create a spectrum provider which provides fft data based on some input
|
||||||
|
_spectrumProvider = new BasicSpectrumProvider(_source.WaveFormat.Channels, _source.WaveFormat.SampleRate,
|
||||||
|
FftSize);
|
||||||
|
|
||||||
|
// the SingleBlockNotificationStream is used to intercept the played samples
|
||||||
|
var notificationSource = new SingleBlockNotificationStream(_source);
|
||||||
|
// pass the intercepted samples as input data to the spectrumprovider (which will calculate a fft based on them)
|
||||||
|
notificationSource.SingleBlockRead += (s, a) => _spectrumProvider.Add(a.Left, a.Right);
|
||||||
|
|
||||||
|
var waveSource = notificationSource.ToWaveSource(16);
|
||||||
|
// We need to read from our source otherwise SingleBlockRead is never called and our spectrum provider is not populated
|
||||||
|
var buffer = new byte[waveSource.WaveFormat.BytesPerSecond / 2];
|
||||||
|
soundInSource.DataAvailable += (s, aEvent) =>
|
||||||
|
{
|
||||||
|
while (waveSource.Read(buffer, 0, buffer.Length) > 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_soundIn.Start();
|
||||||
|
_timer.Start();
|
||||||
|
Running = true;
|
||||||
|
MayStop = false;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Warn(e, "Failed to start WASAPI audio capture");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
if (!Running)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_timer.Stop();
|
||||||
|
_soundIn.Stop();
|
||||||
|
_soundIn.Dispose();
|
||||||
|
_source.Dispose();
|
||||||
|
_soundIn = null;
|
||||||
|
_source = null;
|
||||||
|
|
||||||
|
Running = false;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Warn(e, "Failed to stop WASAPI audio capture");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,133 +1,33 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NAudio.CoreAudioApi;
|
using CSCore.CoreAudioAPI;
|
||||||
using NAudio.Dsp;
|
|
||||||
using NAudio.Wave;
|
|
||||||
using Ninject.Extensions.Logging;
|
using Ninject.Extensions.Logging;
|
||||||
|
|
||||||
namespace Artemis.Profiles.Layers.Types.Audio.AudioCapturing
|
namespace Artemis.Profiles.Layers.Types.Audio.AudioCapturing
|
||||||
{
|
{
|
||||||
public class AudioCaptureManager
|
public class AudioCaptureManager
|
||||||
{
|
{
|
||||||
private readonly SampleAggregator _sampleAggregator = new SampleAggregator(1024);
|
private readonly List<AudioCapture> _audioCaptures;
|
||||||
private readonly WasapiLoopbackCapture _waveIn;
|
|
||||||
private Complex[] _fft;
|
|
||||||
private DateTime _lastAudioUpdate;
|
|
||||||
private DateTime _lastRequest;
|
|
||||||
|
|
||||||
public AudioCaptureManager(ILogger logger)
|
public AudioCaptureManager(ILogger logger)
|
||||||
{
|
{
|
||||||
Logger = logger;
|
Logger = logger;
|
||||||
Device = new MMDeviceEnumerator().EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active).FirstOrDefault();
|
_audioCaptures = new List<AudioCapture>();
|
||||||
|
}
|
||||||
|
|
||||||
_sampleAggregator.FftCalculated += FftCalculated;
|
public AudioCapture GetAudioCapture(MMDevice device)
|
||||||
_sampleAggregator.PerformFFT = true;
|
{
|
||||||
|
// Return existing audio capture if found
|
||||||
|
var audioCapture = _audioCaptures.FirstOrDefault(a => a.Device == device);
|
||||||
|
if (audioCapture != null)
|
||||||
|
return audioCapture;
|
||||||
|
|
||||||
// Start listening for sound data
|
// Else create a new one and return that
|
||||||
_waveIn = new WasapiLoopbackCapture();
|
var newAudioCapture = new AudioCapture(Logger, device);
|
||||||
_waveIn.DataAvailable += OnDataAvailable;
|
_audioCaptures.Add(newAudioCapture);
|
||||||
|
return newAudioCapture;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ILogger Logger { get; set; }
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using CSCore.DSP;
|
||||||
|
|
||||||
|
namespace Artemis.Profiles.Layers.Types.Audio.AudioCapturing
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// BasicSpectrumProvider
|
||||||
|
/// </summary>
|
||||||
|
public class BasicSpectrumProvider : FftProvider, ISpectrumProvider
|
||||||
|
{
|
||||||
|
private readonly List<object> _contexts = new List<object>();
|
||||||
|
private readonly int _sampleRate;
|
||||||
|
|
||||||
|
public BasicSpectrumProvider(int channels, int sampleRate, FftSize fftSize)
|
||||||
|
: base(channels, fftSize)
|
||||||
|
{
|
||||||
|
if (sampleRate <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException("sampleRate");
|
||||||
|
_sampleRate = sampleRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetFftBandIndex(float frequency)
|
||||||
|
{
|
||||||
|
var fftSize = (int) FftSize;
|
||||||
|
var f = _sampleRate / 2.0;
|
||||||
|
// ReSharper disable once PossibleLossOfFraction
|
||||||
|
return (int) (frequency / f * (fftSize / 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool GetFftData(float[] fftResultBuffer, object context)
|
||||||
|
{
|
||||||
|
if (_contexts.Contains(context))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_contexts.Add(context);
|
||||||
|
GetFftData(fftResultBuffer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Add(float[] samples, int count)
|
||||||
|
{
|
||||||
|
base.Add(samples, count);
|
||||||
|
if (count > 0)
|
||||||
|
_contexts.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Add(float left, float right)
|
||||||
|
{
|
||||||
|
base.Add(left, right);
|
||||||
|
_contexts.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,17 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using NAudio.Dsp;
|
|
||||||
|
|
||||||
namespace Artemis.Profiles.Layers.Types.Audio.AudioCapturing
|
|
||||||
{
|
|
||||||
public class FftEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
[DebuggerStepThrough]
|
|
||||||
public FftEventArgs(Complex[] result)
|
|
||||||
{
|
|
||||||
Result = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Complex[] Result { get; private set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
namespace Artemis.Profiles.Layers.Types.Audio.AudioCapturing
|
||||||
|
{
|
||||||
|
public interface ISpectrumProvider
|
||||||
|
{
|
||||||
|
bool GetFftData(float[] fftBuffer, object context);
|
||||||
|
int GetFftBandIndex(float frequency);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Artemis.Profiles.Layers.Models;
|
||||||
|
using CSCore.DSP;
|
||||||
|
|
||||||
|
namespace Artemis.Profiles.Layers.Types.Audio.AudioCapturing
|
||||||
|
{
|
||||||
|
public class LineSpectrum : SpectrumBase
|
||||||
|
{
|
||||||
|
private int _barCount;
|
||||||
|
|
||||||
|
public LineSpectrum(FftSize fftSize)
|
||||||
|
{
|
||||||
|
FftSize = fftSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int BarCount
|
||||||
|
{
|
||||||
|
get { return _barCount; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value <= 0)
|
||||||
|
throw new ArgumentOutOfRangeException("value");
|
||||||
|
_barCount = value;
|
||||||
|
SpectrumResolution = value;
|
||||||
|
UpdateFrequencyMapping();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetupLayersVertical(double height, List<LayerModel> audioLayers)
|
||||||
|
{
|
||||||
|
var fftBuffer = new float[(int)FftSize];
|
||||||
|
|
||||||
|
// get the fft result from the spectrum provider
|
||||||
|
if (!SpectrumProvider.GetFftData(fftBuffer, this))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var spectrumPoints = CalculateSpectrumPoints(height, fftBuffer);
|
||||||
|
foreach (var p in spectrumPoints)
|
||||||
|
audioLayers[p.SpectrumPointIndex].Height = p.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetupLayersHorizontal(double width, List<LayerModel> audioLayers)
|
||||||
|
{
|
||||||
|
var fftBuffer = new float[(int)FftSize];
|
||||||
|
|
||||||
|
// get the fft result from the spectrum provider
|
||||||
|
if (!SpectrumProvider.GetFftData(fftBuffer, this))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var spectrumPoints = CalculateSpectrumPoints(width, fftBuffer);
|
||||||
|
foreach (var p in spectrumPoints)
|
||||||
|
audioLayers[p.SpectrumPointIndex].Width = p.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,52 +0,0 @@
|
|||||||
using System;
|
|
||||||
using NAudio.Dsp;
|
|
||||||
|
|
||||||
namespace Artemis.Profiles.Layers.Types.Audio.AudioCapturing
|
|
||||||
{
|
|
||||||
public class SampleAggregator
|
|
||||||
{
|
|
||||||
private readonly FftEventArgs fftArgs;
|
|
||||||
|
|
||||||
// This Complex is NAudio's own!
|
|
||||||
private readonly Complex[] fftBuffer;
|
|
||||||
private readonly int fftLength;
|
|
||||||
private readonly int m;
|
|
||||||
private int fftPos;
|
|
||||||
|
|
||||||
public SampleAggregator(int fftLength)
|
|
||||||
{
|
|
||||||
if (!IsPowerOfTwo(fftLength))
|
|
||||||
throw new ArgumentException("FFT Length must be a power of two");
|
|
||||||
m = (int) Math.Log(fftLength, 2.0);
|
|
||||||
this.fftLength = fftLength;
|
|
||||||
fftBuffer = new Complex[fftLength];
|
|
||||||
fftArgs = new FftEventArgs(fftBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool PerformFFT { get; set; }
|
|
||||||
// FFT
|
|
||||||
public event EventHandler<FftEventArgs> FftCalculated;
|
|
||||||
|
|
||||||
private bool IsPowerOfTwo(int x)
|
|
||||||
{
|
|
||||||
return (x & (x - 1)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(float value)
|
|
||||||
{
|
|
||||||
if (PerformFFT && FftCalculated != null)
|
|
||||||
{
|
|
||||||
// Remember the window function! There are many others as well.
|
|
||||||
fftBuffer[fftPos].X = (float) (value * FastFourierTransform.HammingWindow(fftPos, fftLength));
|
|
||||||
fftBuffer[fftPos].Y = 0; // This is always zero with audio.
|
|
||||||
fftPos++;
|
|
||||||
if (fftPos >= fftLength)
|
|
||||||
{
|
|
||||||
fftPos = 0;
|
|
||||||
FastFourierTransform.FFT(true, m, fftBuffer);
|
|
||||||
FftCalculated(this, fftArgs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,189 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using CSCore;
|
||||||
|
using CSCore.DSP;
|
||||||
|
|
||||||
|
namespace Artemis.Profiles.Layers.Types.Audio.AudioCapturing
|
||||||
|
{
|
||||||
|
public class SpectrumBase
|
||||||
|
{
|
||||||
|
private const int ScaleFactorLinear = 9;
|
||||||
|
protected const int ScaleFactorSqr = 2;
|
||||||
|
protected const double MinDbValue = -90;
|
||||||
|
protected const double MaxDbValue = 0;
|
||||||
|
protected const double DbScale = MaxDbValue - MinDbValue;
|
||||||
|
|
||||||
|
private int _fftSize;
|
||||||
|
private bool _isXLogScale;
|
||||||
|
private int _maxFftIndex;
|
||||||
|
private int _maximumFrequency = 20000;
|
||||||
|
private int _maximumFrequencyIndex;
|
||||||
|
private int _minimumFrequency = 20; //Default spectrum from 20Hz to 20kHz
|
||||||
|
private int _minimumFrequencyIndex;
|
||||||
|
private int[] _spectrumIndexMax;
|
||||||
|
private int[] _spectrumLogScaleIndexMax;
|
||||||
|
private ISpectrumProvider _spectrumProvider;
|
||||||
|
|
||||||
|
protected int SpectrumResolution;
|
||||||
|
|
||||||
|
public int MaximumFrequency
|
||||||
|
{
|
||||||
|
get { return _maximumFrequency; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value <= MinimumFrequency)
|
||||||
|
throw new ArgumentOutOfRangeException("value",
|
||||||
|
"Value must not be less or equal the MinimumFrequency.");
|
||||||
|
_maximumFrequency = value;
|
||||||
|
UpdateFrequencyMapping();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int MinimumFrequency
|
||||||
|
{
|
||||||
|
get { return _minimumFrequency; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value < 0)
|
||||||
|
throw new ArgumentOutOfRangeException("value");
|
||||||
|
_minimumFrequency = value;
|
||||||
|
UpdateFrequencyMapping();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Browsable(false)]
|
||||||
|
public ISpectrumProvider SpectrumProvider
|
||||||
|
{
|
||||||
|
get { return _spectrumProvider; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
throw new ArgumentNullException("value");
|
||||||
|
_spectrumProvider = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsXLogScale
|
||||||
|
{
|
||||||
|
get { return _isXLogScale; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_isXLogScale = value;
|
||||||
|
UpdateFrequencyMapping();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScalingStrategy ScalingStrategy { get; set; }
|
||||||
|
|
||||||
|
public bool UseAverage { get; set; }
|
||||||
|
|
||||||
|
[Browsable(false)]
|
||||||
|
public FftSize FftSize
|
||||||
|
{
|
||||||
|
get { return (FftSize) _fftSize; }
|
||||||
|
protected set
|
||||||
|
{
|
||||||
|
if ((int) Math.Log((int) value, 2) % 1 != 0)
|
||||||
|
throw new ArgumentOutOfRangeException("value");
|
||||||
|
|
||||||
|
_fftSize = (int) value;
|
||||||
|
_maxFftIndex = _fftSize / 2 - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void UpdateFrequencyMapping()
|
||||||
|
{
|
||||||
|
_maximumFrequencyIndex = Math.Min(_spectrumProvider.GetFftBandIndex(MaximumFrequency) + 1, _maxFftIndex);
|
||||||
|
_minimumFrequencyIndex = Math.Min(_spectrumProvider.GetFftBandIndex(MinimumFrequency), _maxFftIndex);
|
||||||
|
|
||||||
|
var actualResolution = SpectrumResolution;
|
||||||
|
|
||||||
|
var indexCount = _maximumFrequencyIndex - _minimumFrequencyIndex;
|
||||||
|
var linearIndexBucketSize = Math.Round(indexCount / (double) actualResolution, 3);
|
||||||
|
|
||||||
|
_spectrumIndexMax = _spectrumIndexMax.CheckBuffer(actualResolution, true);
|
||||||
|
_spectrumLogScaleIndexMax = _spectrumLogScaleIndexMax.CheckBuffer(actualResolution, true);
|
||||||
|
|
||||||
|
var maxLog = Math.Log(actualResolution, actualResolution);
|
||||||
|
for (var i = 1; i < actualResolution; i++)
|
||||||
|
{
|
||||||
|
var logIndex =
|
||||||
|
(int) ((maxLog - Math.Log(actualResolution + 1 - i, actualResolution + 1)) * indexCount) +
|
||||||
|
_minimumFrequencyIndex;
|
||||||
|
|
||||||
|
_spectrumIndexMax[i - 1] = _minimumFrequencyIndex + (int) (i * linearIndexBucketSize);
|
||||||
|
_spectrumLogScaleIndexMax[i - 1] = logIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (actualResolution > 0)
|
||||||
|
_spectrumIndexMax[_spectrumIndexMax.Length - 1] =
|
||||||
|
_spectrumLogScaleIndexMax[_spectrumLogScaleIndexMax.Length - 1] = _maximumFrequencyIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual SpectrumPointData[] CalculateSpectrumPoints(double maxValue, float[] fftBuffer)
|
||||||
|
{
|
||||||
|
var dataPoints = new List<SpectrumPointData>();
|
||||||
|
|
||||||
|
double value0 = 0, value = 0;
|
||||||
|
double lastValue = 0;
|
||||||
|
var actualMaxValue = maxValue;
|
||||||
|
var spectrumPointIndex = 0;
|
||||||
|
|
||||||
|
for (var i = _minimumFrequencyIndex; i <= _maximumFrequencyIndex; i++)
|
||||||
|
{
|
||||||
|
switch (ScalingStrategy)
|
||||||
|
{
|
||||||
|
case ScalingStrategy.Decibel:
|
||||||
|
value0 = (20 * Math.Log10(fftBuffer[i]) - MinDbValue) / DbScale * actualMaxValue;
|
||||||
|
break;
|
||||||
|
case ScalingStrategy.Linear:
|
||||||
|
value0 = fftBuffer[i] * ScaleFactorLinear * actualMaxValue;
|
||||||
|
break;
|
||||||
|
case ScalingStrategy.Sqrt:
|
||||||
|
value0 = Math.Sqrt(fftBuffer[i]) * ScaleFactorSqr * actualMaxValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var recalc = true;
|
||||||
|
|
||||||
|
value = Math.Max(0, Math.Max(value0, value));
|
||||||
|
|
||||||
|
while (spectrumPointIndex <= _spectrumIndexMax.Length - 1 &&
|
||||||
|
i ==
|
||||||
|
(IsXLogScale
|
||||||
|
? _spectrumLogScaleIndexMax[spectrumPointIndex]
|
||||||
|
: _spectrumIndexMax[spectrumPointIndex]))
|
||||||
|
{
|
||||||
|
if (!recalc)
|
||||||
|
value = lastValue;
|
||||||
|
|
||||||
|
if (value > maxValue)
|
||||||
|
value = maxValue;
|
||||||
|
|
||||||
|
if (UseAverage && spectrumPointIndex > 0)
|
||||||
|
value = (lastValue + value) / 2.0;
|
||||||
|
|
||||||
|
dataPoints.Add(new SpectrumPointData {SpectrumPointIndex = spectrumPointIndex, Value = value});
|
||||||
|
|
||||||
|
lastValue = value;
|
||||||
|
value = 0.0;
|
||||||
|
spectrumPointIndex++;
|
||||||
|
recalc = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataPoints.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerDisplay("{Value}")]
|
||||||
|
protected struct SpectrumPointData
|
||||||
|
{
|
||||||
|
public int SpectrumPointIndex;
|
||||||
|
public double Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -21,4 +21,11 @@ namespace Artemis.Profiles.Layers.Types.Audio
|
|||||||
[Description("Left to right")] LeftToRight,
|
[Description("Left to right")] LeftToRight,
|
||||||
[Description("Right to left")] RightToLeft
|
[Description("Right to left")] RightToLeft
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum ScalingStrategy
|
||||||
|
{
|
||||||
|
[Description("Decibel")] Decibel,
|
||||||
|
[Description("Linear")] Linear,
|
||||||
|
[Description("Square root")] Sqrt
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -24,16 +24,15 @@ namespace Artemis.Profiles.Layers.Types.Audio
|
|||||||
private DateTime _lastUpdate;
|
private DateTime _lastUpdate;
|
||||||
private int _lines;
|
private int _lines;
|
||||||
private string _previousSettings;
|
private string _previousSettings;
|
||||||
|
private LineSpectrum _lineSpectrum;
|
||||||
|
private AudioCapture _audioCapture;
|
||||||
|
|
||||||
public AudioType(IKernel kernel, AudioCaptureManager audioCaptureManager)
|
public AudioType(IKernel kernel, AudioCaptureManager audioCaptureManager)
|
||||||
{
|
{
|
||||||
_kernel = kernel;
|
_kernel = kernel;
|
||||||
AudioCaptureManager = audioCaptureManager;
|
_audioCapture = audioCaptureManager.GetAudioCapture(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonIgnore]
|
|
||||||
public AudioCaptureManager AudioCaptureManager { get; set; }
|
|
||||||
|
|
||||||
public string Name => "Keyboard - Audio visualization";
|
public string Name => "Keyboard - Audio visualization";
|
||||||
public bool ShowInEdtor => true;
|
public bool ShowInEdtor => true;
|
||||||
public DrawType DrawType => DrawType.Keyboard;
|
public DrawType DrawType => DrawType.Keyboard;
|
||||||
@ -83,23 +82,25 @@ namespace Artemis.Profiles.Layers.Types.Audio
|
|||||||
if (isPreview)
|
if (isPreview)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Start audio capture in case it wasn't running
|
||||||
|
_audioCapture.Start();
|
||||||
|
_audioCapture.MayStop = false;
|
||||||
|
|
||||||
lock (_audioLayers)
|
lock (_audioLayers)
|
||||||
{
|
{
|
||||||
|
// Called every update but only runs every second
|
||||||
SetupLayers(layerModel);
|
SetupLayers(layerModel);
|
||||||
var spectrumData = AudioCaptureManager.GetSpectrumData(_lines);
|
|
||||||
if (!spectrumData.Any())
|
|
||||||
return;
|
|
||||||
|
|
||||||
var settings = (AudioPropertiesModel) layerModel.Properties;
|
var settings = (AudioPropertiesModel) layerModel.Properties;
|
||||||
switch (settings.Direction)
|
switch (settings.Direction)
|
||||||
{
|
{
|
||||||
case Direction.TopToBottom:
|
case Direction.TopToBottom:
|
||||||
case Direction.BottomToTop:
|
case Direction.BottomToTop:
|
||||||
ApplyVertical(spectrumData, settings);
|
_lineSpectrum.SetupLayersVertical(layerModel.Height, _audioLayers);
|
||||||
break;
|
break;
|
||||||
case Direction.LeftToRight:
|
case Direction.LeftToRight:
|
||||||
case Direction.RightToLeft:
|
case Direction.RightToLeft:
|
||||||
ApplyHorizontal(spectrumData, settings);
|
_lineSpectrum.SetupLayersHorizontal(layerModel.Width, _audioLayers);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,96 +126,6 @@ namespace Artemis.Profiles.Layers.Types.Audio
|
|||||||
return new AudioPropertiesViewModel(layerEditorViewModel);
|
return new AudioPropertiesViewModel(layerEditorViewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
else
|
|
||||||
height = 0;
|
|
||||||
|
|
||||||
// Apply Sensitivity setting
|
|
||||||
height = height*settings.Sensitivity;
|
|
||||||
|
|
||||||
var newHeight = settings.Height/100.0*height;
|
|
||||||
if (newHeight >= audioLayer.Properties.Height)
|
|
||||||
audioLayer.Properties.Height = newHeight;
|
|
||||||
else
|
|
||||||
audioLayer.Properties.Height = audioLayer.Properties.Height - settings.FadeSpeed;
|
|
||||||
if (audioLayer.Properties.Height < 0)
|
|
||||||
audioLayer.Properties.Height = 0;
|
|
||||||
|
|
||||||
// Reverse the direction if settings require it
|
|
||||||
if (settings.Direction == Direction.BottomToTop)
|
|
||||||
audioLayer.Properties.Y = settings.Y + (settings.Height - audioLayer.Properties.Height);
|
|
||||||
|
|
||||||
FakeUpdate(settings, audioLayer);
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
else
|
|
||||||
width = 0;
|
|
||||||
|
|
||||||
// Apply Sensitivity setting
|
|
||||||
width = width*settings.Sensitivity;
|
|
||||||
|
|
||||||
var newWidth = settings.Width/100.0*width;
|
|
||||||
if (newWidth >= audioLayer.Properties.Width)
|
|
||||||
audioLayer.Properties.Width = newWidth;
|
|
||||||
else
|
|
||||||
audioLayer.Properties.Width = audioLayer.Properties.Width - settings.FadeSpeed;
|
|
||||||
if (audioLayer.Properties.Width < 0)
|
|
||||||
audioLayer.Properties.Width = 0;
|
|
||||||
|
|
||||||
audioLayer.Properties.Brush = settings.Brush;
|
|
||||||
audioLayer.Properties.Contain = false;
|
|
||||||
|
|
||||||
// Reverse the direction if settings require it
|
|
||||||
if (settings.Direction == Direction.RightToLeft)
|
|
||||||
audioLayer.Properties.X = settings.X + (settings.Width - audioLayer.Properties.Width);
|
|
||||||
|
|
||||||
FakeUpdate(settings, audioLayer);
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the layer manually faking the width and height for a properly working animation
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="settings"></param>
|
|
||||||
/// <param name="audioLayer"></param>
|
|
||||||
private static void FakeUpdate(LayerPropertiesModel settings, LayerModel audioLayer)
|
|
||||||
{
|
|
||||||
// Call the regular update
|
|
||||||
audioLayer.LayerType?.Update(audioLayer, null);
|
|
||||||
|
|
||||||
// Store the original height and width
|
|
||||||
var oldHeight = audioLayer.Properties.Height;
|
|
||||||
var oldWidth = audioLayer.Properties.Width;
|
|
||||||
|
|
||||||
// Fake the height and width and update the animation
|
|
||||||
audioLayer.Properties.Width = settings.Width;
|
|
||||||
audioLayer.Properties.Height = settings.Height;
|
|
||||||
audioLayer.LastRender = DateTime.Now;
|
|
||||||
audioLayer.LayerAnimation?.Update(audioLayer, true);
|
|
||||||
|
|
||||||
// Restore the height and width
|
|
||||||
audioLayer.Properties.Height = oldHeight;
|
|
||||||
audioLayer.Properties.Width = oldWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets up the inner layers when the settings have changed
|
/// Sets up the inner layers when the settings have changed
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -230,7 +141,7 @@ namespace Artemis.Profiles.Layers.Types.Audio
|
|||||||
var currentSettings = JsonConvert.SerializeObject(settings, Formatting.Indented);
|
var currentSettings = JsonConvert.SerializeObject(settings, Formatting.Indented);
|
||||||
var currentType = _audioLayers.FirstOrDefault()?.LayerAnimation?.GetType();
|
var currentType = _audioLayers.FirstOrDefault()?.LayerAnimation?.GetType();
|
||||||
|
|
||||||
if (currentSettings == _previousSettings && (layerModel.LayerAnimation.GetType() == currentType))
|
if (currentSettings == _previousSettings && layerModel.LayerAnimation.GetType() == currentType)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_previousSettings = JsonConvert.SerializeObject(settings, Formatting.Indented);
|
_previousSettings = JsonConvert.SerializeObject(settings, Formatting.Indented);
|
||||||
@ -249,6 +160,7 @@ namespace Artemis.Profiles.Layers.Types.Audio
|
|||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
_lineSpectrum = _audioCapture.GetLineSpectrum(_audioLayers.Count, 5, ScalingStrategy.Decibel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupVertical(LayerModel layerModel)
|
private void SetupVertical(LayerModel layerModel)
|
||||||
|
|||||||
@ -118,7 +118,7 @@ namespace Artemis.ViewModels.Profiles
|
|||||||
|
|
||||||
var renderLayers = GetRenderLayers();
|
var renderLayers = GetRenderLayers();
|
||||||
// Draw the current frame to the preview
|
// Draw the current frame to the preview
|
||||||
var keyboardRect = _deviceManager.ActiveKeyboard.KeyboardRectangle(4);
|
var keyboardRect = _deviceManager.ActiveKeyboard.KeyboardRectangle();
|
||||||
var visual = new DrawingVisual();
|
var visual = new DrawingVisual();
|
||||||
using (var drawingContext = visual.RenderOpen())
|
using (var drawingContext = visual.RenderOpen())
|
||||||
{
|
{
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
<package id="Caliburn.Micro.Core" version="3.0.2" targetFramework="net461" />
|
<package id="Caliburn.Micro.Core" version="3.0.2" targetFramework="net461" />
|
||||||
<package id="Castle.Core" version="3.3.3" targetFramework="net452" />
|
<package id="Castle.Core" version="3.3.3" targetFramework="net452" />
|
||||||
<package id="Colore" version="5.1.0" targetFramework="net461" />
|
<package id="Colore" version="5.1.0" targetFramework="net461" />
|
||||||
|
<package id="CSCore" version="1.1.0" targetFramework="net461" />
|
||||||
<package id="CUE.NET" version="1.1.0.2" targetFramework="net461" />
|
<package id="CUE.NET" version="1.1.0.2" targetFramework="net461" />
|
||||||
<package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net461" />
|
<package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net461" />
|
||||||
<package id="DynamicExpresso.Core" version="1.3.3.4" targetFramework="net461" />
|
<package id="DynamicExpresso.Core" version="1.3.3.4" targetFramework="net461" />
|
||||||
@ -15,7 +16,6 @@
|
|||||||
<package id="MahApps.Metro.Resources" version="0.6.1.0" targetFramework="net452" />
|
<package id="MahApps.Metro.Resources" version="0.6.1.0" targetFramework="net452" />
|
||||||
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net461" />
|
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net461" />
|
||||||
<package id="MoonSharp" version="2.0.0.0" targetFramework="net461" />
|
<package id="MoonSharp" version="2.0.0.0" targetFramework="net461" />
|
||||||
<package id="NAudio" version="1.7.3" targetFramework="net452" />
|
|
||||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" />
|
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net461" />
|
||||||
<package id="Ninject" version="3.2.2.0" targetFramework="net452" />
|
<package id="Ninject" version="3.2.2.0" targetFramework="net452" />
|
||||||
<package id="Ninject.Extensions.Conventions" version="3.2.0.0" targetFramework="net461" />
|
<package id="Ninject.Extensions.Conventions" version="3.2.0.0" targetFramework="net461" />
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user