static bool CurveDisplay(IAudioEffectPlugin plugin, Rect r0, ref float threshold, ref float ratio, ref float makeupGain, ref float attackTime, ref float releaseTime, ref float knee, float sidechainLevel, float outputLevel, float blend) { Event evt = Event.current; int controlID = GUIUtility.GetControlID(FocusType.Passive); Rect r = AudioCurveRendering.BeginCurveFrame(r0); const float thresholdActiveWidth = 10f; float vuWidth = 10f; float minThreshold, maxThreshold, defThreshold; plugin.GetFloatParameterInfo(kThresholdName, out minThreshold, out maxThreshold, out defThreshold); float minRatio, maxRatio, defRatio; plugin.GetFloatParameterInfo(kRatioName, out minRatio, out maxRatio, out defRatio); float minMakeupGain, maxMakeupGain, defMakeupGain; plugin.GetFloatParameterInfo(kMakeupGainName, out minMakeupGain, out maxMakeupGain, out defMakeupGain); float minKnee, maxKnee, defKnee; plugin.GetFloatParameterInfo(kKneeName, out minKnee, out maxKnee, out defKnee); float dbRange = 100.0f, dbMin = -80.0f; float thresholdPosX = r.width * (threshold - dbMin) / dbRange; bool modifiedValue = false; switch (evt.GetTypeForControl(controlID)) { case EventType.MouseDown: if (r.Contains(Event.current.mousePosition) && evt.button == 0) { dragtype = DragType.None; GUIUtility.hotControl = controlID; EditorGUIUtility.SetWantsMouseJumping(1); evt.Use(); // Ensure visible state change on mousedown to make it clear that interaction is possible if ((Mathf.Abs(r.x + thresholdPosX - evt.mousePosition.x) >= thresholdActiveWidth)) { dragtype = (evt.mousePosition.x < r.x + thresholdPosX) ? DragType.MakeupGain : DragType.Ratio; } else { dragtype = DragType.ThresholdAndKnee; } } break; case EventType.MouseUp: if (GUIUtility.hotControl == controlID && evt.button == 0) { dragtype = DragType.None; GUIUtility.hotControl = 0; EditorGUIUtility.SetWantsMouseJumping(0); evt.Use(); AudioMixerEffectPlugin.OnParameterChangesDone(); } break; case EventType.MouseDrag: if (GUIUtility.hotControl == controlID) { float dragAcceleration = evt.alt ? .25f : 1f; if (dragtype == DragType.ThresholdAndKnee) { bool dragKnee = Mathf.Abs(evt.delta.x) < Mathf.Abs(evt.delta.y); if (dragKnee) { knee = Mathf.Clamp(knee + evt.delta.y * 0.5f * dragAcceleration, minKnee, maxKnee); } else { threshold = Mathf.Clamp(threshold + evt.delta.x * 0.1f * dragAcceleration, minThreshold, maxThreshold); } } else if (dragtype == DragType.Ratio) { ratio = Mathf.Clamp(ratio + evt.delta.y * (ratio > 1.0f ? 0.05f : 0.003f) * dragAcceleration, minRatio, maxRatio); } else if (dragtype == DragType.MakeupGain) { makeupGain = Mathf.Clamp(makeupGain - evt.delta.y * 0.5f * dragAcceleration, minMakeupGain, maxMakeupGain); } else { Debug.LogError("Drag: Unhandled enum"); } modifiedValue = true; evt.Use(); } break; } if (evt.type == EventType.Repaint) { // Curve HandleUtility.ApplyWireMaterial(); //float sidechainPosX = r.width * (sidechainLevel - dbMin) / dbRange; float thresholdPosY = r.height * (1.0f - ((threshold - dbMin + makeupGain) / dbRange)); Color thresholdColor = new Color(0.7f, 0.7f, 0.7f); Color sidechainColor = Color.black; float duckGradient = 1.0f / ratio; float duckThreshold = threshold; float duckSidechainLevel = sidechainLevel; float duckMakeupGain = makeupGain; float duckKnee = knee; float duckKneeC1 = (knee > 0.0f) ? ((duckGradient - 1.0f) / (4.0f * knee)) : 0.0f; float duckKneeC2 = duckThreshold - knee; // Main filled curve AudioCurveRendering.DrawFilledCurve( r, delegate(float x, out Color col) { float level = x * dbRange + dbMin; float gain = level; float t = level - duckThreshold; col = ScaleAlpha(duckSidechainLevel > level ? AudioCurveRendering.kAudioOrange : Color.grey, blend); if (t > -duckKnee && t < duckKnee) { t += duckKnee; gain = t * (duckKneeC1 * t + 1.0f) + duckKneeC2; if (dragtype == DragType.ThresholdAndKnee) { const float mult = 1.2f; col = new Color(col.r * mult, col.g * mult, col.b * mult); } } else if (t > 0.0f) { gain = duckThreshold + duckGradient * t; } return((2.0f * (gain + duckMakeupGain - dbMin) / dbRange) - 1.0f); } ); // Curve shown when modifying MakeupGain if (dragtype == DragType.MakeupGain) { AudioCurveRendering.DrawCurve( r, delegate(float x) { float level = x * dbRange + dbMin; float gain = level; float t = level - duckThreshold; if (t > -duckKnee && t < duckKnee) { t += duckKnee; gain = t * (duckKneeC1 * t + 1.0f) + duckKneeC2; } else if (t > 0.0f) { gain = duckThreshold + duckGradient * t; } return((2.0f * (gain + duckMakeupGain - dbMin) / dbRange) - 1.0f); }, Color.white ); } // Threshold text and line textStyle10.normal.textColor = ScaleAlpha(thresholdColor, blend); EditorGUI.DrawRect(new Rect(r.x + thresholdPosX, r.y, 1, r.height), textStyle10.normal.textColor); DrawText(r.x + thresholdPosX + 4, r.y + 6, string.Format(CultureInfo.InvariantCulture.NumberFormat, "Threshold: {0:F1} dB", threshold)); // Sidechain text and line textStyle10.normal.textColor = ScaleAlpha(sidechainColor, blend); DrawText(r.x + 4, r.y + r.height - 10, sidechainLevel < -80 ? "Input: None" : string.Format(CultureInfo.InvariantCulture.NumberFormat, "Input: {0:F1} dB", sidechainLevel)); if (dragtype == DragType.Ratio) { float aspect = r.height / r.width; Handles.DrawAAPolyLine(2.0f, new[] { Color.black, Color.black }, new[] { new Vector3(r.x + thresholdPosX + r.width, r.y + thresholdPosY - aspect * r.width, 0.0f), new Vector3(r.x + thresholdPosX - r.width, r.y + thresholdPosY + aspect * r.width, 0.0f) }); Handles.DrawAAPolyLine(3.0f, new[] { Color.white, Color.white }, new[] { new Vector3(r.x + thresholdPosX + r.width, r.y + thresholdPosY - aspect * duckGradient * r.width, 0.0f), new Vector3(r.x + thresholdPosX - r.width, r.y + thresholdPosY + aspect * duckGradient * r.width, 0.0f) }); } else if (dragtype == DragType.ThresholdAndKnee) { // Knee min and max lines float normalizedKnee1 = (threshold - knee - dbMin) / dbRange; float normalizedKnee2 = (threshold + knee - dbMin) / dbRange; float y1 = EvaluateDuckingVolume(normalizedKnee1, ratio, threshold, makeupGain, knee, dbRange, dbMin); float y2 = EvaluateDuckingVolume(normalizedKnee2, ratio, threshold, makeupGain, knee, dbRange, dbMin); float knee1PosY = r.yMax - (y1 + 1f) * 0.5f * r.height; float knee2PosY = r.yMax - (y2 + 1f) * 0.5f * r.height; EditorGUI.DrawRect(new Rect(r.x + normalizedKnee1 * r.width, knee1PosY, 1, r.height - knee1PosY), new Color(0, 0, 0, 0.5f)); EditorGUI.DrawRect(new Rect(r.x + normalizedKnee2 * r.width - 1, knee2PosY, 1, r.height - knee2PosY), new Color(0, 0, 0, 0.5f)); // Enhanced threshold EditorGUI.DrawRect(new Rect(r.x + thresholdPosX - 1, r.y, 3, r.height), Color.white); } outputLevel = (Mathf.Clamp(outputLevel - makeupGain, dbMin, dbMin + dbRange) - dbMin) / dbRange; if (EditorApplication.isPlaying) { const int margin = 2; Rect vuRect = new Rect(r.x + r.width - vuWidth + margin, r.y + margin, vuWidth - 2 * margin, r.height - 2 * margin); DrawVU(vuRect, outputLevel, blend, true); } } AudioCurveRendering.EndCurveFrame(); return(modifiedValue); }
static bool ParamEqualizerCurveEditor(IAudioEffectPlugin plugin, Rect r, ref float centerFreq, ref float bandwidth, ref float gain, float blend) { Event evt = Event.current; int controlID = GUIUtility.GetControlID(FocusType.Passive); r = AudioCurveRendering.BeginCurveFrame(r); float minCenterFreq, maxCenterFreq, defCenterFreq; plugin.GetFloatParameterInfo(kCenterFreqName, out minCenterFreq, out maxCenterFreq, out defCenterFreq); float minOctaveRange, maxOctaveRange, defOctaveRange; plugin.GetFloatParameterInfo(kOctaveRangeName, out minOctaveRange, out maxOctaveRange, out defOctaveRange); float minGain, maxGain, defGain; plugin.GetFloatParameterInfo(kFrequencyGainName, out minGain, out maxGain, out defGain); bool modifiedValue = false; switch (evt.GetTypeForControl(controlID)) { case EventType.MouseDown: if (r.Contains(Event.current.mousePosition) && evt.button == 0) { GUIUtility.hotControl = controlID; EditorGUIUtility.SetWantsMouseJumping(1); evt.Use(); } break; case EventType.MouseUp: // Signal if (GUIUtility.hotControl == controlID && evt.button == 0) { GUIUtility.hotControl = 0; EditorGUIUtility.SetWantsMouseJumping(0); evt.Use(); AudioMixerEffectPlugin.OnParameterChangesDone(); } break; case EventType.MouseDrag: if (GUIUtility.hotControl == controlID) { float dragAcceleration = Event.current.alt ? .25f : 1f; centerFreq = Mathf.Clamp((float)MapNormalizedFrequency(MapNormalizedFrequency(centerFreq, plugin.GetSampleRate(), useLogScale, false) + evt.delta.x / r.width, plugin.GetSampleRate(), useLogScale, true), minCenterFreq, maxCenterFreq); if (Event.current.shift) { bandwidth = Mathf.Clamp(bandwidth - evt.delta.y * 0.02f * dragAcceleration, minOctaveRange, maxOctaveRange); } else { gain = Mathf.Clamp(gain - evt.delta.y * 0.01f * dragAcceleration, minGain, maxGain); } modifiedValue = true; evt.Use(); } break; } if (Event.current.type == EventType.Repaint) { // Mark CenterFreq with a vertical line float c = (float)MapNormalizedFrequency(centerFreq, plugin.GetSampleRate(), useLogScale, false); EditorGUI.DrawRect(new Rect(c * r.width + r.x, r.y, 1f, r.height), GUIUtility.hotControl == controlID ? new Color(0.6f, 0.6f, 0.6f) : new Color(0.4f, 0.4f, 0.4f)); // Curve HandleUtility.ApplyWireMaterial(); double kPI = 3.1415926; double wm = -2.0f * kPI / plugin.GetSampleRate(); double w0 = 2.0 * kPI * centerFreq / plugin.GetSampleRate(); double Q = 1.0 / bandwidth; double A = gain; double alpha = Math.Sin(w0) / (2.0 * Q); double b0 = 1.0 + alpha * A; double b1 = -2.0 * Math.Cos(w0); double b2 = 1.0 - alpha * A; double a0 = 1.0 + alpha / A; double a1 = -2.0 * Math.Cos(w0); double a2 = 1.0 - alpha / A; AudioCurveRendering.DrawCurve( r, delegate(float x) { double f = MapNormalizedFrequency(x, plugin.GetSampleRate(), useLogScale, true); ComplexD w = ComplexD.Exp(wm * f); ComplexD n = w * (w * b2 + b1) + b0; ComplexD d = w * (w * a2 + a1) + a0; ComplexD h = n / d; double mag = Math.Log10(h.Mag2()); return((float)(0.5 * mag)); // 20 dB range }, ScaleAlpha(AudioCurveRendering.kAudioOrange, blend) ); } DrawFrequencyTickMarks(r, plugin.GetSampleRate(), useLogScale, new Color(1.0f, 1.0f, 1.0f, 0.3f * blend)); AudioCurveRendering.EndCurveFrame(); return(modifiedValue); }