Skip to content

Main Bus File Playback#100

Merged
joelmacx merged 11 commits intomainfrom
player-mb-state
Feb 12, 2026
Merged

Main Bus File Playback#100
joelmacx merged 11 commits intomainfrom
player-mb-state

Conversation

@joelmacx
Copy link
Copy Markdown
Collaborator

@joelmacx joelmacx commented Feb 2, 2026

Description

Playing audio back through arbitrary system devices causes issues in some DAWs. This work moves file playback to the audio processor chain.

Changes

  1. Add a playback processor for file playback.
  2. Remove dead player and UI code.
  3. Simplify the async work required by the IAMF decoder.

Validation and Acceptance Criteria

  • Added unit test coverage for the new processor.
  • DAW testing. Test basic player functionality as well as different state transitions like exporting while playing a file, deleting the processor while buffering, deleting the processor while playing etc.

Validated in:

  • Pro Tools (MacOS)
  • Reaper (MacOS)
  • Premiere Pro (MacOS)
  • Pro Tools (Windows)
  • Reaper (Windows)

}
if (selectionBox_.getNumItems() == 1) {
selectionBox_.setSelectedId(1);
selectionBox_.setSelectedId(1, juce::dontSendNotification);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This was causing hard to trace state changes during UI initialization.

return seekFrame(frameIdx, abort);
}

bool IAMFFileReader::seekFrame(const size_t frameIdx,
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Updating the seek method to make it cancellable as seeking often requires parsing large amounts of data.

FilePlayback fpb = fpbr_.get();
fpb.setPlaybackFile("");
fpb.setPlaybackCommand(FilePlayback::PlaybackCommand::kPause);
fpbr_.update(fpb);
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I've learned the hard way that it's much simpler to have processors depend on one repository for their state / commands. This is also a more obvious approach to resetting the player.

if (FileExport::validateFilePath(
FileExport::expandTildePath(kIamfPath).toStdString(), false)) {
// Clean up the file if it exists
std::filesystem::remove(kIamfPath.toStdString());
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This line causes difficult problems.

As it relates to the player, when export starts we want to release any handles we have to the file that is to be written. This is done asynchronously (we don't want to freeze the audio thread) as it requires joining multiple threads and doing other cleanup. As it's asynchronous there's no guarantee by the time we reach this line that the file has been relinquished.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What happens if we export to a file that is being held or being played?

I guess it's fine if writing to the file doesn't cause issues, maybe this is handled sensibly by the filesystem somehow. But if it blocks export then we should try and release the handles and then flag for the process to continue somehow.

Handle and filesystem behaviour might differ between windows and macos as well.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

We do destroy the reader when export begins here so it should technically be fine to delete this file.

I would prefer to let the host OS handle what to do in case things got out of sync at some point and there is a write to a file currently being read. If this were to occur, my position is that it's better in this case to continue reading from the outdated file than to crash - let the OS handle the file conflicts.

In my testing in MacOS and Windows DAWs there aren't any crashes if you start an export while buffering or while playing.

audioElementSpatialLayoutRepository_->registerListener(this);

// Tie the horizontal scrollbars together
profileSelectionBox_.onChange([this]() {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Moved callback enabling for this component to after all the other initialization is done.

@joelmacx joelmacx self-assigned this Feb 3, 2026
Copy link
Copy Markdown
Collaborator

@BrandenAvalonCx BrandenAvalonCx left a comment

Choose a reason for hiding this comment

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

I noticed 2 issues when testing:

  • After seeking to the midpoint of the file, if I change Mix Presentation layout and then press play, the player shows that it will play from the middle of the file, but actually plays from the start again. Probably the file should be played from the middle, where the caret shows.
  • Seeking in general is a bit tough, since there's an immediate load when you click on the seek bar. Maybe we can start seeking on release / mouse button up? In this way would I be able to see the value I'm scrolling the seek to? Not sure if this worked before, so if not we can make it a future improvement instead.

if (FileExport::validateFilePath(
FileExport::expandTildePath(kIamfPath).toStdString(), false)) {
// Clean up the file if it exists
std::filesystem::remove(kIamfPath.toStdString());
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What happens if we export to a file that is being held or being played?

I guess it's fine if writing to the file doesn't cause issues, maybe this is handled sensibly by the filesystem somehow. But if it blocks export then we should try and release the handles and then flag for the process to continue somehow.

Handle and filesystem behaviour might differ between windows and macos as well.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Superficial test changes as I renamed the type it was testing and adjusted its constructor

@joelmacx
Copy link
Copy Markdown
Collaborator Author

I noticed 2 issues when testing:

  • After seeking to the midpoint of the file, if I change Mix Presentation layout and then press play, the player shows that it will play from the middle of the file, but actually plays from the start again. Probably the file should be played from the middle, where the caret shows.
  • Seeking in general is a bit tough, since there's an immediate load when you click on the seek bar. Maybe we can start seeking on release / mouse button up? In this way would I be able to see the value I'm scrolling the seek to? Not sure if this worked before, so if not we can make it a future improvement instead.

Changing the layout properly resets playback position. Seeking is now only submitted after release on drag.

Copy link
Copy Markdown
Collaborator

@BrandenAvalonCx BrandenAvalonCx left a comment

Choose a reason for hiding this comment

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

I think this looks good, I think the cleanup makes this a bit simpler. Tested with REAPER and playback seems to be working fine. I wouldn't mind a few minor improvements, but I think these can be handled as later work.

I think just a general comment, I wouldn't mind seeing more comments in these larger changes. It may be worth writing a longer comment at the top of the FilePlaybackProcessor explaining the logic and how it works in case we need to make adjustments in the future.

@joelmacx joelmacx merged commit f58bc28 into main Feb 12, 2026
3 checks passed
@joelmacx joelmacx deleted the player-mb-state branch February 12, 2026 17:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants