Getting an const dsp::AudioBlock out of a const AudioBuffer

I don’t see a (non-ugly, involving const_casts etc.) way to get a const dsp::AudioBlock view of a const AudioBuffer. Is there one?

A nice way to do it would be to have a “const constructor” for dsp::AudioBlock which would accept a const AudioBuffer& and produce a const dsp::AudioBlock. Unfortunately, C++ doesn’t have such a thing as a “const constructor” :slight_smile:

My use case is that I have an existing method returning const AudioBuffer&, and I would like to get a view of a channel of that buffer, using dsp::AudioBlock. Of course, it’s possible to just change the existing method, but that would entail more changes to any other users of the existing interface. Being able to more gradually integrate dsp::AudioBlock with existing use of AudioBuffer would be nice.

Edit: Trying to modify my method to return a dsp::AudioBlock instead of an const AudioBuffer& doesn’t work either, since my method is const, and so the AudioBuffer member is considered const, so constructing a dsp::AudioBlock from it fails (it also makes sense logically that it does - returning a dsp::AudioBlock would allow any caller to later modify the data it refers to, that is the AudioBuffer member, which shouldn’t be possible since the method is const).

Edit2: On second thought, even if I could get a const dsp::AudioBlock, once I copy it to a non-const one I would be able to modify the underlying buffer. So I guess it just come down to needing a different class for non-modifiable slices of buffers (similar to std::string_view).

Thoughts / suggestions?

3 Likes

Bumping due to no reply. JUCE team, would love to hear your thoughts about how to support slicing const AudioBuffers with existing classes, or whether you think a new class is required.

Thanks,
Dan

Bump.

A statement about this from someone from the JUCE team would be deeply appreciated.

Yeah… it’s a tricky one because of the vagueness of const-ness… For example, it’d be easy enough for us to add a function that takes a const AudioBuffer and returns a const AudioBlock from it. No problem. BUT then you can easily take that const AudioBlock and make a copy of it, which is now non-const, but which refers to the same underlying data, and lets you modify the original const AudioBuffer.

…however, just chatting about it here, we started to think that maybe that doesn’t matter so much, and it might just be OK to modify the existing constructor to allow a const AudioBuffer to be passed in… Thoughts?

1 Like

How about permitting AudioBlock<const T>, and then slicing either const AudioBuffer<T> or AudioBuffer<const T> (or const at both places) could return that type?

Has this ever been solved?

const juce::AudioBuffer<float> constBuffer;
const juce::dsp::AudioBlock<float> constBlock(constBuffer);


juce_dsp\containers\juce_AudioBlock.h(160,20): error C2440: 'initializing': cannot convert from 'const Type **' to 'SampleType *const *'
1>        with
1>        [
1>            Type=float
1>        ]
1>        and
1>        [
1>            SampleType=float
1>        ]
juce_dsp\containers\juce_AudioBlock.h(160,20): message : Conversion loses qualifiers

If you are on the current JUCE tip, this should work:

const juce::AudioBuffer<float> constBuffer;
juce::dsp::AudioBlock<const float> constBlock (constBuffer);

This wasn‘t possible at some point in JUCE 5, so we modified our JUCE fork to allow this, however it had been added at some point because when we updated to JUCE 6 a short time ago, we found this constructor in the official codebase :wink:

Note, that you can still write to a const dsp::AudioBlock<float> while a const dsp::AudioBlock<const float> is read-only.

Edit: This comes in handy when you are writing functions that take blocks as const references.

foo (const dsp::AudioBlock<float>& readWriteBlock, const dsp::AudioBlock<const float>& readOnlyBlock)
Can be called like

juce::AudioBuffer<float> a;
const juce::AudioBuffer<float> b;
juce::dsp::AudioBlock<float> c;
juce::dsp::AudioBlock<const float> d;

foo (a, a);
foo (a, b);
foo (c, c);
foo (c, d);

The implicit converting constructors and the const ref make it possible to write functions that accept all kinds of buffers & blocks which is nice if you have to work with a legacy AudioBuffer based codebase

4 Likes

Thanks a lot!