- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试构建一个可靠的实体系统,以使用 SWIFT 在我的应用程序中构建节拍器。
到目前为止,我已经使用 NSTimer 构建了一个看似可靠的系统。我现在遇到的唯一问题是,当计时器启动时,前两次点击是关闭时间,但随后它会陷入一个可靠的时间范围。
现在,经过我的研究,我看到人们提到你应该使用其他不依赖 NSTimer 的音频工具。或者如果你选择使用 NSTimer 那么它应该在它自己的线程上。现在我看到很多人对此感到困惑,包括我自己,我很想深入了解节拍器业务的真相,解决这个问题,并与所有正在苦苦挣扎的人分享。
更新
因此,在我上次收到反馈后,我已经实现并清理了这一点。此时,我的代码的结构如下。它正在播放。但一开始我仍然快速点击 2 次,然后就稳定下来了。
对于我对此事的无知,我深表歉意。我希望我走在正确的道路上。
我目前也在制作另一种方法的原型(prototype)。我有一个非常小的音频文件,只需单击一下,其末尾就有死区,并具有正确的持续时间,直到达到特定节奏的循环点为止。我正在循环这个并且效果很好。但唯一的事情是我无法检测视觉更新的循环点,所以我的基本 NStimer 只是检测正在处理的音频下方的时间间隔,并且它似乎自始至终匹配得很好,没有延迟。但我还是宁愿用这个 NSTimer 来实现这一切。如果你能很容易地发现我的错误,那么在正确的方向上再踢一脚就太好了,我相信它很快就会起作用!非常感谢。
//VARIABLES
//AUDIO
var clickPlayer:AVAudioPlayer = AVAudioPlayer()
let soundFileClick = NSBundle.mainBundle().pathForResource("metronomeClick", ofType: ".mp3")
//TIMERS
var metroTimer = NSTimer()
var nextTimer = NSTimer()
var previousClick = CFAbsoluteTimeGetCurrent() //When Metro Starts Last Click
//Metro Features
var isOn = false
var bpm = 60.0 //Tempo Used for beeps, calculated into time value
var barNoteValue = 4 //How Many Notes Per Bar (Set To Amount Of Hits Per Pattern)
var noteInBar = 0 //What Note You Are On In Bar
//********* FUNCTIONS ***********
func startMetro()
{
MetronomeCount()
barNoteValue = 4 // How Many Notes Per Bar (Set To Amount Of Hits Per Pattern)
noteInBar = 0 // What Note You Are On In Bar
isOn = true //
}
//Main Metro Pulse Timer
func MetronomeCount()
{
previousClick = CFAbsoluteTimeGetCurrent()
metroTimer = NSTimer.scheduledTimerWithTimeInterval(60.0 / bpm, target: self, selector: Selector ("MetroClick"), userInfo: nil, repeats: true)
nextTimer = NSTimer(timeInterval: (60.0/Double(bpm)) * 0.01, target: self, selector: "tick:", userInfo: ["bpm":bpm], repeats: true)
}
func MetroClick()
{
tick(nextTimer)
}
func tick(timer:NSTimer)
{
let elapsedTime:CFAbsoluteTime = CFAbsoluteTimeGetCurrent() - previousClick
let targetTime:Double = 60/timer.userInfo!.objectForKey("bpm")!.doubleValue!
if (elapsedTime > targetTime) || (abs(elapsedTime - targetTime) < 0.003)
{
previousClick = CFAbsoluteTimeGetCurrent()
//Play the click here
if noteInBar == barNoteValue
{
clickPlayer.play() //Play Sound
noteInBar = 1
}
else//If We Are Still On Same Bar
{
clickPlayer.play() //Play Sound
noteInBar++ //Increase Note Value
}
countLabel.text = String(noteInBar) //Update UI Display To Show Note We Are At
}
}
最佳答案
纯粹使用 NSTimer
构建的节拍器不会非常准确,正如 Apple 在其文档中所解释的那样。
Because of the various input sources a typical run loop manages, the effective resolution of the time interval for a timer is limited to on the order of 50-100 milliseconds. If a timer’s firing time occurs during a long callout or while the run loop is in a mode that is not monitoring the timer, the timer does not fire until the next time the run loop checks the timer.
我建议使用一个NSTimer
,它在每个所需的滴答声中触发大约 50 次(例如,如果您想要每分钟 60 次滴答声,则可以使用 NSTimeInterval
大约为 1/50 秒。
然后,您应该存储一个CFAbsoluteTime
,它存储“最后一个刻度”时间,并将其与当前时间进行比较。如果当前时间和“最后一个刻度”时间之间的差异的绝对值小于某个容差(我会将其设置为每个间隔的刻度数的 4 倍,例如,如果您选择 1/50 秒每次 NSTimer 触发,您应该应用大约 4/50 秒的容差),您可以播放“滴答声”。
您可能需要校准容差才能达到所需的精度,但这个一般概念将使您的节拍器更加准确。
以下是有关 another SO post 的更多信息。它还包括一些使用我讨论的理论的代码。我希望这有帮助!
更新您计算公差的方式不正确。在计算中,请注意容差与 bpm 的平方成反比。这样做的问题是容差最终将小于计时器每秒触发的次数。看看this graph看看我的意思。这会在高 BPM 时产生问题。另一个潜在的错误来源是您的顶部边界条件。您确实不需要检查容忍度的上限,因为从理论上讲,计时器那时应该已经启动了。因此,如果耗时大于理论时间,你可以不管它。 (例如,如果耗时是 0.1 秒,而真实 BPM 的实际时间应该是 0.05 秒,那么无论您的容忍度如何,您都应该继续并触发计时器)。
这是我的计时器“tick”功能,它似乎工作正常。您需要对其进行调整以满足您的需求(包括悲观情绪等),但它在概念上是有效的。
func tick(timer:NSTimer) {
let elapsedTime:CFAbsoluteTime = CFAbsoluteTimeGetCurrent() - lastTick
let targetTime:Double = 60/timer.userInfo!.objectForKey("bpm")!.doubleValue!
if (elapsedTime > targetTime) || (abs(elapsedTime - targetTime) < 0.003) {
lastTick = CFAbsoluteTimeGetCurrent()
# Play the click here
}
}
我的计时器初始化如下:nextTimer = NSTimer(timeInterval: (60.0/Double(bpm)) * 0.01,target:self,selector:“tick:”,userInfo:[“bpm”:bpm] ,重复:正确)
关于Swift 固体节拍器系统,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35819731/
我正在尝试使用 Typescript(和 Angular 2)构建一个节拍器。感谢 @Nitzan-Tomer ( Typescript Loop with Delay ),他帮助我完成了基础知识。
作为练习,我正在尝试使用 Thread.sleep 作为计时器并使用 JMF 作为声音来使用 Java 创建一个节拍器。它运行良好,但出于某种原因,JMF 似乎只能以每分钟最多 207 拍的速度播放声
我想用jquery制作一个节拍器,用单击声音并用一种颜色可视化速度。在这一点上,视觉部分工作正常,但声音有问题。 无法使其正常工作,它应每分钟发出哔哔声,其速度是所选速度的多少倍。 这是代码: $(f
我正在尝试通过实现苹果提供的示例代码来创建一个节拍器应用程序。一切正常,但我看到节拍视觉效果出现延迟,它与播放器时间不正确同步。这是苹果提供的示例代码 let secondsPerBeat = 60.
如标题中所述,我正在尝试创建一个基于 jQuery/JavaScript 的节拍器以及 HTML 标签来播放声音。 它工作“没问题”,但在我看来 setInterval方法不够准确。我在这里搜索了一些
我是一名优秀的程序员,十分优秀!