@@ -51,7 +51,7 @@ open class FDWaveformView: UIView {
5151 }
5252
5353 /// The samples to be highlighted in a different color
54- /*@IBInspectable*/ open var highlightedSamples : CountableRange < Int > ? = 0 ..< 0 {
54+ /*@IBInspectable*/ open var highlightedSamples : CountableRange < Int > ? = nil {
5555 didSet {
5656 guard totalSamples > 0 else {
5757 return
@@ -68,10 +68,10 @@ open class FDWaveformView: UIView {
6868 @available ( * , deprecated, message: " Use `zoomSamples` to set range " )
6969 open var progressSamples : Int {
7070 get {
71- return highlightedSamples? . last ?? 0
71+ return highlightedSamples? . upperBound ?? 0
7272 }
73- set ( newSamples ) {
74- highlightedSamples = 0 ..< newSamples
73+ set {
74+ highlightedSamples = 0 ..< newValue
7575 }
7676 }
7777
@@ -144,31 +144,29 @@ open class FDWaveformView: UIView {
144144 }
145145
146146
147- //TODO MAKE PUBLIC
148-
149- // Drawing a larger image than needed to have it available for scrolling
150- fileprivate var horizontalMinimumBleed : CGFloat = 0.1
151- fileprivate var horizontalMaximumBleed : CGFloat = 3.0
152- fileprivate var horizontalTargetBleed : CGFloat = 0.5
153-
154- /// Drawing more pixels than shown to get antialiasing, 1.0 = no overdraw, 2.0 = twice as many pixels
155- fileprivate var horizontalMinimumOverdraw : CGFloat = 2.0
156-
157- /// Drawing more pixels than shown to get antialiasing, 1.0 = no overdraw, 2.0 = twice as many pixels
158- fileprivate var horizontalMaximumOverdraw : CGFloat = 5.0
159-
160- /// Drawing more pixels than shown to get antialiasing, 1.0 = no overdraw, 2.0 = twice as many pixels
161- fileprivate var horizontalTargetOverdraw : CGFloat = 3.0
162-
163- /// Drawing more pixels than shown to get antialiasing, 1.0 = no overdraw, 2.0 = twice as many pixels
164- fileprivate var verticalMinimumOverdraw : CGFloat = 1.0
165-
166- /// Drawing more pixels than shown to get antialiasing, 1.0 = no overdraw, 2.0 = twice as many pixels
167- fileprivate var verticalMaximumOverdraw : CGFloat = 3.0
147+ //TODO: MAKE PUBLIC
168148
169- /// Drawing more pixels than shown to get antialiasing, 1.0 = no overdraw, 2.0 = twice as many pixels
170- fileprivate var verticalTargetOverdraw : CGFloat = 2.0
149+ /// The portion of extra pixels to render left and right of the viewable region
150+ private var horizontalBleedTarget = 0.5
151+
152+ /// The required portion of extra pixels to render left and right of the viewable region
153+ /// If this portion is not available then a re-render will be performed
154+ private var horizontalBleedAllowed = 0.1 ... 3.0
171155
156+ /// The number of horizontal pixels to render per visible pixel on the screen (for antialiasing)
157+ private var horizontalOverdrawTarget = 3.0
158+
159+ /// The required number of horizontal pixels to render per visible pixel on the screen (for antialiasing)
160+ /// If this number is not available then a re-render will be performed
161+ private var horizontalOverdrawAllowed = 1.5 ... 5.0
162+
163+ /// The number of vertical pixels to render per visible pixel on the screen (for antialiasing)
164+ private var verticalOverdrawTarget = 2.0
165+
166+ /// The required number of vertical pixels to render per visible pixel on the screen (for antialiasing)
167+ /// If this number is not available then a re-render will be performed
168+ private var verticalOverdrawAllowed = 1.0 ... 3.0
169+
172170 /// The "zero" level (in dB)
173171 fileprivate let noiseFloor : CGFloat = - 50.0
174172
@@ -341,36 +339,30 @@ open class FDWaveformView: UIView {
341339
342340 func isWaveformRenderOperationDirty( _ renderOperation: FDWaveformRenderOperation ? ) -> Bool ? {
343341 guard let renderOperation = renderOperation else { return nil }
344-
345- let imageSize = renderOperation. imageSize
346- let sampleRange = renderOperation. sampleRange
347342
348343 if renderOperation. format. type != waveformRenderType {
349344 return true
350345 }
351346 if renderOperation. format. scale != desiredImageScale {
352347 return true
353348 }
354- if sampleRange. lowerBound < ( zoomSamples. startIndex - Int( CGFloat ( sampleRange. count) * horizontalMaximumBleed) ) . clamped ( from: 0 , to: totalSamples) {
355- return true
356- }
357- if sampleRange. lowerBound > ( zoomSamples. startIndex - Int( CGFloat ( sampleRange. count) * horizontalMinimumBleed) ) . clamped ( from: 0 , to: totalSamples) {
358- return true
359- }
360- if sampleRange. upperBound < ( zoomSamples. endIndex + Int( CGFloat ( sampleRange. count) * horizontalMinimumBleed) ) . clamped ( from: 0 , to: totalSamples) {
349+
350+ let requiredSamples = zoomSamples. extended ( byFactor: horizontalBleedAllowed. lowerBound) . clamped ( to: 0 ..< totalSamples)
351+ if requiredSamples. clamped ( to: renderOperation. sampleRange) != requiredSamples {
361352 return true
362353 }
363- if sampleRange. upperBound > ( zoomSamples. endIndex + Int( CGFloat ( sampleRange. count) * horizontalMaximumBleed) ) . clamped ( from: 0 , to: totalSamples) {
354+
355+ let allowedSamples = zoomSamples. extended ( byFactor: horizontalBleedAllowed. upperBound) . clamped ( to: 0 ..< totalSamples)
356+ if renderOperation. sampleRange. clamped ( to: allowedSamples) != renderOperation. sampleRange {
364357 return true
365358 }
366359
367- let allowableWidths = frame . width * CGFloat ( horizontalMinimumOverdraw ) ... frame. width * CGFloat ( horizontalMaximumOverdraw )
368- if !allowableWidths . contains ( imageSize . width ) {
360+ let verticalOverdrawRequested = Double ( renderOperation . imageSize . height / frame. height )
361+ if !verticalOverdrawAllowed . contains ( verticalOverdrawRequested ) {
369362 return true
370363 }
371-
372- let allowableHeights = frame. height * CGFloat( verticalMinimumOverdraw) ... frame. height * CGFloat( verticalMaximumOverdraw)
373- if !allowableHeights. contains ( imageSize. height) {
364+ let horizontalOverdrawRequested = Double ( renderOperation. imageSize. height / frame. height)
365+ if !horizontalOverdrawAllowed. contains ( horizontalOverdrawRequested) {
374366 return true
375367 }
376368
@@ -418,15 +410,13 @@ open class FDWaveformView: UIView {
418410 guard let audioContext = audioContext else { return }
419411 guard !zoomSamples. isEmpty else { return }
420412
421- let renderStartSamples = ( zoomSamples. startIndex - Int( CGFloat ( zoomSamples. count) * horizontalTargetBleed) ) . clamped ( from: 0 , to: totalSamples)
422- let renderEndSamples = ( zoomSamples. endIndex + Int( CGFloat ( zoomSamples. count) * horizontalTargetBleed) ) . clamped ( from: 0 , to: totalSamples)
423- let renderSampleRange = renderStartSamples ..< renderEndSamples
424- let widthInPixels = floor ( frame. width * horizontalTargetOverdraw)
425- let heightInPixels = frame. height * horizontalTargetOverdraw
413+ let renderSamples = zoomSamples. extended ( byFactor: horizontalBleedTarget) . clamped ( to: 0 ..< totalSamples)
414+ let widthInPixels = floor ( frame. width * CGFloat( horizontalOverdrawTarget) )
415+ let heightInPixels = frame. height * CGFloat( horizontalOverdrawTarget)
426416 let imageSize = CGSize ( width: widthInPixels, height: heightInPixels)
427417 let renderFormat = FDWaveformRenderFormat ( type: waveformRenderType, wavesColor: . black, scale: desiredImageScale)
428418
429- let waveformRenderOperation = FDWaveformRenderOperation ( audioContext: audioContext, imageSize: imageSize, sampleRange: renderSampleRange , format: renderFormat) { image in
419+ let waveformRenderOperation = FDWaveformRenderOperation ( audioContext: audioContext, imageSize: imageSize, sampleRange: renderSamples , format: renderFormat) { image in
430420 DispatchQueue . main. async {
431421 self . renderForCurrentAssetFailed = ( image == nil )
432422 self . waveformImage = image
@@ -544,13 +534,15 @@ extension FDWaveformView: UIGestureRecognizerDelegate {
544534 }
545535 }
546536 else if doesAllowScrubbing {
547- highlightedSamples = 0 ..< zoomSamples. startIndex + Int( CGFloat ( zoomSamples. startIndex) * recognizer. location ( in: self ) . x / bounds. width)
537+ let rangeSamples = CGFloat ( zoomSamples. count)
538+ highlightedSamples = 0 ..< Int ( ( CGFloat ( zoomSamples. startIndex) + rangeSamples * recognizer. location ( in: self ) . x / bounds. width) )
548539 }
549540 }
550541
551542 func handleTapGesture( _ recognizer: UITapGestureRecognizer ) {
552543 if doesAllowScrubbing {
553- highlightedSamples = 0 ..< zoomSamples. startIndex + Int( CGFloat ( zoomSamples. startIndex) * recognizer. location ( in: self ) . x / bounds. width)
544+ let rangeSamples = CGFloat ( zoomSamples. count)
545+ highlightedSamples = 0 ..< Int ( ( CGFloat ( zoomSamples. startIndex) + rangeSamples * recognizer. location ( in: self ) . x / bounds. width) )
554546 }
555547 }
556548}
@@ -578,8 +570,8 @@ extension FDWaveformView: UIGestureRecognizerDelegate {
578570
579571//MARK -
580572
581- extension Comparable
582- {
573+ extension Comparable {
574+
583575 func clamped( from lowerBound: Self , to upperBound: Self ) -> Self {
584576 return min ( max ( self , lowerBound) , upperBound)
585577 }
@@ -595,3 +587,13 @@ extension Strideable where Self.Stride: SignedInteger
595587 return min ( max ( self , range. lowerBound) , range. upperBound)
596588 }
597589}
590+
591+ extension CountableRange where Bound: Strideable {
592+
593+ // Extend each bound away from midpoint by `factor`, a portion of the distance from begin to end
594+ func extended( byFactor factor: Double ) -> CountableRange < Bound > {
595+ let theCount : Int = numericCast ( count)
596+ let amountToMove : Bound . Stride = numericCast ( Int ( Double ( theCount) * factor) )
597+ return lowerBound - amountToMove ..< upperBound + amountToMove
598+ }
599+ }
0 commit comments