/[svn]/linuxsampler/trunk/src/engines/common/Note.h
ViewVC logotype

Annotation of /linuxsampler/trunk/src/engines/common/Note.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3561 - (hide annotations) (download) (as text)
Fri Aug 23 11:44:00 2019 UTC (4 years, 7 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 19694 byte(s)
NKSP: Added standard units support for numbers and final "!" operator:

* NKSP strictness: Variable names, function names and preprocessor condition
  names must start with a regular character (a-z or A-Z); starting them with
  a digit or underscore is no longer allowed.

* NKSP parser fix: equal comparison operator "=" and not equal comparison
  operator "#" must only accept integer operands.

* NKSP language: Implemented support for standard units like Hertz, seconds,
  Bel including support for metric unit prefixes; so one can now e.g.
  conveniently use numbers in scripts like "5us" meaning "5 microseconds",
  or e.g. "12kHz" meaning "12 kilo Hertz", or e.g. "-14mdB" meaning
  "minus 14 Millidecibel", or e.g. "28c" meaning "28 cents" (for tuning).

* NKSP language: Introduced "final" operator "!" which is specifically
  intended for synthesis parameter values to denote that the synthesis
  parameter value is intended to be the "final" value for that synthesis
  parameter that should explicitly be used by the engine and thus causing
  the sampler engine to ignore all other modulation sources for the same
  synthesis parameter (like e.g. LFO, EG); by simply prefixing a value,
  variable or formula with this new "!" operator the expression is marked as
  being "final".

* Bumped version (2.1.1.svn4).

1 schoenebeck 2879 /*
2 schoenebeck 3557 * Copyright (c) 2016 - 2019 Christian Schoenebeck
3 schoenebeck 2879 *
4     * http://www.linuxsampler.org
5     *
6     * This file is part of LinuxSampler and released under the same terms.
7     * See README file for details.
8     */
9    
10     #ifndef LS_NOTE_H
11     #define LS_NOTE_H
12    
13     #include "../../common/Pool.h"
14     #include "Event.h"
15 schoenebeck 3246 #include "Fade.h"
16 schoenebeck 2879
17 schoenebeck 3218 #define DEFAULT_NOTE_VOLUME_TIME_S 0.013f /* 13ms */
18     #define DEFAULT_NOTE_PITCH_TIME_S 0.013f /* 13ms */
19 schoenebeck 3335 #define DEFAULT_NOTE_PAN_TIME_S 0.013f /* 13ms */
20 schoenebeck 3188
21 schoenebeck 2879 namespace LinuxSampler {
22    
23 schoenebeck 3444 /// Whether release trigger sample(s) should be played and if yes under which circumstance(s). Options are bit flags to be able to combine them bitwise.
24     enum release_trigger_t {
25     release_trigger_none = 0, ///< Don't play release trigger sample.
26     release_trigger_noteoff = 1, ///< Play release trigger sample on MIDI note-off event.
27     release_trigger_sustain_maxvelocity = (1 << 1), ///< Play release trigger sample on sustain pedal up, use 127 as MIDI velocity.
28     release_trigger_sustain_keyvelocity = (1 << 2) ///< Play release trigger sample on sustain pedal up, use latest MIDI note-on velocity on key.
29     };
30    
31     /// convenience macro for checking playing release trigger sample by sustain pedal in general
32     #define release_trigger_sustain \
33     (release_trigger_sustain_maxvelocity | release_trigger_sustain_keyvelocity)
34    
35     // remove strictness of C++ regarding raw bitwise operations (on type release_trigger_t)
36     inline release_trigger_t operator|(release_trigger_t a, release_trigger_t b) {
37 schoenebeck 3452 return (release_trigger_t) ((int)a | (int)b);
38 schoenebeck 3444 }
39     inline release_trigger_t& operator|=(release_trigger_t& a, release_trigger_t b) {
40 schoenebeck 3452 a = (release_trigger_t) ((int)a | (int)b);
41 schoenebeck 3444 return a;
42     }
43    
44 schoenebeck 2879 /**
45     * Abstract base class of its deriving @c Note class, this class (NoteBase)
46     * is not intended to be instantiated directly. It just provides access to
47     * the parts of a Note object which do not depend on any C++ template
48     * parameter.
49     */
50     class NoteBase {
51     public:
52 schoenebeck 3561 enum class ValueScope : unsigned char {
53     RELATIVE = (unsigned char) Event::ValueScope::RELATIVE,
54     FINAL_NORM = (unsigned char) Event::ValueScope::FINAL_NORM,
55     FINAL_NATIVE = (unsigned char) Event::ValueScope::FINAL_NATIVE,
56     };
57    
58     /**
59     * General purpose note parameter value which might be both either in
60     * normalized value range (0..1) or in a native unit (i.e. seconds, Hz)
61     * depending on member variable @c Scope.
62     */
63     struct Param {
64     float Value;
65     ValueScope Scope;
66    
67     Param() {
68     Value = 1.f;
69     Scope = ValueScope::RELATIVE;
70     }
71    
72     bool isFinal() const {
73     return Scope == ValueScope::FINAL_NORM ||
74     Scope == ValueScope::FINAL_NATIVE;
75     }
76    
77     template<typename T>
78     inline void applyTo(T& dst) {
79     if (isFinal())
80     dst = Value;
81     else
82     dst *= Value;
83     }
84     };
85    
86     /**
87     * Parameter value being in normalized value range (0..1).
88     */
89     struct Norm {
90     float Value;
91     bool Final;
92    
93     Norm() {
94     Value = 1.f;
95     Final = false;
96     }
97    
98     template<typename T>
99     inline void applyTo(T& dst) {
100     if (Final)
101     dst = Value;
102     else
103     dst *= Value;
104     }
105     };
106    
107     /**
108     * Parameter value being in signed normalized value range (-1..+1).
109     */
110     struct SNorm {
111     float Value;
112     bool Final;
113     int64_t Sources; ///< Might be used for calculating an average pan value in differential way: amount of times the @c Value had been changed and shall be calculated relatively upon.
114    
115     SNorm() {
116     Value = 0.f;
117     Final = false;
118     Sources = 0;
119     }
120     };
121    
122 schoenebeck 2879 int hostKey; ///< Key on which this is @c Note is allocated on. This is usually the note-on event's note number, however in case of a child note this will rather be the parent note's key instead!
123     note_id_t parentNoteID; ///< If not null: unique ID of the parent note of this note (see comments of field @c pChildNotes).
124     RTList<note_id_t>* pChildNotes; ///< Note ID list of "child" notes of this note. These are special notes that must be released once this note gets released.
125     Event cause; ///< Copy of the original event (usually a note-on event) which caused this note.
126     event_id_t eventID; ///< Unique ID of the actual original @c Event which caused this note.
127 schoenebeck 2962 sched_time_t triggerSchedTime; ///< Engine's scheduler time when this note was launched.
128 schoenebeck 2931 /// Optional synthesis parameters that might be overridden (by calling real-time instrument script functions like change_vol(), change_pitch(), etc.).
129     struct _Override {
130 schoenebeck 3561 Norm Volume; ///< as linear amplification ratio (1.0 being neutral)
131 schoenebeck 3188 float VolumeTime; ///< Transition duration (in seconds) for changes to @c Volume.
132 schoenebeck 3561 Norm Pitch; ///< as linear frequency ratio (1.0 being neutral)
133 schoenebeck 3188 float PitchTime; ///< Transition duration (in seconds) for changes to @c Pitch.
134 schoenebeck 3561 SNorm Pan; ///< between -1.0 (most left) and +1.0 (most right) and 0.0 being neutral.
135 schoenebeck 3335 float PanTime; ///< Transition duration (in seconds) for changes to @c Pan.
136 schoenebeck 3561 Param Cutoff; ///< between 0.0 and 1.0
137     Norm Resonance; ///< between 0.0 and 1.0
138     Param Attack; ///< between 0.0 and 1.0
139     Param Decay; ///< between 0.0 and 1.0
140     Norm Sustain; ///< between 0.0 and 1.0
141     Param Release; ///< between 0.0 and 1.0
142     Param CutoffAttack; ///< between 0.0 and 1.0
143     Param CutoffDecay; ///< between 0.0 and 1.0
144     Norm CutoffSustain;///< between 0.0 and 1.0
145     Param CutoffRelease;///< between 0.0 and 1.0
146     Norm AmpLFODepth; ///< between 0.0 and 1.0
147     Param AmpLFOFreq; ///< between 0.0 and 1.0
148     Norm CutoffLFODepth;///< between 0.0 and 1.0
149     Param CutoffLFOFreq; ///< between 0.0 and 1.0
150     Norm PitchLFODepth; ///< between 0.0 and 1.0
151     Param PitchLFOFreq; ///< between 0.0 and 1.0
152 schoenebeck 3246 fade_curve_t VolumeCurve;
153     fade_curve_t PitchCurve;
154 schoenebeck 3335 fade_curve_t PanCurve;
155 schoenebeck 3251 int SampleOffset; ///< Where the sample shall start playback in microseconds (otherwise this is -1 for being ignored).
156 schoenebeck 2931 } Override;
157 schoenebeck 2879 /// Sampler format specific informations and variables.
158     union _Format {
159     /// Gigasampler/GigaStudio format specifics.
160     struct _Gig {
161     uint8_t DimMask; ///< May be used to override the Dimension zone to be selected for a new voice: each 1 bit means that respective bit shall be overridden by taking the respective bit from DimBits instead.
162     uint8_t DimBits; ///< Used only in conjunction with DimMask: Dimension bits that shall be selected.
163     } Gig;
164     } Format;
165 schoenebeck 3557 vmint userPar[4]; ///< Used only for real-time instrument script functions set_event_par() and get_event_par() to store script author's user specific data ($EVENT_PAR_0 to $EVENT_PAR_3).
166 schoenebeck 3561
167     inline
168     void apply(RTList<Event>::Iterator& itEvent, Param _Override::*noteParam) {
169     const Event::ValueScope& scope = itEvent->Param.NoteSynthParam.Scope;
170     switch (scope) {
171     case Event::ValueScope::SELF_RELATIVE:
172     if ((this->Override.*noteParam).Scope == ValueScope::FINAL_NATIVE)
173     (this->Override.*noteParam) = Param();
174     itEvent->Param.NoteSynthParam.AbsValue =
175     ((this->Override.*noteParam).Value *= itEvent->Param.NoteSynthParam.Delta);
176     (this->Override.*noteParam).Scope = ValueScope::RELATIVE;
177     break;
178     case Event::ValueScope::RELATIVE:
179     (this->Override.*noteParam).Value =
180     itEvent->Param.NoteSynthParam.AbsValue =
181     itEvent->Param.NoteSynthParam.Delta;
182     (this->Override.*noteParam).Scope = ValueScope::RELATIVE;
183     break;
184     case Event::ValueScope::FINAL_SELF_RELATIVE:
185     if ((this->Override.*noteParam).Scope == ValueScope::FINAL_NATIVE)
186     (this->Override.*noteParam) = Param();
187     itEvent->Param.NoteSynthParam.AbsValue =
188     ((this->Override.*noteParam).Value *= itEvent->Param.NoteSynthParam.Delta);
189     (this->Override.*noteParam).Scope = ValueScope::FINAL_NORM;
190     break;
191     case Event::ValueScope::FINAL_NORM:
192     (this->Override.*noteParam).Value =
193     itEvent->Param.NoteSynthParam.AbsValue =
194     itEvent->Param.NoteSynthParam.Delta;
195     (this->Override.*noteParam).Scope = ValueScope::FINAL_NORM;
196     break;
197     case Event::ValueScope::FINAL_NATIVE:
198     (this->Override.*noteParam).Value =
199     itEvent->Param.NoteSynthParam.AbsValue =
200     itEvent->Param.NoteSynthParam.Delta;
201     (this->Override.*noteParam).Scope = ValueScope::FINAL_NATIVE;
202     break;
203     }
204     }
205    
206     inline
207     void apply(RTList<Event>::Iterator& itEvent, Norm _Override::*noteParam) {
208     const Event::ValueScope& scope = itEvent->Param.NoteSynthParam.Scope;
209     switch (scope) {
210     case Event::ValueScope::SELF_RELATIVE:
211     itEvent->Param.NoteSynthParam.AbsValue =
212     ((this->Override.*noteParam).Value *= itEvent->Param.NoteSynthParam.Delta);
213     (this->Override.*noteParam).Final = false;
214     break;
215     case Event::ValueScope::RELATIVE:
216     (this->Override.*noteParam).Value =
217     itEvent->Param.NoteSynthParam.AbsValue =
218     itEvent->Param.NoteSynthParam.Delta;
219     (this->Override.*noteParam).Final = false;
220     break;
221     case Event::ValueScope::FINAL_SELF_RELATIVE:
222     itEvent->Param.NoteSynthParam.AbsValue =
223     ((this->Override.*noteParam).Value *= itEvent->Param.NoteSynthParam.Delta);
224     (this->Override.*noteParam).Final = true;
225     break;
226     case Event::ValueScope::FINAL_NORM:
227     (this->Override.*noteParam).Value =
228     itEvent->Param.NoteSynthParam.AbsValue =
229     itEvent->Param.NoteSynthParam.Delta;
230     (this->Override.*noteParam).Final = true;
231     break;
232     case Event::ValueScope::FINAL_NATIVE:
233     dmsg(1,("BUG: Attempt to assign a value in native unit to a Note parameter being in normalized value range only!\n"));
234     break;
235     }
236     }
237    
238     inline
239     void apply(RTList<Event>::Iterator& itEvent, SNorm _Override::*noteParam) {
240     const Event::ValueScope& scope = itEvent->Param.NoteSynthParam.Scope;
241     switch (scope) {
242     case Event::ValueScope::SELF_RELATIVE:
243     itEvent->Param.NoteSynthParam.AbsValue =
244     (this->Override.*noteParam).Value = RTMath::RelativeSummedAvg(
245     (this->Override.*noteParam).Value,
246     itEvent->Param.NoteSynthParam.Delta,
247     ++(this->Override.*noteParam).Sources
248     );
249     (this->Override.*noteParam).Final = false;
250     break;
251     case Event::ValueScope::RELATIVE:
252     (this->Override.*noteParam).Value =
253     itEvent->Param.NoteSynthParam.AbsValue =
254     itEvent->Param.NoteSynthParam.Delta;
255     (this->Override.*noteParam).Sources = 1;
256     (this->Override.*noteParam).Final = false;
257     break;
258     case Event::ValueScope::FINAL_SELF_RELATIVE:
259     itEvent->Param.NoteSynthParam.AbsValue =
260     (this->Override.*noteParam).Value = RTMath::RelativeSummedAvg(
261     (this->Override.*noteParam).Value,
262     itEvent->Param.NoteSynthParam.Delta,
263     ++(this->Override.*noteParam).Sources
264     );
265     (this->Override.*noteParam).Final = true;
266     break;
267     case Event::ValueScope::FINAL_NORM:
268     (this->Override.*noteParam).Value =
269     itEvent->Param.NoteSynthParam.AbsValue =
270     itEvent->Param.NoteSynthParam.Delta;
271     (this->Override.*noteParam).Sources = 1;
272     (this->Override.*noteParam).Final = true;
273     break;
274     case Event::ValueScope::FINAL_NATIVE:
275     dmsg(1,("BUG: Attempt to assign a value in native unit to a Note parameter being in signed normalized value range only!\n"));
276     break;
277     }
278     }
279    
280     inline static ValueScope scopeBy_FinalUnit(bool bFinal, bool bNativeUnit) {
281     if (!bFinal) return ValueScope::RELATIVE;
282     return (bNativeUnit) ? ValueScope::FINAL_NATIVE : ValueScope::FINAL_NORM;
283     }
284 schoenebeck 2879 protected:
285     NoteBase() : hostKey(0), parentNoteID(0), pChildNotes(NULL) {
286 schoenebeck 3561 Override.Volume = Norm();
287 schoenebeck 3188 Override.VolumeTime = DEFAULT_NOTE_VOLUME_TIME_S;
288 schoenebeck 3561 Override.Pitch = Norm();
289 schoenebeck 3188 Override.PitchTime = DEFAULT_NOTE_PITCH_TIME_S;
290 schoenebeck 3561 Override.Pan = SNorm();
291 schoenebeck 3335 Override.PanTime = DEFAULT_NOTE_PAN_TIME_S;
292 schoenebeck 3561 Override.Cutoff = Param();
293     Override.Resonance = Norm();
294     Override.Attack = Param();
295     Override.Decay = Param();
296     Override.Sustain = Norm();
297     Override.Release = Param();
298     Override.CutoffAttack = Param();
299     Override.CutoffDecay = Param();
300     Override.CutoffSustain = Norm();
301     Override.CutoffRelease = Param();
302     Override.AmpLFODepth = Norm();
303     Override.AmpLFOFreq = Param();
304     Override.CutoffLFODepth = Norm();
305     Override.CutoffLFOFreq = Param();
306     Override.PitchLFODepth = Norm();
307     Override.PitchLFOFreq = Param();
308 schoenebeck 3246 Override.VolumeCurve = DEFAULT_FADE_CURVE;
309     Override.PitchCurve = DEFAULT_FADE_CURVE;
310 schoenebeck 3335 Override.PanCurve = DEFAULT_FADE_CURVE;
311 schoenebeck 3251 Override.SampleOffset = -1;
312 schoenebeck 3118
313 schoenebeck 2880 Format = _Format();
314 schoenebeck 3193
315     userPar[0] = 0;
316     userPar[1] = 0;
317     userPar[2] = 0;
318     userPar[3] = 0;
319 schoenebeck 2879 }
320     };
321    
322     /**
323     * Contains the voices caused by one specific note, as well as basic
324 schoenebeck 3188 * information about the note itself. You can see a Note object as one
325 schoenebeck 2938 * specific event in time where one or more voices were spawned at the same
326     * time and all those voices due to the same cause.
327     *
328     * For example when you press down and hold the sustain pedal, and then
329     * trigger the same note on the keyboard multiple times, for each key
330 schoenebeck 3188 * strokes a separate Note instance is created. Assuming you have a layered
331     * sound with 4 layers, then for each note that is triggered 4 voices will
332     * be spawned and assigned to the same Note object. By grouping those voices
333     * to one specific Note object, it allows to control the synthesis paramters
334     * of those layered voices simultaniously.
335 schoenebeck 2938 *
336     * If your instrument contains a real-time instrument script, then that
337     * script might also trigger additional voices programmatically (by
338     * calling the built-in script function play_note()). Each time the script
339     * calls play_note() a new Note instance is created and the script may then
340     * further control the voices of specific notes independently from each
341     * other. For example for each key stroke on your keyboard the instrument
342     * script might trigger 3 additional notes programmatically and assign a
343     * different tuning filter parameters for each one of the 3 notes
344     * independently.
345 schoenebeck 2879 */
346     template<class V>
347     class Note : public NoteBase {
348     public:
349     RTList<V>* pActiveVoices; ///< Contains the active voices associated with this note.
350    
351     Note() : NoteBase(), pActiveVoices(NULL) {}
352    
353     virtual ~Note() {
354     if (pChildNotes) delete pChildNotes;
355     if (pActiveVoices) delete pActiveVoices;
356     }
357    
358     void init(Pool<V>* pVoicePool, Pool<note_id_t>* pNoteIDPool) {
359     if (pActiveVoices) delete pActiveVoices;
360     pActiveVoices = new RTList<V>(pVoicePool);
361     if (pChildNotes) delete pChildNotes;
362     pChildNotes = new RTList<note_id_t>(pNoteIDPool);
363     }
364    
365     void reset() {
366     hostKey = 0;
367     parentNoteID = 0;
368     if (pChildNotes)
369     pChildNotes->clear();
370     cause = Event();
371     eventID = 0;
372 schoenebeck 3561 Override.Volume = Norm();
373 schoenebeck 3188 Override.VolumeTime = DEFAULT_NOTE_VOLUME_TIME_S;
374 schoenebeck 3561 Override.Pitch = Norm();
375 schoenebeck 3188 Override.PitchTime = DEFAULT_NOTE_PITCH_TIME_S;
376 schoenebeck 3561 Override.Pan = SNorm();
377 schoenebeck 3335 Override.PanTime = DEFAULT_NOTE_PAN_TIME_S;
378 schoenebeck 3561 Override.Cutoff = Param();
379     Override.Resonance = Norm();
380     Override.Attack = Param();
381     Override.Decay = Param();
382     Override.Sustain = Norm();
383     Override.Release = Param();
384     Override.CutoffAttack = Param();
385     Override.CutoffDecay = Param();
386     Override.CutoffSustain = Norm();
387     Override.CutoffRelease = Param();
388     Override.AmpLFODepth = Norm();
389     Override.AmpLFOFreq = Param();
390     Override.CutoffLFODepth = Norm();
391     Override.CutoffLFOFreq = Param();
392     Override.PitchLFODepth = Norm();
393     Override.PitchLFOFreq = Param();
394 schoenebeck 3246 Override.VolumeCurve = DEFAULT_FADE_CURVE;
395     Override.PitchCurve = DEFAULT_FADE_CURVE;
396 schoenebeck 3335 Override.PanCurve = DEFAULT_FADE_CURVE;
397 schoenebeck 3251 Override.SampleOffset = -1;
398 schoenebeck 2880 Format = _Format();
399 schoenebeck 3193 userPar[0] = 0;
400     userPar[1] = 0;
401     userPar[2] = 0;
402     userPar[3] = 0;
403 schoenebeck 2879 if (pActiveVoices) {
404     typename RTList<V>::Iterator itVoice = pActiveVoices->first();
405     typename RTList<V>::Iterator itVoicesEnd = pActiveVoices->end();
406     for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
407     itVoice->VoiceFreed();
408     }
409     pActiveVoices->clear();
410     }
411     }
412     };
413    
414     } // namespace LinuxSampler
415    
416     #endif // LS_NOTE_H

  ViewVC Help
Powered by ViewVC