diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj
index f80ef2f2c..ab2de8b36 100644
--- a/Artemis/Artemis/Artemis.csproj
+++ b/Artemis/Artemis/Artemis.csproj
@@ -151,6 +151,10 @@
..\packages\Colore.5.1.0\lib\net35\Corale.Colore.dll
True
+
+ ..\packages\CSCore.1.1.0\lib\net35-client\CSCore.dll
+ True
+
..\packages\CUE.NET.1.1.0.2\lib\net45\CUE.NET.dll
True
@@ -211,10 +215,6 @@
..\packages\MoonSharp.2.0.0.0\lib\net40-client\MoonSharp.Interpreter.dll
True
-
- ..\packages\NAudio.1.7.3\lib\net35\NAudio.dll
- True
-
..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
True
@@ -489,9 +489,12 @@
+
-
-
+
+
+
+
AudioPropertiesView.xaml
diff --git a/Artemis/Artemis/Modules/Abstract/ModuleModel.cs b/Artemis/Artemis/Modules/Abstract/ModuleModel.cs
index a3bbfc5c8..6734de719 100644
--- a/Artemis/Artemis/Modules/Abstract/ModuleModel.cs
+++ b/Artemis/Artemis/Modules/Abstract/ModuleModel.cs
@@ -99,6 +99,11 @@ namespace Artemis.Modules.Abstract
ProfileModel = profileModel;
ProfileModel?.Activate(_luaManager);
+ if (ProfileModel != null)
+ {
+ Settings.LastProfile = ProfileModel.Name;
+ Settings.Save();
+ }
RaiseProfileChangedEvent(new ProfileChangedEventArgs(ProfileModel));
}
diff --git a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs
index 750c29643..729b16765 100644
--- a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs
+++ b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs
@@ -54,18 +54,21 @@ namespace Artemis.Modules.Games.RocketLeague
{
Updater.GetPointers();
_pointer = SettingsProvider.Load().RocketLeague;
-
- var tempProcess = MemoryHelpers.GetProcessIfRunning(ProcessName);
- if (tempProcess == null)
- return;
-
- _memory = new Memory(tempProcess);
-
+
base.Enable();
}
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)
return;
diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs b/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs
index e1aa1688a..1df6ff02f 100644
--- a/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs
@@ -72,19 +72,17 @@ namespace Artemis.Modules.Games.WoW
_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()
{
+ 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)
return;
diff --git a/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioCapturing/AudioCapture.cs b/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioCapturing/AudioCapture.cs
new file mode 100644
index 000000000..a8602a20b
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioCapturing/AudioCapture.cs
@@ -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");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioCapturing/AudioCaptureManager.cs b/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioCapturing/AudioCaptureManager.cs
index 04ca51a5d..cece1ddb0 100644
--- a/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioCapturing/AudioCaptureManager.cs
+++ b/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioCapturing/AudioCaptureManager.cs
@@ -1,133 +1,33 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
-using NAudio.CoreAudioApi;
-using NAudio.Dsp;
-using NAudio.Wave;
+using CSCore.CoreAudioAPI;
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;
+ private readonly List _audioCaptures;
public AudioCaptureManager(ILogger logger)
{
Logger = logger;
- Device = new MMDeviceEnumerator().EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active).FirstOrDefault();
+ _audioCaptures = new List();
+ }
- _sampleAggregator.FftCalculated += FftCalculated;
- _sampleAggregator.PerformFFT = true;
+ public AudioCapture GetAudioCapture(MMDevice device)
+ {
+ // Return existing audio capture if found
+ var audioCapture = _audioCaptures.FirstOrDefault(a => a.Device == device);
+ if (audioCapture != null)
+ return audioCapture;
- // Start listening for sound data
- _waveIn = new WasapiLoopbackCapture();
- _waveIn.DataAvailable += OnDataAvailable;
+ // Else create a new one and return that
+ var newAudioCapture = new AudioCapture(Logger, device);
+ _audioCaptures.Add(newAudioCapture);
+ return newAudioCapture;
}
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 GetSpectrumData(int lines)
- {
- _lastRequest = DateTime.Now;
- if (!Running)
- Start();
-
- var spectrumData = new List();
-
- 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;
- }
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioCapturing/BaseSpectrumProvider.cs b/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioCapturing/BaseSpectrumProvider.cs
new file mode 100644
index 000000000..a89a3724f
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioCapturing/BaseSpectrumProvider.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using CSCore.DSP;
+
+namespace Artemis.Profiles.Layers.Types.Audio.AudioCapturing
+{
+ ///
+ /// BasicSpectrumProvider
+ ///
+ public class BasicSpectrumProvider : FftProvider, ISpectrumProvider
+ {
+ private readonly List