reckfellENGINE

Эффекты: обработка шины и захват сэмплов

Порядок обработки, фильтр и усиление, Capture и Record; как выбрать эффект под задачу.

На этой странице

Где действует эффект

Эффект обрабатывает суммарный сигнал своей шины, а не только последний запущенный плеер. Цепочка идёт сверху вниз. Затем применяется громкость/mute этой шины, и результат отправляется дальше. Компрессор перед усилителем и после него даст разный результат; фиксируйте порядок намеренно.

Один ресурс AudioEffect хранит параметры, а AudioEffectInstance выполняет обработку. Если назначить один ресурс в разные места, изменение его параметров будет общим. Для отдельных настроек создавайте отдельные ресурсы. Тяжёлая цепочка на каждой отдельной шине стоит дороже общей обработки категории.

Проверить цепочку без внешнего файла

Сохраните DemoTone.cs в проекте. Прикрепите EffectsDemo.cs ниже к корню Control отдельного уровня, соберите и запустите F6. Запустить / остановить включает тон 3000 Гц. Отключение фильтра 500 Гц делает его заметно сильнее, переключатель -6 dB меняет усиление примерно вдвое по амплитуде. Это проверка маршрута, не настройка комфортной громкости ваших колонок.

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);
    }
}

Класс создаёт собственную шину с уникальным именем, добавляет Amplify → LowPass → Capture и удаляет только эту шину при выходе. Выключение отдельного эффекта сохраняет остальные; bypass всей шины обходит и фильтр, и Capture. Не ожидайте новых захваченных кадров, пока Capture выключен или обойдён.

Выберите эффект по задаче

ЗадачаAPIЧто проверить
Постоянный коэффициентAudioEffectAmplifyУсиление и запас до перегрузки
Убрать верх / низLowPass, HighPassCutoffHz; фильтр не заменяет акустическую модель стены
Выделить / ослабить диапазонBandPass, BandLimit, NotchЧастота и резонанс
Коррекция спектраEQ6, EQ10, EQ21, LowShelf, HighShelfПолосы и уровни; несколько усилений суммируются
Сжать динамический диапазонCompressorThreshold, Ratio, время атаки/восстановления; Sidechain для внешнего управляющего сигнала
Ограничить пикиHardLimiterCeilingDb, PreGainDb, Release; старый AudioEffectLimiter помечен устаревшим
Анализировать спектрSpectrumAnalyzerПолучает уровни частот; сам не изменяет звук и не подавляет шум
Эхо / пространствоDelay, ReverbDry/wet, feedback/время хвоста; исходный звук и хвост — разные сигналы
Модуляция и окраскаChorus, Phaser, Distortion, StereoEnhanceИзменение тембра, фазы, уровня и моносовместимости
Сдвиг высоты после микшированияPitchShiftРазмер FFT и артефакты; это не то же самое, что PitchScale плеера
Ручная панорама шиныPannerДействует на все источники шины; для положения объекта используйте 2D/3D-плеер
Получить сырые данныеCaptureЁмкость кольцевого буфера, чтение и потерянные кадры
Собрать записанный ресурсRecordНачало/конец записи, формат и длительность

Читать Capture

Один элемент Vector2 — один стереокадр: X левый, Y правый; это float PCM, не два последовательных момента времени. GetFramesAvailable() показывает доступное число кадров, GetBuffer(n) потребляет n кадров. Для безопасного запроса сначала используйте CanGetBuffer(n); пример возвращает пустой массив при недостатке. Читайте данные регулярно в основном потоке и выносите дорогой анализ из кадра. Не удерживайте глобальную блокировку аудиосервера на время своей обработки.

BufferLength задаётся до добавления эффекта: уже созданный буфер не меняет ёмкость от простого присваивания. Если потребитель не успевает, GetDiscardedFrames() растёт. Это потеря данных, а не корректное прореживание. ClearBuffer() отбрасывает накопленное; для непрерывной записи не очищайте буфер между каждым чтением. Float-сигнал до конечного выхода может выйти за ±1; при переводе в int PCM ограничивайте диапазон явно.

Capture внутри шины находится до её фейдера/mute. Для измерения уже ослабленной Music разместите захват на принимающей шине. Захват на Master всё ещё находится перед фейдером самого Master; это не запись физического выхода устройства.

Capture или Record

Capture отдаёт сырые кадры для визуализации/анализа/вашего транспорта. Record собирает AudioStreamWav: добавьте эффект в шину, вызовите SetRecordingActive(true), после нужного интервала — SetRecordingActive(false), затем GetRecording(). Новый старт очищает предыдущую запись. При сохранении через SaveToWav("user://recording.wav") проверяйте Error; длинная запись требует памяти. Захват шины не требует доступа к микрофону, пока источником не назначен микрофон.

Диагностика

СимптомПроверка
Эффект не слышенРеальный Bus плеера, enable, bypass, порядок и режим Stream
Capture пустСигнал доходит до шины, эффект активен, запрошено не больше доступного
Захват теряет участкиGetDiscardedFrames, частота чтения и ёмкость до инициализации
Треск после «улучшения»Суммарное усиление, feedback, перегрузка и стоимость DSP
Одинаково меняются разные цепочкиОни используют общий ресурс эффекта
Документация Reckfell EngineНаверх ↑
БЫСТРЫЙ ПЕРЕХОДНачало работыEntity и иерархияC# & .NET 10Сцены и префабы
Руководства и полный API Reckfell K
reckfellENGINE
RECKFELL ACCOUNT

Вход в аккаунт

Войдите в аккаунт Reckfell.

Один аккаунт для всей платформы Reckfell.