Почему этот конверт не проходит через коммутатор? - PullRequest
0 голосов
/ 01 ноября 2018

Я работаю над модификацией простого звукового конверта, размещенного здесь . Опубликованная версия запускает простые случаи экспоненциальной атаки, затухания, сустейна и выпуска коммутатора и проходит через огибающую, основываясь на ожидаемой продолжительности выборки каждой фазы.

Мне требуются более сложные и индивидуализированные уравнения для каждого случая. Я мог рассчитать прогнозируемую длину каждого случая на основе моих уравнений и поддерживать эту методологию, основанную на времени. Тем не менее, я думал, что было бы легче контролировать прогресс через случаи, основанные на отсечениях амплитуды. то есть. Если уровень> = 1.0, переходите от случая атаки к случаю затухания.

Но у меня проблемы с выполнением этой работы или выяснением, почему это не будет.

Вот соответствующий оригинальный код:

enum EnvelopeStage {
        ENVELOPE_STAGE_OFF = 0,
        ENVELOPE_STAGE_ATTACK,
        ENVELOPE_STAGE_DECAY,
        ENVELOPE_STAGE_SUSTAIN,
        ENVELOPE_STAGE_RELEASE,
        kNumEnvelopeStages
    };

double EnvelopeGenerator::nextSample() {
    if (currentStage != ENVELOPE_STAGE_OFF &&
        currentStage != ENVELOPE_STAGE_SUSTAIN) {
        if (currentSampleIndex == nextStageSampleIndex) {
            EnvelopeStage newStage = static_cast<EnvelopeStage>(
                                                                (currentStage + 1) % kNumEnvelopeStages
                                                                );
            enterStage(newStage);
        }
        currentLevel *= multiplier;
        currentSampleIndex++;
    }

    return currentLevel;
}

void EnvelopeGenerator::calculateMultiplier(double startLevel,
                                            double endLevel,
                                            unsigned long long lengthInSamples) {
    multiplier = 1.0 + (log(endLevel) - log(startLevel)) / (lengthInSamples);
}

void EnvelopeGenerator::enterStage(EnvelopeStage newStage) {
    currentStage = newStage;
    currentSampleIndex = 0;
    if (currentStage == ENVELOPE_STAGE_OFF ||
        currentStage == ENVELOPE_STAGE_SUSTAIN) {
        nextStageSampleIndex = 0;
    } else {
        nextStageSampleIndex = stageValue[currentStage] * sampleRate;
    }
    switch (newStage) {
        case ENVELOPE_STAGE_OFF:
            currentLevel = 0.0;
            multiplier = 1.0;
            break;
        case ENVELOPE_STAGE_ATTACK:
            currentLevel = minimumLevel;
            calculateMultiplier(currentLevel,
                                1.0,
                                nextStageSampleIndex);
            break;
        case ENVELOPE_STAGE_DECAY:
            currentLevel = 1.0;
            calculateMultiplier(currentLevel,
                                fmax(stageValue[ENVELOPE_STAGE_SUSTAIN], minimumLevel),
                                nextStageSampleIndex);
            break;
        case ENVELOPE_STAGE_SUSTAIN:
            currentLevel = stageValue[ENVELOPE_STAGE_SUSTAIN];
            multiplier = 1.0;
            break;
        case ENVELOPE_STAGE_RELEASE:
            // We could go from ATTACK/DECAY to RELEASE,
            // so we're not changing currentLevel here.
            calculateMultiplier(currentLevel,
                                minimumLevel,
                                nextStageSampleIndex);
            break;
        default:
            break;
    }
}

Таким образом, прогресс по делам контролируется double EnvelopeGenerator::nextSample().

Вот что я пытаюсь сделать, чтобы по-другому контролировать его:

double EnvelopeGenerator::nextSample() {

    if (currentStage = ENVELOPE_STAGE_ATTACK) {

            currentLevel = pow(currentSampleIndex / 30000.0f, 2.0f);
            currentSampleIndex++;

            if (currentLevel >= 1.0) {
                enterStage(ENVELOPE_STAGE_DECAY);
            }
    }

    else if (currentStage = ENVELOPE_STAGE_DECAY) {

            currentLevel = 1/ pow((currentSampleIndex / 30000.0f)+1, 2.0f);
            currentSampleIndex++;

            if (currentLevel = 0.1) {
                enterStage(ENVELOPE_STAGE_RELEASE);
            }   
    }
    else if (currentStage = ENVELOPE_STAGE_RELEASE) {

            currentLevel = currentLevel = 1 / pow((currentSampleIndex / 30000.0f) + 1, 2.0f);
            currentSampleIndex++;

            if (currentLevel = 0.0001) {
                enterStage(ENVELOPE_STAGE_OFF);
            }
    }
    else {}

Это не последние уравнения, которые мне нужны для каждого случая. Это просто тестовые уравнения. Но в настоящее время с этим вместо функции nextSample я просто получаю фазу цикличной атаки на неопределенный срок.

Я не могу понять, почему он бесконечно зацикливается при атаке. Я думал, что дал понять, что если уровень достигнет 1,0, он должен переключиться на случай распада.

Что я делаю не так и как мне это исправить? У меня нет достаточного опыта работы с C ++, чтобы знать, как это сделать правильно.

1 Ответ

0 голосов
/ 01 ноября 2018

Вы используете один = в ваших if утверждениях, который является назначением . Для сравнения вы хотите использовать ==.

if (currentStage == ENVELOPE_STAGE_ATTACK)
...