Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add an option to prevent scrolling past the end of the audio #104

Open
calioptrix opened this issue Jul 19, 2017 · 6 comments
Open

add an option to prevent scrolling past the end of the audio #104

calioptrix opened this issue Jul 19, 2017 · 6 comments

Comments

@calioptrix
Copy link

When zoomed in, you can swipe the view until the last part of the waveform is on the left edge of the screen. This seems a bit disorienting to me. It would be nice to have an option so that the end of the waveform stays at the right edge of the screen.

@fulldecent fulldecent added the bug label Jul 24, 2017
@fulldecent
Copy link
Owner

This is not intended behavior and sounds like a bug.

@DamonChen117
Copy link

DamonChen117 commented Dec 31, 2017

I fixed it locally by:


 @objc func handlePinchGesture(_ recognizer: UIPinchGestureRecognizer) {
        if !doesAllowStretch {
            return
        }
        
        if recognizer.scale == 1 {
            return
        }
        
        setScale(scale: scale * recognizer.scale, fixedX: recognizer.location(in: self).x/bounds.width)
        recognizer.scale = 1
    }



    private var scale:CGFloat = 1
    
    func setScale(scale:CGFloat, fixedX:CGFloat) {
        if scale < 1
        {
            return
        }
        self.scale = scale
        
        let zoomSamplesCount = CGFloat(zoomSamples.count)
        let pinchCenterSample = zoomSamples.lowerBound + Int(zoomSamplesCount * fixedX)
        
        let newZoomSamplesCount = CGFloat(totalSamples)/scale
        var newZoomStart = pinchCenterSample - Int(newZoomSamplesCount * fixedX )
        var newZoomEnd = newZoomStart + Int(newZoomSamplesCount)
        if newZoomEnd > totalSamples
        {
            newZoomStart = totalSamples - Int(newZoomSamplesCount)
            newZoomEnd = totalSamples
        }
        
        zoomSamples = (newZoomStart ..< newZoomEnd).clamped(to: 0 ..< totalSamples)
    }



override open func layoutSubviews() {
        super.layoutSubviews()
        guard audioContext != nil && !zoomSamples.isEmpty else {
            return
        }

        switch cacheStatus() {
        case .dirty:
            renderWaveform()
            return
        case .notDirty(let cancelInProgressRenderOperation):
            if cancelInProgressRenderOperation {
                inProgressWaveformRenderOperation = nil
            }
        }

        let childFrame : CGRect
        
        
        if let cachedSampleRange = cachedWaveformRenderOperation?.sampleRange, !cachedSampleRange.isEmpty , !zoomSamples.isEmpty
        {
            let cacheScale = CGFloat(cachedSampleRange.count)/CGFloat(zoomSamples.count)
            
            let width = frame.width * cacheScale
            let x = CGFloat(cachedSampleRange.lowerBound-zoomSamples.lowerBound)*width/CGFloat(cachedSampleRange.count)
            childFrame = CGRect(x: x, y: 0, width: width, height: frame.height)
        }
        else
        {
            childFrame = CGRect(x: 0, y: 0, width: frame.width, height: frame.height)
        }
        
        imageView.frame = childFrame
        highlightedImage.frame = childFrame
        //clipping.frame = CGRect(x: frame.width * scaledHighlightedX, y: 0, width: frame.width * scaledHighlightedWidth, height: frame.height)
        clipping.isHidden = !(highlightedSamples?.overlaps(zoomSamples) ?? false)
        print("layed-out frames: \(frame) -- \(imageView.frame)")
    }

Note: clipping.frame is not set

@fulldecent
Copy link
Owner

Thanks for sharing. Does this work for anyone else?

Also related: #96

@jesseditson
Copy link

I was experiencing this in a consumer app because I'm manually placing some additional controls over the waveform, and it seemed like my math was ok but the handles still would end up in the wrong place when zooming/scrolling the waveform (and otherwise ok, but that proves little since the math isn't used when at zero zoom).

I tried the above fix, but it clearly is not the issue since all it does is not apply the frame changes to the clipping view, which is only for the highlighted frames functionality. You can see this by commenting the above line, building the test app, and scrubbing. You'll see that the scrub and zoom are now no longer in sync.

I believe the underlying issue here is not that it is being scrolled outside of the view, but that the render cache is wrong and it's not being re-rendered often enough. In the demo app, you can see the waveform sometimes "catch up" to the current (or perhaps just a recent) render. I'll be playing with with spare time to see if I can find a reasonable fix.

@jesseditson
Copy link

I started testing this, and it seems to be at least one very old issue - the simple repro case I'm working with is that when you are zoomed in, the waveform should not compress when panning.
I figured it once worked and regressed, but trying to bisect the issue got me all the way back to before v1.0, and I could reproduce on every version that I could see a waveform in (I stopped testing at 9ba0b65, which I couldn't get to render anything).
Given that, I think this is less of a bug and more of a fundamental logic issue. I suspect that zoom functionality will need to be rewritten or heavily refactored to be accurate, and I do not have reason to believe that it works in any version of this lib - I'd be happy to help review or debug further as this library would save me a lot of time if it worked!

@fulldecent
Copy link
Owner

Hello, checking in to see if anybody here has solved this issue for themselves and could share back the solution as a PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants