对于能够确定耳鸣频率的应用程序,会发生以下情况:
用户“mousedown”一个 html5 slider -> 启动某个频率的振荡器。通过移动 handle ,用户可以改变音符的音量。
这是负责整个音频处理的 (CoffeeScript-) 代码:
# CoffeScript for Tuner element
# Enables playing notes via Web Audio API
class @Tuner
constructor: () ->
@playing = false
@whobbling = false
@stopping = false
@atVolumeChange = false
@atFadeIn = false
@activeBtn = undefined
if typeof AudioContext isnt "undefined"
@audioCtx ?= new AudioContext()
else if typeof webkitAudioContext isnt "undefined"
@audioCtx = new webkitAudioContext()
else
console.log "Browser hat keine WebAudioAPI"
# make sure listener is set correct:
listener = @audioCtx.listener
listener.setOrientation(0,0,-1,0,1,0)
listener.setPosition(0,0,0)
# Create PannerNode and set initially to L and R
@pannerNode = @audioCtx.createPanner()
@pannerNode.setOrientation(0,0,0)
@pannerNode.setPosition(0,0,1)
@pannerNode.connect( @audioCtx.destination )
# Create GainNode and set to 0.0
@gainNode = @audioCtx.createGain()
@gainNode.gain.value = 0.0
@gainNode.connect @pannerNode
@actualFreq = 500
@currentVolume = 0.0
start: (volume, elem_id) ->
if @playing or @stopping
return
@playing = true
@currentVolume = volume
@oscillator = @audioCtx.createOscillator()
@oscillator.type = "sine"
@oscillator.frequency.value = @actualFreq
@oscillator.connect @gainNode
# if whobbling is active, create LFO & LFOGain for effect
if @whobbling
lfo = @audioCtx.createOscillator()
lfo.type = "sine"
lfo.frequency.value = 5
whobGain = @actualFreq * 5.0 / 100.0
lfo_gain = @audioCtx.createGain()
lfo_gain.gain.value = whobGain
lfo.connect(lfo_gain)
lfo_gain.connect(@oscillator.frequency)
lfo.start(0)
# starting process
@activeBtn = elem_id
matchingGUI.highlightPlay( @activeBtn ) if @activeBtn
now = @audioCtx.currentTime
@atFadeIn = true
@gainNode.gain.setValueAtTime 0.0, now + 0.01
@oscillator.start(now + 0.02)
@gainNode.gain.setValueAtTime 0.0, now + 0.03
@gainNode.gain.linearRampToValueAtTime volume, now + 0.2
that = @
setTimeout ->
that.atFadeIn = false
, 200
stop: () ->
if @playing and not @stopping
@stopping = true
now = @audioCtx.currentTime
now += 0.3 if @atVolumeChange
now += 0.3 if @atFadeIn
@gainNode.gain.setValueAtTime @currentVolume, now + 0.01
@gainNode.gain.linearRampToValueAtTime 0.0, now + 0.45
@oscillator.stop( now + 0.5 )
matchingGUI.highlightStop(@activeBtn) if @activeBtn
that = @
setTimeout ->
that.stopping = false
that.playing = false
that.whobbling = false
, 750
setFrequency: (newFreq) ->
@actualFreq = newFreq
@oscillator.frequency.value = newFreq if @playing and not @stopping
changeVolume: (newVolume) ->
newVolumeDb = @linearToDb newVolume
if not @stopping
@atVolumeChange = true
now = @audioCtx.currentTime
@currentVolume = newVolumeDb
@gainNode.gain.exponentialRampToValueAtTime @currentVolume, now + 0.333
that = @
setTimeout ->
that.atVolumeChange = false
, 300
setWhobbling: () ->
@whobbling = true
setPanToLR: () ->
@pannerNode.setPosition(0,0,1) unless @playing
setPanToL: () ->
@pannerNode.setPosition(-3,0,0) unless @playing
setPanToR: () ->
@pannerNode.setPosition(3,0,0) unless @playing
play: (frequency, volume, whob, elem_id) ->
whob ?= false
@setFrequency frequency
@setWhobbling() if whob
volumeDb = @linearToDb( volume )
@start( volumeDb, elem_id )
linearToDb: (s) ->
dbStart = 90
s = s * dbStart - dbStart
return Math.pow 10, s/20
# === End Class Tuner ===
#
# export Tuner
root = exports ? window
root.Tuner = Tuner
Tuner.play() 连接到 slider “mousedown”回调,Tuner.changeVolume() 连接到 slider “输入”回调。
问题如下:
每次移动 slider 时,都会发生一次点击。我猜这是因为每次 slider 触发“输入”时,当前由 Tuner.changeVolume 方法驱动的斜坡被另一个斜坡覆盖。
我做了很多实验(没有调度,cancelScheduledValues,...),当最初为 Mac 上的各种浏览器移动 slider 时,上面的版本只留下最后一次单击。但是对于 Windows 机器上的浏览器,点击量会显着增加。
(顺便说一句。当斜坡被驱动时,似乎无法读出@gainNode.gain.value。)
知道如何处理这个问题吗?
我会感谢任何提示...
最佳答案
可能是您的振荡器正在重新启动。对 CoffeeScript 不太熟悉(需要更多咖啡...),因此无法直接解决问题,但如果它是单击和拖动滑动事件,则浏览器可能不正确地使用 mousemove 事件发送多个鼠标按下。
相反,为什么不让振荡器始终运行,但增益节点为 0,实际上没有输出。然后当用户越过增益斜坡并跟踪用户输入时。通常使用斜坡是一种很好的做法,但是如果您使用 mousemove 触发音量变化,大多数用户不会快速移动 slider 以使您获得我认为您想要避免的“压缩”效果。
关于javascript - 网络音频 API : Clicks on volume change with slider,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38095909/