Comments (19)
There's many different ways this could be achieved.
In this particular case, it looks like the "2nd color" is simply the same white, just with 40% or so opacity.
So what you could do is:
- render yourself one waveform as a 100% white image
- assign this to one waveform image view (below that's the
viewModel.playbackWaveformImageView
) - assign it to a 2nd waveform image view that you position exactly underneath the 1st one
- set the
secondImageView.opacity = 0.4
or similar - as the audio plays back, update your upmost waveform's layerMask so that it only covers a part of the space
I happen to have done this masking in one of my apps, so for illustration here's that code:
func updateProgressWaveform(_ progress: Double) {
let fullRect = viewModel.playbackWaveformImageView.bounds
let newWidth = Double(fullRect.size.width) * progress
let maskLayer = CAShapeLayer()
let maskRect = CGRect(x: 0.0, y: 0.0, width: newWidth, height: Double(fullRect.size.height))
let path = CGPath(rect: maskRect, transform: nil)
maskLayer.path = path
viewModel.playbackWaveformImageView.layer.mask = maskLayer
}
from dswaveformimage.
from dswaveformimage.
There's tons of different ways to achieve this, one of the simplest might be
// @State var progress: CGFloat = 0 // must be between 0 and 1
ZStack(alignment: .leading) {
WaveformView(audioURL: audioURL, configuration: configuration)
WaveformView(audioURL: audioURL, configuration: configuration.with(style: .filled(.red)))
.mask(alignment: .leading) {
GeometryReader { geometry in
Rectangle().frame(width: geometry.size.width * progress)
}
}
}
[Edit] I've added this to the README now so that it's easier to find in the future :)
from dswaveformimage.
Hey @tayyab13-git,
getting a striped waveform is easy via sth similar to this
WaveformView(audioURL: audioURL, configuration: configuration.with(style: .striped(StripeConfig(color: .red, width: 3, spacing: 5, lineCap: .round))))
Making the overlay from the above example draggable is also relatively straightforward. You'll just need to add a DragGesture on the outer ZStack
which would need to modify some @State
variable using its onChanged(_:) modifier. That would then be used instead of the simplistic progress
to manipulate the width of the .mask
.
Maybe also have a look at https://developer.apple.com/documentation/swiftui/adding-interactivity-with-gestures in case you haven't used gestures in SwiftUI yet.
from dswaveformimage.
Ah my bad. Well. So with UIKit then, yeah, you could in principle just re-use updateProgressWaveform
as-is. You'd then need to add a UIPanGestureRecognizer
to your view hierarchy where it makes sense in your specific case. And then just use its translation(in:)
to infer a value within the interval (0...1)
to be able to call it without modifications.
from dswaveformimage.
So in the example above you need 2 identical images of your waveform on top of each other, each with a different color. The one referenced in that example as playbackWaveformImageView
is the top one, which indicates the playback progress / dragging position.
That is the one getting the mask applied, so you only need 2 images. (The lower one just isn't referenced in that code, cause its static).
Where you add the pan gesture recognizer depends on your desired UX. One option is you'll add it on the view containing both the images. And yes, then you will need to do some math to map the current dragging position to the desired progress of the waveform. Maybe taking the initial position where the user touched into account or maybe not. Definitely with some calculation, because the pan recognizer gives you CGPoint
and updateProgrssWaveform
requires a Double between 0 and 1. It really depends a whole lot on how you want this to behave in the end.
from dswaveformimage.
There’s no intrinsic content size being calculated. So the short answer is, there is none. Instead, you define the size of the view (and thus waveform) by either setting the view’s frame or via auto layout constraints. The audio file is then downsampled to fit into the width and height you define.
If you want a specific resolution instead, you’ll have to do some manual math based on the audio files total duration and then set the view’s dimension accordingly.
from dswaveformimage.
So by „unfilled“, you mean „unplayed“ then, assuming that image you posted represents playback progress?
In that case, you‘d need to do sth similar to what I had originally described in #21 (comment)
If you do still need the dimensions and position of the unplayed / unfilled area, you’ll just need to calculate the „inverse“ of that answer‘s maskLayer
. So sth along the lines of let unplayedWidth = fullRect.width - newWidth
. The origin is essentially newWidth
Plus the x-position of the waveform view.
Im just on my phone right now, so can’t write a full code sample but I hope this gives the direction.
from dswaveformimage.
Hey @dmrschmidt,
Any idea if is possible doing this in SwiftUI? thx.
from dswaveformimage.
can you please help me how can i make it draggable also currently i have the design requirement to show stripped waves
thank you @dmrschmidt
from dswaveformimage.
Im using UIKit and i think it will same on UIKIt too i need to add gesture in updateProgressWaveform function? Am i right?
from dswaveformimage.
Thank you for answering Please tell me should i need to add another image over the static image as mask then on that mask i should add pan gesture and for progress i should use the value that is coming from Pan gesture in and pass it to updateProgrssWaveform Thanks for help 🙌🏻
from dswaveformimage.
So in the example above you need 2 identical images of your waveform on top of each other, each with a different color. The one referenced in that example as
playbackWaveformImageView
is the top one, which indicates the playback progress / dragging position.That is the one getting the mask applied, so you only need 2 images. (The lower one just isn't referenced in that code, cause its static).
Where you add the pan gesture recognizer depends on your desired UX. One option is you'll add it on the view containing both the images. And yes, then you will need to do some math to map the current dragging position to the desired progress of the waveform. Maybe taking the initial position where the user touched into account or maybe not. Definitely with some calculation, because the pan recognizer gives you
CGPoint
andupdateProgrssWaveform
requires a Double between 0 and 1. It really depends a whole lot on how you want this to behave in the end.
Thank you soo much. I am working on a text to speech converter app and I'm working on a simple player to show the progress and allow user to drag the seek bar
from dswaveformimage.
you're welcome. and good luck with that @tayyab13-git!
from dswaveformimage.
Can you give me detailed instructions on how to play an audio file that has a waveform like this?
Thank you @dmrschmidt
from dswaveformimage.
I still don't understand what is the viewModel here? and where is playbackWaveformIamgeView
from dswaveformimage.
Are you using UIKit or SwiftUI?
from dswaveformimage.
I use SwiftUI
from dswaveformimage.
Then the code mentioned in #21 (comment) does everything you need to show the playback progress.
The comments referencing playbackWaveformImageView are irrelevant for you, as that’s UIKit.
from dswaveformimage.
Related Issues (20)
- Wavefrom form Data in SwiftUI HOT 7
- WaveformLiveView for Local Path HOT 13
- There's many different ways this could be achieved. HOT 3
- Fatal error HOT 3
- Current amplitude HOT 1
- Empty audio not displayed even with Should Draw Silence HOT 6
- Compile error in Xcode 15 beta. HOT 2
- Missing Pause Functionality HOT 1
- -11800 Error code when generation samples on iOS 17 beta HOT 10
- mp3 File not support HOT 8
- xcode 15 not support. Stored properties cannot be marked unavailable with '@available' HOT 1
- Striped style with gradient HOT 2
- Stored properties cannot be marked unavailable with '@available' HOT 3
- Stored properties cannot be marked unavailable with '@available' HOT 1
- Thread 1: EXC_BAD_ACCESS (code=2, address=0x2829857c4) HOT 1
- WaveForm Flickering HOT 2
- Extra argument position in call error in MacOS HOT 1
- I need to show loader till complete image generating from audio URL. HOT 2
- Update version in cocoapod HOT 2
- crash in iOS 17 HOT 10
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from dswaveformimage.