AudioKit:如何将AnalogSynthX示例中的Knob改为指数型而非线性型?
嘿,这个问题问得很到位——毕竟音频参数(比如音量)的人耳感知是非线性的,选对曲线缩放的处理位置确实能让旋钮操作更符合直觉。在AudioKit AnalogSynthX的Knob.swift里,最佳的处理位置有两个方向,其中贴合你提到的setPercentagesWithTouchPoint(_:)方法的方案,以及更优雅的封装方案都值得参考:
setPercentagesWithTouchPoint中拆分线性输入与曲线转换 你考虑的这个方法确实是合理的切入点,但需要调整逻辑,避免直接把触摸的线性变化直接映射到曲线参数上(会导致拖动手感怪异):
首先,我们在Knob类里新增一个内部变量,用来存储触摸拖动产生的线性百分比值(范围0-1),然后单独提供一个经过曲线缩放的属性给外部使用:
// 内部存储线性拖动的百分比(0.0到1.0) private var linearDragPercentage: Double = 0.0 // 对外暴露的经过曲线缩放的参数值 var scaledParameterValue: Double { guard linearDragPercentage > 0 else { return 0 } // 这里用三次方曲线模拟对数感知(人耳对音量的感知更接近对数) // 你也可以根据需求换用log10或者其他指数曲线 return pow(linearDragPercentage, 3.0) }
然后修改setPercentagesWithTouchPoint的逻辑,只更新线性百分比,再通过scaledParameterValue向外提供曲线化的值:
func setPercentagesWithTouchPoint(_ touchPoint: CGPoint) { // Knobs assume up or right is increasing, and down or left is decreasing let horizontalChange = Double(touchPoint.x - lastX) * knobSensitivity linearDragPercentage += horizontalChange // 把值限制在0-1的合理范围内 linearDragPercentage = max(0.0, min(1.0, linearDragPercentage)) lastX = touchPoint.x lastY = touchPoint.y // 通知外部值已更新 sendActions(for: .valueChanged) }
这么做的好处是:用户拖动旋钮的操作是线性直观的(拖动距离和感知上的参数变化匹配),但最终作用到音频引擎的是符合人耳感知的曲线值,两全其美。
如果你不想改动触摸处理的核心逻辑,更推荐把曲线转换封装在value属性的getter/setter里——让Knob内部存储线性百分比,对外暴露的value直接是曲线化后的参数:
// 内部存储线性拖动百分比 private var linearValue: Double = 0.0 // 对外的参数值,自动处理曲线转换 var value: Double { get { guard linearValue > 0 else { return 0 } // 应用曲线转换,这里示例用三次方,可按需调整 return pow(linearValue, 3.0) } set { // 外部设置值时,反向转换回线性百分比 linearValue = pow(newValue, 1.0/3.0) linearValue = max(0.0, min(1.0, linearValue)) } } func setPercentagesWithTouchPoint(_ touchPoint: CGPoint) { let horizontalChange = Double(touchPoint.x - lastX) * knobSensitivity linearValue += horizontalChange linearValue = max(0.0, min(1.0, linearValue)) lastX = touchPoint.x lastY = touchPoint.y sendActions(for: .valueChanged) }
这种方式的优势是:外部代码完全不需要关心曲线转换的细节,直接使用value即可,触摸处理的代码也保持了简洁性,后期调整曲线类型也只需要修改计算属性的逻辑,非常便于维护。
如果你直接在value += horizontalChange之后对value应用曲线转换,会导致拖动相同的距离,在旋钮的不同位置产生的参数变化量差异很大,用户会觉得旋钮操作“手感奇怪”。先维护线性的触摸比例,再转换为曲线参数,才是兼顾操作直观性和音频感知合理性的正确方式。
内容的提问来源于stack exchange,提问作者headkit

