Я работаю над изменением простого аудио конверта Вот. Опубликованная версия запускает простые случаи экспоненциальной атаки, затухания, поддержания и выпуска коммутатора и проходит через огибающую, основываясь на ожидаемой продолжительности выборки каждой фазы.
Мне требуются более сложные и индивидуальные уравнения для каждого случая. Я мог рассчитать прогнозируемую длину каждого случая на основе моих уравнений и поддерживать эту методологию, основанную на времени. Тем не менее, я думал, что было бы легче контролировать прогресс через случаи, основанные на отсечениях амплитуды. то есть. Если уровень> = 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 ++, чтобы знать, как сделать это правильно.
Вы используете один =
в вашем if
заявления, который является назначение. Для сравнения вы хотите использовать ==
,
if (currentStage == ENVELOPE_STAGE_ATTACK)
Других решений пока нет …