gpt4 book ai didi

Swift 固体节拍器系统

转载 作者:行者123 更新时间:2023-11-30 13:38:41 25 4
gpt4 key购买 nike

我正在尝试构建一个可靠的实体系统,以使用 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com