Skip to content

v2 "processors"#1

Draft
Axwabo wants to merge 126 commits intomainfrom
processors
Draft

v2 "processors"#1
Axwabo wants to merge 126 commits intomainfrom
processors

Conversation

@Axwabo
Copy link
Owner

@Axwabo Axwabo commented Jan 3, 2026

This PR adds a new system to manage encapsulated resources, allowing for automatic disposal of resources without the consumer having to store and dispose of everything.

Users are strongly encouraged to migrate to this system instead of manually disposing of audio resources.

Several helper extension methods and properties have been added to simplify code.

There are many breaking changes, however, most functionality should work when using binaries compiled against v1.

Migration Guide

See the wiki

Important notes
  • Resources are now managed by the AudioPlayer and audio processors. If you manage a resource yourself, pass false to methods with an isOwned parameter
    • Call WithUnmanagedProvider or WithProviderOwnership, or set OwnsProvider to control whether the AudioPlayer should dispose of the provider
  • Prefer using the IAudioProcessor interface and its existing implementations. See the Processors namespace
    • This interface extends ISampleProvider and IDisposable
    • Use the ProcessorChain class (also available with the ToCompatibleChain extension method) to stack effects while preserving public access to the original provider
    • Use the Mixer class instead of MixingSampleProvider
    • Use the AudioQueue class instead of ConcatenatingSampleProvider
    • Use the StreamAudioProcessor class instead of managing WaveStreams yourself. Factory methods are available via static extensions or the CreateAudioProcessor and TryCreateAudioProcessor classes
  • Many methods have been marked obsolete and will prevent projects from being built. The messages should mostly explain how to migrate each call
  • Call UseFile on an AudioPlayer to have it play a file and dispose of the stream when the provider changes or if the player is destroyed/pooled
  • AudioPlayer extension properties such as CurrentTime and TotalTime will work if the player uses a StreamAudioProcessor/RawSourceSampleProvider, or if there's a single mixer input with an aforementioned type
  • Check out the example changes below to see how some things can be migrated

Important

Obsolete members will be removed after the beta (when v2 is fully released).

Caution

Several AudioPlayer extension methods and properties rely on getting the single mixer input. This means that either the provider itself has to match, or if the provider is a Mixer, there should be exactly one input matching.
Mixer takes precedence over the AudioQueue in such scenarios.

Tip

Upgrade your project to C# 14 (optional, but encouraged). Add <LangVersion>14</LangVersion> into a PropertyGroup in your csproj.
You will need the .NET 10 SDK.

Example Changes

See the wiki

Changes (breaking)

To reduce ambiguity and breaking changes, old methods have been kept, and the ones using new functionality have received different names.

  • Marked the following classes obsolete: LoopingRawSampleProvider LoopingWaveProvider ConditionalOneTimeDisposable
    • RawSourceSampleProvider now has a Loop property
    • Use the StreamAudioProcessor class and set the Loop property (or call WithLoop)
  • Marked SampleProviderExtensions/WaveProviderExtensions and their methods obsolete in favor of audio processors; if absolutely needed, most methods have been moved to SecretLabNAudio.Core.Extensions.Providers.NonProcessorExtensions
    • Queue - use the AudioQueue class
    • Buffer - use a ProcessorChain, or call the BufferedSampleProvider constructor
    • MixWith use a Mixer
  • Marked some AudioPlayerExtensions obsolete:
    • DisposeOnDestroy - encapsulate resources in an audio processor instead, or manage the disposal yourself
    • MixingSampleProvider-related methods - call the new Mix methods
    • WithProvider methods - use audio processors, or call WithUnmanagedProvider if the provider shouldn't be disposed automatically
    • Buffer - use a ProcessorChain
    • ProviderAs - call ImmediateProviderAs
  • Marked RawSampleProviderExtensions.Loop obsolete; call WithLoop
  • Marked WaveStreamExtensions.Loop obsolete; create a StreamAudioProcessor instead

Fixes

  • System.ValueTuple.dll is now included in releases (also as an embedded resource in SecretLabNAudio.dll), this fixes some .ogg files not being able to load
  • SpeakerPersonalization will no longer throw an exception when changing the speaker settings for a disconnected player
  • Speakers returned to the pool will now be unparented
  • ShortClipCache no longer sets the ClipName of the copy to the provided key
  • Fixed some docs
  • AudioPlayerPool.Return no longer throws if passing a destroyed player

Additions

  • SpeakerToyGroup and extensions
  • AudioPlayer properties: OwnsProvider AlwaysRead
  • AudioPlayer extension properties:
    • Queue gets the single AudioQueue input
    • Mixer safely casts the SampleProvider
    • CurrentTime TotalTime IsLooping (when there's a single ILoopable or ISeekable input)
    • Group IsGrouped IsGroupController IsGroupChild
  • AudioPlayer extension methods:
    • Resume WithoutProvider WithProviderOwnership
    • Generic methods SourceAs MasterAs SingleInputAs to extract a type of processor
    • Several new Mixer-related methods
    • Loop Restart (when there's a single ILoopable or ISeekable input)
    • Use methods to replace providers
    • Mix methods to add providers to the Mixer
    • Enqueue methods to queue inputs in the AudioQueue
    • CloneOutput and other grouping methods
    • WithLivePersonalizedSendEngine overload without the SpeakerPersonalization component (will use the attached component, or add one to the speaker if needed)
  • SpeakerToy extensions:
    • DestroySafe doesn't throw if the speaker's been destroyed
    • SpeakerToyGroup-related methods and properties
  • SpeakerPersonalization extension method ClearAllOverrides
  • Audio processors that dispose of encapsulated resources: AudioQueue Mixer ProcessorChain SampleProviderWrapper StreamAudioProcessor
  • Audio processor extensions namespace
  • CreateAudioProcessor and TryCreateAudioProcessor classes
  • ILoopable and ISeekable interfaces (implemented by StreamAudioProcessor and RawSourceSampleProvider, as well as the now obsolete LoopingRawSampleProvider)
    • LoopingWaveProvider (obsolete) implements ISeekable
  • Static SpeakerSettings.GloballyAudible property
  • ClipName struct
  • Maximum duration support in ShortClipCache
  • ShortClipCache methods: AddAllFromDirectory GetSafe Get
  • WaveFormatExtensions methods: Time Matches
  • IsPooled methods in pool classes
  • Added a README to the demo project

Note

Extension properties are only available in C# 14 (or newer).

Changes (non-breaking)

  • Simplified the release workflow
  • Changed global usings
  • Refactored (almost) all extension methods to be in extension blocks
  • Used XML documentation includes to reduce duplicated lines in some places
  • Simplified the AudioPlayer::OnDestroy Unity event
  • AudioPlayerExtensions.UnsetProviderOnEnd now sets the AlwaysRead property instead of subscribing to NoSamplesRead
  • Bumped LabAPI to 1.1.5

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.

1 participant