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