Exemplo n.º 1
0
void EngineEffectChain::process(const QString& group,
                                const CSAMPLE* pInput, CSAMPLE* pOutput,
                                const unsigned int numSamples,
                                const GroupFeatureState& groupFeatures) {
    GroupStatus& group_info = m_groupStatus[group];
    bool bEnabled = m_bEnabled && group_info.enabled;

    // If the chain is not enabled and the group is not enabled and we are not
    // ramping out then do nothing.
    if (!bEnabled && !group_info.ramp_out) {
        // If not in-place then copy. This is slow because every
        // EngineEffectChain does this. We should pull the processing decision
        // out into a predicate that EngineEffectsManager calls but that would
        // result in two QMap lookups.
        if (pInput != pOutput) {
            SampleUtil::copyWithGain(pOutput, pInput, 1.0, numSamples);
            if (kEffectDebugOutput) {
                qDebug() << "WARNING: EngineEffectChain took the slow path!"
                         << "If you want to do this talk to rryan.";
            }
        }
        return;
    }

    // At this point either the chain and group are enabled or we are ramping
    // out. If we are ramping out then ramp to 0 instead of m_dMix.
    CSAMPLE wet_gain = group_info.ramp_out ? 0 : m_dMix;
    CSAMPLE wet_gain_old = group_info.old_gain;

    // INSERT mode: output = input * (1-wet) + effect(input) * wet
    if (m_insertionType == EffectChain::INSERT) {
        if (wet_gain_old == 1.0 && wet_gain == 1.0) {
            bool anyProcessed = false;
            // Fully wet, no ramp, insert optimization. No temporary buffer needed.
            for (int i = 0; i < m_effects.size(); ++i) {
                EngineEffect* pEffect = m_effects[i];
                if (pEffect == NULL || !pEffect->enabled()) {
                    continue;
                }
                const CSAMPLE* pIntermediateInput = (i == 0) ? pInput : pOutput;
                CSAMPLE* pIntermediateOutput = pOutput;
                pEffect->process(group, pIntermediateInput, pIntermediateOutput,
                                 numSamples, groupFeatures);
                anyProcessed = true;
            }
            // If no effects were active then we have to copy input to output if
            // they are not the same.
            if (!anyProcessed && pInput != pOutput) {
                SampleUtil::copyWithGain(pOutput, pInput, 1.0, numSamples);
                if (kEffectDebugOutput) {
                    qDebug() << "WARNING: EngineEffectChain took the slow path!"
                             << "If you want to do this talk to rryan.";
                }
            }
        } else if (wet_gain_old == 0.0 && wet_gain == 0.0) {
            // Fully dry, no ramp, insert optimization. No action is needed
            // unless we are not processing in-place.
            if (pInput != pOutput) {
                SampleUtil::copyWithGain(pOutput, pInput, 1.0, numSamples);
                if (kEffectDebugOutput) {
                    qDebug() << "WARNING: EngineEffectChain took the slow path!"
                             << "If you want to do this talk to rryan.";
                }
            }
        } else {
            // Clear scratch buffer.
            SampleUtil::applyGain(m_pBuffer, 0.0, numSamples);

            // Chain each effect
            bool anyProcessed = false;
            for (int i = 0; i < m_effects.size(); ++i) {
                EngineEffect* pEffect = m_effects[i];
                if (pEffect == NULL || !pEffect->enabled()) {
                    continue;
                }
                const CSAMPLE* pIntermediateInput = (i == 0) ? pInput : m_pBuffer;
                CSAMPLE* pIntermediateOutput = m_pBuffer;
                pEffect->process(group, pIntermediateInput, pIntermediateOutput,
                                 numSamples, groupFeatures);
                anyProcessed = true;
            }

            if (anyProcessed) {
                // m_pBuffer now contains the fully wet output.
                // TODO(rryan): benchmark applyGain followed by addWithGain versus
                // copy2WithGain.
                SampleUtil::copy2WithRampingGain(
                    pOutput, pInput, 1.0 - wet_gain_old, 1.0 - wet_gain,
                    m_pBuffer, wet_gain_old, wet_gain, numSamples);
            } else if (pInput != pOutput) {
                // If no effects processed then we have to copy input to output
                // if they are not the same.
                SampleUtil::copyWithGain(pOutput, pInput, 1.0, numSamples);
                if (kEffectDebugOutput) {
                    qDebug() << "WARNING: EngineEffectChain took the slow path!"
                             << "If you want to do this talk to rryan.";
                }
            }
        }
    } else { // SEND mode: output = input + effect(input) * wet
        // Clear scratch buffer.
        SampleUtil::applyGain(m_pBuffer, 0.0, numSamples);

        // Chain each effect
        bool anyProcessed = false;
        for (int i = 0; i < m_effects.size(); ++i) {
            EngineEffect* pEffect = m_effects[i];
            if (pEffect == NULL || !pEffect->enabled()) {
                continue;
            }
            const CSAMPLE* pIntermediateInput = (i == 0) ? pInput : m_pBuffer;
            CSAMPLE* pIntermediateOutput = m_pBuffer;
            pEffect->process(group, pIntermediateInput,
                             pIntermediateOutput, numSamples, groupFeatures);
            anyProcessed = true;
        }

        if (anyProcessed) {
            // m_pBuffer now contains the fully wet output.
            if (pInput == pOutput) {
                SampleUtil::addWithRampingGain(pOutput, m_pBuffer,
                                               wet_gain_old, wet_gain, numSamples);
            } else {
                SampleUtil::copy2WithRampingGain(pOutput, pInput, 1.0, 1.0,
                                                 m_pBuffer, wet_gain_old, wet_gain,
                                                 numSamples);
            }
        } else if (pInput != pOutput) {
            // If no effects processed then we have to copy input to output
            // if they are not the same.
            SampleUtil::copyWithGain(pOutput, pInput, 1.0, numSamples);
            if (kEffectDebugOutput) {
                qDebug() << "WARNING: EngineEffectChain took the slow path!"
                         << "If you want to do this talk to rryan.";
            }
        }
    }

    // Update GroupStatus with the latest values.
    group_info.old_gain = wet_gain;
    group_info.ramp_out = false;
}
Exemplo n.º 2
0
void EngineEffectChain::process(const ChannelHandle& handle,
                                CSAMPLE* pInOut,
                                const unsigned int numSamples,
                                const unsigned int sampleRate,
                                const GroupFeatureState& groupFeatures) {
    ChannelStatus& channel_info = getChannelStatus(handle);

    if (m_enableState == EffectProcessor::DISABLED
            || channel_info.enable_state == EffectProcessor::DISABLED) {
        // If the chain is not enabled and the channel is not enabled and we are not
        // ramping out then do nothing.
        return;
    }

    EffectProcessor::EnableState effectiveEnableState = channel_info.enable_state;

    if (m_enableState == EffectProcessor::DISABLING) {
        effectiveEnableState = EffectProcessor::DISABLING;
    } else if (m_enableState == EffectProcessor::ENABLING) {
        effectiveEnableState = EffectProcessor::ENABLING;
    }

    // At this point either the chain and channel are enabled or we are ramping
    // out. If we are ramping out then ramp to 0 instead of m_dMix.
    CSAMPLE wet_gain = m_dMix;
    CSAMPLE wet_gain_old = channel_info.old_gain;

    // INSERT mode: output = input * (1-wet) + effect(input) * wet
    if (m_insertionType == EffectChain::INSERT) {
        if (wet_gain_old == 1.0 && wet_gain == 1.0) {
            // Fully wet, no ramp, insert optimization. No temporary buffer needed.
            for (int i = 0; i < m_effects.size(); ++i) {
                EngineEffect* pEffect = m_effects[i];
                if (pEffect == NULL || !pEffect->enabled()) {
                    continue;
                }
                pEffect->process(handle, pInOut, pInOut,
                                 numSamples, sampleRate,
                                 effectiveEnableState, groupFeatures);
            }
        } else if (wet_gain_old == 0.0 && wet_gain == 0.0) {
            // Fully dry, no ramp, insert optimization. No action is needed
        } else {
            // Clear scratch buffer.
            SampleUtil::clear(m_pBuffer, numSamples);

            // Chain each effect
            bool anyProcessed = false;
            for (int i = 0; i < m_effects.size(); ++i) {
                EngineEffect* pEffect = m_effects[i];
                if (pEffect == NULL || !pEffect->enabled()) {
                    continue;
                }
                const CSAMPLE* pIntermediateInput = (anyProcessed) ?  m_pBuffer : pInOut;
                CSAMPLE* pIntermediateOutput = m_pBuffer;
                pEffect->process(handle, pIntermediateInput, pIntermediateOutput,
                                 numSamples, sampleRate,
                                 effectiveEnableState, groupFeatures);
                anyProcessed = true;
            }

            if (anyProcessed) {
                // m_pBuffer now contains the fully wet output.
                // TODO(rryan): benchmark applyGain followed by addWithGain versus
                // copy2WithGain.
                SampleUtil::copy2WithRampingGain(
                    pInOut, pInOut, 1.0 - wet_gain_old, 1.0 - wet_gain,
                    m_pBuffer, wet_gain_old, wet_gain, numSamples);
            }
        }
    } else { // SEND mode: output = input + effect(input) * wet
        // Clear scratch buffer.
        SampleUtil::applyGain(m_pBuffer, 0.0, numSamples);

        // Chain each effect
        bool anyProcessed = false;
        for (int i = 0; i < m_effects.size(); ++i) {
            EngineEffect* pEffect = m_effects[i];
            if (pEffect == NULL || !pEffect->enabled()) {
                continue;
            }
            const CSAMPLE* pIntermediateInput = (i == 0) ? pInOut : m_pBuffer;
            CSAMPLE* pIntermediateOutput = m_pBuffer;
            pEffect->process(handle, pIntermediateInput,
                             pIntermediateOutput, numSamples, sampleRate,
                             effectiveEnableState, groupFeatures);
            anyProcessed = true;
        }

        if (anyProcessed) {
            // m_pBuffer now contains the fully wet output.
            SampleUtil::addWithRampingGain(pInOut, m_pBuffer,
                                           wet_gain_old, wet_gain, numSamples);
        }
    }

    // Update ChannelStatus with the latest values.
    channel_info.old_gain = wet_gain;

    if (m_enableState == EffectProcessor::DISABLING) {
        m_enableState = EffectProcessor::DISABLED;
    } else if (m_enableState == EffectProcessor::ENABLING) {
        m_enableState = EffectProcessor::ENABLED;
    }

    if (channel_info.enable_state == EffectProcessor::DISABLING) {
        channel_info.enable_state = EffectProcessor::DISABLED;
    } else if (channel_info.enable_state == EffectProcessor::ENABLING) {
        channel_info.enable_state = EffectProcessor::ENABLED;
    }
}
Exemplo n.º 3
0
void EngineEffectChain::process(const QString& group,
                                CSAMPLE* pInOut,
                                const unsigned int numSamples,
                                const GroupFeatureState& groupFeatures) {
    GroupStatus& group_info = m_groupStatus[group];
    bool bEnabled = m_bEnabled && group_info.enabled;

    // If the chain is not enabled and the group is not enabled and we are not
    // ramping out then do nothing.
    if (!bEnabled && !group_info.ramp_out) {
        return;
    }

    // At this point either the chain and group are enabled or we are ramping
    // out. If we are ramping out then ramp to 0 instead of m_dMix.
    CSAMPLE wet_gain = group_info.ramp_out ? 0 : m_dMix;
    CSAMPLE wet_gain_old = group_info.old_gain;

    // INSERT mode: output = input * (1-wet) + effect(input) * wet
    if (m_insertionType == EffectChain::INSERT) {
        if (wet_gain_old == 1.0 && wet_gain == 1.0) {
            // Fully wet, no ramp, insert optimization. No temporary buffer needed.
            for (int i = 0; i < m_effects.size(); ++i) {
                EngineEffect* pEffect = m_effects[i];
                if (pEffect == NULL || !pEffect->enabled()) {
                    continue;
                }
                pEffect->process(group, pInOut, pInOut,
                                 numSamples, groupFeatures);
            }
        } else if (wet_gain_old == 0.0 && wet_gain == 0.0) {
            // Fully dry, no ramp, insert optimization. No action is needed
        } else {
            // Clear scratch buffer.
            SampleUtil::clear(m_pBuffer, numSamples);

            // Chain each effect
            bool anyProcessed = false;
            for (int i = 0; i < m_effects.size(); ++i) {
                EngineEffect* pEffect = m_effects[i];
                if (pEffect == NULL || !pEffect->enabled()) {
                    continue;
                }
                const CSAMPLE* pIntermediateInput = (i == 0) ? pInOut : m_pBuffer;
                CSAMPLE* pIntermediateOutput = m_pBuffer;
                pEffect->process(group, pIntermediateInput, pIntermediateOutput,
                                 numSamples, groupFeatures);
                anyProcessed = true;
            }

            if (anyProcessed) {
                // m_pBuffer now contains the fully wet output.
                // TODO(rryan): benchmark applyGain followed by addWithGain versus
                // copy2WithGain.
                SampleUtil::copy2WithRampingGain(
                    pInOut, pInOut, 1.0 - wet_gain_old, 1.0 - wet_gain,
                    m_pBuffer, wet_gain_old, wet_gain, numSamples);
            }
        }
    } else { // SEND mode: output = input + effect(input) * wet
        // Clear scratch buffer.
        SampleUtil::applyGain(m_pBuffer, 0.0, numSamples);

        // Chain each effect
        bool anyProcessed = false;
        for (int i = 0; i < m_effects.size(); ++i) {
            EngineEffect* pEffect = m_effects[i];
            if (pEffect == NULL || !pEffect->enabled()) {
                continue;
            }
            const CSAMPLE* pIntermediateInput = (i == 0) ? pInOut : m_pBuffer;
            CSAMPLE* pIntermediateOutput = m_pBuffer;
            pEffect->process(group, pIntermediateInput,
                             pIntermediateOutput, numSamples, groupFeatures);
            anyProcessed = true;
        }

        if (anyProcessed) {
            // m_pBuffer now contains the fully wet output.
            SampleUtil::addWithRampingGain(pInOut, m_pBuffer,
                                           wet_gain_old, wet_gain, numSamples);
        }
    }

    // Update GroupStatus with the latest values.
    group_info.old_gain = wet_gain;
    group_info.ramp_out = false;
}