Подтвердить что ты не робот

Эффективный метод построения линии с миллионами точек

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

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

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

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 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);