按一下按钮就会发出声音。快速按下按钮,声音播放会弹出并发出咔哒声

发布于 2024-11-18 14:15:35 字数 2618 浏览 2 评论 0原文

我有 6 个按钮,每个按钮都播放 .caf 文件中的音频样本。如果我按下一个按钮,声音播放得很好,如果我等待它结束并再次按下它,它播放得很好,但如果我快速按下按钮,那么声音会在播放前弹出并点击。

每次单击按钮时简单地分配 AVAudioPlayer 时,我最初没有遇到此弹出问题,但这会导致多次分配的内存泄漏。所以我为每个按钮创建了 6 个 AVAudioPlayers 并重新使用它,这消除了内存泄漏,但现在样本在被覆盖时会点击/弹出。

我尝试了很多不同的方法来阻止这种情况发生,例如将音量设置为 0、在播放下一个样本之前停止 AVAudioPlayer 实例等,但无法找到通过快速按钮按下重复播放相同样本声音并停止弹出的正确方法。

我确实在 .h 中保留了 AVAudioPlayer 属性,并在 alloc 语句中使用 autorelease 。

有什么帮助吗?

** 编辑:找到了一个解决方案,它不太漂亮,但它有效。

基本上我创建了 10 个自动释放的 AVAudioPlayers,如果其中一个 [myPlayer1 isPlaying],那么我使用下一个。

例如

 BOOL done = NO;

if(![self.audioPlayer0 isPlaying] && done == NO) {
    self.audioPlayer0 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer0 play];
    done = YES;
}

if(![self.audioPlayer1 isPlaying] && done == NO) {
    self.audioPlayer1 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer1 play];
    done = YES;
}

if(![self.audioPlayer2 isPlaying] && done == NO) {
    self.audioPlayer2 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer2 play];
    done = YES;
}

if(![self.audioPlayer3 isPlaying] && done == NO) {
    self.audioPlayer3 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer3 play];
    done = YES;
}

if(![self.audioPlayer4 isPlaying] && done == NO) {
    self.audioPlayer4 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer4 play];
    done = YES;
}

if(![self.audioPlayer5 isPlaying] && done == NO) {
    self.audioPlayer5 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer5 play];
    done = YES;
}

if(![self.audioPlayer6 isPlaying] && done == NO) {
    self.audioPlayer6 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer6 play];
    done = YES;
}

if(![self.audioPlayer7 isPlaying] && done == NO) {
    self.audioPlayer7 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer7 play];
    done = YES;
}

if(![self.audioPlayer8 isPlaying] && done == NO) {
    self.audioPlayer8 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer8 play];
    done = YES;
}

if(![self.audioPlayer9 isPlaying] && done == NO) {
    self.audioPlayer9 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer9 play];
}

I have 6 buttons that each play an audio sample from a .caf file. If I press a button the sound plays fine, if I wait for it to end and press it again it plays fine but if I press the button fast then the sound will pop and click before playing.

I initially didn't have this popping problem when simply allocating the AVAudioPlayer each time the button is clicked but this created a memory leak with multiple allocations. So I created 6 AVAudioPlayers for each button and re-used it, this got rid of the memory leak but now the samples click/pop when overwritten.

I have tried lots of different ways to stop this happening from setting the volume to 0, stopping the AVAudioPlayer instance before playing the next sample etc but cant find the correct way to repeatedly play the same sample sound with fast button presses and stop the popping.

I do have the AVAudioPlayer property as retain in the .h and use autorelease in the alloc statement.

Any help please?

** Edit: found a solution, its not pretty but it works.

Basically I created 10 AVAudioPlayers that autorelease and if one [myPlayer1 isPlaying] then I use the next one.

e.g.

 BOOL done = NO;

if(![self.audioPlayer0 isPlaying] && done == NO) {
    self.audioPlayer0 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer0 play];
    done = YES;
}

if(![self.audioPlayer1 isPlaying] && done == NO) {
    self.audioPlayer1 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer1 play];
    done = YES;
}

if(![self.audioPlayer2 isPlaying] && done == NO) {
    self.audioPlayer2 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer2 play];
    done = YES;
}

if(![self.audioPlayer3 isPlaying] && done == NO) {
    self.audioPlayer3 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer3 play];
    done = YES;
}

if(![self.audioPlayer4 isPlaying] && done == NO) {
    self.audioPlayer4 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer4 play];
    done = YES;
}

if(![self.audioPlayer5 isPlaying] && done == NO) {
    self.audioPlayer5 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer5 play];
    done = YES;
}

if(![self.audioPlayer6 isPlaying] && done == NO) {
    self.audioPlayer6 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer6 play];
    done = YES;
}

if(![self.audioPlayer7 isPlaying] && done == NO) {
    self.audioPlayer7 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer7 play];
    done = YES;
}

if(![self.audioPlayer8 isPlaying] && done == NO) {
    self.audioPlayer8 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer8 play];
    done = YES;
}

if(![self.audioPlayer9 isPlaying] && done == NO) {
    self.audioPlayer9 = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
    [audioPlayer9 play];
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

就此别过 2024-11-25 14:15:35

为什么要记住所有十个音频播放器而不是动态创建它们?

在您的新解决方案中,您实际上所做的就是循环遍历所有音频播放器以找到未播放的播放器。为什么不在数组中做同样的事情呢?

NSMutableArray *playerHolder = [[NSMutableArray alloc] init];
int maxNumberOfBuffers = 10;

for (int i=0; i<maxNumberOfBuffers; i++)
{
    AVAudioPlayer *audioPlayer;
    [playerHolder addObject:audioPlayer];
}

然后,在尝试播放某些内容时只需查看数组即可:

for (int i=0; i<playerHolder.count; i++)
{
    if (![[playerHolder objectAtIndex:i] isPlaying])
    {
        AVAudioPlayer *freePlayer = [playerHolder objectAtIndex:i];
        freePlayer = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
        [freePlayer play];
    }
}

理论上,这应该实现与您的解决方案相同的效果,而不会造成混乱。

Why remember all ten audio players instead of dynamically creating them?

In your new solution, what you're effectively doing is looping through all the audio players to find one that isn't playing. Why not do the same thing in an array?

NSMutableArray *playerHolder = [[NSMutableArray alloc] init];
int maxNumberOfBuffers = 10;

for (int i=0; i<maxNumberOfBuffers; i++)
{
    AVAudioPlayer *audioPlayer;
    [playerHolder addObject:audioPlayer];
}

Then, simply look through the array when trying to play something:

for (int i=0; i<playerHolder.count; i++)
{
    if (![[playerHolder objectAtIndex:i] isPlaying])
    {
        AVAudioPlayer *freePlayer = [playerHolder objectAtIndex:i];
        freePlayer = [ [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil] autorelease ];
        [freePlayer play];
    }
}

In theory, that should achieve the same thing as your solution, without the clutter.

将军与妓 2024-11-25 14:15:35

我不能确定,但​​问题可能会发生,因为您在非过零处截断波,这会导致波形中出现垂直部分(令人讨厌的谐波、咔嗒声/爆裂声)。您需要淡化波形而不是将其剪切掉。研究升余弦平滑/整形。

I can't be sure, but the problem probably occurs because you are truncating the wave at a non zero-crossing, which causes a vertical portion in the waveform (nasty harmonics, click/pop). You need to fade the waveform instead of cutting it out. Look into raised cosine smoothing/shaping.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文