public void CopyTo(LightData destination) { destination.Time = Time; if (ColourData != null) { byte[] colourData = new byte[ColourData.Length]; Buffer.BlockCopy(ColourData, 0, colourData, 0, ColourData.Length); destination.ColourData = colourData; } }
/// <summary> /// Thread safe retrieval of the previous frame's final adjusted light data /// </summary> /// <returns>A copy of the current light data (can be null if no light data)</returns> /// <remarks>Frequent calling of this method may have a performance impact due to thread synchronisation.</remarks> public LightData GetPreviousLightData() { lock (previousSync) { if (_prevLightData == null) { return(null); } LightData data = new LightData(_prevLightData); return(data); } }
private void OutputLoop() { try { //Get Light Setup Plugin ILightSetupPlugin lightSetupPlugin = CurrentProfile.LightSetupPlugin; Stopwatch timer = new Stopwatch(); double waitTicks = 1.0 / CurrentProfile.OutputFrequency; double freq = 1.0 / Stopwatch.Frequency; long lastUpdate = 0; // Initialise temporary lightData LightData lightData = new LightData(lightSetupPlugin.Lights.Count); while (Active) { timer.Restart(); // If available, replace _currentLightData with _nextLightData lock (sync) { if (lastUpdate < _nextLightData.Time) { var t = lightData; lightData = _nextLightData; _nextLightData = t; lastUpdate = lightData.Time; } } if (lightData != null) { // Run pre-output plugins CurrentProfile.PreOutputPlugins.ToList().ForEach(po => po.PreOutput(lightSetupPlugin.Lights, lightData)); //Run Output Plugin(s) CurrentProfile.OutputPlugins.ToList().ForEach(o => o.Output(lightSetupPlugin.Lights, lightData)); } // Copy the last frame to _prevLightData lock (previousSync) { Buffer.BlockCopy(lightData.ColourData, 0, _prevLightData.ColourData, 0, lightData.ColourData.Length); } // Throttle Output Frequency while (timer.ElapsedTicks * freq < waitTicks) { Task.Delay(5); } _outputLoopFPS.Tick(); } } catch (Exception e) { lock (sync) { Active = false; AfterglowRuntime.Logger.Error(e, "Afterglow Runtime - Output Loop"); } } finally { // Allow plugins to clean up CurrentProfile.PreOutputPlugins.ForEach(po => po.Stop()); CurrentProfile.OutputPlugins.ForEach(o => o.Stop()); } }
private void CaptureLoop() { try { //Get Light Setup Plugin ILightSetupPlugin lightSetupPlugin = CurrentProfile.LightSetupPlugin; Stopwatch timer = Stopwatch.StartNew(); long lastTicks = 0; double waitTicks = 1.0 / CurrentProfile.CaptureFrequency; double freq = 1.0 / Stopwatch.Frequency; LightData newLightData = new LightData(_nextLightData); while (Active) { lastTicks = timer.ElapsedTicks; //Get screen segments IDictionary <Light, PixelReader> ledSources = CurrentProfile.CapturePlugin.Capture(lightSetupPlugin); newLightData.Time = timer.ElapsedTicks; try { //Extract Colours from segments int i = 0; foreach (var keyValue in ledSources) { newLightData[i] = CurrentProfile.ColourExtractionPlugin.Extract(keyValue.Key, keyValue.Value); i++; } } finally { //Dispose of screen segments foreach (var keyValue in ledSources) { keyValue.Value.Dispose(); } //Dispose of whole screen CurrentProfile.CapturePlugin.ReleaseCapture(); } //Run any Post Process Plugins foreach (var postProcessPlugin in CurrentProfile.PostProcessPlugins) { (postProcessPlugin as IPostProcessPlugin).Process(lightSetupPlugin.Lights, newLightData); } // Thread safe swap of new light data into _nextLightData lock (sync) { var t = _nextLightData; _nextLightData = newLightData; newLightData = t; } // Throttle Capture Frequency while ((timer.ElapsedTicks - lastTicks) * freq < waitTicks) { Task.Delay(5); } // Update capture FPS counter _captureLoopFPS.Tick(); } } catch (Exception e) { lock (sync) { Active = false; AfterglowRuntime.Logger.Error(e, "Afterglow Runtime - Capture Loop"); } } finally { // Allow plugins to clean up CurrentProfile.CapturePlugins.ForEach(cp => cp.Stop()); CurrentProfile.PostProcessPlugins.ForEach(pp => pp.Stop()); } }
/// <summary> /// Start running the current profile /// </summary> public void Start() { Stop(); Logger.Info("Starting..."); bool profileJustSet = false; if (this.CurrentProfile == null) { this.CurrentProfile = (from p in this.Setup.Profiles where p.Id == this.Setup.CurrentProfileId select p).FirstOrDefault(); profileJustSet = true; } if (this.CurrentProfile == null) { CurrentProfile = this.Setup.Profiles.FirstOrDefault(); profileJustSet = true; } if (CurrentProfile == null) { Logger.Error("No profile has been selected"); return; } else { //Reset current profile incase there has been any setting changes if (!profileJustSet) { this.CurrentProfile = (from p in this.Setup.Profiles where p.Id == this.CurrentProfile.Id select p).First(); } CurrentProfile.Validate(); if (!Active) { Active = true; // Prepare light data buffer _nextLightData = new LightData(CurrentProfile.LightSetupPlugin.Lights.Count); _prevLightData = new LightData(CurrentProfile.LightSetupPlugin.Lights.Count);; // Start all plugins CurrentProfile.CapturePlugin.Start(); CurrentProfile.ColourExtractionPlugin.Start(); CurrentProfile.PostProcessPlugins.ToList().ForEach(p => p.Start()); CurrentProfile.PreOutputPlugins.ToList().ForEach(p => p.Start()); string errorMessage = String.Empty; int outputFailures = 0; List <IOutputPlugin> outputPluginsInError = new List <IOutputPlugin>(); foreach (IOutputPlugin outputPlugin in CurrentProfile.OutputPlugins) { if (!outputPlugin.TryStart()) { outputFailures++; outputPluginsInError.Add(outputPlugin); } } //If all output plugins are in error then stop if (outputFailures == CurrentProfile.OutputPlugins.Count()) { Stop(); } else { //Remove plugins in error and allow other plugins to continue to run outputPluginsInError.ForEach(o => this.CurrentProfile.OutputPlugins.Remove(o)); // Commence capture and output threads _captureLoopTask = Task.Factory.StartNew(CaptureLoop); _outputLoopTask = Task.Factory.StartNew(OutputLoop); } } } }
public LightData(LightData copyFrom) { copyFrom.CopyTo(this); }