summaryrefslogtreecommitdiffstats
path: root/PolyDrums_v0_1_5_DelayNoLPF/ADSRslow.h
diff options
context:
space:
mode:
authorfakebitpolytechnic <fakebitpoly@gmail.com>2013-10-23 16:06:09 +0100
committerfakebitpolytechnic <fakebitpoly@gmail.com>2013-10-23 16:06:09 +0100
commit09b78d13623d72192f568aa4be7b6229279f2a51 (patch)
tree9e346f93535c7c59b9ae05385fa97e424dca8d5b /PolyDrums_v0_1_5_DelayNoLPF/ADSRslow.h
parente67a18d2e2e4c38a1fe3bd7e6c8486363ba20e26 (diff)
3note polyphony+drums+sequences, delay fx, no LPF
Diffstat (limited to 'PolyDrums_v0_1_5_DelayNoLPF/ADSRslow.h')
-rw-r--r--PolyDrums_v0_1_5_DelayNoLPF/ADSRslow.h309
1 files changed, 309 insertions, 0 deletions
diff --git a/PolyDrums_v0_1_5_DelayNoLPF/ADSRslow.h b/PolyDrums_v0_1_5_DelayNoLPF/ADSRslow.h
new file mode 100644
index 0000000..e4d6813
--- /dev/null
+++ b/PolyDrums_v0_1_5_DelayNoLPF/ADSRslow.h
@@ -0,0 +1,309 @@
+/*
+ * ADSRslow.h
+ *
+ * Copyright 2012 Tim Barrass.
+ * - tiny modification by Dave Green in setPhase for calling at Control Rate
+
+ * This file is part of Mozzi.
+ *
+ * Mozzi 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Mozzi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mozzi. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef ADSR_H_
+#define ADSR_H_
+
+#include "Arduino.h"
+//#include <util/atomic.h>
+#include "Line.h"
+#include "mozzi_fixmath.h"
+
+/** A simple ADSR envelope generator.
+@todo Test whether using the template parameter makes any difference to speed,
+and rationalise which units which do and don't need them.
+Template objects are messy when you try to use pointers to them,
+you have to include the whole template shebang in the pointer handling.
+*/
+template <unsigned int CONTROL_UPDATE_RATE>
+class ADSR
+{
+private:
+
+ const unsigned int AUDIO_TICKS_PER_CONTROL;
+
+ unsigned int phase_control_step_counter;
+ unsigned int phase_num_control_steps;
+
+ enum {ATTACK,DECAY,SUSTAIN,RELEASE,IDLE};
+
+
+ struct phase{
+ byte phase_type;
+ unsigned int control_steps;
+ unsigned long audio_steps;
+ Q8n0 level;
+ }attack,decay,sustain,release,idle;
+
+ phase * current_phase;
+
+ // Linear audio rate transitions for envelope
+ Line <unsigned long> transition;
+
+ inline
+ unsigned int convertMsecToControlSteps(unsigned int msec){
+ return (uint) (((ulong)msec*CONTROL_UPDATE_RATE)>>10); // approximate /1000 with shift
+ }
+
+ inline
+ void setPhase(phase * next_phase) {
+ phase_control_step_counter = 0;
+ phase_num_control_steps = next_phase->control_steps;
+ transition.set(Q8n0_to_Q16n16(next_phase->level),next_phase-> control_steps);
+// Dave G: divide by control_steps rather than audio_steps to call at Control Rate instead!
+ current_phase = next_phase;
+ }
+
+
+
+ inline
+ void checkForAndSetNextPhase(phase * next_phase) {
+ if (++phase_control_step_counter >= phase_num_control_steps){
+ setPhase(next_phase);
+ }
+ }
+
+
+ inline
+ void checkForAndSetIdle() {
+ if (++phase_control_step_counter >= phase_num_control_steps){
+ transition.set(0,0,1);
+ current_phase = &idle;
+ }
+ }
+
+
+
+inline
+ void setTime(phase * p, unsigned int msec)
+ {
+ p->control_steps=convertMsecToControlSteps(msec);
+ p->audio_steps = (ulong) p->control_steps * AUDIO_TICKS_PER_CONTROL;
+ }
+
+
+public:
+
+ /** Constructor.
+ */
+ ADSR():AUDIO_TICKS_PER_CONTROL(AUDIO_RATE/CONTROL_UPDATE_RATE)
+ {
+ attack.phase_type = ATTACK;
+ decay.phase_type = DECAY;
+ sustain.phase_type = SUSTAIN;
+ release.phase_type = RELEASE;
+ idle.phase_type = IDLE;
+ release.level = 0;
+ }
+
+
+/** Updates the internal controls of the ADSR.
+ Call this in updateControl().
+ */
+ void update(){ // control rate
+
+ switch(current_phase->phase_type) {
+
+ case ATTACK:
+ checkForAndSetNextPhase(&decay);
+ break;
+
+ case DECAY:
+ checkForAndSetNextPhase(&sustain);
+ break;
+
+ case SUSTAIN:
+ checkForAndSetNextPhase(&release);
+ break;
+
+ case RELEASE:
+ checkForAndSetIdle();
+ break;
+
+ }
+ }
+
+ /** Advances one audio step along the ADSR and returns the level.
+ Call this in updateAudio().
+ @return the next value, as an unsigned int.
+ */
+ inline
+ unsigned int next()
+ {
+ return Q16n16_to_Q16n0(transition.next());
+ }
+
+
+
+ /** Start the attack phase of the ADSR. THis will restart the ADSR no matter what phase it is up to.
+ */
+ inline
+ void noteOn(){
+ setPhase(&attack);
+ }
+
+
+
+ /** Start the release phase of the ADSR.
+ @todo fix release for rate rather than steps (time), so it releases at the same rate whatever the current level.
+ */
+ inline
+ void noteOff(){
+ setPhase(&release);
+ }
+
+
+
+
+
+ /** Set the attack level of the ADSR.
+ @param value the attack level.
+ */
+ inline
+ void setAttackLevel(byte value)
+ {
+ attack.level=value;
+ }
+
+
+
+ /** Set the decay level of the ADSR.
+ @param value the decay level.
+ */
+ inline
+ void setDecayLevel(byte value)
+ {
+ decay.level=value;
+ }
+
+
+ /** Set the sustain level of the ADSR.
+ @param value the sustain level. Usually the same as the decay level,
+ for a steady sustained note.
+ */
+ inline
+ void setSustainLevel(byte value)
+ {
+ sustain.level=value;
+ }
+
+ /** Set the release level of the ADSR. Normally you'd make this 0,
+ but you have the option of some other value.
+ @param value the release level (normally 0).
+ */
+ inline
+ void setReleaseLevel(byte value)
+ {
+ release.level=value;
+ }
+
+
+
+ /** Set the attack and decay levels of the ADSR. This assumes a conventional
+ ADSR where the sustain continues at the same level as the decay, till the release ramps to 0.
+ @param attack the new attack level.
+ @param value the new sustain level.
+ */
+ inline
+ void setADLevels(byte attack, byte decay)
+ {
+ setAttackLevel(attack);
+ setDecayLevel(decay);
+ setSustainLevel(decay);
+ setReleaseLevel(0);
+ }
+
+
+
+
+
+
+
+ /** Set the attack time of the ADSR in milliseconds.
+ The actual time taken will be resolved within the resolution of CONTROL_RATE.
+ @param value the unsigned int attack time in milliseconds.
+ */
+ inline
+ void setAttackTime(unsigned int msec)
+ {
+ setTime(&attack, msec);
+ }
+
+
+ /** Set the decay time of the ADSR in milliseconds.
+ The actual time taken will be resolved within the resolution of CONTROL_RATE.
+ @param value the unsigned int decay time in milliseconds.
+ */
+ inline
+ void setDecayTime(unsigned int msec)
+ {
+ setTime(&decay, msec);
+ }
+
+
+ /** Set the sustain time of the ADSR in milliseconds.
+ The actual time taken will be resolved within the resolution of CONTROL_RATE.
+ The sustain phase will finish if the ADSR recieves a noteOff().
+ @param value the unsigned int sustain time in milliseconds.
+ */
+ inline
+ void setSustainTime(unsigned int msec)
+ {
+ setTime(&sustain, msec);
+ }
+
+
+
+ /** Set the release time of the ADSR in milliseconds.
+ The actual time taken will be resolved within the resolution of CONTROL_RATE.
+ @param value the unsigned int release time in milliseconds.
+ */
+ inline
+ void setReleaseTime(unsigned int msec)
+ {
+ setTime(&release, msec);
+ }
+
+
+
+ /** Set the attack, decay and release times of the ADSR in milliseconds.
+ The actual times will be resolved within the resolution of CONTROL_RATE.
+ @param attack_ms the new attack time in milliseconds.
+ @param decay_ms the new decay time in milliseconds.
+ @param decay_ms the new sustain time in milliseconds.
+ @param release_ms the new release time in milliseconds.
+ */
+ inline
+ void setTimes(unsigned int attack_ms, unsigned int decay_ms, unsigned int sustain_ms, unsigned int release_ms)
+ {
+ setAttackTime(attack_ms);
+ setDecayTime(decay_ms);
+ setSustainTime(sustain_ms);
+ setReleaseTime(release_ms);
+ }
+
+
+};
+
+#endif /* ADSR_H_ */
+