|
- /*
- ZynAddSubFX - a software synthesizer
-
- Envelope.cpp - Envelope implementation
- Copyright (C) 2002-2005 Nasca Octavian Paul
- Author: Nasca Octavian Paul
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- */
-
- #include <cmath>
- #include "Envelope.h"
- #include "../Params/EnvelopeParams.h"
-
- namespace zyncarla {
-
- Envelope::Envelope(EnvelopeParams &pars, float basefreq, float bufferdt,
- WatchManager *m, const char *watch_prefix)
- :watchOut(m, watch_prefix, "out")
- {
- envpoints = pars.Penvpoints;
- if(envpoints > MAX_ENVELOPE_POINTS)
- envpoints = MAX_ENVELOPE_POINTS;
- envsustain = (pars.Penvsustain == 0) ? -1 : pars.Penvsustain;
- forcedrelease = pars.Pforcedrelease;
- envstretch = powf(440.0f / basefreq, pars.Penvstretch / 64.0f);
- linearenvelope = pars.Plinearenvelope;
-
- if(!pars.Pfreemode)
- pars.converttofree();
-
- int mode = pars.Envmode;
-
- //for amplitude envelopes
- if((mode == 1) && !linearenvelope)
- mode = 2; //change to log envelope
- if((mode == 2) && linearenvelope)
- mode = 1; //change to linear
-
- for(int i = 0; i < MAX_ENVELOPE_POINTS; ++i) {
- const float tmp = pars.getdt(i) / 1000.0f * envstretch;
- if(tmp > bufferdt)
- envdt[i] = bufferdt / tmp;
- else
- envdt[i] = 2.0f; //any value larger than 1
-
- switch(mode) {
- case 2:
- envval[i] = (1.0f - pars.Penvval[i] / 127.0f) * -40;
- break;
- case 3:
- envval[i] =
- (powf(2, 6.0f
- * fabs(pars.Penvval[i]
- - 64.0f) / 64.0f) - 1.0f) * 100.0f;
- if(pars.Penvval[i] < 64)
- envval[i] = -envval[i];
- break;
- case 4:
- envval[i] = (pars.Penvval[i] - 64.0f) / 64.0f * 6.0f; //6 octaves (filtru)
- break;
- case 5:
- envval[i] = (pars.Penvval[i] - 64.0f) / 64.0f * 10;
- break;
- default:
- envval[i] = pars.Penvval[i] / 127.0f;
- }
- }
-
- envdt[0] = 1.0f;
-
- currentpoint = 1; //the envelope starts from 1
- keyreleased = false;
- t = 0.0f;
- envfinish = false;
- inct = envdt[1];
- envoutval = 0.0f;
- }
-
- Envelope::~Envelope()
- {}
-
-
- /*
- * Release the key (note envelope)
- */
- void Envelope::releasekey()
- {
- if(keyreleased)
- return;
- keyreleased = true;
- if(forcedrelease)
- t = 0.0f;
- }
-
- void Envelope::forceFinish(void)
- {
- envfinish = true;
- }
-
- /*
- * Envelope Output
- */
- float Envelope::envout(bool doWatch)
- {
- float out;
-
- if(envfinish) { //if the envelope is finished
- envoutval = envval[envpoints - 1];
- if(doWatch) {
- float pos[2] = {(float)envpoints - 1, envoutval};
- watchOut(pos, 2);
- }
- return envoutval;
- }
- if((currentpoint == envsustain + 1) && !keyreleased) { //if it is sustaining now
- envoutval = envval[envsustain];
- if(doWatch) {
- float pos[2] = {(float)envsustain, envoutval};
- watchOut(pos, 2);
- }
- return envoutval;
- }
-
- if(keyreleased && forcedrelease) { //do the forced release
- int tmp = (envsustain < 0) ? (envpoints - 1) : (envsustain + 1); //if there is no sustain point, use the last point for release
-
- if(envdt[tmp] < 0.00000001f)
- out = envval[tmp];
- else
- out = envoutval + (envval[tmp] - envoutval) * t;
- t += envdt[tmp] * envstretch;
-
- if(t >= 1.0f) {
- currentpoint = envsustain + 2;
- forcedrelease = 0;
- t = 0.0f;
- inct = envdt[currentpoint];
- if((currentpoint >= envpoints) || (envsustain < 0))
- envfinish = true;
- }
-
- if(doWatch) {
- float pos[2] = {(float)tmp + t, envoutval};
- watchOut(pos, 2);
- }
-
- return out;
- }
- if(inct >= 1.0f)
- out = envval[currentpoint];
- else
- out = envval[currentpoint - 1]
- + (envval[currentpoint] - envval[currentpoint - 1]) * t;
-
- t += inct;
- if(t >= 1.0f) {
- if(currentpoint >= envpoints - 1)
- envfinish = true;
- else
- currentpoint++;
- t = 0.0f;
- inct = envdt[currentpoint];
- }
-
- envoutval = out;
-
- if(doWatch) {
- float pos[2] = {(float)currentpoint + t, envoutval};
- watchOut(pos, 2);
- }
- return out;
- }
-
- /*
- * Envelope Output (dB)
- */
- float Envelope::envout_dB()
- {
- float out;
- if(linearenvelope)
- return envout(true);
-
- if((currentpoint == 1) && (!keyreleased || !forcedrelease)) { //first point is always lineary interpolated
- float v1 = EnvelopeParams::env_dB2rap(envval[0]);
- float v2 = EnvelopeParams::env_dB2rap(envval[1]);
- out = v1 + (v2 - v1) * t;
-
- t += inct;
- if(t >= 1.0f) {
- t = 0.0f;
- inct = envdt[2];
- currentpoint++;
- out = v2;
- }
-
- if(out > 0.001f)
- envoutval = EnvelopeParams::env_rap2dB(out);
- else
- envoutval = MIN_ENVELOPE_DB;
- } else
- out = EnvelopeParams::env_dB2rap(envout(false));
-
- float pos[2] = {(float)currentpoint + t, out};
- watchOut(pos, 2);
-
- return out;
- }
-
- bool Envelope::finished() const
- {
- return envfinish;
- }
-
- }
|