Skip to content

max: fix crash on DSP start with fixed/wider output buses#127

Merged
jcelerier merged 1 commit into
mainfrom
fix/max-audio-output-channel-count
Jul 1, 2026
Merged

max: fix crash on DSP start with fixed/wider output buses#127
jcelerier merged 1 commit into
mainfrom
fix/max-audio-output-channel-count

Conversation

@jcelerier

Copy link
Copy Markdown
Member

Bug

A Max audio external built from an object with a fixed output bus (e.g. fixed_audio_bus<double, 2>) crashes the instant audio (DSP) starts when fed a mono source.

Root cause

audio_processor's multichanneloutputs handler reported the runtime input channel count:

static constexpr auto outputcount = +[](instance* x, long index) -> long {
    // FIXME compute it better
    return x->m_runtime_input_count;
};

But dsp() allocates — and the object writes — max(output_channels, input_chans) output channels. With a mono cycle~ → the effect, Max was told to allocate 1 output channel, while the object's operator() unconditionally writes outputs.audio.channel(1, N) too → out-of-bounds write in perform() → hard crash on the first DSP tick.

Fix

Report the same count dsp() uses:

const long ins = std::max<long>(instance::input_channels, x->m_runtime_input_count);
return std::max<long>(instance::output_channels, ins);

A mono source into a fixed-stereo effect now gets 2 output channels allocated, matching what the object writes.

Verification

Built the oscr_Distortion external (Tutorial/Distortion, fixed_audio_bus<double, 2> output) and ran it in Max 8: cycle~ 220oscr_Distortionezdac~ with DSP auto-started via loadbang → [; dsp 1(. Before: crash on DSP start. After: runs cleanly for 30s+, empty Max console, no crash dialog.

Found while GUI-verifying the auto-generated help patches (unrelated PR #126); this is a pre-existing Max-binding bug.

🤖 Generated with Claude Code

The Max audio object's `multichanneloutputs` handler returned the runtime
*input* channel count, but dsp() allocates and the object writes
max(output_channels, input_chans) output channels. For an effect with a fixed
output bus (e.g. fixed_audio_bus<double, 2>) fed a mono signal, Max was told to
allocate 1 output channel while the object unconditionally writes channel 1 too
-> out-of-bounds write in perform() -> hard crash the moment DSP starts.

Report the same channel count dsp() uses: max(output_channels,
max(input_channels, runtime_input_count)). Now a mono source into a fixed-stereo
effect gets 2 output channels allocated and runs cleanly.

Verified in Max 8: cycle~ -> oscr_Distortion (fixed_audio_bus<..,2> out) -> ezdac~
with DSP on no longer crashes (survives with an empty console; previously it
crashed on the first perform call).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011s7huWR2wFsLFiMJPjx1z2
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