/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.common.midi.synth; /** * Very simple Attack, Decay, Sustain, Release envelope with linear ramps. * * Times are in seconds. */ public class EnvelopeADSR extends SynthUnit { private static final int IDLE = 0; private static final int ATTACK = 1; private static final int DECAY = 2; private static final int SUSTAIN = 3; private static final int RELEASE = 4; private static final int FINISHED = 5; private static final float MIN_TIME = 0.001f; private float mAttackRate; private float mRreleaseRate; private float mSustainLevel; private float mDecayRate; private float mCurrent; private int mSstate = IDLE; public EnvelopeADSR() { setAttackTime(0.003f); setDecayTime(0.08f); setSustainLevel(0.3f); setReleaseTime(1.0f); } public void setAttackTime(float time) { if (time < MIN_TIME) time = MIN_TIME; mAttackRate = 1.0f / (SynthEngine.FRAME_RATE * time); } public void setDecayTime(float time) { if (time < MIN_TIME) time = MIN_TIME; mDecayRate = 1.0f / (SynthEngine.FRAME_RATE * time); } public void setSustainLevel(float level) { if (level < 0.0f) level = 0.0f; mSustainLevel = level; } public void setReleaseTime(float time) { if (time < MIN_TIME) time = MIN_TIME; mRreleaseRate = 1.0f / (SynthEngine.FRAME_RATE * time); } public void on() { mSstate = ATTACK; } public void off() { mSstate = RELEASE; } @Override public float render() { switch (mSstate) { case ATTACK: mCurrent += mAttackRate; if (mCurrent > 1.0f) { mCurrent = 1.0f; mSstate = DECAY; } break; case DECAY: mCurrent -= mDecayRate; if (mCurrent < mSustainLevel) { mCurrent = mSustainLevel; mSstate = SUSTAIN; } break; case RELEASE: mCurrent -= mRreleaseRate; if (mCurrent < 0.0f) { mCurrent = 0.0f; mSstate = FINISHED; } break; } return mCurrent; } public boolean isDone() { return mSstate == FINISHED; } }