private void TrimEndTime_KeyDown(object sender, Windows.UI.Xaml.Input.KeyRoutedEventArgs e) { if (e.Key == Windows.System.VirtualKey.Enter) { CutRange.Focus(FocusState.Programmatic); } }
private void CutRange_ValueChanged(object sender, Microsoft.Toolkit.Uwp.UI.Controls.RangeChangedEventArgs e) { TrimStartTime.LostFocus -= TrimStartTime_LostFocus; TrimEndTime.LostFocus -= TrimEndTime_LostFocus; CutRange.Focus(FocusState.Programmatic); TrimStartTime.LostFocus += TrimStartTime_LostFocus; TrimEndTime.LostFocus += TrimEndTime_LostFocus; if (e.ChangedRangeProperty == Microsoft.Toolkit.Uwp.UI.Controls.RangeSelectorProperty.MaximumValue) { UpdatePreviewVideoOnDisplay(true, CutRange.RangeMax, null); } else { UpdatePreviewVideoOnDisplay(false, null, CutRange.RangeMin); } }
/// <summary> /// This method doesn't say the specific cut, but it constraints /// the time for searching interesting events. It is mostly /// dependent on current emotion. /// </summary> public CutRange EvaluateCutRangeForEvent(EmotionEvent e) { CutRange range = new CutRange(); EmotionSpectrum emotionAtEventTime = emotionEngine.GetSpectrum(e.timestamp); CoreEmotion coreEmotion = EmotionEngine.FindMainEmotion(emotionAtEventTime); // In seconds switch (coreEmotion) { case CoreEmotion.Joy: range.minCutTime = ProceduralEngine.RandomRange(1f, 2f); range.maxCutTime = ProceduralEngine.RandomRange(7f, 8f); break; case CoreEmotion.Trust: range.minCutTime = ProceduralEngine.RandomRange(2f, 5f); range.maxCutTime = ProceduralEngine.RandomRange(7f, 10f); break; case CoreEmotion.Fear: range.minCutTime = ProceduralEngine.RandomRange(1f, 2f); range.maxCutTime = ProceduralEngine.RandomRange(4f, 6f); break; case CoreEmotion.Surprise: range.minCutTime = ProceduralEngine.RandomRange(1.5f, 2f); range.maxCutTime = ProceduralEngine.RandomRange(2f, 4f); break; case CoreEmotion.Sadness: range.minCutTime = ProceduralEngine.RandomRange(1f, 1.5f); range.maxCutTime = ProceduralEngine.RandomRange(2f, 4f); break; case CoreEmotion.Disgust: range.minCutTime = ProceduralEngine.RandomRange(1f, 2f); range.maxCutTime = ProceduralEngine.RandomRange(3f, 4f); break; case CoreEmotion.Anger: range.minCutTime = ProceduralEngine.RandomRange(.3f, 1f); range.maxCutTime = ProceduralEngine.RandomRange(1f, 3f); break; case CoreEmotion.Anticipation: range.minCutTime = ProceduralEngine.RandomRange(2f, 4f); range.maxCutTime = ProceduralEngine.RandomRange(4f, 5f); break; } switch (e.type) { case EmotionEvent.EmotionEventType.Start: // Longer cuts when showing for first time range.minCutTime *= e.chunkDelimitsSegment ? 1f : .75f; range.maxCutTime *= e.chunkDelimitsSegment ? 1f : .75f; break; case EmotionEvent.EmotionEventType.End: // Longer cuts when something disappears for good range.minCutTime *= e.chunkDelimitsSegment ? 1.5f : 1f; range.maxCutTime *= e.chunkDelimitsSegment ? 1.5f : 1f; break; case EmotionEvent.EmotionEventType.LocalMaximum: range.minCutTime *= 1f; range.maxCutTime *= 1f; break; case EmotionEvent.EmotionEventType.LocalMinimum: range.minCutTime *= 2f; range.maxCutTime *= 2f; break; } TrackChunkData structureData = emotionEngine.GetCurrentStructureData(e.timestamp); if (structureData != null) { // More intense -> shorter float normalizedStructuralIntensity = Mathf.Pow(structureData.GetIntensity(e.timestamp), 2f); range.minCutTime *= 1.35f - normalizedStructuralIntensity * .5f; range.maxCutTime *= 1.35f - normalizedStructuralIntensity * .5f; // TODO: decide if we need further modifications of cut time based on type. // Intensity curve should cover most I think StructureType currentStructure = emotionEngine.GetStructureAtTime(e.timestamp); switch (currentStructure) { case StructureType.None: break; case StructureType.Sustain: break; case StructureType.Increasing: break; case StructureType.Decreasing: break; } } range.minCutTime = Mathf.Max(0.01f, range.minCutTime); range.maxCutTime = Mathf.Max(0.02f, range.maxCutTime); float tmp = range.minCutTime; range.minCutTime = Mathf.Min(range.minCutTime, range.maxCutTime); range.maxCutTime = Mathf.Max(tmp, range.maxCutTime); // Normalize times range.minCutTime /= ProceduralEngine.Instance.Duration; range.maxCutTime /= ProceduralEngine.Instance.Duration; return(range); }
/// <summary> /// This method has two main responsibilities: /// - Decide when to cut /// - Decide what shot to take /// It is tied to a specific event, so that the chaining of shots is possible /// </summary> protected ShotInformation TryFindCut(EmotionEvent startEvent) { ShotInformation shot = new ShotInformation(); shot.valid = false; shot.selectedCamera = null; shot.type = TransitionType.Cut; // TODO: for now... shot.strategy = null; shot.interestPoint = null; shot.sampledStrategies = new List <KeyValuePair <ProceduralCameraStrategy, float> >(); shot.startEvent = startEvent; // Make sure we don't lag float timestamp = Mathf.Max(startEvent.timestamp, ProceduralEngine.Instance.CurrentTimeNormalized); CutRange searchRange = EvaluateCutRangeForEvent(startEvent); float minT = timestamp + searchRange.minCutTime; float maxT = timestamp + searchRange.maxCutTime * (1f + nextShotTries * .1f); // Increase search range when it fails List <EmotionEventGroup> searchEvents = ProceduralEngine.Instance.EventDispatcher.GetFutureEventGroups(minT, maxT); if (searchEvents.Count == 0) { Debug.Log("Could not find event groups... " + minT + ", " + maxT); return(shot); } EmotionEventGroup selectedGroup = null; bool structural = false; foreach (EmotionEventGroup g in searchEvents) { if (g.ContainsStructuralEvent()) { selectedGroup = g; structural = true; } } if (selectedGroup == null) { selectedGroup = ProceduralEngine.SelectRandomWeighted(searchEvents, x => x.GetPriority()); } // We found a subset of interesting events, now we can pick something in here if (selectedGroup != null && selectedGroup.events.Count > 0) { EmotionEvent selectedEvent; if (structural) { selectedEvent = selectedGroup.GetStructuralEvent(); } else { selectedEvent = ProceduralEngine.SelectRandomWeighted(selectedGroup.events, x => GetEventPriority(x)); } shot.duration = (selectedEvent.timestamp - timestamp); shot.selectedNextEventTrigger = selectedEvent; // Try cutting before, but not after float margin = emotionEngine.BeatDurationNormalized * .5f; float fuzzyDuration = shot.duration - ProceduralEngine.RandomRange(0f, margin); if (fuzzyDuration > searchRange.minCutTime && fuzzyDuration < searchRange.maxCutTime) { shot.duration = fuzzyDuration; } shot.valid = true; } return(shot); }