按下一个按钮它会发出声音。快速点击按钮和声音播放弹出和点击
Posted
技术标签:
【中文标题】按下一个按钮它会发出声音。快速点击按钮和声音播放弹出和点击【英文标题】:Press a button it makes a sound. Hit button fast and sound playback pops and clicks 【发布时间】:2011-07-06 10:17:54 【问题描述】:我有 6 个按钮,每个按钮都播放 .caf 文件中的音频样本。如果我按下一个按钮,声音会正常播放,如果我等待它结束并再次按下它会正常播放,但如果我快速按下按钮,那么声音会在播放前弹出并单击。
我最初在每次单击按钮时仅分配 AVAudioPlayer 时没有出现此弹出问题,但这会导致多次分配的内存泄漏。所以我为每个按钮创建了 6 个 AVAudioPlayers 并重新使用它,这消除了内存泄漏,但现在样本在被覆盖时单击/弹出。
我尝试了很多不同的方法来阻止这种情况的发生,包括将音量设置为 0、在播放下一个样本之前停止 AVAudioPlayer 实例等,但找不到正确的方法来通过快速按钮重复播放相同的样本声音并停止爆裂声。
我确实在 .h 中保留了 AVAudioPlayer 属性,并在 alloc 语句中使用了 autorelease。
有什么帮助吗?
** 编辑:找到了一个解决方案,它不漂亮,但它有效。
基本上我创建了 10 个自动释放的 AVAudioPlayer,如果有一个 [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];
【问题讨论】:
【参考方案1】:为什么要记住所有十个音频播放器而不是动态创建它们?
在您的新解决方案中,您实际上所做的是循环播放所有音频播放器以查找未播放的播放器。为什么不在数组中做同样的事情?
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];
理论上,这应该与您的解决方案实现相同的效果,而不会造成混乱。
【讨论】:
请注意,在这两种解决方案中,都无法处理所有玩家都被使用的情况。如果发生这种情况,声音将根本不会播放。在这两种解决方案中,您都可以将玩家数量增加到大约 16 人,而不会出现问题。这完全取决于你的声音的长度。 现在阵列运行良好,必须对示例代码进行一些更改才能使其最终运行,但这个概念是合理的。再次感谢。 当心:该代码有问题。我是这样做的:gist.github.com/alexch/5453875(尚未完全调试——ymmv)。顺便说一句,这种技术被称为“实例池”。 感谢您澄清亚历克斯-您介意详细说明为什么它有问题吗?我认为这与缺乏正确的内存管理有关,理论上如果使用 ARC 就可以解决。此外,这是完全从内存中编写的伪代码,所以老实说,我对它有问题并不感到惊讶。【参考方案2】:我不能确定,但可能会出现问题,因为您在非零交叉处截断波形,这会导致波形出现垂直部分(讨厌的谐波、咔嗒声/爆音)。您需要淡化波形而不是将其剪掉。查看升余弦平滑/整形。
【讨论】:
这也可以工作,但在研究设置后决定尝试生成一个新的 AVAudioPlayer,如果现有的仍在播放。这允许多个样本相互叠加,而不是使用单个 AVAudioPlayer 对象一次叠加一个。还是谢谢。以上是关于按下一个按钮它会发出声音。快速点击按钮和声音播放弹出和点击的主要内容,如果未能解决你的问题,请参考以下文章