/[svn]/linuxsampler/trunk/src/engines/sfz/SfzSignalUnitRack.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/sfz/SfzSignalUnitRack.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2221 by iliev, Thu Jul 28 17:17:42 2011 UTC revision 2237 by iliev, Fri Aug 12 13:07:05 2011 UTC
# Line 34  namespace LinuxSampler { namespace sfz { Line 34  namespace LinuxSampler { namespace sfz {
34          return pVoice->GetSampleRate() / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;          return pVoice->GetSampleRate() / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
35      }      }
36            
37        float SfzSignalUnit::GetInfluence(ArrayList< ::sfz::CC>& cc) {
38            float f = 0;
39            for (int i = 0; i < cc.size(); i++) {
40                int val = pVoice->GetControllerValue(cc[i].Controller);
41                f += (val / 127.0f) * cc[i].Influence;
42            }
43            return f;
44        }
45        
46        void XFInCCUnit::SetCrossFadeCCs(::sfz::Array<int>& loCCs, ::sfz::Array<int>& hiCCs) {
47            RemoveAllCCs();
48            
49            for (int cc = 0; cc < 128; cc++) {
50                if (loCCs[cc] == 0 && hiCCs[cc] == 0) continue;
51                int i = loCCs[cc];
52                int j = hiCCs[cc];
53                if (j == 0) j = 127;
54                i += j << 8; // workaround to keep both values in the Influence parameter
55                AddCC(cc, i);
56            }
57        }
58            
59      void EGv1Unit::Trigger() {      void XFInCCUnit::Calculate() {
60          ::sfz::Region* const pRegion = pVoice->pRegion;          float l = 1;
61                    
62            for (int i = 0; i < Ctrls.size(); i++) {
63                float c = 1;
64                int influence = Ctrls[i].Influence;
65                int lo = influence & 0xff;
66                int hi = influence >> 8;
67                if (Ctrls[i].Value <= lo) {
68                    c = 0;
69                } else if (Ctrls[i].Value >= hi) {
70                    c = 1;
71                } else {
72                    float xfVelSize = hi - lo;
73                    float velPos = Ctrls[i].Value - lo;
74                    c = velPos / xfVelSize;
75                    if (pVoice->pRegion->xf_cccurve == ::sfz::POWER) {
76                        c = sin(c * M_PI / 2.0);
77                    }
78                }
79                
80                l *= c;
81            }
82                    
83          // the length of the decay and release curves are dependent on the velocity          if (Level != l) {
84          const double velrelease = 1 / pVoice->GetVelocityRelease(pVoice->MIDIVelocity);              Level = l;
85                if (pListener != NULL) pListener->ValueChanged(this);
86          // set the delay trigger          }
87          uiDelayTrigger = (pRegion->ampeg_delay + pRegion->ampeg_vel2delay * velrelease) * GetSampleRate();      }
88        
89        
90        void XFOutCCUnit::Calculate() {
91            float l = 1;
92                    
93            for (int i = 0; i < Ctrls.size(); i++) {
94                float c = 1;
95                int influence = Ctrls[i].Influence;
96                int lo = influence & 0xff;
97                int hi = influence >> 8;
98                if (Ctrls[i].Value >= hi) {
99                    c = 0;
100                } else if (Ctrls[i].Value <= lo) {
101                    c = 1;
102                } else {
103                    float xfVelSize = hi - lo;
104                    float velPos = Ctrls[i].Value - lo;
105                    c = 1.0f - velPos / xfVelSize;
106                    if (pVoice->pRegion->xf_cccurve == ::sfz::POWER) {
107                        c = sin(c * M_PI / 2.0);
108                    }
109                }
110                
111                l *= c;
112            }
113                    
114          EG.trigger(uint(pRegion->ampeg_start * 10),          if (Level != l) {
115                     std::max(0.0, pRegion->ampeg_attack + pRegion->ampeg_vel2attack * velrelease),              Level = l;
116                     std::max(0.0, pRegion->ampeg_hold + pRegion->ampeg_vel2hold * velrelease),              if (pListener != NULL) pListener->ValueChanged(this);
117                     std::max(0.0, pRegion->ampeg_decay + pRegion->ampeg_vel2decay * velrelease),          }
                    uint(std::min(std::max(0.0, 10 * (pRegion->ampeg_sustain + pRegion->ampeg_vel2sustain * velrelease)), 1000.0)),  
                    std::max(0.0, pRegion->ampeg_release + pRegion->ampeg_vel2release * velrelease),  
                    GetSampleRate());  
118      }      }
119            
120            
121        EGv2Unit::EGv2Unit(SfzSignalUnitRack* rack)
122            : EGUnit< ::LinuxSampler::sfz::EG>(rack), suAmpOnCC(rack), suVolOnCC(rack),
123              suPitchOnCC(rack), suCutoffOnCC(rack), suResOnCC(rack), suPanOnCC(rack)
124        { }
125        
126      void EGv2Unit::Trigger() {      void EGv2Unit::Trigger() {
127          EG.trigger(*pEGInfo, GetSampleRate(), pVoice->MIDIVelocity);          egInfo = *pEGInfo;
128            for (int i = 0; i < egInfo.node.size(); i++) {
129                float f = GetInfluence(egInfo.node[i].level_oncc);
130                egInfo.node[i].level = std::min(egInfo.node[i].level + f, 1.0f);
131                
132                f = GetInfluence(egInfo.node[i].time_oncc);
133                egInfo.node[i].time = std::min(egInfo.node[i].time + f, 100.0f);
134            }
135            EG.trigger(egInfo, GetSampleRate(), pVoice->MIDIVelocity);
136      }      }
137            
138            
# Line 78  namespace LinuxSampler { namespace sfz { Line 155  namespace LinuxSampler { namespace sfz {
155                     GetSampleRate());                     GetSampleRate());
156      }      }
157            
158        
159        void FilEGUnit::Trigger() {
160            ::sfz::Region* const pRegion = pVoice->pRegion;
161            depth = pRegion->fileg_depth;
162            
163            // the length of the decay and release curves are dependent on the velocity
164            const double velrelease = 1 / pVoice->GetVelocityRelease(pVoice->MIDIVelocity);
165    
166            // set the delay trigger
167            uiDelayTrigger = (pRegion->fileg_delay + pRegion->fileg_vel2delay * velrelease) * GetSampleRate();
168            
169            EG.trigger(uint(pRegion->fileg_start * 10),
170                       std::max(0.0, pRegion->fileg_attack + pRegion->fileg_vel2attack * velrelease),
171                       std::max(0.0, pRegion->fileg_hold + pRegion->fileg_vel2hold * velrelease),
172                       std::max(0.0, pRegion->fileg_decay + pRegion->fileg_vel2decay * velrelease),
173                       uint(std::min(std::max(0.0, 10 * (pRegion->fileg_sustain + pRegion->fileg_vel2sustain * velrelease)), 1000.0)),
174                       std::max(0.0, pRegion->fileg_release + pRegion->fileg_vel2release * velrelease),
175                       GetSampleRate());
176        }
177        
178        
179        void AmpEGUnit::Trigger() {
180            ::sfz::Region* const pRegion = pVoice->pRegion;
181            
182            // the length of the decay and release curves are dependent on the velocity
183            const double velrelease = 1 / pVoice->GetVelocityRelease(pVoice->MIDIVelocity);
184    
185            // set the delay trigger
186            float delay = pRegion->ampeg_delay + pRegion->ampeg_vel2delay * velrelease;
187            delay += GetInfluence(pRegion->ampeg_delaycc);
188            uiDelayTrigger = std::max(0.0f, delay) * GetSampleRate();
189            
190            float start = (pRegion->ampeg_start + GetInfluence(pRegion->ampeg_startcc)) * 10;
191            
192            float attack = pRegion->ampeg_attack + pRegion->ampeg_vel2attack * velrelease;
193            attack = std::max(0.0f, attack + GetInfluence(pRegion->ampeg_attackcc));
194            
195            float hold = pRegion->ampeg_hold + pRegion->ampeg_vel2hold * velrelease;
196            hold = std::max(0.0f, hold + GetInfluence(pRegion->ampeg_holdcc));
197            
198            float decay = pRegion->ampeg_decay + pRegion->ampeg_vel2decay * velrelease;
199            decay = std::max(0.0f, decay + GetInfluence(pRegion->ampeg_decaycc));
200            
201            float sustain = pRegion->ampeg_sustain + pRegion->ampeg_vel2sustain * velrelease;
202            sustain = 10 * (sustain + GetInfluence(pRegion->ampeg_sustaincc));
203            
204            float release = pRegion->ampeg_release + pRegion->ampeg_vel2release * velrelease;
205            release = std::max(0.0f, release + GetInfluence(pRegion->ampeg_releasecc));
206            
207            EG.trigger (
208                uint(std::min(std::max(0.0f, start), 1000.0f)), attack, hold, decay,
209                uint(std::min(std::max(0.0f, sustain), 1000.0f)), release, GetSampleRate()
210            );
211        }
212        
213        
214        LFOUnit::LFOUnit(SfzSignalUnitRack* rack)
215            : SfzSignalUnit(rack), pLfoInfo(NULL), pLFO(NULL),
216              suFadeEG(rack), suFreqOnCC(rack, this), suDepthOnCC(rack)
217        { }
218        
219        LFOUnit::LFOUnit(const LFOUnit& Unit)
220            : SfzSignalUnit(Unit), suFadeEG(static_cast<SfzSignalUnitRack*>(Unit.pRack)),
221              suFreqOnCC(static_cast<SfzSignalUnitRack*>(Unit.pRack), this),
222              suDepthOnCC(static_cast<SfzSignalUnitRack*>(Unit.pRack))
223        {
224            Copy(Unit);
225        }
226    
227      void LFOUnit::Increment() {      void LFOUnit::Increment() {
228          if (DelayStage()) return;          if (DelayStage()) return;
229                    
230          SignalUnit::Increment();          SignalUnit::Increment();
231                    
232          Level = lfo.render();          Level = pLFO->Render();
233            if (suFadeEG.Active()) Level *= suFadeEG.GetLevel();
234      }      }
235            
236      void LFOUnit::Trigger() {      void LFOUnit::Trigger() {
# Line 92  namespace LinuxSampler { namespace sfz { Line 238  namespace LinuxSampler { namespace sfz {
238          Level = 0;          Level = 0;
239                    
240          // set the delay trigger          // set the delay trigger
241          uiDelayTrigger = pLfoInfo->delay * GetSampleRate();          uiDelayTrigger = (pLfoInfo->delay + GetInfluence(pLfoInfo->delay_oncc)) * GetSampleRate();
242            if(pLfoInfo->fade != 0 || !pLfoInfo->fade_oncc.empty()) {
243                float f = pLfoInfo->fade;
244                f += GetInfluence(pLfoInfo->fade_oncc);
245                
246                if (f != 0) {
247                    suFadeEG.uiDelayTrigger = pLfoInfo->delay * GetSampleRate();
248                    suFadeEG.EG.trigger(0, f, 0, 0, 1000, 0, GetSampleRate());
249                }
250            }
251        }
252        
253        void LFOUnit::ValueChanged(CCSignalUnit* pUnit) {
254            pLFO->SetFrequency(std::max(0.0f, suFreqOnCC.GetLevel() + pLfoInfo->freq), GetSampleRate());
255      }      }
256            
257        
258      void LFOv1Unit::Trigger() {      void LFOv1Unit::Trigger() {
259          LFOUnit::Trigger();          LFOUnit::Trigger();
260                    
261          lfo.trigger (          lfo.trigger (
262              pLfoInfo->freq,              pLfoInfo->freq + suFreqOnCC.GetLevel(),
263              start_level_mid,              start_level_mid,
264              1, 0, false, GetSampleRate()              1, 0, false, GetSampleRate()
265          );          );
266          lfo.update(0);          lfo.update(0);
267      }      }
268            
269        
270        LFOv2Unit::LFOv2Unit(SfzSignalUnitRack* rack)
271            : LFOUnit(rack), lfos(8), lfo0(1200.0f), lfo1(1200.0f), lfo2(1200.0f),
272              lfo3(1200.0f), lfo4(1200.0f), lfo5(1200.0f), lfo6(1200.0f), lfo7(1200.0f),
273              suVolOnCC(rack), suPitchOnCC(rack), suPanOnCC(rack), suCutoffOnCC(rack), suResOnCC(rack)
274        {
275            lfos.add(&lfo0);
276            lfos.add(&lfo1);
277            lfos.add(&lfo2);
278            lfos.add(&lfo3);
279            lfos.add(&lfo4);
280            lfos.add(&lfo5);
281            lfos.add(&lfo6);
282            lfos.add(&lfo7);
283        }
284        
285      void LFOv2Unit::Trigger() {      void LFOv2Unit::Trigger() {
286          LFOUnit::Trigger();          LFOUnit::Trigger();
287                    
288          lfo.trigger (          if (pLfoInfo->wave < 0 || pLfoInfo->wave >= lfos.size()) pLFO = &lfo0;
289              pLfoInfo->freq,          else pLFO = lfos[pLfoInfo->wave];
290            
291            pLFO->Trigger (
292                pLfoInfo->freq + suFreqOnCC.GetLevel(),
293              start_level_mid,              start_level_mid,
294              1, 0, false, GetSampleRate()              1, 0, false, GetSampleRate()
295          );          );
296          lfo.update(0);          pLFO->Update(0);
297            
298            float phase = pLfoInfo->phase + GetInfluence(pLfoInfo->phase_oncc);
299            if (phase != 0) pLFO->SetPhase(phase);
300      }      }
301            
302      void AmpLFOUnit::Trigger() {      void AmpLFOUnit::Trigger() {
303          ::sfz::Region* const pRegion = pVoice->pRegion;          ::sfz::Region* const pRegion = pVoice->pRegion;
304          pLfoInfo->delay = pRegion->amplfo_delay;          pLfoInfo->delay  = pRegion->amplfo_delay;
305          pLfoInfo->freq = pRegion->amplfo_freq;          pLfoInfo->freq   = pRegion->amplfo_freq;
306            pLfoInfo->fade   = pRegion->amplfo_fade;
307          pLfoInfo->volume = pRegion->amplfo_depth;          pLfoInfo->volume = pRegion->amplfo_depth;
308                    
309          LFOv1Unit::Trigger();          LFOv1Unit::Trigger();
# Line 129  namespace LinuxSampler { namespace sfz { Line 312  namespace LinuxSampler { namespace sfz {
312      void PitchLFOUnit::Trigger() {      void PitchLFOUnit::Trigger() {
313          ::sfz::Region* const pRegion = pVoice->pRegion;          ::sfz::Region* const pRegion = pVoice->pRegion;
314          pLfoInfo->delay = pRegion->pitchlfo_delay;          pLfoInfo->delay = pRegion->pitchlfo_delay;
315          pLfoInfo->freq = pRegion->pitchlfo_freq;          pLfoInfo->freq  = pRegion->pitchlfo_freq;
316            pLfoInfo->fade  = pRegion->pitchlfo_fade;
317          pLfoInfo->pitch = pRegion->pitchlfo_depth;          pLfoInfo->pitch = pRegion->pitchlfo_depth;
318                    
319          LFOv1Unit::Trigger();          LFOv1Unit::Trigger();
# Line 137  namespace LinuxSampler { namespace sfz { Line 321  namespace LinuxSampler { namespace sfz {
321            
322      void FilLFOUnit::Trigger() {      void FilLFOUnit::Trigger() {
323          ::sfz::Region* const pRegion = pVoice->pRegion;          ::sfz::Region* const pRegion = pVoice->pRegion;
324          pLfoInfo->delay = pRegion->fillfo_delay;          pLfoInfo->delay  = pRegion->fillfo_delay;
325          pLfoInfo->freq = pRegion->fillfo_freq;          pLfoInfo->freq   = pRegion->fillfo_freq;
326            pLfoInfo->fade   = pRegion->fillfo_fade;
327          pLfoInfo->cutoff = pRegion->fillfo_depth;          pLfoInfo->cutoff = pRegion->fillfo_depth;
328                    
329          LFOv1Unit::Trigger();          LFOv1Unit::Trigger();
330      }      }
331        
332        CCUnit::CCUnit(SfzSignalUnitRack* rack, Listener* l): CCSignalUnit(rack, l) {
333            pVoice = NULL;
334        }
335        
336        void CCUnit::Trigger() {
337            for (int i = 0; i < Ctrls.size(); i++) {
338                Ctrls[i].Value = pVoice->GetControllerValue(Ctrls[i].Controller);
339                if (Ctrls[i].pSmoother != NULL) Ctrls[i].pSmoother->setValue(Ctrls[i].Value);
340            }
341            CCSignalUnit::Trigger();
342        }
343        
344         void CCUnit::SetCCs(::sfz::Array<int>& cc) {
345             RemoveAllCCs();
346             for (int i = 0; i < 128; i++) {
347                 if (cc[i] != 0) AddCC(i, cc[i]);
348             }
349         }
350        
351         void CCUnit::SetCCs(ArrayList< ::sfz::CC>& cc) {
352             RemoveAllCCs();
353             for (int i = 0; i < cc.size(); i++) {
354                 if (cc[i].Influence != 0) {
355                     short int curve = cc[i].Curve;
356                     if (curve >= GetCurveCount()) curve = -1;
357                     AddSmoothCC(cc[i].Controller, cc[i].Influence, curve, cc[i].Smooth);
358                 }
359             }
360         }
361        
362         void CCUnit::AddSmoothCC(uint8_t Controller, float Influence, short int Curve, float Smooth) {
363             AddCC(Controller, Influence, Curve);
364         }
365        
366         int CCUnit::GetCurveCount() {
367             return pVoice->pRegion->GetInstrument()->curves.size();
368         }
369        
370         ::sfz::Curve* CCUnit::GetCurve(int idx) {
371             return &pVoice->pRegion->GetInstrument()->curves[idx];
372         }
373        
374         double CCUnit::GetSampleRate() {
375            return pVoice->GetSampleRate() / CONFIG_DEFAULT_SUBFRAGMENT_SIZE;
376        }
377        
378         void SmoothCCUnit::AddSmoothCC(uint8_t Controller, float Influence, short int Curve, float Smooth) {
379             if (Smooth > 0) {
380                 Smoothers[Controller].trigger(Smooth / 1000.0f, GetSampleRate());
381                 AddCC(Controller, Influence, Curve, &Smoothers[Controller]);
382             } else {
383                 AddCC(Controller, Influence, Curve);
384             }
385         }
386    
387    
388      EndpointUnit::EndpointUnit(SfzSignalUnitRack* rack): EndpointSignalUnit(rack) {      EndpointUnit::EndpointUnit(SfzSignalUnitRack* rack)
389            : EndpointSignalUnit(rack), suXFInCC(rack), suXFOutCC(rack), suPanOnCC(rack), pitchVeltrackRatio(0)
390        {
391                    
392      }      }
393            
# Line 154  namespace LinuxSampler { namespace sfz { Line 396  namespace LinuxSampler { namespace sfz {
396      }      }
397            
398      void EndpointUnit::Trigger() {      void EndpointUnit::Trigger() {
399            float xfInVelCoeff = 1;
400            
401            if (pVoice->MIDIVelocity <= pVoice->pRegion->xfin_lovel) {
402                xfInVelCoeff = 0;
403            } else if (pVoice->MIDIVelocity >= pVoice->pRegion->xfin_hivel) {
404                xfInVelCoeff = 1;
405            } else {
406                float xfVelSize = pVoice->pRegion->xfin_hivel - pVoice->pRegion->xfin_lovel;
407                float velPos = pVoice->MIDIVelocity - pVoice->pRegion->xfin_lovel;
408                xfInVelCoeff = velPos / xfVelSize;
409                if (pVoice->pRegion->xf_velcurve == ::sfz::POWER) {
410                    xfInVelCoeff = sin(xfInVelCoeff * M_PI / 2.0);
411                }
412            }
413            
414            float xfOutVelCoeff = 1;
415                    
416            if (pVoice->MIDIVelocity >= pVoice->pRegion->xfout_hivel) {
417                if (pVoice->pRegion->xfout_lovel < 127 /* is set */) xfOutVelCoeff = 0;
418            } else if (pVoice->MIDIVelocity <= pVoice->pRegion->xfout_lovel) {
419                xfOutVelCoeff = 1;
420            } else {
421                float xfVelSize = pVoice->pRegion->xfout_hivel - pVoice->pRegion->xfout_lovel;
422                float velPos = pVoice->MIDIVelocity - pVoice->pRegion->xfout_lovel;
423                xfOutVelCoeff = 1.0f - velPos / xfVelSize;
424                if (pVoice->pRegion->xf_velcurve == ::sfz::POWER) {
425                    xfOutVelCoeff = sin(xfOutVelCoeff * M_PI / 2.0);
426                }
427            }
428            
429            float xfInKeyCoeff = 1;
430            
431            if (pVoice->MIDIKey <= pVoice->pRegion->xfin_lokey) {
432                if (pVoice->pRegion->xfin_hikey > 0 /* is set */) xfInKeyCoeff = 0;
433            } else if (pVoice->MIDIKey >= pVoice->pRegion->xfin_hikey) {
434                xfInKeyCoeff = 1;
435            } else {
436                float xfKeySize = pVoice->pRegion->xfin_hikey - pVoice->pRegion->xfin_lokey;
437                float keyPos = pVoice->MIDIKey - pVoice->pRegion->xfin_lokey;
438                xfInKeyCoeff = keyPos / xfKeySize;
439                if (pVoice->pRegion->xf_keycurve == ::sfz::POWER) {
440                    xfInKeyCoeff = sin(xfInKeyCoeff * M_PI / 2.0);
441                }
442            }
443            
444            float xfOutKeyCoeff = 1;
445            
446            if (pVoice->MIDIKey >= pVoice->pRegion->xfout_hikey) {
447                if (pVoice->pRegion->xfout_lokey < 127 /* is set */) xfOutKeyCoeff = 0;
448            } else if (pVoice->MIDIKey <= pVoice->pRegion->xfout_lokey) {
449                xfOutKeyCoeff = 1;
450            } else {
451                float xfKeySize = pVoice->pRegion->xfout_hikey - pVoice->pRegion->xfout_lokey;
452                float keyPos = pVoice->MIDIKey - pVoice->pRegion->xfout_lokey;
453                xfOutKeyCoeff = 1.0f - keyPos / xfKeySize;
454                if (pVoice->pRegion->xf_keycurve == ::sfz::POWER) {
455                    xfOutKeyCoeff = sin(xfOutKeyCoeff * M_PI / 2.0);
456                }
457            }
458            
459            xfCoeff = xfInVelCoeff * xfOutVelCoeff * xfInKeyCoeff * xfOutKeyCoeff;
460            
461            suXFInCC.SetCrossFadeCCs(pVoice->pRegion->xfin_locc, pVoice->pRegion->xfin_hicc);
462            suXFOutCC.SetCrossFadeCCs(pVoice->pRegion->xfout_locc, pVoice->pRegion->xfout_hicc);
463            
464            suPanOnCC.SetCCs(pVoice->pRegion->pan_oncc);
465            
466            pitchVeltrackRatio = RTMath::CentsToFreqRatioUnlimited((pVoice->MIDIVelocity / 127.0f) * pVoice->pRegion->pitch_veltrack);
467      }      }
468            
469      bool EndpointUnit::Active() {      bool EndpointUnit::Active() {
# Line 174  namespace LinuxSampler { namespace sfz { Line 483  namespace LinuxSampler { namespace sfz {
483          for (int i = 0; i < GetRack()->volEGs.size(); i++) {          for (int i = 0; i < GetRack()->volEGs.size(); i++) {
484              EGv2Unit* eg = GetRack()->volEGs[i];              EGv2Unit* eg = GetRack()->volEGs[i];
485              if (!eg->Active()) continue;              if (!eg->Active()) continue;
486              vol += eg->GetLevel() * (eg->pEGInfo->amplitude / 100.0f);              
487                float dB = eg->suVolOnCC.Active() ? eg->suVolOnCC.GetLevel() : -200;
488                if (dB < -144) dB = eg->pEGInfo->volume;
489                else if (eg->pEGInfo->volume >= -144) dB += eg->pEGInfo->volume;
490                
491                float amp = eg->suAmpOnCC.Active() ? eg->suAmpOnCC.GetLevel() : 0;
492                amp = (amp + eg->pEGInfo->amplitude) / 100.0f;
493                
494                if (dB >= -144) {
495                    if (amp == 0 && eg->suAmpOnCC.GetCCCount() == 0) amp = 1.0f;
496                    amp *= ::sf2::ToRatio(dB * 10.0);
497                }
498                
499                vol += amp * eg->GetLevel();
500          }          }
501                    
502          AmpLFOUnit* u = &(GetRack()->suAmpLFO);          AmpLFOUnit* u = &(GetRack()->suAmpLFO);
503          vol *= u->Active() ? ::sf2::ToRatio((u->GetLevel() * u->pLfoInfo->volume) * 10.0) : 1;          CCSignalUnit* u2 = &(GetRack()->suAmpLFO.suDepthOnCC);
504            float f = u2->Active() ? u2->GetLevel() : 0;
505            vol *= u->Active() ? ::sf2::ToRatio((u->GetLevel() * (u->pLfoInfo->volume + f) * 10.0)) : 1;
506                    
507          return vol;          vol *= ::sf2::ToRatio(GetRack()->suVolOnCC.GetLevel() * 10.0);
508            
509            for (int i = 0; i < GetRack()->volLFOs.size(); i++) {
510                LFOv2Unit* lfo = GetRack()->volLFOs[i];
511                if (!lfo->Active()) continue;
512                
513                float f = lfo->suVolOnCC.Active() ? lfo->suVolOnCC.GetLevel() : 0;
514                vol *= ::sf2::ToRatio(lfo->GetLevel() * (lfo->pLfoInfo->volume + f) * 10.0);
515            }
516            
517            if (suXFInCC.Active())  vol *= suXFInCC.GetLevel();
518            if (suXFOutCC.Active()) vol *= suXFOutCC.GetLevel();
519            return vol * xfCoeff;
520      }      }
521            
522      float EndpointUnit::GetFilterCutoff() {      float EndpointUnit::GetFilterCutoff() {
523          float val;          float val;
524                    
525          FilLFOUnit* u = &(GetRack()->suFilLFO);          FilLFOUnit* u = &(GetRack()->suFilLFO);
526          val = u->Active() ? RTMath::CentsToFreqRatioUnlimited(u->GetLevel() * u->pLfoInfo->cutoff) : 1;          CCSignalUnit* u1 = &(GetRack()->suFilLFO.suDepthOnCC);
527            float f = u1->Active() ? u1->GetLevel() : 0;
528            val = u->Active() ? RTMath::CentsToFreqRatioUnlimited(u->GetLevel() * (u->pLfoInfo->cutoff + f)) : 1;
529            
530            FilEGUnit* u2 = &(GetRack()->suFilEG);
531            val *= u2->Active() ? RTMath::CentsToFreqRatioUnlimited(u2->GetLevel() * u2->depth) : 1;
532            
533            for (int i = 0; i < GetRack()->filEGs.size(); i++) {
534                EGv2Unit* eg = GetRack()->filEGs[i];
535                if (!eg->Active()) continue;
536                
537                float f = eg->suCutoffOnCC.Active() ? eg->suCutoffOnCC.GetLevel() : 0;
538                f = eg->GetLevel() * (eg->pEGInfo->cutoff + f);
539                val *= RTMath::CentsToFreqRatioUnlimited(f);
540            }
541                    
542          for (int i = 0; i < GetRack()->filLFOs.size(); i++) {          for (int i = 0; i < GetRack()->filLFOs.size(); i++) {
543              LFOv2Unit* lfo = GetRack()->filLFOs[i];              LFOv2Unit* lfo = GetRack()->filLFOs[i];
544              if (!lfo->Active()) continue;              if (!lfo->Active()) continue;
545                            
546              float f = lfo->GetLevel() * lfo->pLfoInfo->cutoff;              float f = lfo->suCutoffOnCC.Active() ? lfo->suCutoffOnCC.GetLevel() : 0;
547                f = lfo->GetLevel() * (lfo->pLfoInfo->cutoff + f);
548              val *= RTMath::CentsToFreqRatioUnlimited(f);              val *= RTMath::CentsToFreqRatioUnlimited(f);
549          }          }
550                    
551          return val;          return val;
552      }      }
553            
554        float EndpointUnit::CalculateFilterCutoff(float cutoff) {
555             cutoff *= GetFilterCutoff();
556             float maxCutoff = 0.49 * pVoice->GetSampleRate();
557             return cutoff > maxCutoff ? maxCutoff : cutoff;
558        }
559        
560      float EndpointUnit::GetPitch() {      float EndpointUnit::GetPitch() {
561          double p;          double p;
562          EGv1Unit* u = &(GetRack()->suPitchEG);          EGv1Unit* u = &(GetRack()->suPitchEG);
563          p = u->Active() ? RTMath::CentsToFreqRatioUnlimited(u->GetLevel() * u->depth) : 1;          p = u->Active() ? RTMath::CentsToFreqRatioUnlimited(u->GetLevel() * u->depth) : 1;
564                    
565            for (int i = 0; i < GetRack()->pitchEGs.size(); i++) {
566                EGv2Unit* eg = GetRack()->pitchEGs[i];
567                if (!eg->Active()) continue;
568                
569                float f = eg->suPitchOnCC.Active() ? eg->suPitchOnCC.GetLevel() : 0;
570                p *= RTMath::CentsToFreqRatioUnlimited(eg->GetLevel() * (eg->pEGInfo->pitch + f));
571            }
572            
573          PitchLFOUnit* u2 = &(GetRack()->suPitchLFO);          PitchLFOUnit* u2 = &(GetRack()->suPitchLFO);
574          p *= u2->Active() ? RTMath::CentsToFreqRatioUnlimited(u2->GetLevel() * u2->pLfoInfo->pitch) : 1;          CCSignalUnit* u3 = &(GetRack()->suPitchLFO.suDepthOnCC);
575            float f = u3->Active() ? u3->GetLevel() : 0;
576            p *= u2->Active() ? RTMath::CentsToFreqRatioUnlimited(u2->GetLevel() * (u2->pLfoInfo->pitch + f)) : 1;
577            
578            for (int i = 0; i < GetRack()->pitchLFOs.size(); i++) {
579                LFOv2Unit* lfo = GetRack()->pitchLFOs[i];
580                if (!lfo->Active()) continue;
581                
582                float f = lfo->suPitchOnCC.Active() ? lfo->suPitchOnCC.GetLevel() : 0;
583                p *= RTMath::CentsToFreqRatioUnlimited(lfo->GetLevel() * (lfo->pLfoInfo->pitch + f));
584            }
585                    
586          return p;          return p * pitchVeltrackRatio;
587      }      }
588            
589      float EndpointUnit::GetResonance() {      float EndpointUnit::GetResonance() {
590           float val = 0;           float val = 0;
591                    
592            for (int i = 0; i < GetRack()->resEGs.size(); i++) {
593                EGv2Unit* eg = GetRack()->resEGs[i];
594                if (!eg->Active()) continue;
595                
596                float f = eg->suResOnCC.Active() ? eg->suResOnCC.GetLevel() : 0;
597                val += eg->GetLevel() * (eg->pEGInfo->resonance + f);
598            }
599            
600          for (int i = 0; i < GetRack()->resLFOs.size(); i++) {          for (int i = 0; i < GetRack()->resLFOs.size(); i++) {
601              LFOv2Unit* lfo = GetRack()->resLFOs[i];              LFOv2Unit* lfo = GetRack()->resLFOs[i];
602              if (!lfo->Active()) continue;              if (!lfo->Active()) continue;
603                            
604              val += lfo->GetLevel() * lfo->pLfoInfo->resonance;              float f = lfo->suResOnCC.Active() ? lfo->suResOnCC.GetLevel() : 0;
605                val += lfo->GetLevel() * (lfo->pLfoInfo->resonance + f);
606          }          }
607                    
608          return val;          return val;
609      }      }
610            
611      float EndpointUnit::GetPan() {      float EndpointUnit::GetPan() {
612          float pan = 0;          float pan = suPanOnCC.Active() ? suPanOnCC.GetLevel() : 0;
613            
614            for (int i = 0; i < GetRack()->panEGs.size(); i++) {
615                EGv2Unit* eg = GetRack()->panEGs[i];
616                if (!eg->Active()) continue;
617                
618                float f = eg->suPanOnCC.Active() ? eg->suPanOnCC.GetLevel() : 0;
619                
620                if (eg->pEGInfo->pan_curve >= 0 && eg->pEGInfo->pan_curve < suPanOnCC.GetCurveCount()) {
621                    uint8_t val = eg->GetLevel() * 127;
622                    if (val > 127) val = 127;
623                    pan += eg->pEGInfo->pan * suPanOnCC.GetCurve(eg->pEGInfo->pan_curve)->v[val] +  eg->GetLevel() * f;
624                } else {
625                    pan += eg->GetLevel() * (eg->pEGInfo->pan + f);
626                }
627            }
628                    
629          for (int i = 0; i < GetRack()->panLFOs.size(); i++) {          for (int i = 0; i < GetRack()->panLFOs.size(); i++) {
630              LFOv2Unit* lfo = GetRack()->panLFOs[i];              LFOv2Unit* lfo = GetRack()->panLFOs[i];
631              if (!lfo->Active()) continue;              if (!lfo->Active()) continue;
632                            
633              pan += lfo->GetLevel() * lfo->pLfoInfo->pan;              float f = lfo->suPanOnCC.Active() ? lfo->suPanOnCC.GetLevel() : 0;
634                pan += lfo->GetLevel() * (lfo->pLfoInfo->pan + f);
635          }          }
636                    
637          if(pan < -100) return -100;          if(pan < -100) return -100;
# Line 242  namespace LinuxSampler { namespace sfz { Line 642  namespace LinuxSampler { namespace sfz {
642            
643            
644      SfzSignalUnitRack::SfzSignalUnitRack(Voice* voice)      SfzSignalUnitRack::SfzSignalUnitRack(Voice* voice)
645          : SignalUnitRack(MaxUnitCount), pVoice(voice), suEndpoint(this), suVolEG(this), suPitchEG(this),          : SignalUnitRack(MaxUnitCount), pVoice(voice), suEndpoint(this), suVolEG(this), suFilEG(this), suPitchEG(this),
646          EGs(maxEgCount), volEGs(maxEgCount), pitchEGs(maxEgCount),          EGs(maxEgCount), volEGs(maxEgCount), pitchEGs(maxEgCount), filEGs(maxEgCount), resEGs(maxEgCount), panEGs(maxEgCount), suVolOnCC(this),
647          suAmpLFO(this), suPitchLFO(this), suFilLFO(this),          suAmpLFO(this), suPitchLFO(this), suFilLFO(this),
648          LFOs(maxLfoCount), filLFOs(maxLfoCount), resLFOs(maxLfoCount), panLFOs(maxLfoCount)          LFOs(maxLfoCount), volLFOs(maxLfoCount), pitchLFOs(maxLfoCount),
649            filLFOs(maxLfoCount), resLFOs(maxLfoCount), panLFOs(maxLfoCount)
650      {      {
651          suEndpoint.pVoice = suVolEG.pVoice = suPitchEG.pVoice = voice;          suEndpoint.pVoice = suEndpoint.suXFInCC.pVoice = suEndpoint.suXFOutCC.pVoice = suEndpoint.suPanOnCC.pVoice = voice;
652          suAmpLFO.pVoice = suPitchLFO.pVoice = suFilLFO.pVoice = voice;          suVolEG.pVoice = suFilEG.pVoice = suPitchEG.pVoice = voice;
653            suAmpLFO.pVoice = suPitchLFO.pVoice = suFilLFO.pVoice = suVolOnCC.pVoice = voice;
654            suPitchLFO.suDepthOnCC.pVoice = suPitchLFO.suFadeEG.pVoice = suPitchLFO.suFreqOnCC.pVoice = voice;
655            suFilLFO.suFadeEG.pVoice = suFilLFO.suDepthOnCC.pVoice = suFilLFO.suFreqOnCC.pVoice = voice;
656            suAmpLFO.suFadeEG.pVoice = suAmpLFO.suDepthOnCC.pVoice = suAmpLFO.suFreqOnCC.pVoice = voice;
657                    
658          for (int i = 0; i < EGs.capacity(); i++) {          for (int i = 0; i < EGs.capacity(); i++) {
659              EGs[i] = new EGv2Unit(this);              EGs[i] = new EGv2Unit(this);
660              EGs[i]->pVoice = voice;              EGs[i]->pVoice = voice;
661                EGs[i]->suAmpOnCC.pVoice = voice;
662                EGs[i]->suVolOnCC.pVoice = voice;
663                EGs[i]->suPitchOnCC.pVoice = voice;
664                EGs[i]->suCutoffOnCC.pVoice = voice;
665                EGs[i]->suResOnCC.pVoice = voice;
666                EGs[i]->suPanOnCC.pVoice = voice;
667          }          }
668                    
669          for (int i = 0; i < LFOs.capacity(); i++) {          for (int i = 0; i < LFOs.capacity(); i++) {
670              LFOs[i] = new LFOv2Unit(this);              LFOs[i] = new LFOv2Unit(this);
671              LFOs[i]->pVoice = voice;              LFOs[i]->pVoice = voice;
672                LFOs[i]->suFadeEG.pVoice = voice;
673                LFOs[i]->suVolOnCC.pVoice = voice;
674                LFOs[i]->suPitchOnCC.pVoice = voice;
675                LFOs[i]->suFreqOnCC.pVoice = voice;
676                LFOs[i]->suPanOnCC.pVoice = voice;
677                LFOs[i]->suCutoffOnCC.pVoice = voice;
678                LFOs[i]->suResOnCC.pVoice = voice;
679          }          }
680      }      }
681            
# Line 275  namespace LinuxSampler { namespace sfz { Line 693  namespace LinuxSampler { namespace sfz {
693          EGs.clear();          EGs.clear();
694          volEGs.clear();          volEGs.clear();
695          pitchEGs.clear();          pitchEGs.clear();
696            filEGs.clear();
697            resEGs.clear();
698            panEGs.clear();
699                    
700          LFOs.clear();          LFOs.clear();
701            volLFOs.clear();
702            pitchLFOs.clear();
703          filLFOs.clear();          filLFOs.clear();
704          resLFOs.clear();          resLFOs.clear();
705          panLFOs.clear();          panLFOs.clear();
706                    
707          ::sfz::Region* const pRegion = pVoice->pRegion;          ::sfz::Region* const pRegion = pVoice->pRegion;
708                    
709            suVolOnCC.SetCCs(pRegion->volume_oncc);
710            
711          for (int i = 0; i < pRegion->eg.size(); i++) {          for (int i = 0; i < pRegion->eg.size(); i++) {
712              if (pRegion->eg[i].node.size() == 0) continue;              if (pRegion->eg[i].node.size() == 0) continue;
713                            
# Line 290  namespace LinuxSampler { namespace sfz { Line 715  namespace LinuxSampler { namespace sfz {
715                  EGv2Unit eg(this);                  EGv2Unit eg(this);
716                  eg.pEGInfo = &(pRegion->eg[i]);                  eg.pEGInfo = &(pRegion->eg[i]);
717                  EGs.increment()->Copy(eg);                  EGs.increment()->Copy(eg);
718                    EGs[EGs.size() - 1]->suAmpOnCC.SetCCs(pRegion->eg[i].amplitude_oncc);
719                    EGs[EGs.size() - 1]->suVolOnCC.SetCCs(pRegion->eg[i].volume_oncc);
720                    EGs[EGs.size() - 1]->suPitchOnCC.SetCCs(pRegion->eg[i].pitch_oncc);
721                    EGs[EGs.size() - 1]->suCutoffOnCC.SetCCs(pRegion->eg[i].cutoff_oncc);
722                    EGs[EGs.size() - 1]->suResOnCC.SetCCs(pRegion->eg[i].resonance_oncc);
723                    EGs[EGs.size() - 1]->suPanOnCC.SetCCs(pRegion->eg[i].pan_oncc);
724              } else { std::cerr << "Maximum number of EGs reached!" << std::endl; break; }              } else { std::cerr << "Maximum number of EGs reached!" << std::endl; break; }
725                            
726              if (pRegion->eg[i].amplitude > 0) {              if ( pRegion->eg[i].amplitude > 0 || !pRegion->eg[i].amplitude_oncc.empty() ||
727                     pRegion->eg[i].volume > -145 || !pRegion->eg[i].volume_oncc.empty()
728                ) {
729                  if(volEGs.size() < volEGs.capacity()) volEGs.add(EGs[EGs.size() - 1]);                  if(volEGs.size() < volEGs.capacity()) volEGs.add(EGs[EGs.size() - 1]);
730                  else std::cerr << "Maximum number of EGs reached!" << std::endl;                  else std::cerr << "Maximum number of EGs reached!" << std::endl;
731              }              }
732                
733                if (pRegion->eg[i].cutoff != 0 || !pRegion->eg[i].cutoff_oncc.empty()) {
734                    if(filEGs.size() < filEGs.capacity()) filEGs.add(EGs[EGs.size() - 1]);
735                    else std::cerr << "Maximum number of EGs reached!" << std::endl;
736                }
737                
738                if (pRegion->eg[i].resonance != 0 || !pRegion->eg[i].resonance_oncc.empty()) {
739                    if(resEGs.size() < resEGs.capacity()) resEGs.add(EGs[EGs.size() - 1]);
740                    else std::cerr << "Maximum number of EGs reached!" << std::endl;
741                }
742                
743                if (pRegion->eg[i].pitch != 0 || !pRegion->eg[i].pitch_oncc.empty()) {
744                    if(pitchEGs.size() < pitchEGs.capacity()) pitchEGs.add(EGs[EGs.size() - 1]);
745                    else std::cerr << "Maximum number of EGs reached!" << std::endl;
746                }
747                
748                if (pRegion->eg[i].pan != 0 || !pRegion->eg[i].pan_oncc.empty()) {
749                    if(panEGs.size() < panEGs.capacity()) panEGs.add(EGs[EGs.size() - 1]);
750                    else std::cerr << "Maximum number of EGs reached!" << std::endl;
751                }
752          }          }
753                    
754          if (pRegion->ampeg_sustain == -1) {          if (pRegion->ampeg_sustain == -1) {
# Line 311  namespace LinuxSampler { namespace sfz { Line 764  namespace LinuxSampler { namespace sfz {
764                  LFOv2Unit lfo(this);                  LFOv2Unit lfo(this);
765                  lfo.pLfoInfo = &(pRegion->lfos[i]);                  lfo.pLfoInfo = &(pRegion->lfos[i]);
766                  LFOs.increment()->Copy(lfo);                  LFOs.increment()->Copy(lfo);
767                    LFOs[LFOs.size() - 1]->suVolOnCC.SetCCs(pRegion->lfos[i].volume_oncc);
768                    LFOs[LFOs.size() - 1]->suPitchOnCC.SetCCs(pRegion->lfos[i].pitch_oncc);
769                    LFOs[LFOs.size() - 1]->suFreqOnCC.SetCCs(pRegion->lfos[i].freq_oncc);
770                    LFOs[LFOs.size() - 1]->suPanOnCC.SetCCs(pRegion->lfos[i].pan_oncc);
771                    LFOs[LFOs.size() - 1]->suCutoffOnCC.SetCCs(pRegion->lfos[i].cutoff_oncc);
772                    LFOs[LFOs.size() - 1]->suResOnCC.SetCCs(pRegion->lfos[i].resonance_oncc);
773              } else { std::cerr << "Maximum number of LFOs reached!" << std::endl; break; }              } else { std::cerr << "Maximum number of LFOs reached!" << std::endl; break; }
774                            
775              if (pRegion->lfos[i].cutoff != 0) {              if (pRegion->lfos[i].volume != 0 || !pRegion->lfos[i].volume_oncc.empty()) {
776                    if(volLFOs.size() < volLFOs.capacity()) volLFOs.add(LFOs[LFOs.size() - 1]);
777                    else std::cerr << "Maximum number of LFOs reached!" << std::endl;
778                }
779                
780                if (pRegion->lfos[i].pitch != 0 || !pRegion->lfos[i].pitch_oncc.empty()) {
781                    if(pitchLFOs.size() < pitchLFOs.capacity()) pitchLFOs.add(LFOs[LFOs.size() - 1]);
782                    else std::cerr << "Maximum number of LFOs reached!" << std::endl;
783                }
784                
785                if (pRegion->lfos[i].cutoff != 0 || !pRegion->lfos[i].cutoff_oncc.empty()) {
786                  if(filLFOs.size() < filLFOs.capacity()) filLFOs.add(LFOs[LFOs.size() - 1]);                  if(filLFOs.size() < filLFOs.capacity()) filLFOs.add(LFOs[LFOs.size() - 1]);
787                  else std::cerr << "Maximum number of LFOs reached!" << std::endl;                  else std::cerr << "Maximum number of LFOs reached!" << std::endl;
788              }              }
789                            
790              if (pRegion->lfos[i].resonance != 0) {              if (pRegion->lfos[i].resonance != 0 || !pRegion->lfos[i].resonance_oncc.empty()) {
791                  if(resLFOs.size() < resLFOs.capacity()) resLFOs.add(LFOs[LFOs.size() - 1]);                  if(resLFOs.size() < resLFOs.capacity()) resLFOs.add(LFOs[LFOs.size() - 1]);
792                  else std::cerr << "Maximum number of LFOs reached!" << std::endl;                  else std::cerr << "Maximum number of LFOs reached!" << std::endl;
793              }              }
794                            
795              if (pRegion->lfos[i].pan != 0) {              if (pRegion->lfos[i].pan != 0 || !pRegion->lfos[i].pan_oncc.empty()) {
796                  if(panLFOs.size() < panLFOs.capacity()) panLFOs.add(LFOs[LFOs.size() - 1]);                  if(panLFOs.size() < panLFOs.capacity()) panLFOs.add(LFOs[LFOs.size() - 1]);
797                  else std::cerr << "Maximum number of LFOs reached!" << std::endl;                  else std::cerr << "Maximum number of LFOs reached!" << std::endl;
798              }              }
799          }          }
800                    
801            suPitchLFO.suDepthOnCC.SetCCs(pRegion->pitchlfo_depthcc);
802            suPitchLFO.suFreqOnCC.SetCCs(pRegion->pitchlfo_freqcc);
803            
804            suFilLFO.suDepthOnCC.SetCCs(pRegion->fillfo_depthcc);
805            suFilLFO.suFreqOnCC.SetCCs(pRegion->fillfo_freqcc);
806            
807            suAmpLFO.suDepthOnCC.SetCCs(pRegion->amplfo_depthcc);
808            suAmpLFO.suFreqOnCC.SetCCs(pRegion->amplfo_freqcc);
809            
810          Units.clear();          Units.clear();
811                    
812            Units.add(&suVolOnCC);
813            
814          Units.add(&suVolEG);          Units.add(&suVolEG);
815            Units.add(&suFilEG);
816          Units.add(&suPitchEG);          Units.add(&suPitchEG);
817            
818            Units.add(&suPitchLFO.suFreqOnCC); // Don't change order! (should be triggered before the LFO)
819          Units.add(&suPitchLFO);          Units.add(&suPitchLFO);
820            Units.add(&suPitchLFO.suDepthOnCC);
821            Units.add(&suPitchLFO.suFadeEG);
822            
823            Units.add(&suAmpLFO.suFreqOnCC); // Don't change order! (should be triggered before the LFO)
824            Units.add(&suAmpLFO.suDepthOnCC);
825          Units.add(&suAmpLFO);          Units.add(&suAmpLFO);
826            Units.add(&suAmpLFO.suFadeEG);
827            
828            Units.add(&suFilLFO.suFreqOnCC); // Don't change order! (should be triggered before the LFO)
829            Units.add(&suFilLFO.suDepthOnCC);
830          Units.add(&suFilLFO);          Units.add(&suFilLFO);
831            Units.add(&suFilLFO.suFadeEG);
832                    
833          for (int i = 0; i < EGs.size(); i++) {          for (int i = 0; i < EGs.size(); i++) {
834              Units.add(EGs[i]);              Units.add(EGs[i]);
835                Units.add(&(EGs[i]->suAmpOnCC));
836                Units.add(&(EGs[i]->suVolOnCC));
837                Units.add(&(EGs[i]->suPitchOnCC));
838                Units.add(&(EGs[i]->suCutoffOnCC));
839                Units.add(&(EGs[i]->suResOnCC));
840                Units.add(&(EGs[i]->suPanOnCC));
841          }          }
842                    
843          for (int i = 0; i < LFOs.size(); i++) {          for (int i = 0; i < LFOs.size(); i++) {
844                Units.add(&(LFOs[i]->suFreqOnCC)); // Don't change order! (should be triggered before the LFO)
845              Units.add(LFOs[i]);              Units.add(LFOs[i]);
846                Units.add(&(LFOs[i]->suFadeEG));
847                Units.add(&(LFOs[i]->suVolOnCC));
848                Units.add(&(LFOs[i]->suPitchOnCC));
849                Units.add(&(LFOs[i]->suPanOnCC));
850                Units.add(&(LFOs[i]->suCutoffOnCC));
851                Units.add(&(LFOs[i]->suResOnCC));
852          }          }
853                    
854          Units.add(&suEndpoint);          Units.add(&suEndpoint);
855            Units.add(&suEndpoint.suXFInCC);
856            Units.add(&suEndpoint.suXFOutCC);
857            Units.add(&suEndpoint.suPanOnCC);
858                    
859          SignalUnitRack::Trigger();          SignalUnitRack::Trigger();
860      }      }

Legend:
Removed from v.2221  
changed lines
  Added in v.2237

  ViewVC Help
Powered by ViewVC