reckfellENGINE

Effects: bus processing and sample capture

Processing order, filtering and gain, Capture and Record; choose an effect for the task.

On this page

Where an effect acts

An effect processes its bus's combined signal, not just the most recently started player. The chain runs top to bottom. The bus then applies its volume/mute and sends the result onward. A compressor before an amplifier produces a different result than after it; choose order deliberately.

An AudioEffect resource holds parameters; an AudioEffectInstance performs processing. Reusing one resource in several places shares parameter changes. Create separate resources for independent settings. A heavy chain on every individual bus costs more than shared category processing.

Test a chain without an external file

Keep DemoTone.cs in the project. Attach EffectsDemo.cs below to a separate level's Control root, build and run with F6. Play / stop enables a 3000 Hz tone. Disabling the 500 Hz filter makes it substantially stronger; the -6 dB toggle changes gain by approximately half in amplitude. This checks routing, not comfortable loudspeaker volume.

EffectsDemo.cs
C#
using System;
using Reckfell;

public partial class EffectsDemo : Control
{
    public AudioStreamPlayer Voice { get; private set; } = null!;
    public AudioEffectAmplify Gain { get; private set; } = null!;
    public AudioEffectLowPassFilter Filter { get; private set; } = null!;
    public AudioEffectCapture Capture { get; private set; } = null!;
    public int BusIndex => AudioServer.GetBusIndex(_bus);
    private string _bus = "";

    public override void _Ready()
    {
        bool ru = TranslationServer.GetLocale().StartsWith("ru", StringComparison.OrdinalIgnoreCase);
        _bus = "EffectsDemo_" + GetInstanceId();
        AudioServer.AddBus(); int bus = AudioServer.BusCount - 1;
        AudioServer.SetBusName(bus, _bus); AudioServer.SetBusSend(bus, "Master");
        Gain = new AudioEffectAmplify { VolumeDb = -6 };
        Filter = new AudioEffectLowPassFilter { CutoffHz = 500 };
        Capture = new AudioEffectCapture { BufferLength = 1 };
        AudioServer.AddBusEffect(bus, Gain);
        AudioServer.AddBusEffect(bus, Filter);
        AudioServer.AddBusEffect(bus, Capture);
        Voice = new AudioStreamPlayer { Stream = DemoTone.Create(3000, loop: true), Bus = _bus, PlaybackType = AudioServer.PlaybackType.Stream };
        AddChild(Voice);
        var layout = new VBoxContainer { Position = new Vector2(24, 24) }; AddChild(layout);
        var play = new Button { Text = ru ? "Запустить / остановить" : "Play / stop" }; layout.AddChild(play);
        play.Pressed += () => { if (Voice.IsPlaying()) Voice.Stop(); else Voice.Play(); };
        var filter = new CheckButton { Text = ru ? "Фильтр 500 Гц" : "500 Hz filter", ButtonPressed = true }; layout.AddChild(filter);
        filter.Toggled += enabled => AudioServer.SetBusEffectEnabled(BusIndex, 1, enabled);
        var gain = new CheckButton { Text = "-6 dB", ButtonPressed = true }; layout.AddChild(gain);
        gain.Toggled += enabled => AudioServer.SetBusEffectEnabled(BusIndex, 0, enabled);
    }

    public Vector2[] ReadFrames(int count)
    {
        if (count <= 0 || !Capture.CanGetBuffer(count)) return [];
        return Capture.GetBuffer(count);
    }

    public override void _ExitTree()
    {
        Voice?.Stop();
        int index = BusIndex;
        if (index > 0) AudioServer.RemoveBus(index);
    }
}

The class creates its own uniquely named bus, adds Amplify → LowPass → Capture and removes only that bus on exit. Disabling one effect retains the others; bypassing the whole bus skips both filtering and Capture. Do not expect new captured frames while Capture is disabled or bypassed.

Choose an effect for the task

TaskAPICheck
Constant gainAudioEffectAmplifyGain and headroom
Remove highs / lowsLowPass, HighPassCutoffHz; a filter does not replace a wall's acoustic model
Pass / attenuate a bandBandPass, BandLimit, NotchFrequency and resonance
Spectral balanceEQ6, EQ10, EQ21, LowShelf, HighShelfBands and levels; boosts accumulate
Reduce dynamic rangeCompressorThreshold, Ratio, attack/release; Sidechain for an external control signal
Limit peaksHardLimiterCeilingDb, PreGainDb, Release; the older AudioEffectLimiter is deprecated
Analyze the spectrumSpectrumAnalyzerMeasures frequency levels; does not modify sound or remove noise
Echo / spaceDelay, ReverbDry/wet, feedback/tail time; original signal and tail are different
Modulation and colorationChorus, Phaser, Distortion, StereoEnhanceTimbre, phase, level and mono compatibility
Shift pitch after mixingPitchShiftFFT size and artifacts; differs from a player's PitchScale
Manual bus panningPannerActs on all sources in the bus; use a 2D/3D player for an object's position
Access raw dataCaptureRing-buffer capacity, reads and discarded frames
Build a recorded resourceRecordStart/stop, format and duration

Read Capture

Each Vector2 is one stereo frame: X is left and Y is right, not two successive moments. Data is float PCM. GetFramesAvailable() reports available frames; GetBuffer(n) consumes n frames. Check CanGetBuffer(n) before requesting; the example returns an empty array when insufficient. Read regularly on the main thread and move expensive analysis out of the frame. Do not retain a global audio-server lock while doing your own processing.

Set BufferLength before adding the effect: assigning it later does not resize an initialized buffer. GetDiscardedFrames() grows if the consumer falls behind. That is data loss, not controlled downsampling. ClearBuffer() discards accumulated frames; do not clear between every read during continuous recording. Float signals before final output can exceed ±1; explicitly clamp when converting to integer PCM.

Capture inside a bus is before its fader/mute. To measure Music after its gain, capture on a receiving bus. Capture on Master is still before Master's own fader; it is not a physical device-output recording.

Capture or Record

Capture supplies raw frames for visualization, analysis or your transport. Record builds an AudioStreamWav: add the effect to a bus, call SetRecordingActive(true), then SetRecordingActive(false) after the intended interval and GetRecording(). Starting again clears the previous recording. Check Error when saving through SaveToWav("user://recording.wav"); long recordings require memory. Capturing a bus does not require microphone access unless a microphone is its source.

Diagnostics

SymptomCheck
Effect is inaudibleActual player Bus, enable, bypass, order and Stream mode
Capture is emptySignal reaches the bus, effect active, requested count within availability
Captured sections are missingGetDiscardedFrames, read frequency and capacity before initialization
Crackles after an adjustmentCombined gain, feedback, overload and DSP cost
Different chains change togetherThey share an effect resource
Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.