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

Adds split_once to Source #675

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open

Adds split_once to Source #675

wants to merge 10 commits into from

Conversation

dvdsk
Copy link
Collaborator

@dvdsk dvdsk commented Jan 10, 2025

split_once can be used chop a source into two sources without duplicating the first. Those sources can then not be played simultaneously. This is usefull for adding a fadeout at the end of a song for example. Though we could later specialize fadeout at end.

The implementation uses a SplitAt struct, split_once returns an array of two of those. In the future we can introduce methods like split that return a vec of SplitAt's allowing users to chop a source into multiple sections

split_once can be used chop a source into two sources without
duplicating the first. Those sources can then not be played simultaneously.
This is usefull for adding a fadeout at the end of a song for example.
Though we could later specialize fadeout at end.

The implementation uses a `SplitAt` struct, `split_once` returns an array of
two of those. In the future we can introduce methods like `split` that
return a vec of SplitAt's allowing users to chop a source into multiple
sections
Copy link
Collaborator

@PetrGlad PetrGlad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I do not like that first_span_ stuff but this can be cleaned up later.

Alternatively, if the motivation is to support for fade-out, we can modify fade-out to start at some later moment (it would pass-through until it's time to ramp down). Maybe we can even have arbitrary "automation" lane, with piece-wise gain function (can be even smoothed with splines :)

@@ -498,6 +500,15 @@ where
skippable::skippable(self)
}

/// returns two sources, the second source is inactive and will return
/// `None` until the first has passed the split_point.
fn split_once(self, at: Duration) -> [SplitAt<Self>; 2]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not split_at? To me it sounds easier to understand.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

named after: https://doc.rust-lang.org/std/primitive.str.html#method.split_once, we might later want a split method that takes a vec of durations and returns a vec of SplitAts

We can do split_once_at?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

split_once in std uses content of the sequence as delimiter. So, number of pieces in the result is unpredictable, the delimiter can occur more than once. Therefore, in that case it is necessary to distinguish the method that uses only first delimiter from one that returns all the fragments. In this case of the Source splitter, the delimiter is time which is unique.

Copy link
Collaborator Author

@dvdsk dvdsk Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point however I think there is still a good case here: we are returning the results on the stack (via the array) allows unpacking & increasing performance, for example:

let [start, end] = some_source.split_once(..);

is easier and safer (hidden panic in [0] & [1] that can not be checked compile time) then:

let split = some_source.split(..);
let start = split[0];
let end = split[1];

@@ -622,6 +635,9 @@ impl fmt::Display for SeekError {
#[cfg(feature = "wav")]
SeekError::HoundDecoder(err) => write!(f, "Error seeking in wav source: {}", err),
SeekError::Other(_) => write!(f, "An error occurred"),
SeekError::SplitNotActive => {
Copy link
Collaborator

@PetrGlad PetrGlad Jan 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FragmentNotActive (or FragmentIsNotActive), maybe...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By using the word split I hope to have users associate the error with the split_once function and SplitAt struct. Fragment is another term so that association is gone.

What is the problem with SplitNotActive? I agree its not a very clear term.

Copy link
Collaborator

@PetrGlad PetrGlad Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, maybe. I thought that "fragment" maybe become useful in other places where partial sources will be used...

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

English is not my native language but to me it feels like "split" normally refers to the location or cause of divide, not the parts it separates.

Copy link
Collaborator Author

@dvdsk dvdsk Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with your motivation, Ill rename it to Segment (fragment means a small bit of a larger whole and these segments can be quite large)

src/source/split_at.rs Outdated Show resolved Hide resolved
src/source/split_at.rs Outdated Show resolved Hide resolved
src/source/split_at.rs Outdated Show resolved Hide resolved
src/source/split_at.rs Outdated Show resolved Hide resolved
@dvdsk
Copy link
Collaborator Author

dvdsk commented Jan 12, 2025

Alternatively, if the motivation is to support for fade-out, we can modify fade-out to start at some later moment (it would pass-through until it's time to ramp down).

That was the one of the motivations for creating this. It seemed valuable to have a method of splitting a source into two "mutable" sections for other effects. I thought about a fadeout_end source but it would only be marginally more efficient. It is easier to use/find but I think Sink/ the new Player should help out with that. The Player should get a fadeout_end setting.

@dvdsk
Copy link
Collaborator Author

dvdsk commented Jan 12, 2025

Maybe we can even have arbitrary "automation" lane, with piece-wise gain function (can be even smoothed with splines :)

This sounds interesting though I do not fully get how it should work yet.

@dvdsk
Copy link
Collaborator Author

dvdsk commented Jan 12, 2025

ill fixup your suggestions later, gotta get to bed now 🌔

edit: oh and thanks for a clear and useful review!

@dvdsk
Copy link
Collaborator Author

dvdsk commented Jan 14, 2025

ready for review again

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

Successfully merging this pull request may close these issues.

2 participants