diff --git a/Artemis/Artemis.sln b/Artemis/Artemis.sln
index 785b97bb9..e10b6c3a6 100644
--- a/Artemis/Artemis.sln
+++ b/Artemis/Artemis.sln
@@ -1,7 +1,7 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
-VisualStudioVersion = 14.0.25123.0
+VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Artemis", "Artemis\Artemis.csproj", "{ED9997A2-E54C-4E9F-9350-62BE672C3ABE}"
EndProject
diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj
index f80ef2f2c..86e374573 100644
--- a/Artemis/Artemis/Artemis.csproj
+++ b/Artemis/Artemis/Artemis.csproj
@@ -56,6 +56,7 @@
prompt
4
false
+ true
x64
@@ -65,6 +66,7 @@
TRACE
prompt
4
+ true
EAC088BE27A2DE790AE6F37A020409F4A1B5EC0E
@@ -108,6 +110,7 @@
x64
prompt
MinimumRecommendedRules.ruleset
+ true
bin\x64\Release\
@@ -118,6 +121,7 @@
prompt
MinimumRecommendedRules.ruleset
true
+ true
@@ -131,16 +135,16 @@
..\packages\Betwixt.1.4.1\lib\net35\Betwixt.dll
True
-
- ..\packages\Caliburn.Micro.Core.3.0.2\lib\net45\Caliburn.Micro.dll
+
+ ..\packages\Caliburn.Micro.Core.3.0.3\lib\net45\Caliburn.Micro.dll
True
-
- ..\packages\Caliburn.Micro.3.0.2\lib\net45\Caliburn.Micro.Platform.dll
+
+ ..\packages\Caliburn.Micro.3.0.3\lib\net45\Caliburn.Micro.Platform.dll
True
-
- ..\packages\Caliburn.Micro.3.0.2\lib\net45\Caliburn.Micro.Platform.Core.dll
+
+ ..\packages\Caliburn.Micro.3.0.3\lib\net45\Caliburn.Micro.Platform.Core.dll
True
@@ -151,8 +155,12 @@
..\packages\Colore.5.1.0\lib\net35\Corale.Colore.dll
True
-
- ..\packages\CUE.NET.1.1.0.2\lib\net45\CUE.NET.dll
+
+ ..\packages\CSCore.1.1.0\lib\net35-client\CSCore.dll
+ True
+
+
+ ..\packages\CUE.NET.1.1.1\lib\net45\CUE.NET.dll
True
@@ -168,7 +176,7 @@
True
- ..\packages\DynamicExpresso.Core.1.3.3.4\lib\net40\DynamicExpresso.Core.dll
+ ..\packages\DynamicExpresso.Core.1.3.3.5\lib\net40\DynamicExpresso.Core.dll
True
@@ -180,15 +188,15 @@
True
- ..\packages\squirrel.windows.1.4.4\lib\Net45\ICSharpCode.SharpZipLib.dll
+ ..\packages\squirrel.windows.1.5.1\lib\Net45\ICSharpCode.SharpZipLib.dll
True
-
- ..\packages\log4net.2.0.5\lib\net45-full\log4net.dll
+
+ ..\packages\log4net.2.0.7\lib\net45-full\log4net.dll
True
-
- ..\packages\MahApps.Metro.1.3.0\lib\net45\MahApps.Metro.dll
+
+ ..\packages\MahApps.Metro.1.4.1\lib\net45\MahApps.Metro.dll
True
@@ -211,10 +219,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
@@ -240,11 +244,15 @@
True
- ..\packages\squirrel.windows.1.4.4\lib\Net45\NuGet.Squirrel.dll
+ ..\packages\squirrel.windows.1.5.1\lib\Net45\NuGet.Squirrel.dll
+ True
+
+
+ ..\packages\Open.WinKeyboardHook.1.0.11\lib\net45\Open.WinKeyboardHook.dll
True
- ..\packages\Process.NET.1.0.5\lib\Process.NET.dll
+ ..\packages\Process.NET.1.0.8\lib\Process.NET.dll
True
@@ -263,8 +271,8 @@
..\packages\SpotifyAPI-NET.2.12.0\lib\SpotifyAPI.dll
True
-
- ..\packages\squirrel.windows.1.4.4\lib\Net45\Squirrel.dll
+
+ ..\packages\squirrel.windows.1.5.1\lib\Net45\Squirrel.dll
True
@@ -278,7 +286,7 @@
- ..\packages\MahApps.Metro.1.3.0\lib\net45\System.Windows.Interactivity.dll
+ ..\packages\MahApps.Metro.1.4.1\lib\net45\System.Windows.Interactivity.dll
True
@@ -294,10 +302,6 @@
..\packages\WpfExceptionViewer.1.0.0.0\lib\VioletTape.WpfExceptionViewer.dll
True
-
- ..\packages\VirtualInput.1.0.1\lib\net20\VirtualInput.dll
- True
-
@@ -350,12 +354,15 @@
+
-
+
+
+
@@ -489,9 +496,21 @@
-
-
-
+
+
+ ConicalBrushPropertiesView.xaml
+
+
+
+
+
+
+
+
+
+
+
+
AudioPropertiesView.xaml
@@ -618,6 +637,7 @@
+
@@ -649,17 +669,16 @@
-
-
+
-
+
@@ -704,7 +723,7 @@
LayerDynamicPropertiesView.xaml
-
+
LayerEditorView.xaml
@@ -716,7 +735,7 @@
LayerTweenView.xaml
-
+
ProfileEditorView.xaml
@@ -855,6 +874,10 @@
MSBuild:Compile
Designer
+
+ Designer
+ MSBuild:Compile
+
MSBuild:Compile
Designer
@@ -947,7 +970,7 @@
Designer
MSBuild:Compile
-
+
MSBuild:Compile
Designer
@@ -963,7 +986,7 @@
Designer
MSBuild:Compile
-
+
Designer
MSBuild:Compile
@@ -1010,12 +1033,12 @@
-
+
This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
diff --git a/Artemis/Artemis/Modules/Games/ProjectCars/ProjectCarsModel.cs b/Artemis/Artemis/Modules/Games/ProjectCars/ProjectCarsModel.cs
index 787b5a12a..d2251d659 100644
--- a/Artemis/Artemis/Modules/Games/ProjectCars/ProjectCarsModel.cs
+++ b/Artemis/Artemis/Modules/Games/ProjectCars/ProjectCarsModel.cs
@@ -11,7 +11,7 @@ namespace Artemis.Modules.Games.ProjectCars
{
Settings = SettingsProvider.Load();
DataModel = new ProjectCarsDataModel();
- ProcessName = "pCARS64";
+ ProcessNames.Add("pCARS64");
}
public override string Name => "ProjectCars";
diff --git a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs
index 750c29643..5358b8072 100644
--- a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs
+++ b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs
@@ -18,7 +18,7 @@ namespace Artemis.Modules.Games.RocketLeague
{
Settings = SettingsProvider.Load();
DataModel = new RocketLeagueDataModel();
- ProcessName = "RocketLeague";
+ ProcessNames.Add("RocketLeague");
// Generate a new offset when the game is updated
//var offset = new GamePointersCollection
@@ -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(ProcessNames[0]);
+ if (tempProcess == null)
+ return;
+
+ _memory = new Memory(tempProcess);
+ }
+
if (ProfileModel == null || DataModel == null || _memory == null)
return;
diff --git a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueViewModel.cs b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueViewModel.cs
index 2358213d7..1f4370272 100644
--- a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueViewModel.cs
+++ b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueViewModel.cs
@@ -32,8 +32,6 @@ namespace Artemis.Modules.Games.RocketLeague
}
}
- public RocketLeagueModel RocketLeagueModel { get; set; }
-
private void SetVersionText()
{
if (!SettingsProvider.Load().EnablePointersUpdate)
diff --git a/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionModel.cs b/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionModel.cs
index 9892a08f1..613ee5d12 100644
--- a/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionModel.cs
+++ b/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionModel.cs
@@ -22,7 +22,7 @@ namespace Artemis.Modules.Games.TheDivision
Settings = SettingsProvider.Load();
DataModel = new TheDivisionDataModel();
- ProcessName = "TheDivision";
+ ProcessNames.Add("TheDivision");
}
public override string Name => "TheDivision";
diff --git a/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentModel.cs b/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentModel.cs
index 09e9cf587..5a6ba3d87 100644
--- a/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentModel.cs
+++ b/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentModel.cs
@@ -30,7 +30,7 @@ namespace Artemis.Modules.Games.UnrealTournament
Settings = SettingsProvider.Load();
DataModel = new UnrealTournamentDataModel();
- ProcessName = "UE4-Win64-Shipping";
+ ProcessNames.Add("UE4-Win64-Shipping");
_killTimer = new Timer(3500);
_killTimer.Elapsed += KillTimerOnElapsed;
diff --git a/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentView.xaml b/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentView.xaml
index fcf0154aa..d24410ab0 100644
--- a/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentView.xaml
+++ b/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentView.xaml
@@ -50,7 +50,7 @@
cal:Message.Attach="[Event LostFocus] = [Action PlaceFiles]" />
+ Style="{DynamicResource SquareButtonStyle}" Height="26" />
diff --git a/Artemis/Artemis/Modules/Games/Witcher3/Witcher3Model.cs b/Artemis/Artemis/Modules/Games/Witcher3/Witcher3Model.cs
index b1f74fc23..fe3b6faa5 100644
--- a/Artemis/Artemis/Modules/Games/Witcher3/Witcher3Model.cs
+++ b/Artemis/Artemis/Modules/Games/Witcher3/Witcher3Model.cs
@@ -22,7 +22,7 @@ namespace Artemis.Modules.Games.Witcher3
Settings = SettingsProvider.Load();
DataModel = new Witcher3DataModel();
- ProcessName = "witcher3";
+ ProcessNames.Add("witcher3");
}
public override string Name => "Witcher3";
diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs b/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs
index e1aa1688a..c50926dfa 100644
--- a/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs
+++ b/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs
@@ -21,7 +21,7 @@ namespace Artemis.Modules.Games.WoW
{
Settings = SettingsProvider.Load();
DataModel = new WoWDataModel();
- ProcessName = "Wow-64";
+ ProcessNames.Add("Wow-64");
// Currently WoW is locked behind a hidden trigger (obviously not that hidden since you're reading this)
// It is using memory reading and lets first try to contact Blizzard
@@ -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(ProcessNames[0]);
+ if (tempProcess == null)
+ return;
+
+ _process = new ProcessSharp(tempProcess, MemoryType.Remote);
+ }
+
if (ProfileModel == null || DataModel == null || _process == null)
return;
diff --git a/Artemis/Artemis/Modules/General/GeneralProfile/GeneralProfileDataModel.cs b/Artemis/Artemis/Modules/General/GeneralProfile/GeneralProfileDataModel.cs
index 7400ad81f..443be1c79 100644
--- a/Artemis/Artemis/Modules/General/GeneralProfile/GeneralProfileDataModel.cs
+++ b/Artemis/Artemis/Modules/General/GeneralProfile/GeneralProfileDataModel.cs
@@ -15,6 +15,7 @@ namespace Artemis.Modules.General.GeneralProfile
CurrentTime = new CurrentTime();
Keyboard = new KbDataModel();
ActiveWindow = new ActiveWindow();
+ Audio = new Audio();
}
public CpuDataModel Cpu { get; set; }
@@ -24,6 +25,23 @@ namespace Artemis.Modules.General.GeneralProfile
public CurrentTime CurrentTime { get; set; }
public KbDataModel Keyboard { get; set; }
public ActiveWindow ActiveWindow { get; set; }
+ public Audio Audio { get; set; }
+ }
+
+ [MoonSharpUserData]
+ public class Audio
+ {
+ public float Volume { get; set; }
+ public AudioDevice Recording { get; set; } = new AudioDevice();
+ public AudioDevice Playback { get; set; } = new AudioDevice();
+ }
+
+ [MoonSharpUserData]
+ public class AudioDevice
+ {
+ public float OverallPeak { get; set; }
+ public float LeftPeak { get; set; }
+ public float RightPeak { get; set; }
}
[MoonSharpUserData]
diff --git a/Artemis/Artemis/Modules/General/GeneralProfile/GeneralProfileModel.cs b/Artemis/Artemis/Modules/General/GeneralProfile/GeneralProfileModel.cs
index 73162b267..4f7bea4e5 100644
--- a/Artemis/Artemis/Modules/General/GeneralProfile/GeneralProfileModel.cs
+++ b/Artemis/Artemis/Modules/General/GeneralProfile/GeneralProfileModel.cs
@@ -7,9 +7,11 @@ using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Artemis.DAL;
+using Artemis.Events;
using Artemis.Managers;
using Artemis.Modules.Abstract;
using Artemis.Utilities;
+using CSCore.CoreAudioAPI;
using Newtonsoft.Json;
using SpotifyAPI.Local;
@@ -17,19 +19,19 @@ namespace Artemis.Modules.General.GeneralProfile
{
public class GeneralProfileModel : ModuleModel
{
- private List _cores;
- private int _cpuFrames;
private DateTime _lastMusicUpdate;
- private PerformanceCounter _overallCpu;
private SpotifyLocalAPI _spotify;
private bool _spotifySetupBusy;
- public GeneralProfileModel(DeviceManager deviceManager, LuaManager luaManager) : base(deviceManager, luaManager)
+ public GeneralProfileModel(DeviceManager deviceManager, LuaManager luaManager,
+ AudioCaptureManager audioCaptureManager) : base(deviceManager, luaManager)
{
_lastMusicUpdate = DateTime.Now;
Settings = SettingsProvider.Load();
DataModel = new GeneralProfileDataModel();
+
+ audioCaptureManager.AudioDeviceChanged += AudioDeviceChanged;
}
public override string Name => "GeneralProfile";
@@ -40,6 +42,7 @@ namespace Artemis.Modules.General.GeneralProfile
{
SetupCpu();
SetupSpotify();
+ SetupAudio();
base.Enable();
}
@@ -52,6 +55,7 @@ namespace Artemis.Modules.General.GeneralProfile
UpdateDay(dataModel);
UpdateKeyStates(dataModel);
UpdateActiveWindow(dataModel);
+ UpdateAudio(dataModel);
}
#region Current Time
@@ -67,8 +71,63 @@ namespace Artemis.Modules.General.GeneralProfile
#endregion
+ #region Audio
+
+ private MMDevice _defaultRecording;
+ private MMDevice _defaultPlayback;
+ private AudioMeterInformation _recordingInfo;
+ private AudioMeterInformation _playbackInfo;
+
+ private void SetupAudio()
+ {
+ _defaultRecording = MMDeviceEnumerator.TryGetDefaultAudioEndpoint(DataFlow.Capture, Role.Multimedia);
+ _defaultPlayback = MMDeviceEnumerator.TryGetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
+
+ if (_defaultRecording != null)
+ _recordingInfo = AudioMeterInformation.FromDevice(_defaultRecording);
+ if (_defaultPlayback != null)
+ _playbackInfo = AudioMeterInformation.FromDevice(_defaultPlayback);
+ }
+
+ private void AudioDeviceChanged(object sender, AudioDeviceChangedEventArgs e)
+ {
+ _defaultRecording = e.DefaultRecording;
+ _defaultPlayback = e.DefaultPlayback;
+
+ if (_defaultRecording != null)
+ _recordingInfo = AudioMeterInformation.FromDevice(_defaultRecording);
+ if (_defaultPlayback != null)
+ _playbackInfo = AudioMeterInformation.FromDevice(_defaultPlayback);
+ }
+
+ private void UpdateAudio(GeneralProfileDataModel dataModel)
+ {
+ // Update microphone, only bother with OverallPeak
+ if (_defaultRecording != null)
+ dataModel.Audio.Recording.OverallPeak = _recordingInfo.PeakValue;
+
+ if (_defaultPlayback == null)
+ return;
+
+ // Update volume if a default device is found
+ dataModel.Audio.Volume = AudioEndpointVolume.FromDevice(_defaultPlayback).GetMasterVolumeLevelScalar();
+
+ // Update speakers, only do overall, left and right for now
+ // TODO: When adding list support lets do all channels
+ var peakValues = _playbackInfo.GetChannelsPeakValues();
+ dataModel.Audio.Playback.OverallPeak = _playbackInfo.PeakValue;
+ dataModel.Audio.Playback.LeftPeak = peakValues[0];
+ dataModel.Audio.Playback.LeftPeak = peakValues[1];
+ }
+
+ #endregion
+
#region CPU
+ private List _cores;
+ private int _cpuFrames;
+ private PerformanceCounter _overallCpu;
+
private void SetupCpu()
{
try
diff --git a/Artemis/Artemis/Modules/Overlays/OverlayProfile/OverlayProfileDataModel.cs b/Artemis/Artemis/Modules/Overlays/OverlayProfile/OverlayProfileDataModel.cs
index 7e94aee59..595471b87 100644
--- a/Artemis/Artemis/Modules/Overlays/OverlayProfile/OverlayProfileDataModel.cs
+++ b/Artemis/Artemis/Modules/Overlays/OverlayProfile/OverlayProfileDataModel.cs
@@ -1,5 +1,6 @@
using Artemis.Modules.Abstract;
using Artemis.Modules.General.GeneralProfile;
+using MoonSharp.Interpreter;
namespace Artemis.Modules.Overlays.OverlayProfile
{
@@ -7,9 +8,17 @@ namespace Artemis.Modules.Overlays.OverlayProfile
{
public OverlayProfileDataModel()
{
- GeneralDataModel = new GeneralProfileDataModel();
+ Keyboard = new KbDataModel();
+ Audio = new Audio();
}
- public GeneralProfileDataModel GeneralDataModel { get; set; }
+ public KbDataModel Keyboard { get; set; }
+ public Audio Audio { get; set; }
+ }
+
+ [MoonSharpUserData]
+ public class Audio
+ {
+ public float Volume { get; set; }
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Modules/Overlays/OverlayProfile/OverlayProfileModel.cs b/Artemis/Artemis/Modules/Overlays/OverlayProfile/OverlayProfileModel.cs
index c9882a1b5..72414dfef 100644
--- a/Artemis/Artemis/Modules/Overlays/OverlayProfile/OverlayProfileModel.cs
+++ b/Artemis/Artemis/Modules/Overlays/OverlayProfile/OverlayProfileModel.cs
@@ -1,32 +1,65 @@
using Artemis.DAL;
+using Artemis.Events;
using Artemis.Managers;
using Artemis.Modules.Abstract;
using Artemis.Modules.General.GeneralProfile;
-using Ninject;
+using CSCore.CoreAudioAPI;
namespace Artemis.Modules.Overlays.OverlayProfile
{
public class OverlayProfileModel : ModuleModel
{
- private readonly GeneralProfileModel _generalProfileModel;
+ private AudioEndpointVolume _endPointVolume;
public OverlayProfileModel(DeviceManager deviceManager, LuaManager luaManager,
- [Named(nameof(GeneralProfileModel))] ModuleModel generalProfileModel) : base(deviceManager, luaManager)
+ AudioCaptureManager audioCaptureManager) : base(deviceManager, luaManager)
{
- _generalProfileModel = (GeneralProfileModel) generalProfileModel;
Settings = SettingsProvider.Load();
DataModel = new OverlayProfileDataModel();
+
+ var defaultPlayback = MMDeviceEnumerator.TryGetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
+ if (defaultPlayback != null)
+ _endPointVolume = AudioEndpointVolume.FromDevice(defaultPlayback);
+
+ audioCaptureManager.AudioDeviceChanged += OnAudioDeviceChanged;
+
+ Enable();
}
public override string Name => "OverlayProfile";
public override bool IsOverlay => true;
public override bool IsBoundToProcess => false;
+ private void OnAudioDeviceChanged(object sender, AudioDeviceChangedEventArgs e)
+ {
+ if (e.DefaultPlayback != null)
+ _endPointVolume = AudioEndpointVolume.FromDevice(e.DefaultPlayback);
+ }
+
public override void Update()
{
- // TODO: Find a clean way to update the parent profile model
- ((OverlayProfileDataModel) DataModel).GeneralDataModel =
- (GeneralProfileDataModel) _generalProfileModel.DataModel;
+ if (!Settings.IsEnabled)
+ return;
+
+ var dataModel = (OverlayProfileDataModel) DataModel;
+
+ dataModel.Keyboard.NumLock = ((ushort) GeneralProfileModel.GetKeyState(0x90) & 0xffff) != 0;
+ dataModel.Keyboard.CapsLock = ((ushort) GeneralProfileModel.GetKeyState(0x14) & 0xffff) != 0;
+ dataModel.Keyboard.ScrollLock = ((ushort) GeneralProfileModel.GetKeyState(0x91) & 0xffff) != 0;
+
+ if (_endPointVolume != null)
+ dataModel.Audio.Volume = _endPointVolume.GetMasterVolumeLevelScalar();
+ }
+
+ public override void Render(RenderFrame frame, bool keyboardOnly)
+ {
+ if (Settings.IsEnabled)
+ base.Render(frame, keyboardOnly);
+ }
+
+ public override void Dispose()
+ {
+ PreviewLayers = null;
}
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Abstract/LayerPropertiesViewModel.cs b/Artemis/Artemis/Profiles/Layers/Abstract/LayerPropertiesViewModel.cs
index 33ea330e7..3669713a0 100644
--- a/Artemis/Artemis/Profiles/Layers/Abstract/LayerPropertiesViewModel.cs
+++ b/Artemis/Artemis/Profiles/Layers/Abstract/LayerPropertiesViewModel.cs
@@ -1,5 +1,6 @@
using System.Windows.Media;
using Artemis.Profiles.Layers.Models;
+using Artemis.ViewModels;
using Artemis.ViewModels.Profiles;
using Caliburn.Micro;
diff --git a/Artemis/Artemis/Profiles/Layers/Animations/GrowAnimation.cs b/Artemis/Artemis/Profiles/Layers/Animations/GrowAnimation.cs
index 0d5144150..83e9479e8 100644
--- a/Artemis/Artemis/Profiles/Layers/Animations/GrowAnimation.cs
+++ b/Artemis/Artemis/Profiles/Layers/Animations/GrowAnimation.cs
@@ -27,17 +27,17 @@ namespace Artemis.Profiles.Layers.Animations
layerModel.AnimationProgress = progress;
}
- public void Draw(LayerModel layerModel, DrawingContext c)
+ public void Draw(LayerModel layerModel, DrawingContext c, int drawScale)
{
if (layerModel.Brush == null)
return;
// Set up variables for this frame
var rect = layerModel.Properties.Contain
- ? layerModel.LayerRect()
- : layerModel.Properties.PropertiesRect();
+ ? layerModel.LayerRect(drawScale)
+ : layerModel.Properties.PropertiesRect(drawScale);
- var clip = layerModel.LayerRect();
+ var clip = layerModel.LayerRect(drawScale);
// Take an offset of 4 to allow layers to slightly leave their bounds
var progress = (6.0 - layerModel.AnimationProgress)*10.0;
diff --git a/Artemis/Artemis/Profiles/Layers/Animations/NoneAnimation.cs b/Artemis/Artemis/Profiles/Layers/Animations/NoneAnimation.cs
index 0d0e759ea..1defbd18a 100644
--- a/Artemis/Artemis/Profiles/Layers/Animations/NoneAnimation.cs
+++ b/Artemis/Artemis/Profiles/Layers/Animations/NoneAnimation.cs
@@ -12,7 +12,7 @@ namespace Artemis.Profiles.Layers.Animations
{
}
- public void Draw(LayerModel layerModel, DrawingContext c)
+ public void Draw(LayerModel layerModel, DrawingContext c, int drawScale)
{
}
diff --git a/Artemis/Artemis/Profiles/Layers/Animations/PulseAnimation.cs b/Artemis/Artemis/Profiles/Layers/Animations/PulseAnimation.cs
index 669452134..52fbf1d88 100644
--- a/Artemis/Artemis/Profiles/Layers/Animations/PulseAnimation.cs
+++ b/Artemis/Artemis/Profiles/Layers/Animations/PulseAnimation.cs
@@ -27,17 +27,17 @@ namespace Artemis.Profiles.Layers.Animations
layerModel.AnimationProgress = progress;
}
- public void Draw(LayerModel layerModel, DrawingContext c)
+ public void Draw(LayerModel layerModel, DrawingContext c, int drawScale)
{
if (layerModel.Brush == null)
return;
// Set up variables for this frame
var rect = layerModel.Properties.Contain
- ? layerModel.LayerRect()
- : layerModel.Properties.PropertiesRect();
+ ? layerModel.LayerRect(drawScale)
+ : layerModel.Properties.PropertiesRect(drawScale);
- var clip = layerModel.LayerRect();
+ var clip = layerModel.LayerRect(drawScale);
// Can't meddle with the original brush because it's frozen.
var brush = layerModel.Brush.Clone();
diff --git a/Artemis/Artemis/Profiles/Layers/Animations/SlideDownAnimation.cs b/Artemis/Artemis/Profiles/Layers/Animations/SlideDownAnimation.cs
index 81a7cbca8..ed584e6f8 100644
--- a/Artemis/Artemis/Profiles/Layers/Animations/SlideDownAnimation.cs
+++ b/Artemis/Artemis/Profiles/Layers/Animations/SlideDownAnimation.cs
@@ -14,29 +14,29 @@ namespace Artemis.Profiles.Layers.Animations
var progress = layerModel.AnimationProgress;
if (MustExpire(layerModel))
progress = 0;
- progress = progress + layerModel.Properties.AnimationSpeed*2;
+ progress = progress + layerModel.Properties.AnimationSpeed * 2 / 4 * layerModel.LayerType.DrawScale;
// If not previewing, store the animation progress in the actual model for the next frame
if (updateAnimations)
layerModel.AnimationProgress = progress;
}
- public void Draw(LayerModel layerModel, DrawingContext c)
+ public void Draw(LayerModel layerModel, DrawingContext c, int drawScale)
{
if (layerModel.Brush == null)
return;
// Set up variables for this frame
var rect = layerModel.Properties.Contain
- ? layerModel.LayerRect()
- : layerModel.Properties.PropertiesRect();
+ ? layerModel.LayerRect(drawScale)
+ : layerModel.Properties.PropertiesRect(drawScale);
var s1 = new Rect(new Point(rect.X, rect.Y + layerModel.AnimationProgress),
new Size(rect.Width, rect.Height));
- var s2 = new Rect(new Point(s1.X, s1.Y - rect.Height),
+ var s2 = new Rect(new Point(s1.X, s1.Y - rect.Height),
new Size(rect.Width, rect.Height + .5));
- var clip = layerModel.LayerRect();
+ var clip = layerModel.LayerRect(drawScale);
c.PushClip(new RectangleGeometry(clip));
c.DrawRectangle(layerModel.Brush, null, s1);
@@ -46,7 +46,8 @@ namespace Artemis.Profiles.Layers.Animations
public bool MustExpire(LayerModel layer)
{
- return layer.AnimationProgress + layer.Properties.AnimationSpeed*2 >= layer.Properties.Height*4;
+ return layer.AnimationProgress + layer.Properties.AnimationSpeed * 2 >=
+ layer.Properties.Height * layer.LayerType.DrawScale;
}
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Animations/SlideLeftAnimation.cs b/Artemis/Artemis/Profiles/Layers/Animations/SlideLeftAnimation.cs
index 8f64ddae0..b8c8bf62d 100644
--- a/Artemis/Artemis/Profiles/Layers/Animations/SlideLeftAnimation.cs
+++ b/Artemis/Artemis/Profiles/Layers/Animations/SlideLeftAnimation.cs
@@ -14,29 +14,29 @@ namespace Artemis.Profiles.Layers.Animations
var progress = layerModel.AnimationProgress;
if (MustExpire(layerModel))
progress = 0;
- progress = progress + layerModel.Properties.AnimationSpeed*2;
+ progress = progress + layerModel.Properties.AnimationSpeed * 2 / 4 * layerModel.LayerType.DrawScale;
// If not previewing, store the animation progress in the actual model for the next frame
if (updateAnimations)
layerModel.AnimationProgress = progress;
}
- public void Draw(LayerModel layerModel, DrawingContext c)
+ public void Draw(LayerModel layerModel, DrawingContext c, int drawScale)
{
if (layerModel.Brush == null)
return;
// Set up variables for this frame
var rect = layerModel.Properties.Contain
- ? layerModel.LayerRect()
- : layerModel.Properties.PropertiesRect();
+ ? layerModel.LayerRect(drawScale)
+ : layerModel.Properties.PropertiesRect(drawScale);
var s1 = new Rect(new Point(rect.X - layerModel.AnimationProgress, rect.Y),
new Size(rect.Width + .5, rect.Height));
var s2 = new Rect(new Point(s1.X + rect.Width, rect.Y),
new Size(rect.Width, rect.Height));
- var clip = layerModel.LayerRect();
+ var clip = layerModel.LayerRect(drawScale);
c.PushClip(new RectangleGeometry(clip));
c.DrawRectangle(layerModel.Brush, null, s1);
@@ -46,7 +46,8 @@ namespace Artemis.Profiles.Layers.Animations
public bool MustExpire(LayerModel layer)
{
- return layer.AnimationProgress + layer.Properties.AnimationSpeed*2 >= layer.Properties.Width*4;
+ return layer.AnimationProgress + layer.Properties.AnimationSpeed * 2 >=
+ layer.Properties.Width * layer.LayerType.DrawScale;
}
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Animations/SlideRightAnimation.cs b/Artemis/Artemis/Profiles/Layers/Animations/SlideRightAnimation.cs
index 6f99d7b3e..f9873e037 100644
--- a/Artemis/Artemis/Profiles/Layers/Animations/SlideRightAnimation.cs
+++ b/Artemis/Artemis/Profiles/Layers/Animations/SlideRightAnimation.cs
@@ -14,29 +14,29 @@ namespace Artemis.Profiles.Layers.Animations
var progress = layerModel.AnimationProgress;
if (MustExpire(layerModel))
progress = 0;
- progress = progress + layerModel.Properties.AnimationSpeed*2;
+ progress = progress + layerModel.Properties.AnimationSpeed * 2 / 4 * layerModel.LayerType.DrawScale;
// If not previewing, store the animation progress in the actual model for the next frame
if (updateAnimations)
layerModel.AnimationProgress = progress;
}
- public void Draw(LayerModel layerModel, DrawingContext c)
+ public void Draw(LayerModel layerModel, DrawingContext c, int drawScale)
{
if (layerModel.Brush == null)
return;
// Set up variables for this frame
var rect = layerModel.Properties.Contain
- ? layerModel.LayerRect()
- : layerModel.Properties.PropertiesRect();
+ ? layerModel.LayerRect(drawScale)
+ : layerModel.Properties.PropertiesRect(drawScale);
- var s1 = new Rect(new Point(rect.X + layerModel.AnimationProgress, rect.Y),
+ var s1 = new Rect(new Point(rect.X + layerModel.AnimationProgress, rect.Y),
new Size(rect.Width, rect.Height));
- var s2 = new Rect(new Point(s1.X - rect.Width, rect.Y),
+ var s2 = new Rect(new Point(s1.X - rect.Width, rect.Y),
new Size(rect.Width + .5, rect.Height));
- var clip = layerModel.LayerRect();
+ var clip = layerModel.LayerRect(drawScale);
c.PushClip(new RectangleGeometry(clip));
c.DrawRectangle(layerModel.Brush, null, s1);
@@ -46,7 +46,8 @@ namespace Artemis.Profiles.Layers.Animations
public bool MustExpire(LayerModel layer)
{
- return layer.AnimationProgress + layer.Properties.AnimationSpeed*2 >= layer.Properties.Width*4;
+ return layer.AnimationProgress + layer.Properties.AnimationSpeed * 2 >=
+ layer.Properties.Width * layer.LayerType.DrawScale;
}
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Animations/SlideUpAnimation.cs b/Artemis/Artemis/Profiles/Layers/Animations/SlideUpAnimation.cs
index 14de66902..e83c9188a 100644
--- a/Artemis/Artemis/Profiles/Layers/Animations/SlideUpAnimation.cs
+++ b/Artemis/Artemis/Profiles/Layers/Animations/SlideUpAnimation.cs
@@ -14,28 +14,28 @@ namespace Artemis.Profiles.Layers.Animations
var progress = layerModel.AnimationProgress;
if (MustExpire(layerModel))
progress = 0;
- progress = progress + layerModel.Properties.AnimationSpeed*2;
+ progress = progress + layerModel.Properties.AnimationSpeed * 2 / 4 * layerModel.LayerType.DrawScale;
// If not previewing, store the animation progress in the actual model for the next frame
if (updateAnimations)
layerModel.AnimationProgress = progress;
}
- public void Draw(LayerModel layerModel, DrawingContext c)
+ public void Draw(LayerModel layerModel, DrawingContext c, int drawScale)
{
if (layerModel.Brush == null)
return;
// Set up variables for this frame
var rect = layerModel.Properties.Contain
- ? layerModel.LayerRect()
- : layerModel.Properties.PropertiesRect();
+ ? layerModel.LayerRect(drawScale)
+ : layerModel.Properties.PropertiesRect(drawScale);
var s1 = new Rect(new Point(rect.X, rect.Y - layerModel.AnimationProgress),
new Size(rect.Width, rect.Height + .5));
var s2 = new Rect(new Point(s1.X, s1.Y + rect.Height), new Size(rect.Width, rect.Height));
- var clip = layerModel.LayerRect();
+ var clip = layerModel.LayerRect(drawScale);
c.PushClip(new RectangleGeometry(clip));
c.DrawRectangle(layerModel.Brush, null, s1);
@@ -45,7 +45,8 @@ namespace Artemis.Profiles.Layers.Animations
public bool MustExpire(LayerModel layer)
{
- return layer.AnimationProgress + layer.Properties.AnimationSpeed*2 >= layer.Properties.Height*4;
+ return layer.AnimationProgress + layer.Properties.AnimationSpeed * 2 >=
+ layer.Properties.Height * layer.LayerType.DrawScale;
}
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerAnimation.cs b/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerAnimation.cs
index f5d1c45c0..60d7c5910 100644
--- a/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerAnimation.cs
+++ b/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerAnimation.cs
@@ -10,7 +10,7 @@ namespace Artemis.Profiles.Layers.Interfaces
string Name { get; }
void Update(LayerModel layerModel, bool updateAnimations);
- void Draw(LayerModel layerModel, DrawingContext c);
+ void Draw(LayerModel layerModel, DrawingContext c, int drawScale);
bool MustExpire(LayerModel layerModel);
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerType.cs b/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerType.cs
index 83f8c9185..82fe9dfe1 100644
--- a/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerType.cs
+++ b/Artemis/Artemis/Profiles/Layers/Interfaces/ILayerType.cs
@@ -2,7 +2,7 @@
using Artemis.Modules.Abstract;
using Artemis.Profiles.Layers.Abstract;
using Artemis.Profiles.Layers.Models;
-using Artemis.ViewModels.Profiles;
+using Artemis.ViewModels;
using Newtonsoft.Json;
namespace Artemis.Profiles.Layers.Interfaces
@@ -28,6 +28,12 @@ namespace Artemis.Profiles.Layers.Interfaces
[JsonIgnore]
DrawType DrawType { get; }
+ ///
+ /// Gets the scale on which the layer should be drawn
+ ///
+ [JsonIgnore]
+ int DrawScale { get; }
+
///
/// The the thumbnail for this layer type
///
diff --git a/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs b/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs
index e7a02c9d6..71de0a2ce 100644
--- a/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs
+++ b/Artemis/Artemis/Profiles/Layers/Models/LayerConditionModel.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
using Artemis.Modules.Abstract;
using Artemis.Utilities;
using DynamicExpresso;
@@ -8,6 +9,7 @@ namespace Artemis.Profiles.Layers.Models
public class LayerConditionModel
{
private readonly Interpreter _interpreter;
+ private object _lastValue;
public LayerConditionModel()
{
@@ -23,39 +25,92 @@ namespace Artemis.Profiles.Layers.Models
{
lock (subject)
{
- if (string.IsNullOrEmpty(Field) || string.IsNullOrEmpty(Value) || string.IsNullOrEmpty(Type))
+ if (string.IsNullOrEmpty(Field) || string.IsNullOrEmpty(Type))
return false;
var inspect = GeneralHelpers.GetPropertyValue(subject, Field);
if (inspect == null)
+ {
+ _lastValue = null;
return false;
-
- // Put the subject in a list, allowing Dynamic Linq to be used.
- if (Type == "String")
- {
- return _interpreter.Eval($"subject.{Field}.ToLower(){Operator}(value)",
- new Parameter("subject", subject.GetType(), subject),
- new Parameter("value", Value.ToLower()));
}
- Parameter rightParam = null;
- switch (Type)
- {
- case "Enum":
- var enumType = GeneralHelpers.GetPropertyValue(subject, Field).GetType();
- rightParam = new Parameter("value", Enum.Parse(enumType, Value));
- break;
- case "Boolean":
- rightParam = new Parameter("value", bool.Parse(Value));
- break;
- case "Int32":
- rightParam = new Parameter("value", int.Parse(Value));
- break;
- }
+ bool returnValue;
+ if (Operator == "changed" || Operator == "decreased" || Operator == "increased")
+ returnValue = EvaluateEventOperator(subject, inspect);
+ else
+ returnValue = EvaluateOperator(subject);
- return _interpreter.Eval($"subject.{Field} {Operator} value",
- new Parameter("subject", subject.GetType(), subject), rightParam);
+ _lastValue = inspect;
+ return returnValue;
}
}
+
+ private bool EvaluateEventOperator(ModuleDataModel subject, object inspect)
+ {
+ // DynamicExpresso doesn't want a null so when it was previously null (should only happen first iteration)
+ // return false since that would be the only possible outcome
+ if (_lastValue == null)
+ return false;
+
+ // Assign the right parameter
+ var rightParam = new Parameter("value", _lastValue);
+
+ // Come up with the proper operator
+ var changeOperator = "";
+ if (Operator == "changed")
+ changeOperator = "!=";
+ else if (Operator == "decreased")
+ changeOperator = "<";
+ else if (Operator == "increased")
+ changeOperator = ">";
+
+ // Evaluate the result and store it
+ var returnValue = _interpreter.Eval($"subject.{Field} {changeOperator} value",
+ new Parameter("subject", subject.GetType(), subject), rightParam);
+
+ // Set the last value to the new value
+ _lastValue = inspect;
+ // Return the evaluated result
+ return returnValue;
+ }
+
+ private bool EvaluateOperator(ModuleDataModel subject)
+ {
+ // Since _lastValue won't be used, rely on Value to not be null
+ if (string.IsNullOrEmpty(Value))
+ return false;
+
+ // Put the subject in a list, allowing Dynamic Linq to be used.
+ if (Type == "String")
+ {
+ return _interpreter.Eval($"subject.{Field}.ToLower(){Operator}(value)",
+ new Parameter("subject", subject.GetType(), subject),
+ new Parameter("value", Value.ToLower()));
+ }
+
+ Parameter rightParam = null;
+ switch (Type)
+ {
+ case "Enum":
+ var enumType = GeneralHelpers.GetPropertyValue(subject, Field).GetType();
+ rightParam = new Parameter("value", Enum.Parse(enumType, Value));
+ break;
+ case "Boolean":
+ rightParam = new Parameter("value", bool.Parse(Value));
+ break;
+ case "Int32":
+ rightParam = new Parameter("value", int.Parse(Value));
+ break;
+ case "Single":
+ // Parse commas as decimals
+ rightParam = new Parameter("value", float.Parse(Value.Replace(",", "."),
+ CultureInfo.InvariantCulture));
+ break;
+ }
+
+ return _interpreter.Eval($"subject.{Field} {Operator} value",
+ new Parameter("subject", subject.GetType(), subject), rightParam);
+ }
}
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Models/TweenModel.cs b/Artemis/Artemis/Profiles/Layers/Models/TweenModel.cs
index 29e679164..9f180fb87 100644
--- a/Artemis/Artemis/Profiles/Layers/Models/TweenModel.cs
+++ b/Artemis/Artemis/Profiles/Layers/Models/TweenModel.cs
@@ -1,99 +1,126 @@
-using System;
-using Betwixt;
-
-namespace Artemis.Profiles.Layers.Models
-{
- public class TweenModel
- {
- private readonly LayerModel _layerModel;
- private Tweener _xTweener;
- private Tweener _yTweener;
- private float _width;
- private Tweener _widthTweener;
- private float _height;
- private Tweener _heightTweener;
- private float _opacity;
- private Tweener _opacityTweener;
- private float _x;
- private float _y;
-
- public TweenModel(LayerModel layerModel)
- {
- _layerModel = layerModel;
- _xTweener = new Tweener((float) layerModel.X, (float) layerModel.X, 0);
- _yTweener = new Tweener((float) layerModel.Y, (float) layerModel.Y, 0);
- _widthTweener = new Tweener((float) layerModel.Width, (float) layerModel.Width, 0);
- _heightTweener = new Tweener((float) layerModel.Height, (float) layerModel.Height, 0);
- _opacityTweener = new Tweener((float) layerModel.Opacity, (float) layerModel.Opacity, 0);
-
- StoreCurrentValues();
- }
-
- public void Update()
- {
- // Width
- if (Math.Abs(_layerModel.Width - _width) > 0.001)
- {
- var widthFunc = GetEaseFunction(_layerModel.Properties.WidthEase);
- var widthSpeed = _layerModel.Properties.WidthEaseTime;
-
- _xTweener = new Tweener(_xTweener.Value, (float) _layerModel.X, widthSpeed, widthFunc);
- _widthTweener = new Tweener(_widthTweener.Value, (float) _layerModel.Width, widthSpeed, widthFunc);
- }
-
- // Height
- if (Math.Abs(_layerModel.Height - _height) > 0.001)
- {
- var heightFunc = GetEaseFunction(_layerModel.Properties.HeightEase);
- var heightSpeed = _layerModel.Properties.HeightEaseTime;
- _yTweener = new Tweener(_y, (float) _layerModel.Y, heightSpeed, heightFunc);
- _heightTweener = new Tweener(_height, (float) _layerModel.Height, heightSpeed, heightFunc);
- }
-
- // Opacity
- if (Math.Abs(_layerModel.Opacity - _opacity) > 0.001)
- {
- _opacityTweener = new Tweener(_opacity, (float) _layerModel.Opacity,
- _layerModel.Properties.OpacityEaseTime, GetEaseFunction(_layerModel.Properties.OpacityEase));
- }
-
- _xTweener.Update(40);
- _yTweener.Update(40);
- _widthTweener.Update(40);
- _heightTweener.Update(40);
- _opacityTweener.Update(40);
-
- StoreCurrentValues();
-
- _layerModel.X = _xTweener.Value;
- _layerModel.Y = _yTweener.Value;
- _layerModel.Width = _widthTweener.Value;
- _layerModel.Height = _heightTweener.Value;
- _layerModel.Opacity = _opacityTweener.Value;
- }
-
- private void StoreCurrentValues()
- {
- _x = (float) _layerModel.X;
- _y = (float) _layerModel.Y;
- _width = (float) _layerModel.Width;
- _height = (float) _layerModel.Height;
- _opacity = (float) _layerModel.Opacity;
- }
-
- private static EaseFunc GetEaseFunction(string functionName)
- {
- switch (functionName)
- {
- case "In":
- return Ease.Quint.In;
- case "Out":
- return Ease.Quint.Out;
- case "In/out":
- return Ease.Quint.InOut;
- default:
- return Ease.Linear;
- }
- }
- }
+using System;
+using Betwixt;
+
+namespace Artemis.Profiles.Layers.Models
+{
+ public class TweenModel
+ {
+ private readonly LayerModel _layerModel;
+ private Tweener _xTweener;
+ private Tweener _yTweener;
+ private float _width;
+ private Tweener _widthTweener;
+ private float _height;
+ private Tweener _heightTweener;
+ private float _opacity;
+ private Tweener _opacityTweener;
+ private float _x;
+ private float _y;
+
+ public TweenModel(LayerModel layerModel)
+ {
+ _layerModel = layerModel;
+ _xTweener = new Tweener((float) layerModel.X, (float) layerModel.X, 0);
+ _yTweener = new Tweener((float) layerModel.Y, (float) layerModel.Y, 0);
+ _widthTweener = new Tweener((float) layerModel.Width, (float) layerModel.Width, 0);
+ _heightTweener = new Tweener((float) layerModel.Height, (float) layerModel.Height, 0);
+ _opacityTweener = new Tweener((float) layerModel.Opacity, (float) layerModel.Opacity, 0);
+
+ _x = (float)_layerModel.X;
+ _y = (float)_layerModel.Y;
+ _width = (float)_layerModel.Width;
+ _height = (float)_layerModel.Height;
+ _opacity = (float)_layerModel.Opacity;
+ }
+
+ public void Update()
+ {
+ UpdateWidth();
+ UpdateHeight();
+ UpdateOpacity();
+ }
+
+ private void UpdateWidth()
+ {
+ if (_layerModel.Properties.WidthEaseTime < 0.001)
+ return;
+
+ // Width
+ if (Math.Abs(_layerModel.Width - _width) > 0.001)
+ {
+ var widthFunc = GetEaseFunction(_layerModel.Properties.WidthEase);
+ var widthSpeed = _layerModel.Properties.WidthEaseTime;
+
+ _xTweener = new Tweener(_xTweener.Value, (float)_layerModel.X, widthSpeed, widthFunc);
+ _widthTweener = new Tweener(_widthTweener.Value, (float)_layerModel.Width, widthSpeed, widthFunc);
+ }
+
+ _xTweener.Update(40);
+ _widthTweener.Update(40);
+
+ _x = (float) _layerModel.X;
+ _width = (float)_layerModel.Width;
+
+ _layerModel.X = _xTweener.Value;
+ _layerModel.Width = _widthTweener.Value;
+ }
+
+ private void UpdateHeight()
+ {
+ if (_layerModel.Properties.HeightEaseTime < 0.001)
+ return;
+
+ // Height
+ if (Math.Abs(_layerModel.Height - _height) > 0.001)
+ {
+ var heightFunc = GetEaseFunction(_layerModel.Properties.HeightEase);
+ var heightSpeed = _layerModel.Properties.HeightEaseTime;
+ _yTweener = new Tweener(_y, (float)_layerModel.Y, heightSpeed, heightFunc);
+ _heightTweener = new Tweener(_height, (float)_layerModel.Height, heightSpeed, heightFunc);
+ }
+
+ _yTweener.Update(40);
+ _heightTweener.Update(40);
+
+ _y = (float)_layerModel.Y;
+ _height = (float)_layerModel.Height;
+
+ _layerModel.Y = _yTweener.Value;
+ _layerModel.Height = _heightTweener.Value;
+ }
+
+ private void UpdateOpacity()
+ {
+ if (_layerModel.Properties.OpacityEaseTime < 0.001)
+ return;
+
+ // Opacity
+ if (Math.Abs(_layerModel.Opacity - _opacity) > 0.001)
+ {
+ _opacityTweener = new Tweener(_opacity, (float)_layerModel.Opacity,
+ _layerModel.Properties.OpacityEaseTime, GetEaseFunction(_layerModel.Properties.OpacityEase));
+ }
+
+ _opacityTweener.Update(40);
+
+ _opacity = (float)_layerModel.Opacity;
+
+ _layerModel.Opacity = _opacityTweener.Value;
+ }
+
+ private static EaseFunc GetEaseFunction(string functionName)
+ {
+ switch (functionName)
+ {
+ case "In":
+ return Ease.Quint.In;
+ case "Out":
+ return Ease.Quint.Out;
+ case "In/out":
+ return Ease.Quint.InOut;
+ default:
+ return Ease.Linear;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesViewModel.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesViewModel.cs
index 7e71757d0..d4fcf84c1 100644
--- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesViewModel.cs
+++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightPropertiesViewModel.cs
@@ -1,4 +1,5 @@
using Artemis.Profiles.Layers.Abstract;
+using Artemis.ViewModels;
using Artemis.ViewModels.Profiles;
namespace Artemis.Profiles.Layers.Types.AmbientLight
diff --git a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs
index d1170138b..abfc93d5d 100644
--- a/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs
+++ b/Artemis/Artemis/Profiles/Layers/Types/AmbientLight/AmbientLightType.cs
@@ -13,7 +13,7 @@ using Artemis.Profiles.Layers.Types.AmbientLight.Model.Extensions;
using Artemis.Profiles.Layers.Types.AmbientLight.ScreenCapturing;
using Artemis.Properties;
using Artemis.Utilities;
-using Artemis.ViewModels.Profiles;
+using Artemis.ViewModels;
using Newtonsoft.Json;
namespace Artemis.Profiles.Layers.Types.AmbientLight
@@ -25,6 +25,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight
public string Name => "Keyboard - Ambient Light";
public bool ShowInEdtor => true;
public DrawType DrawType => DrawType.Keyboard;
+ public int DrawScale => 4;
[JsonIgnore] private AmbienceCreatorType? _lastAmbienceCreatorType;
@@ -76,11 +77,7 @@ namespace Artemis.Profiles.Layers.Types.AmbientLight
public void Draw(LayerModel layerModel, DrawingContext c)
{
- var rect = new Rect(layerModel.Properties.X*4,
- layerModel.Properties.Y*4,
- layerModel.Properties.Width*4,
- layerModel.Properties.Height*4);
-
+ var rect = layerModel.LayerRect(DrawScale);
c.DrawRectangle(((AmbientLightPropertiesModel) layerModel.Properties).AmbientLightBrush, null, rect);
}
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..8ad1700de
--- /dev/null
+++ b/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioCapturing/AudioCapture.cs
@@ -0,0 +1,216 @@
+using System;
+using System.Linq;
+using System.Timers;
+using CSCore;
+using CSCore.CoreAudioAPI;
+using CSCore.DSP;
+using CSCore.SoundIn;
+using CSCore.SoundOut;
+using CSCore.Streams;
+using Ninject.Extensions.Logging;
+
+namespace Artemis.Profiles.Layers.Types.Audio.AudioCapturing
+{
+ public class AudioCapture
+ {
+ private const FftSize FftSize = CSCore.DSP.FftSize.Fft1024;
+ private readonly Timer _volumeTimer;
+ private readonly double[] _volumeValues;
+ private readonly Timer _disableTimer;
+ private bool _mayStop;
+ private SingleSpectrum _singleSpectrum;
+ private ISoundIn _soundIn;
+ private GainSource _source;
+ private BasicSpectrumProvider _spectrumProvider;
+ private GainSource _volume;
+ private int _volumeIndex;
+
+ public AudioCapture(ILogger logger, MMDevice device, MmDeviceType type)
+ {
+ Logger = logger;
+ Device = device;
+ Type = type;
+ DesiredAverage = 0.75;
+
+ _volumeValues = new double[5];
+ _volumeIndex = 0;
+ _disableTimer = new Timer(1000);
+ _disableTimer.Elapsed += CheckStop;
+ _volumeTimer = new Timer(200);
+ _volumeTimer.Elapsed += VolumeTimerOnElapsed;
+ }
+
+ public ILogger Logger { get; }
+ public MMDevice Device { get; }
+ public MmDeviceType Type { get; }
+ public double DesiredAverage { get; set; }
+
+ public float Volume
+ {
+ get { return _volume.Volume; }
+ set { _volume.Volume = value; }
+ }
+
+ public bool Running { get; set; }
+
+ private void VolumeTimerOnElapsed(object sender, ElapsedEventArgs e)
+ {
+ if (Volume <= 0)
+ Volume = 1;
+
+ var currentValue = _singleSpectrum.GetValue();
+ if (currentValue == null)
+ return;
+
+ _volumeValues[_volumeIndex] = currentValue.Value;
+
+ if (_volumeIndex == 4)
+ {
+ _volumeIndex = 0;
+ }
+ else
+ {
+ _volumeIndex++;
+ return;
+ }
+
+ var averageVolume = _volumeValues.Average();
+ // Don't adjust when there is virtually no audio
+ if (averageVolume < 0.01)
+ return;
+ // Don't bother when the volume with within a certain marigin
+ if (averageVolume > DesiredAverage - 0.1 && averageVolume < DesiredAverage + 0.1)
+ return;
+
+ if (averageVolume < DesiredAverage && Volume < 50)
+ {
+ Logger.Trace("averageVolume:{0} | DesiredAverage:{1} | Volume:{2} so increase.", currentValue,
+ DesiredAverage, Volume);
+ Volume++;
+ }
+ else if (Volume > 1)
+ {
+ Logger.Trace("averageVolume:{0} | DesiredAverage:{1} | Volume:{2} so decrease.", currentValue,
+ DesiredAverage, Volume);
+ Volume--;
+ }
+ }
+
+ public LineSpectrum GetLineSpectrum(int barCount, ScalingStrategy scalingStrategy)
+ {
+ if (_spectrumProvider == null)
+ return null;
+ return new LineSpectrum(FftSize)
+ {
+ SpectrumProvider = _spectrumProvider,
+ UseAverage = true,
+ BarCount = barCount,
+ IsXLogScale = true,
+ ScalingStrategy = scalingStrategy
+ };
+ }
+
+ ///
+ /// Keeps the audio capture active, when not called for longer than 1 sec the capture will
+ /// stop capturing until Pulse is called again
+ ///
+ public void Pulse()
+ {
+ _mayStop = false;
+ if (!Running)
+ Start();
+ }
+
+ private void CheckStop(object sender, ElapsedEventArgs e)
+ {
+ if (_mayStop)
+ {
+ Logger.Debug("Stopping idle audio capture for device: {0}", Device?.FriendlyName ?? "default");
+ Stop();
+ }
+ else
+ _mayStop = true;
+ }
+
+ private void Start()
+ {
+ Logger.Debug("Starting audio capture for device: {0}", Device?.FriendlyName ?? "default");
+
+ try
+ {
+ Stop();
+
+ if (Type == MmDeviceType.Input)
+ {
+ _soundIn = Device != null
+ ? new WasapiCapture {Device = Device}
+ : new WasapiCapture();
+ }
+ else
+ {
+ _soundIn = Device != null
+ ? new WasapiLoopbackCapture {Device = Device}
+ : new WasapiLoopbackCapture();
+ }
+
+ _soundIn.Initialize();
+
+ 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)
+ {
+ }
+ };
+
+ _singleSpectrum = new SingleSpectrum(FftSize, _spectrumProvider);
+ _mayStop = false;
+
+ _disableTimer.Start();
+ _volumeTimer.Start();
+ _soundIn.Start();
+
+ Running = true;
+ }
+ catch (Exception e)
+ {
+ Logger.Warn(e, "Failed to start WASAPI audio capture");
+ }
+ }
+
+ private void Stop()
+ {
+ Running = false;
+
+
+ if (_soundIn != null)
+ {
+ _soundIn.Stop();
+ _soundIn.Dispose();
+ _soundIn = null;
+ }
+ if (_source != null)
+ {
+ _source.Dispose();
+ _source = null;
+ }
+
+ _disableTimer.Stop();
+ _volumeTimer.Stop();
+ }
+ }
+}
\ 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
deleted file mode 100644
index 04ca51a5d..000000000
--- a/Artemis/Artemis/Profiles/Layers/Types/Audio/AudioCapturing/AudioCaptureManager.cs
+++ /dev/null
@@ -1,133 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-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 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