2011-01-31 26 views
19

Tôi đang viết trình chỉnh sửa dạng sóng âm thanh trong Cocoa với một loạt các tùy chọn thu phóng. Rộng nhất, nó cho thấy một dạng sóng cho toàn bộ một bài hát (~ 10 triệu mẫu xem). Tại hẹp nhất của nó, nó cho thấy một điểm ảnh đại diện chính xác của sóng âm thanh (~ 1000 mẫu trong một lần xem). Tôi muốn có thể chuyển đổi suôn sẻ giữa các mức thu phóng này. Một số biên tập viên thương mại như Ableton Live dường như làm điều này theo một cách rất rẻ tiền.Phương pháp hiệu quả để vẽ một đường với hàng triệu điểm

Triển khai hiện tại của tôi đáp ứng phạm vi zoom mong muốn của tôi, nhưng không hiệu quả và bị thay đổi. Việc thiết kế chủ yếu lấy cảm hứng từ bài viết tuyệt vời này trên bản vẽ dạng sóng với thạch anh:

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

tôi tạo ra nhiều của CGMutablePathRef cho các tập tin âm thanh ở mức độ khác nhau của giảm. Khi tôi phóng to hết cỡ, tôi sử dụng đường dẫn được giảm xuống một điểm cho mỗi x nghìn mẫu. Khi tôi phóng to tất cả các con đường, tôi sử dụng đường dẫn đó có chứa một điểm cho mỗi mẫu. Tôi chia tỷ lệ theo chiều ngang khi tôi ở giữa các mức giảm. Điều này có được chức năng, nhưng vẫn còn khá đắt tiền và hiện vật xuất hiện khi chuyển đổi giữa các mức giảm.

Một suy nghĩ về cách tôi có thể thực hiện điều này ít tốn kém hơn là để đưa ra chống răng cưa. Các dạng sóng trong trình soạn thảo của tôi là chống răng cưa trong khi một trong Ableton không phải là (xem so sánh dưới đây). enter image description here enter image description here

Tôi không thấy cách tắt tính năng chống răng cưa cho CGMutablePathRef. Có một thay thế không chống răng cưa cho CGMutablePathRef trong thế giới của ca cao? Nếu không, có ai biết về một số lớp OpenGL hoặc mã mẫu có thể đặt tôi vào khóa học để vẽ đường lớn của tôi hiệu quả hơn?

Cập nhật 2014/01/21: Có bây giờ là một thư viện tuyệt vời mà thực hiện chính xác những gì tôi đang tìm kiếm: https://github.com/syedhali/EZAudio

Trả lời

6

tôi sử dụng CGContextMoveToPoint + CGContextAddLineToPoint + CGContextStrokePath trong ứng dụng của tôi. một điểm cho mỗi điểm trên màn hình để vẽ bằng bộ đệm sao lưu được tính toán trước cho tổng quan. bộ đệm chứa các điểm chính xác để vẽ và sử dụng biểu diễn nội suy của tín hiệu (dựa trên tỷ lệ thu phóng/tỷ lệ). mặc dù nó có thể nhanh hơn và trông đẹp hơn nếu tôi đưa vào bộ đệm ảnh, tôi chưa bao giờ có khiếu nại. bạn có thể calc và render tất cả điều này từ một thread thứ cấp, nếu bạn thiết lập nó một cách chính xác.

chống răng cưa liên quan đến ngữ cảnh đồ họa.

CGFloat (đầu vào gốc cho CGPath) là quá mức cần thiết cho tổng quan, dưới dạng biểu diễn trung gian và để tính tổng quan về dạng sóng. 16 bit phải đầy đủ. tất nhiên, bạn sẽ phải chuyển đổi sang CGFloat khi chuyển sang cuộc gọi CG.

bạn cần phải tìm hồ sơ để tìm ra thời gian của bạn được dành - tập trung vào các phần mất nhiều thời gian nhất. Ngoài ra, hãy chắc chắn rằng bạn chỉ vẽ những gì bạn phải, khi bạn phải và tránh lớp phủ/hình ảnh động khi có thể. nếu bạn cần lớp phủ, tốt hơn là hiển thị hình ảnh/bộ đệm và cập nhật khi cần. đôi khi nó giúp phá vỡ màn hình hiển thị thành nhiều bề mặt vẽ khi bề mặt lớn.

bán OT: ableton sử dụng giá trị s + h, điều này có thể nhanh hơn một chút nhưng ... tôi thích nó như một tùy chọn. nếu việc triển khai của bạn sử dụng nội suy tuyến tính (mà nó có thể, dựa trên sự xuất hiện của nó), hãy xem xét một cách tiếp cận trực quan hơn. nội suy tuyến tính là một chút gian lận, và thực sự không phải là những gì người dùng mong đợi nếu bạn đang phát triển một ứng dụng chuyên nghiệp.

+0

Cảm ơn bạn đã phản hồi chi tiết! Có vẻ như bạn cũng đã ở đây. Thật vậy, tôi vẽ dạng sóng thường xuyên hơn tôi có thể cần. Tôi sẽ xem xét thay thế một bản vẽ đầy đủ với một lớp phủ. Về Ableton sử dụng giá trị s + h, những gì là những? Bạn đúng để giả định rằng việc triển khai của tôi sử dụng nội suy tuyến tính. Có vẻ như đường bình phương của Ableton có thể hiệu quả hơn để vẽ, nhưng không chắc tôi sẽ làm thế nào. – tassock

+0

@tassock bạn được chào đón. bởi 's + h', tôi có nghĩa là các giá trị 'mẫu và giữ' của tín hiệu. điều này chỉ vẽ các bước sóng chính xác khi chúng được thể hiện trong miền thời gian. tốt hơn (imo) để nội suy và xây dựng biểu diễn của tín hiệu. s + h là ok, nhưng nó phải là một tùy chọn, với một biểu diễn nội suy làm mặc định. khi tôi nói nội suy, tôi đang đề cập đến một cách tiếp cận mà là đại diện của một tín hiệu tương tự hơn s + h hoặc nội suy tuyến tính. cho điều đó, nó có thể sẽ yêu cầu bạn cân bằng hiệu suất với độ chính xác. một sinc sẽ là tốt, (cont) – justin

+0

nhưng bạn có thể có khả năng nhận được ngay với một spline thứ tự cao hơn (như một ví dụ). interpolating/reconstructing các dạng sóng một cách chính xác có thể thêm rất nhiều CPU để thực hiện hiện tại của bạn. – justin

2

Liên quan đến câu hỏi cụ thể của anti-aliasing. Trong Quartz, tính năng chống răng cưa được áp dụng cho ngữ cảnh tại thời điểm vẽ. CGPathRef là bất khả tri đối với bối cảnh vẽ. Vì vậy, cùng một CGPathRef có thể được đưa vào một bối cảnh không thiên vị hoặc đến một bối cảnh không chống răng cưa. Ví dụ, để vô hiệu hóa khử răng cưa trong hình ảnh động:

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); 
+0

Ah, cảm ơn bạn đã chỉ ra bối cảnh thiết lập chống răng cưa. Thật không may, nó không có vẻ đã dẫn đến một sự gia tăng hiệu suất đáng kể. Rõ ràng tôi có quá nhiều quy trình không hiệu quả khác trong quá trình thực hiện hiện tại của tôi. – tassock