Эффективный способ нарисовать линию с миллионами точек - PullRequest
19 голосов
/ 31 января 2011

Я пишу звуковой редактор формы волны в Какао с широким диапазоном вариантов увеличения.В самом широком смысле он отображает форму волны для всей песни (примерно 10 миллионов сэмплов).В самом узком виде он отображает звуковую волну с точностью до пикселя (~ 1 тысяча сэмплов в виде).Я хочу иметь возможность плавного перехода между этими уровнями масштабирования.Некоторые коммерческие редакторы, такие как Ableton Live, делают это очень недорого.

Моя текущая реализация удовлетворяет желаемому диапазону масштабирования, но неэффективна и изменчива.Дизайн в значительной степени вдохновлен этой превосходной статьей о рисовании осциллограмм с кварцем:

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

Я создаю несколько CGMutablePathRef для аудиофайла с различными уровнями сокращения.Когда я полностью уменьшаю масштаб, я использую путь, который был уменьшен до одной точки на x тысяч выборок.При полном увеличении я использую этот путь, который содержит точку для каждого образца.Я масштабирую путь горизонтально, когда я нахожусь между уровнями снижения.Это делает его функциональным, но все еще довольно дорогим, и при переходе между уровнями снижения появляются артефакты.

Одна мысль о том, как я могу сделать это менее дорогой, состоит в том, чтобы убрать сглаживание.Форма сигнала в моем редакторе сглажена, а в Ableton - нет (см. Сравнение ниже).enter image description here enter image description here

Я не вижу способа отключить сглаживание для CGMutablePathRef.Есть ли в мире какао альтернатива CGMutablePathRef без сглаживания?Если нет, кто-нибудь знает какие-нибудь классы OpenGL или примеры кода, которые могли бы заставить меня более эффективно рисовать мою огромную линию?

Обновление 1-21-2014: Теперь есть отличныебиблиотека, которая делает именно то, что я искал: https://github.com/syedhali/EZAudio

Ответы [ 2 ]

6 голосов
/ 31 января 2011

Я использую CGContextMoveToPoint + CGContextAddLineToPoint + CGContextStrokePath в моем приложении. одна точка на экранную точку для рисования с использованием предварительно рассчитанного резервного буфера для обзора. буфер содержит точные точки для рисования и использует интерполированное представление сигнала (в зависимости от масштаба / масштаба). хотя это могло бы быть быстрее и выглядеть лучше, если бы я рендерился в буфер изображений, у меня никогда не было жалоб. Вы можете вычислить и визуализировать все это из вторичного потока, если настроите его правильно.

сглаживание относится к графическому контексту.

CGFloat (собственный ввод для CGPaths) является излишним для обзора, в качестве промежуточного представления и для расчета обзора формы сигнала. 16 бит должны быть адекватными. конечно, вам придется конвертировать в CGFloat при переходе на вызовы CG.

вам нужно профилировать, чтобы узнать, на что тратится ваше время - сосредоточьтесь на деталях, которые занимают больше всего времени. Кроме того, убедитесь, что вы рисуете только то, что должны, когда это необходимо, и избегайте наложения / анимации, где это возможно. если вам нужны оверлеи, лучше сделать рендеринг в изображение / буфер и обновить его по мере необходимости. иногда это помогает разбить изображение на несколько поверхностей для рисования, когда поверхность большая.

semi-OT: использование значений s + h в умении может быть немного быстрее, но ... я очень предпочитаю его в качестве опции. если ваша реализация использует линейную интерполяцию (что, возможно, зависит от ее внешнего вида), рассмотрите более интуитивный подход. Линейная интерполяция немного обманывает, и совсем не то, что пользователь ожидал бы, если вы разрабатываете профессиональное приложение.

2 голосов
/ 31 января 2011

По отношению к конкретному вопросу сглаживания. В Кварце сглаживание применяется к контексту в момент рисования. 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);
...