20

我正在 Cocoa 中编写一个具有多种缩放选项的音频波形编辑器。在最宽处,它显示了整首歌曲的波形(大约 1000 万个样本)。在最窄处,它显示了声波的像素精确表示(视图中约 1000 个样本)。我希望能够在这些缩放级别之间平滑过渡。一些像 Ableton Live 这样的商业编辑器似乎以一种非常便宜的方式来做到这一点。

我当前的实现满足了我想要的缩放范围,但效率低下且不稳定。该设计很大程度上受到这篇关于用石英绘制波形的优秀文章的启发:

http://supermegaultragroovy.com/blog/2009/10/06/drawing-waveforms/

我为音频文件创建了多个 CGMutablePathRef's 在不同的减少级别。当我一直放大时,我使用已减少到每 x 千个样本一个点的路径。当我一直放大时,我使用包含每个样本的点的路径。当我处于减少级别之间时,我会水平缩放路径。这使它具有功能性,但仍然非常昂贵,并且在减少级别之间转换时会出现伪影。

关于如何降低成本的一个想法是取消抗锯齿。我的编辑器中的波形是抗锯齿的,而 Ableton 中的波形不是(参见下面的比较)。 在此处输入图像描述 在此处输入图像描述

我看不到关闭 CGMutablePathRef 的抗锯齿的方法。在 Cocoa 的世界中是否有 CGMutablePathRef 的非抗锯齿替代品?如果没有,是否有人知道一些 OpenGL 类或示例代码可能会让我更有效地绘制我的大线?

2014 年 1 月 21 日更新:现在有一个很棒的库可以完全满足我的需求:https ://github.com/syedhali/EZAudio

4

2 回答 2

6

我在我的应用程序中使用 CGContextMoveToPoint+CGContextAddLineToPoint+CGContextStrokePath。使用预先计算的后备缓冲区为概览绘制每个屏幕点一个点。缓冲区包含要绘制的确切点,并使用信号的插值表示(基于缩放/比例)。虽然如果我渲染到图像缓冲区可能会更快并且看起来更好,但我从来没有抱怨过。如果设置正确,您可以从辅助线程计算和渲染所有这些。

抗锯齿与图形上下文有关。

CGFloat(CGPaths 的本机输入)对于概览、作为中间表示和计算波形概览来说太过分了。16 位应该足够了。当然,在传递给 CG 调用时,您必须转换为 CGFloat。

您需要进行概要分析以找出您的时间都花在了哪里——专注于花费最多时间的部分。另外,请确保只在必须时绘制必须绘制的内容,并尽可能避免叠加/动画。如果您需要叠加,最好渲染到图像/缓冲区并根据需要进行更新。有时,当表面很大时,将显示分解为多个绘图表面会有所帮助。

半 OT:ableton 使用 s+h 值,这可能会稍微快一些,但是......我更喜欢它作为一个选项。如果您的实现使用线性插值(根据其外观可能),请考虑更直观的方法。线性插值有点作弊,如果您正在开发专业应用程序,这确实不是用户所期望的。

于 2011-01-31T10:25:58.860 回答
2

关于抗锯齿的特定问题。在 Quartz 中,抗锯齿在绘制时应用于上下文。CGPathRef 与绘图上下文无关。因此,可以将相同的 CGPathRef 渲染到抗锯齿上下文或非抗锯齿上下文中。例如,要在动画期间禁用抗锯齿:

CGContextRef context = UIGraphicsGetCurrentContext();
GMutablePathRef fill_path = CGPathCreateMutable();
// Fill the path with the wave
...

CGContextAddPath(context, fill_path);
if ([self animating])
    CGContextSetAllowsAntialiasing(context, NO);
else
    CGContextSetAllowsAntialiasing(context, YES);
// Do the drawing
CGContextDrawPath(context, kCGPathStroke);
于 2011-01-31T09:58:13.827 回答