Jamoma API  0.6.0.a19
TTAdsr.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup dspGeneratorLib
4  *
5  * @brief GeneratorLib: Generate classic ADSR envelope (attack, decay, sustain, release).
6  *
7  * @details
8  *
9  * @authors Tim Place, Dave Watson, Trond Lossius
10  *
11  * @copyright Copyright © 2009 by Timothy Place @n
12  * This code is licensed under the terms of the "New BSD License" @n
13  * http://creativecommons.org/licenses/BSD/
14  */
15 
16 
17 #include "TTAdsr.h"
18 
19 #define thisTTClass TTAdsr
20 #define thisTTClassName "adsr"
21 #define thisTTClassTags "dspGeneratorLib, audio, generator, envelope"
22 
23 
24 TT_AUDIO_CONSTRUCTOR
25 , output(0.), output_db(NOISE_FLOOR), eg_state(k_eg_inactive), trigger(false), attrMode("linear")
26 {
27  registerAttribute(TT("attack"), kTypeFloat64, &attack_ms, (TTSetterMethod)&TTAdsr::setAttack);
28  registerAttribute(TT("decay"), kTypeFloat64, &decay_ms, (TTSetterMethod)&TTAdsr::setDecay);
29  registerAttribute(TT("release"), kTypeFloat64, &release_ms, (TTSetterMethod)&TTAdsr::setRelease);
30  registerAttribute(TT("linearSustain"), kTypeFloat64, &sustain_amp, (TTSetterMethod)&TTAdsr::setSustainAmp);
31  registerAttribute(TT("sustain"), kTypeFloat64, NULL, (TTGetterMethod)&TTAdsr::getSustainDb, (TTSetterMethod)&TTAdsr::setSustainDb);
32  registerAttribute(TT("trigger"), kTypeBoolean, &trigger);
33  registerAttribute(TT("mode"), kTypeSymbol, &attrMode, (TTSetterMethod)&TTAdsr::setMode);
34 
35  addUpdates(SampleRate);
36  addMessageWithArguments(dictionary);
37 
38  setAttributeValue(TT("attack"), 50.);
39  setAttributeValue(TT("decay"), 100.);
40  setAttributeValue(TT("sustain"), -6.);
41  setAttributeValue(TT("release"), 500.);
42  setAttributeValue(TT("mode"), TT("hybrid")); // <-- sets the process method
43 }
44 
45 
46 TTAdsr::~TTAdsr()
47 {
48  ;
49 }
50 
51 
52 TTErr TTAdsr::dictionary(const TTValue& input, TTValue& output)
53 {
54  TTDictionary d;
55  TTSymbol schema;
56 
57  if (input[0].type() == kTypeDictionary) {
58  d = input[0];
59  schema = d.getSchema();
60  }
61 
62  if (schema == TT("MidiNoteEvent")) {
63  TTValue v;
64  TTErr err;
65  TTUInt8 velocity;
66 
67  err = d.getValue(v);
68  if (!err) {
69  velocity = v[1];
70  if (velocity)
71  trigger = true;
72  else
73  trigger = false;
74  }
75  return err;
76  }
77  else
78  return kTTErrInvalidType;
79 }
80 
81 
83 {
84  TTValue v;
85 
86  v = attack_ms;
87  setAttack(v);
88 
89  v = decay_ms;
90  setDecay(v);
91 
92  v = release_ms;
93  setRelease(v);
94 
95  return kTTErrNone;
96 }
97 
98 
100 {
101  attack_ms = TTClip((TTFloat64)newValue, 1.0, 60000.0);
102  attack_samples = long((attack_ms / 1000.0) * sr);
103  attack_step = 1.0 / attack_samples;
104  attack_step_db = -(double(NOISE_FLOOR) / attack_samples);
105  return kTTErrNone;
106 }
107 
108 
110 {
111  decay_ms = TTClip((TTFloat64)newValue, 1.0, 60000.0);
112  decay_samples = long((decay_ms / 1000.0) * sr);
113  decay_step = 1.0 / decay_samples;
114  decay_step_db = -(double(NOISE_FLOOR) / decay_samples);
115  return kTTErrNone;
116 }
117 
118 
120 {
121  release_ms = TTClip((TTFloat64)newValue, 1.0, 60000.0);
122  release_samples = long((release_ms / 1000.0) * sr);
124  release_step_db = -(double(NOISE_FLOOR) / release_samples);
125  return kTTErrNone;
126 }
127 
128 
130 {
131  sustain_amp = newValue;
133  return kTTErrNone;
134 }
135 
137 {
138  sustain_db = newValue;
140  return kTTErrNone;
141 }
142 
144 {
146  return kTTErrNone;
147 }
148 
149 
150 TTErr TTAdsr::setMode(const TTValue& newValue)
151 {
152  attrMode = newValue;
153 
154  if (attrMode == TT("exponential"))
156  else if (attrMode == TT("hybrid"))
158  else
160 
161  return kTTErrNone;
162 }
163 
164 
166 {
167  TTAudioSignal& in = inputs->getSignal(0);
168  TTAudioSignal& out = outputs->getSignal(0);
169  TTSampleValue* inSample = NULL;
170  TTSampleValue* outSample;
171  TTUInt16 vs = out.getVectorSizeAsInt();
172  bool checkAudioTrigger = false;
173 
174  // TODO: Is there a decent way to do this without having to check this every single vector?
175  if (inputs->numAudioSignals) {
176  checkAudioTrigger = true;
177  inSample = in.mSampleVectors[0];
178  }
179  outSample = out.mSampleVectors[0];
180 
181  while (vs--) {
182  if (checkAudioTrigger)
183  trigger = (TTBoolean)(*inSample++ > 0.5);
184 
185  if (trigger) {
188  } else {
191  }
192 
193  switch(eg_state) {
194  case k_eg_attack:
195  output += attack_step;
196  if (output >= 1.) {
197  output = 1.;
199  }
200  break;
201  case k_eg_decay:
202  output -= decay_step;
203  if (output <= sustain_amp) {
206  }
207  break;
208  case k_eg_sustain:
209 
210  break;
211 
212  case k_eg_release:
213  output -= release_step;
214  if (output <= 0.) {
216  output = 0.;
217  }
218  break;
219  }
220  *outSample++ = output;
221  }
222 
223  return kTTErrNone;
224 }
225 
226 
228 {
229  TTAudioSignal& in = inputs->getSignal(0);
230  TTAudioSignal& out = outputs->getSignal(0);
231  TTSampleValue* inSample = NULL;
232  TTSampleValue* outSample;
233  TTUInt16 vs = out.getVectorSizeAsInt();
234  bool checkAudioTrigger = false;
235 
236  // TODO: Is there a decent way to do this without having to check this every single vector?
237  if (inputs->numAudioSignals) {
238  checkAudioTrigger = true;
239  inSample = in.mSampleVectors[0];
240  }
241  outSample = out.mSampleVectors[0];
242 
243  while (vs--) {
244  if (checkAudioTrigger)
245  trigger = (TTBoolean)(*inSample++ > 0.5);
246 
247  if (trigger) {
250  } else {
253  }
254 
255  switch(eg_state) {
256  case k_eg_attack: // ATTACK
257  output_db += attack_step_db; // Increment the output
258  if (output_db >= 0.0) { // If we've hit the top of the attack,
259  eg_state = k_eg_decay; // start the decay stage
260  output = 1.0; // Make sure we didn't go over 1.0
261  }
262  else
264  break;
265  case k_eg_decay: // DECAY
267  output = TTDecibelsToLinearGain(output_db); // Decrement the output
268  if (output <= sustain_amp) { // If we've hit the bottom of the decay,
269  eg_state = k_eg_sustain; // start the sustain stage
270  output = sustain_amp; // Lock in the sustain value
271  }
272  break;
273  case k_eg_sustain: // SUSTAIN
274  break; // leave it alone
275 
276  case k_eg_release: // RELEASE
278  if (output_db <= NOISE_FLOOR) { // If we've hit the basement,
279  eg_state = k_eg_inactive; // deactivate the eg
280  output = 0.0; // Make sure we didn't dip too low
281  }
282  else
283  output = TTDecibelsToLinearGain(output_db); // Decrement the output
284  break;
285  }
286  *outSample++ = output;
287  }
288 
289  return kTTErrNone;
290 }
291 
292 
293 // 'hybrid' is linear attack (especially for short times) and a exponential release
294 
296 {
297  TTAudioSignal& in = inputs->getSignal(0);
298  TTAudioSignal& out = outputs->getSignal(0);
299  TTSampleValue* inSample = NULL;
300  TTSampleValue* outSample;
301  TTUInt16 vs = out.getVectorSizeAsInt();
302  bool checkAudioTrigger = false;
303 
304  // TODO: Is there a decent way to do this without having to check this every single vector?
305  if (inputs->numAudioSignals) {
306  checkAudioTrigger = true;
307  inSample = in.mSampleVectors[0];
308  }
309  outSample = out.mSampleVectors[0];
310 
311  while (vs--) {
312  if (checkAudioTrigger)
313  trigger = (TTBoolean)(*inSample++ > 0.5);
314 
315  if (trigger) {
318  }
319  else {
322  }
323 
324  switch (eg_state) {
325  case k_eg_attack: // ATTACK
326  output += attack_step;
327  if (output >= 1.0) {
328  output = 1.0;
329  output_db = 0.0;
331  }
332  else
334  break;
335  case k_eg_decay: // DECAY
337  output = TTDecibelsToLinearGain(output_db); // Decrement the output
338  if (output <= sustain_amp) { // If we've hit the bottom of the decay,
339  eg_state = k_eg_sustain; // start the sustain stage
340  output = sustain_amp; // Lock in the sustain value
341  }
342  break;
343  case k_eg_sustain: // SUSTAIN
344  break; // leave it alone
345 
346  case k_eg_release: // RELEASE
348  if (output_db <= NOISE_FLOOR) { // If we've hit the basement,
349  eg_state = k_eg_inactive; // deactivate the eg
350  output = 0.0; // Make sure we didn't dip too low
351  }
352  else
353  output = TTDecibelsToLinearGain(output_db); // Decrement the output
354  break;
355  }
356  *outSample++ = output;
357  }
358 
359  return kTTErrNone;
360 }
361 
TTFloat64 TTDecibelsToLinearGain(TTFloat64 value)
Convert decibels into linear ampliude.
TTErr(TTObjectBase::* TTSetterMethod)(const TTAttribute &attribute, const TTValue &value)
A type that can be used to store a pointer to a message for an object.
Definition: TTObjectBase.h:78
bool TTBoolean
Boolean flag, same as Boolean on the Mac.
Definition: TTBase.h:167
std::uint16_t TTUInt16
16 bit unsigned integer
Definition: TTBase.h:176
TTFloat64 TTLinearGainToDecibels(const TTFloat64 value)
Convert linear amplitude into deciBels.
TTSampleValue output
Current envelope value as linear amplitude.
Definition: TTAdsr.h:48
TTErr updateSampleRate(const TTValue &, TTValue &)
This method must be called when the sample rate change.
Definition: TTAdsr.cpp:82
TTErr setAttack(const TTValue &newValue)
Set the attack time for the enevelope.
Definition: TTAdsr.cpp:99
TTErr setSustainDb(const TTValue &newValue)
Set the signal level to use for the sustain, expressed in decibels.
Definition: TTAdsr.cpp:136
TTErr processAudioLinear(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
The Linear audio processing method use linear amplitude curves for all parts of the envelope...
Definition: TTAdsr.cpp:165
TTFloat64 release_ms
Release duration in milliseconds.
Definition: TTAdsr.h:43
TTErr processAudioHybrid(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
The Hybrid processing method combines a linear attack with an exponential release.
Definition: TTAdsr.cpp:295
Dictionary type.
Definition: TTBase.h:288
Bad DataType for the context.
Definition: TTBase.h:347
#define setProcessMethod(methodName)
A convenience macro to be used by subclasses for setting the process method.
TTInt32 attack_samples
Attack duration in total number of samples.
Definition: TTAdsr.h:31
TTInt16 eg_state
The current state of the envelope. Tracks what envelope phase that we are currently in...
Definition: TTAdsr.h:51
TTFloat64 decay_ms
Decay duration in milliseconds.
Definition: TTAdsr.h:35
TTErr getValue(T &aReturnedValue) const
Get the dictionary's primary value.
Definition: TTDictionary.h:202
Symbol type.
Definition: TTBase.h:282
double TTFloat64
64 bit floating point number
Definition: TTBase.h:188
TTErr dictionary(const TTValue &input, TTValue &output)
Send a dictionary from Jamoma Graph to this object in order to pass a MidiNoteEvent or set attributes...
Definition: TTAdsr.cpp:52
TTFloat64 decay_step_db
Stepsize in decibels for each sample during the decay phase.
Definition: TTAdsr.h:38
A type that represents the key as a C-String and the value as a pointer to the matching TTSymbol obje...
Definition: TTDictionary.h:47
#define TT
This macro is defined as a shortcut for doing a lookup in the symbol table.
Definition: TTSymbol.h:155
TTFloat64 decay_step
Stepsize for each sample during the decay phase.
Definition: TTAdsr.h:37
The envelope is currently inactive (not being executed).
Definition: TTAdsr.h:116
TTErr processAudioExponential(TTAudioSignalArrayPtr inputs, TTAudioSignalArrayPtr outputs)
The Exponential processing methods use exponential curves for all sections of the envelope...
Definition: TTAdsr.cpp:227
64-bit floating point
Definition: TTBase.h:272
TTFloat64 attack_ms
Attack duration in milliseconds.
Definition: TTAdsr.h:30
The TTSymbol class is used to represent a string and efficiently pass and compare that string...
Definition: TTSymbol.h:26
const TTSymbol getSchema() const
TODO: Add documentation.
Definition: TTDictionary.h:181
TTSampleValue output_db
Current envelope value as decibel value.
Definition: TTAdsr.h:49
TTFloat64 sustain_db
Sustain level as decibel value.
Definition: TTAdsr.h:41
Boolean (1/0) or (true/false) flag.
Definition: TTBase.h:281
TTErr getSustainDb(TTValue &returnedValue)
Get the signal level currently used for the sustain, measured in decibels.
Definition: TTAdsr.cpp:143
The TTAudioSignal class represents N vectors of audio samples for M channels.
Definition: TTAudioSignal.h:57
#define addMessageWithArguments(name)
A convenience macro to be used by subclasses for registering messages.
Definition: TTMessage.h:27
TTSampleValue ** mSampleVectors
An array of pointers to the first sample in each vector. Declared Public for fast access...
Definition: TTAudioSignal.h:74
The envelope is currently in the release phase.
Definition: TTAdsr.h:120
TTFloat64 attack_step
Stepsize for each sample in the attack phase.
Definition: TTAdsr.h:32
A simple container for an array of TTAudioSignal pointers.
TTInt32 release_samples
Release duration in total number of samples.
Definition: TTAdsr.h:44
TTErr setSustainAmp(const TTValue &newValue)
Set the signal level to use for the sustain, expressed as linear amplitude.
Definition: TTAdsr.cpp:129
TTErr
Jamoma Error Codes Enumeration of error codes that might be returned by any of the TTBlue functions a...
Definition: TTBase.h:342
The envelope is currently in the decay phase.
Definition: TTAdsr.h:118
TTErr setMode(const TTValue &newValue)
Set the performance mode to use for the envelope.
Definition: TTAdsr.cpp:150
The envelope is currently in the sustain phase.
Definition: TTAdsr.h:119
TTFloat64 sustain_amp
Sustain level as linear amplitude.
Definition: TTAdsr.h:40
TTFloat64 release_step_db
Stepsize in decibels for each sample during the release phase.
Definition: TTAdsr.h:46
No Error.
Definition: TTBase.h:343
The envelope is currently in the attack phase.
Definition: TTAdsr.h:117
TTFloat64 attack_step_db
Stepasize in decibels for each sample in the attack phase.
Definition: TTAdsr.h:33
GeneratorLib: Generate classic ADSR envelope (attack, decay, sustain, release).
TTErr(TTObjectBase::* TTGetterMethod)(const TTAttribute &attribute, TTValue &value)
A type that can be used to store a pointer to a message for an object.
Definition: TTObjectBase.h:73
TTInt32 decay_samples
Decay duration in total number of samples.
Definition: TTAdsr.h:36
TTFloat64 TTSampleValue
A value representing a single audio sample.
Definition: TTBase.h:230
[doxygenAppendixC_copyExample]
Definition: TTValue.h:34
TTErr setDecay(const TTValue &newValue)
Set the decay time for the envelope.
Definition: TTAdsr.cpp:109
TTChannelCount numAudioSignals
The number of audio signal pointers which are actually valid.
TTFloat64 release_step
Stepsize for each sample during the release phase.
Definition: TTAdsr.h:45
#define addUpdates(updateName)
An 'update' is a message sent to a subclass instance from its parent class.
Definition: TTMessage.h:44
unsigned char TTUInt8
8 bit unsigned integer (char)
Definition: TTBase.h:174
TTUInt32 sr
Current sample rate being used by this object.
TTErr setRelease(const TTValue &newValue)
Set the release time in milliseconds.
Definition: TTAdsr.cpp:119