|
| | AudioBuffer ()=delete |
| | AudioBuffer (const AudioBuffer &)=delete |
| | AudioBuffer (AudioBuffer &&) noexcept=default |
| auto | operator= (const AudioBuffer &) -> AudioBuffer &=delete |
| auto | operator= (AudioBuffer &&) noexcept -> AudioBuffer &=default |
| | AudioBuffer (f_cnt_t frames, ch_cnt_t channels=DEFAULT_CHANNELS, std::pmr::memory_resource *resource=std::pmr::get_default_resource()) |
| template<class F> |
| | AudioBuffer (f_cnt_t frames, ch_cnt_t channels, group_cnt_t groups, std::pmr::memory_resource *resource, F &&groupVisitor) |
| void | allocateInterleavedBuffer () |
| | The presence of the temporary interleaved buffer is opt-in. Call this to create it.
|
| auto | hasInterleavedBuffer () const -> bool |
| auto | groupCount () const -> group_cnt_t |
| auto | group (group_cnt_t index) const -> const ChannelGroup & |
| auto | group (group_cnt_t index) -> ChannelGroup & |
| auto | allBuffers () const -> PlanarBufferView< const float > |
| auto | allBuffers () -> PlanarBufferView< float > |
| auto | groupBuffers (group_cnt_t index) const -> PlanarBufferView< const float > |
| auto | groupBuffers (group_cnt_t index) -> PlanarBufferView< float > |
| auto | buffer (ch_cnt_t channel) const -> std::span< const float > |
| auto | buffer (ch_cnt_t channel) -> std::span< float > |
| auto | totalChannels () const -> ch_cnt_t |
| auto | frames () const -> f_cnt_t |
| auto | interleavedBuffer () const -> InterleavedBufferView< const float, 2 > |
| auto | interleavedBuffer () -> InterleavedBufferView< float, 2 > |
| auto | addGroup (ch_cnt_t channels) -> ChannelGroup * |
| | Adds a new channel group at the end of the list.
|
| template<class F> |
| void | setGroups (group_cnt_t groups, F &&groupVisitor) |
| | Changes the channel grouping without changing the channel count. Does not reallocate any buffers.
|
| auto | silenceFlags () const -> const ChannelFlags & |
| void | assumeNonSilent (ch_cnt_t channel) |
| | Forcibly pessimizes silence tracking for a specific channel.
|
| void | enableSilenceTracking (bool enabled) |
| auto | silenceTrackingEnabled () const -> bool |
| void | mixSilenceFlags (const AudioBuffer &other) |
| | Mixes the silence flags of the other AudioBuffer with this AudioBuffer.
|
| auto | hasSignal (const ChannelFlags &channels) const -> bool |
| auto | hasAnySignal () const -> bool |
| | Checks whether any channel is non-silent (has a signal).
|
| void | sanitize (const ChannelFlags &channels, ch_cnt_t upperBound=MaxChannelsPerAudioBuffer) |
| | Sanitizes specified channels of any Inf/NaN values if "nanhandler" setting is enabled.
|
| void | sanitizeAll () |
| | Sanitizes all channels.
|
| auto | updateSilenceFlags (const ChannelFlags &channels, ch_cnt_t upperBound=MaxChannelsPerAudioBuffer) -> bool |
| | Updates the silence status of the given channels, up to the upperBound index.
|
| auto | updateAllSilenceFlags () -> bool |
| | Updates the silence status of all channels.
|
| void | silenceChannels (const ChannelFlags &channels, ch_cnt_t upperBound=MaxChannelsPerAudioBuffer) |
| | Silences (zeroes) the given channels.
|
| void | silenceAllChannels () |
| | Silences (zeroes) all channels.
|
| auto | absPeakValue (ch_cnt_t channel) const -> float |
An owning collection of audio channels for an instrument track, mixer channel, or audio processor.
Features:
- Up to MaxChannelsPerAudioBuffer total channels
- Audio data in planar format (plus a temporary interleaved buffer for conversions until we use planar only)
- All planar buffers are sourced from the same large buffer for better cache locality
- Custom allocator support
- Silence tracking for each channel (NOTE: requires careful use so that non-silent data is not written to a channel marked silent without updating that channel's silence flag afterward)
- Methods for sanitizing, silencing, and calculating the absolute peak value of channels, and doing so more efficiently using the data from silence tracking
- Can organize channels into arbitrary groups. For example, you could have 6 total channels divided into 2 groups where the 1st group contains 2 channels (stereo) and the 2nd contains 4 channels (quadraphonic).
- Extensive unit testing - AudioBufferTest.cpp
Audio data layout explanation:
- All planar audio data for all channels in an AudioBuffer is sourced from the same large contiguous buffer called the source buffer (m_sourceBuffer).
- The source buffer consists of the buffer for 1st channel followed by the buffer for the 2nd channel, and so on for all channels. In total, the number of elements is channels * frames.
- A separate vector of non-owning pointers to channel buffers is also maintained. In this vector, each index corresponds to a channel, providing a mapping from the channel index to a pointer to the start of that channel's buffer within the source buffer. This is called the access buffer (m_accessBuffer).
- The purpose of the access buffer is to provide channel-wise access to buffers within the source buffer, so it's m_accessBuffer[channelIdx][frameIdx] instead of m_sourceBuffer[channelIdx * frames + frameIdx]. This is very important since many APIs dealing with planar audio expect it in this float** 2D array form.
- Groups have no effect on the audio data layout in the source/access buffers and are merely a layer built on top. Conveniently, if you take m_accessBuffer and offset it by channelIndex, you get another float** starting at that channel. This what the float** buffer stored in each ChannelGroup is.
Naming notes:
- When this class is used in an instrument track or mixer channel, its channels could be referred to as "track channels" or "internal channels", since they are equivalent to the "track channels" used in other DAWs such as REAPER.
- When this class is used in an audio processor or audio plugin, its channels could be referred to as "processor channels" or "plugin channels".
| void lmms::AudioBuffer::enableSilenceTracking |
( |
bool | enabled | ) |
|
When silence tracking is enabled, channels will be checked for silence whenever their data may have changed, so it'll always be known whether they are silent or non-silent. There is a performance cost to this, but it is likely worth it since this information allows many effects to be put to sleep when their inputs are silent ("auto-quit"). When a channel is known to be silent, it also enables optimizations in buffer sanitization, buffer zeroing, and finding the absolute peak sample value.
When silence tracking is disabled, channels are not checked for silence, so a silence flag may be unset despite the channel being silent. Non-silence must be assumed whenever the silence status is not known, so the optimizations which silent buffers allow will not be possible as often.
Channels which are known to be quiet, AKA the silence status. 1 = channel is known to be silent 0 = channel is assumed to be non-silent (or, when silence tracking is enabled, known to be non-silent)
NOTE: If any channel buffers are used and their data modified outside of this class, their silence flags will be invalidated until updateSilenceFlags() is called. Therefore, calling code must be careful to always keep the silence flags up-to-date.
Stores which channels are known to be quiet, AKA the silence status.
This must always be kept in sync with the buffer data when enabled - at minimum avoiding any false positives where a channel is marked as "silent" when it isn't. Any channel bits at or above totalChannels() must always be marked silent.
1 = channel is known to be silent 0 = channel is assumed to be non-silent (or, when silence tracking is enabled, known to be non-silent)