Skip to content

Add channel seek and playback position support#15

Open
applebutter180 wants to merge 3 commits into
AmplitudeAudio:developfrom
applebutter180:seek-channel-playback-position
Open

Add channel seek and playback position support#15
applebutter180 wants to merge 3 commits into
AmplitudeAudio:developfrom
applebutter180:seek-channel-playback-position

Conversation

@applebutter180
Copy link
Copy Markdown

@applebutter180 applebutter180 commented May 9, 2026

Add public Channel APIs for setting and querying playback position:
SetPlaybackPosition(AmTime) and GetPlaybackPosition(). The public API uses
AmTime milliseconds, while the mixer continues to use frame-based cursors
internally.

Keep v1 behavior scoped to single-layer channels and blended instancing.
Separate instancing remains unsupported for channel-level playback-position
control and is rejected with a warning. The internal RealChannel::Seek()
path is retained as the implementation detail behind the public API.

Defer playback cursor changes through the Amplimix command queue so cursor
updates run after the current mix iteration. Add AmplimixImpl::ResetLayerState()
to reset the layer data converter and pipeline through ResetPipeline() after
a cursor change, avoiding direct mixer-state mutation during audio rendering.

Add and update tests for normal playback-position changes, paused changes,
playback-position advancement, blended instancing, separate-instancing
rejection, negative position clamping, invalid/stale channel state rejection,
invalid mixer cursor operations, and CI-stable playback cleanup.

This should address #14

Add public Channel APIs for seeking to an AmTime playback position and
querying the current playback position. Wire the calls through channel
state, real channels, and Amplimix cursor access using millisecond-based
public units and frame-based mixer cursors internally.

Keep v1 behavior scoped to single-layer channels and blended instancing,
while warning and rejecting separate instancing. Reset converter and
pipeline state on the mixer thread after cursor changes to avoid racing
audio teardown, and preserve audio converter channel conversion state
across resets.

Add tests for normal seek, paused seek, playback-position advancement,
blended instancing, separate-instancing rejection, and converter reset
configuration preservation.

Co-Authored-By: Codex GPT-5.5 High <[email protected]>
@na2axl na2axl added the enhancement New feature or request label May 9, 2026
Copy link
Copy Markdown
Member

@na2axl na2axl left a comment

Choose a reason for hiding this comment

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

@applebutter180 thank you for your contribution. Here is a small initial review before further tests:

I don't recommend to set the cursor right away. It's better to make use of the command system in Amplimix to push a SetCursor+ResetState command to be executed right after the current mix loop iteration. That will ensure no possible reads of sound data during update. GetCursor() is safe since it only reads data.

You can do that directly in RealChannel::Seek(), with something like:

_mixer->PushCommand([this, layerId = data.mixerLayerId, cursor]() {
  _mixer->SetCursor(_channelId, layerId, cursor);
  _mixer->ResetLayerState(_channelId, layerId); // You may need to create this method
  return true;
});

Amplimix::ResetLayerState() will:

  1. Get the pointer to the layer
  2. Reset the data converter
  3. Reset the pipeline (but using AmplimixLayerImpl::ResetPipeline() insted of raw reset)

Comment thread include/SparkyStudios/Audio/Amplitude/Core/Playback/Channel.h Outdated
Comment thread include/SparkyStudios/Audio/Amplitude/Core/Playback/Channel.h Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented May 10, 2026

Codecov Report

❌ Patch coverage is 58.90411% with 30 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/Mixer/RealChannel.cpp 37.84% 13 Missing and 10 partials ⚠️
src/Mixer/Amplimix.cpp 75.00% 0 Missing and 3 partials ⚠️
src/Core/Playback/Channel.cpp 75.00% 0 Missing and 2 partials ⚠️
src/Core/Playback/ChannelInternalState.cpp 87.50% 0 Missing and 2 partials ⚠️
Files with missing lines Coverage Δ
src/Core/Playback/ChannelInternalState.h 86.67% <ø> (ø)
src/DSP/AudioConverter.cpp 67.45% <ø> (-8.42%) ⬇️
src/Mixer/Amplimix.h 100.00% <ø> (ø)
src/Core/Playback/Channel.cpp 48.00% <75.00%> (-16.10%) ⬇️
src/Core/Playback/ChannelInternalState.cpp 43.80% <87.50%> (+0.91%) ⬆️
src/Mixer/Amplimix.cpp 54.43% <75.00%> (+0.22%) ⬆️
src/Mixer/RealChannel.cpp 41.83% <37.84%> (-7.29%) ⬇️

... and 45 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Rename the public channel seek API to SetPlaybackPosition() while keeping
the internal RealChannel::Seek() path, and update the public Doxygen style
to match the SDK headers.

Defer playback cursor changes through the Amplimix command queue and add
ResetLayerState() so cursor updates reset the converter and pipeline after
the current mix iteration. This follows maintainer feedback and avoids
mutating mixer state directly during playback.

Stabilize the playback-position and basic playback tests for CI, including
the macOS timing-sensitive sound test, Ubuntu playback-position advance
test, and Windows collection cleanup assertion. Add coverage tests for
negative seek clamping, invalid/stale channel state rejection, and invalid
mixer cursor operations.

Co-Authored-By: Codex GPT-5.5 High <[email protected]>
Copy link
Copy Markdown
Member

@na2axl na2axl left a comment

Choose a reason for hiding this comment

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

LGTM! The remaining review comments are just esthetics. I will run some manual smoke tests locally before the final merge.

Comment on lines +218 to +219
* If the audio on this channel
* doesn't support positional data, this method will return an invalid location.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Revert accidental line break here

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Should be fixed in 950fc2b

Comment thread src/Mixer/Amplimix.cpp
AMPLIMIX_STORE(&lay->baseSampleRateRatio, baseRatio);
// store the initial value for sample rate ratio
AMPLIMIX_STORE(&lay->sampleRateRatio, baseRatio * pitch * speed);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Revert accidental line delete

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Should be fixed in 950fc2b

Comment thread src/Mixer/RealChannel.h Outdated
Comment on lines +95 to +96
* @param position The playback
* position in milliseconds.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Remove accidental line break

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Should be fixed in 950fc2b

Comment thread src/Mixer/RealChannel.h Outdated
Comment on lines +105 to +106
* @return The current playback position in
* milliseconds.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Remove accidental line break

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Should be fixed in 950fc2b

AM_EXPECT(channel.GetInstancingMode() == eChannelInstanceMode_Blended);

constexpr AmTime seekPosition = 1000.0;
AM_EXPECT(channel.SetPlaybackPosition(seekPosition));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We can add an expectation that checks if the current playaback position is < than seekPosition before to set

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Should be fixed in 950fc2b

AM_EXPECT(channel.Playing());

constexpr AmTime seekPosition = 1000.0;
AM_EXPECT(channel.SetPlaybackPosition(seekPosition));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We can add an expectation that checks if the current playback position is < than seekPosition before to set

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Should be fixed in 950fc2b

AM_EXPECT_EQ(channel.GetPlaybackState(), eChannelPlaybackState_Paused);

constexpr AmTime seekPosition = 25.0;
AM_EXPECT(channel.SetPlaybackPosition(seekPosition));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We can add an expectation that checks if the current playback position is < than seekPosition before to set

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Should be fixed in 950fc2b

Undo accidental formatting changes in nearby documentation and mixer setup code. Add explicit pre-seek playback-position expectations to the seek tests so they verify the cursor actually moves forward from an earlier position.

Co-Authored-By: Codex GPT-5.5 High <[email protected]>
@applebutter180 applebutter180 requested a review from na2axl May 11, 2026 22:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants