/[svn]/linuxsampler/trunk/src/engines/gig/Voice.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/gig/Voice.cpp

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

revision 56 by schoenebeck, Tue Apr 27 09:21:58 2004 UTC revision 242 by schoenebeck, Wed Sep 15 13:59:08 2004 UTC
# Line 27  Line 27 
27    
28  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
29    
     // FIXME: no support for layers (nor crossfades) yet  
   
30      const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff());      const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff());
31    
32        const int Voice::FILTER_UPDATE_MASK(CalculateFilterUpdateMask());
33    
34      float Voice::CalculateFilterCutoffCoeff() {      float Voice::CalculateFilterCutoffCoeff() {
35          return log(FILTER_CUTOFF_MIN / FILTER_CUTOFF_MAX);          return log(FILTER_CUTOFF_MIN / FILTER_CUTOFF_MAX);
36      }      }
37    
38        int Voice::CalculateFilterUpdateMask() {
39            if (FILTER_UPDATE_PERIOD <= 0) return 0;
40            int power_of_two;
41            for (power_of_two = 0; 1<<power_of_two < FILTER_UPDATE_PERIOD; power_of_two++);
42            return (1 << power_of_two) - 1;
43        }
44    
45      Voice::Voice() {      Voice::Voice() {
46          pEngine     = NULL;          pEngine     = NULL;
47          pDiskThread = NULL;          pDiskThread = NULL;
# Line 48  namespace LinuxSampler { namespace gig { Line 55  namespace LinuxSampler { namespace gig {
55          pLFO1  = NULL;          pLFO1  = NULL;
56          pLFO2  = NULL;          pLFO2  = NULL;
57          pLFO3  = NULL;          pLFO3  = NULL;
58            KeyGroup = 0;
59      }      }
60    
61      Voice::~Voice() {      Voice::~Voice() {
# Line 62  namespace LinuxSampler { namespace gig { Line 70  namespace LinuxSampler { namespace gig {
70          if (pVCOManipulator)  delete pVCOManipulator;          if (pVCOManipulator)  delete pVCOManipulator;
71      }      }
72    
     void Voice::SetOutput(AudioOutputDevice* pAudioOutputDevice) {  
         this->pOutputLeft        = pAudioOutputDevice->Channel(0)->Buffer();  
         this->pOutputRight       = pAudioOutputDevice->Channel(1)->Buffer();  
         this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();  
         this->SampleRate         = pAudioOutputDevice->SampleRate();  
     }  
   
73      void Voice::SetEngine(Engine* pEngine) {      void Voice::SetEngine(Engine* pEngine) {
74          this->pEngine = pEngine;          this->pEngine = pEngine;
75    
# Line 95  namespace LinuxSampler { namespace gig { Line 96  namespace LinuxSampler { namespace gig {
96          pLFO3  = new LFO<gig::VCOManipulator>(-1200.0f, 1200.0f, LFO<VCOManipulator>::propagation_middle_balanced, pVCOManipulator, pEngine->pEventPool); // +-1 octave (+-1200 cents) max.          pLFO3  = new LFO<gig::VCOManipulator>(-1200.0f, 1200.0f, LFO<VCOManipulator>::propagation_middle_balanced, pVCOManipulator, pEngine->pEventPool); // +-1 octave (+-1200 cents) max.
97    
98          this->pDiskThread = pEngine->pDiskThread;          this->pDiskThread = pEngine->pDiskThread;
99          dmsg(1,("Voice::SetEngine()\n"));          dmsg(6,("Voice::SetEngine()\n"));
100      }      }
101    
102      /**      /**
103       *  Initializes and triggers the voice, a disk stream will be launched if       *  Initializes and triggers the voice, a disk stream will be launched if
104       *  needed.       *  needed.
105       *       *
106       *  @param pNoteOnEvent - event that caused triggering of this voice       *  @param pNoteOnEvent        - event that caused triggering of this voice
107       *  @param PitchBend    - MIDI detune factor (-8192 ... +8191)       *  @param PitchBend           - MIDI detune factor (-8192 ... +8191)
108       *  @param pInstrument  - points to the loaded instrument which provides sample wave(s) and articulation data       *  @param pInstrument         - points to the loaded instrument which provides sample wave(s) and articulation data
109       *  @returns            0 on success, a value < 0 if something failed       *  @param iLayer              - layer number this voice refers to (only if this is a layered sound of course)
110         *  @param ReleaseTriggerVoice - if this new voice is a release trigger voice (optional, default = false)
111         *  @returns 0 on success, a value < 0 if something failed
112       */       */
113      int Voice::Trigger(Event* pNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument) {      int Voice::Trigger(Event* pNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer, bool ReleaseTriggerVoice) {
114          if (!pInstrument) {          if (!pInstrument) {
115             dmsg(1,("voice::trigger: !pInstrument\n"));             dmsg(1,("voice::trigger: !pInstrument\n"));
116             exit(EXIT_FAILURE);             exit(EXIT_FAILURE);
117          }          }
118    
119            Type            = type_normal;
120          Active          = true;          Active          = true;
121          MIDIKey         = pNoteOnEvent->Key;          MIDIKey         = pNoteOnEvent->Key;
122          pRegion         = pInstrument->GetRegion(MIDIKey);          pRegion         = pInstrument->GetRegion(MIDIKey);
123          PlaybackState   = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed          PlaybackState   = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed
         Pos             = 0;  
124          Delay           = pNoteOnEvent->FragmentPos();          Delay           = pNoteOnEvent->FragmentPos();
125          pTriggerEvent   = pNoteOnEvent;          pTriggerEvent   = pNoteOnEvent;
126            pKillEvent      = NULL;
127    
128          if (!pRegion) {          if (!pRegion) {
129              std::cerr << "Audio Thread: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;              std::cerr << "gig::Voice: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;
130              Kill();              KillImmediately();
131              return -1;              return -1;
132          }          }
133    
134          //TODO: current MIDI controller values are not taken into account yet          KeyGroup = pRegion->KeyGroup;
135          ::gig::DimensionRegion* pDimRgn = NULL;  
136          for (int i = pRegion->Dimensions - 1; i >= 0; i--) { // Check if instrument has a velocity split          // get current dimension values to select the right dimension region
137              if (pRegion->pDimensionDefinitions[i].dimension == ::gig::dimension_velocity) {          //FIXME: controller values for selecting the dimension region here are currently not sample accurate
138                  uint DimValues[5] = {0,0,0,0,0};          uint DimValues[5] = {0,0,0,0,0};
139            for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
140                switch (pRegion->pDimensionDefinitions[i].dimension) {
141                    case ::gig::dimension_samplechannel:
142                        DimValues[i] = 0; //TODO: we currently ignore this dimension
143                        break;
144                    case ::gig::dimension_layer:
145                        DimValues[i] = iLayer;
146                        // if this is the 1st layer then spawn further voices for all the other layers
147                        if (iLayer == 0)
148                            for (int iNewLayer = 1; iNewLayer < pRegion->pDimensionDefinitions[i].zones; iNewLayer++)
149                                pEngine->LaunchVoice(pNoteOnEvent, iNewLayer, ReleaseTriggerVoice);
150                        break;
151                    case ::gig::dimension_velocity:
152                      DimValues[i] = pNoteOnEvent->Velocity;                      DimValues[i] = pNoteOnEvent->Velocity;
153                  pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);                      break;
154                  break;                  case ::gig::dimension_channelaftertouch:
155                        DimValues[i] = 0; //TODO: we currently ignore this dimension
156                        break;
157                    case ::gig::dimension_releasetrigger:
158                        Type = (ReleaseTriggerVoice) ? type_release_trigger : (!iLayer) ? type_release_trigger_required : type_normal;
159                        DimValues[i] = (uint) ReleaseTriggerVoice;
160                        break;
161                    case ::gig::dimension_keyboard:
162                        DimValues[i] = (uint) pNoteOnEvent->Key;
163                        break;
164                    case ::gig::dimension_modwheel:
165                        DimValues[i] = pEngine->ControllerTable[1];
166                        break;
167                    case ::gig::dimension_breath:
168                        DimValues[i] = pEngine->ControllerTable[2];
169                        break;
170                    case ::gig::dimension_foot:
171                        DimValues[i] = pEngine->ControllerTable[4];
172                        break;
173                    case ::gig::dimension_portamentotime:
174                        DimValues[i] = pEngine->ControllerTable[5];
175                        break;
176                    case ::gig::dimension_effect1:
177                        DimValues[i] = pEngine->ControllerTable[12];
178                        break;
179                    case ::gig::dimension_effect2:
180                        DimValues[i] = pEngine->ControllerTable[13];
181                        break;
182                    case ::gig::dimension_genpurpose1:
183                        DimValues[i] = pEngine->ControllerTable[16];
184                        break;
185                    case ::gig::dimension_genpurpose2:
186                        DimValues[i] = pEngine->ControllerTable[17];
187                        break;
188                    case ::gig::dimension_genpurpose3:
189                        DimValues[i] = pEngine->ControllerTable[18];
190                        break;
191                    case ::gig::dimension_genpurpose4:
192                        DimValues[i] = pEngine->ControllerTable[19];
193                        break;
194                    case ::gig::dimension_sustainpedal:
195                        DimValues[i] = pEngine->ControllerTable[64];
196                        break;
197                    case ::gig::dimension_portamento:
198                        DimValues[i] = pEngine->ControllerTable[65];
199                        break;
200                    case ::gig::dimension_sostenutopedal:
201                        DimValues[i] = pEngine->ControllerTable[66];
202                        break;
203                    case ::gig::dimension_softpedal:
204                        DimValues[i] = pEngine->ControllerTable[67];
205                        break;
206                    case ::gig::dimension_genpurpose5:
207                        DimValues[i] = pEngine->ControllerTable[80];
208                        break;
209                    case ::gig::dimension_genpurpose6:
210                        DimValues[i] = pEngine->ControllerTable[81];
211                        break;
212                    case ::gig::dimension_genpurpose7:
213                        DimValues[i] = pEngine->ControllerTable[82];
214                        break;
215                    case ::gig::dimension_genpurpose8:
216                        DimValues[i] = pEngine->ControllerTable[83];
217                        break;
218                    case ::gig::dimension_effect1depth:
219                        DimValues[i] = pEngine->ControllerTable[91];
220                        break;
221                    case ::gig::dimension_effect2depth:
222                        DimValues[i] = pEngine->ControllerTable[92];
223                        break;
224                    case ::gig::dimension_effect3depth:
225                        DimValues[i] = pEngine->ControllerTable[93];
226                        break;
227                    case ::gig::dimension_effect4depth:
228                        DimValues[i] = pEngine->ControllerTable[94];
229                        break;
230                    case ::gig::dimension_effect5depth:
231                        DimValues[i] = pEngine->ControllerTable[95];
232                        break;
233                    case ::gig::dimension_none:
234                        std::cerr << "gig::Voice::Trigger() Error: dimension=none\n" << std::flush;
235                        break;
236                    default:
237                        std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush;
238              }              }
239          }          }
240          if (!pDimRgn) { // if there was no velocity split          pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);
241              pDimRgn = pRegion->GetDimensionRegionByValue(0,0,0,0,0);  
242            // get starting crossfade volume level
243            switch (pDimRgn->AttenuationController.type) {
244                case ::gig::attenuation_ctrl_t::type_channelaftertouch:
245                    CrossfadeVolume = 1.0f; //TODO: aftertouch not supported yet
246                    break;
247                case ::gig::attenuation_ctrl_t::type_velocity:
248                    CrossfadeVolume = CrossfadeAttenuation(pNoteOnEvent->Velocity);
249                    break;
250                case ::gig::attenuation_ctrl_t::type_controlchange: //FIXME: currently not sample accurate
251                    CrossfadeVolume = CrossfadeAttenuation(pEngine->ControllerTable[pDimRgn->AttenuationController.controller_number]);
252                    break;
253                case ::gig::attenuation_ctrl_t::type_none: // no crossfade defined
254                default:
255                    CrossfadeVolume = 1.0f;
256          }          }
257    
258          pSample = pDimRgn->pSample; // sample won't change until the voice is finished          pSample = pDimRgn->pSample; // sample won't change until the voice is finished
259    
260            Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
261    
262          // Check if the sample needs disk streaming or is too short for that          // Check if the sample needs disk streaming or is too short for that
263          long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;          long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
264          DiskVoice          = cachedsamples < pSample->SamplesTotal;          DiskVoice          = cachedsamples < pSample->SamplesTotal;
265    
266          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
267              MaxRAMPos = cachedsamples - (MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels; //TODO: this calculation is too pessimistic and may better be moved to Render() method, so it calculates MaxRAMPos dependent to the current demand of sample points to be rendered (e.g. in case of JACK)              MaxRAMPos = cachedsamples - (pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels; //TODO: this calculation is too pessimistic and may better be moved to Render() method, so it calculates MaxRAMPos dependent to the current demand of sample points to be rendered (e.g. in case of JACK)
268    
269              // check if there's a loop defined which completely fits into the cached (RAM) part of the sample              // check if there's a loop defined which completely fits into the cached (RAM) part of the sample
270              if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {              if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
# Line 159  namespace LinuxSampler { namespace gig { Line 275  namespace LinuxSampler { namespace gig {
275    
276              if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {              if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {
277                  dmsg(1,("Disk stream order failed!\n"));                  dmsg(1,("Disk stream order failed!\n"));
278                  Kill();                  KillImmediately();
279                  return -1;                  return -1;
280              }              }
281              dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos, (RAMLoop) ? "yes" : "no"));              dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
# Line 179  namespace LinuxSampler { namespace gig { Line 295  namespace LinuxSampler { namespace gig {
295          {          {
296              double pitchbasecents = pDimRgn->FineTune * 10;              double pitchbasecents = pDimRgn->FineTune * 10;
297              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;
298              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents);              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate()));
299              this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents              this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents
300          }          }
301    
# Line 305  namespace LinuxSampler { namespace gig { Line 421  namespace LinuxSampler { namespace gig {
421                            pDimRgn->LFO1ControlDepth,                            pDimRgn->LFO1ControlDepth,
422                            pEngine->ControllerTable[pLFO1->ExtController],                            pEngine->ControllerTable[pLFO1->ExtController],
423                            pDimRgn->LFO1FlipPhase,                            pDimRgn->LFO1FlipPhase,
424                            this->SampleRate,                            pEngine->SampleRate,
425                            Delay);                            Delay);
426          }          }
427    
# Line 343  namespace LinuxSampler { namespace gig { Line 459  namespace LinuxSampler { namespace gig {
459                            pDimRgn->LFO2ControlDepth,                            pDimRgn->LFO2ControlDepth,
460                            pEngine->ControllerTable[pLFO2->ExtController],                            pEngine->ControllerTable[pLFO2->ExtController],
461                            pDimRgn->LFO2FlipPhase,                            pDimRgn->LFO2FlipPhase,
462                              pEngine->SampleRate,
463                            Delay);                            Delay);
464          }          }
465      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
# Line 380  namespace LinuxSampler { namespace gig { Line 497  namespace LinuxSampler { namespace gig {
497                            pDimRgn->LFO3ControlDepth,                            pDimRgn->LFO3ControlDepth,
498                            pEngine->ControllerTable[pLFO3->ExtController],                            pEngine->ControllerTable[pLFO3->ExtController],
499                            false,                            false,
500                            this->SampleRate,                            pEngine->SampleRate,
501                            Delay);                            Delay);
502          }          }
503    
# Line 478  namespace LinuxSampler { namespace gig { Line 595  namespace LinuxSampler { namespace gig {
595              VCFCutoffCtrl.fvalue    = cutoff - FILTER_CUTOFF_MIN;              VCFCutoffCtrl.fvalue    = cutoff - FILTER_CUTOFF_MIN;
596              VCFResonanceCtrl.fvalue = resonance;              VCFResonanceCtrl.fvalue = resonance;
597    
598              FilterLeft.SetParameters(cutoff,  resonance, SampleRate);              FilterLeft.SetParameters(cutoff,  resonance, pEngine->SampleRate);
599              FilterRight.SetParameters(cutoff, resonance, SampleRate);              FilterRight.SetParameters(cutoff, resonance, pEngine->SampleRate);
600    
601              FilterUpdateCounter = -1;              FilterUpdateCounter = -1;
602          }          }
# Line 489  namespace LinuxSampler { namespace gig { Line 606  namespace LinuxSampler { namespace gig {
606          }          }
607      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
608    
         // ************************************************  
         // TODO: ARTICULATION DATA HANDLING IS MISSING HERE  
         // ************************************************  
   
609          return 0; // success          return 0; // success
610      }      }
611    
# Line 510  namespace LinuxSampler { namespace gig { Line 623  namespace LinuxSampler { namespace gig {
623      void Voice::Render(uint Samples) {      void Voice::Render(uint Samples) {
624    
625          // Reset the synthesis parameter matrix          // Reset the synthesis parameter matrix
626          pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume);          pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngine->GlobalVolume);
627          pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);          pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);
628      #if ENABLE_FILTER      #if ENABLE_FILTER
629          pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);          pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);
# Line 523  namespace LinuxSampler { namespace gig { Line 636  namespace LinuxSampler { namespace gig {
636    
637    
638          // Let all modulators write their parameter changes to the synthesis parameter matrix for the current audio fragment          // Let all modulators write their parameter changes to the synthesis parameter matrix for the current audio fragment
639          pEG1->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);          pEG1->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->PitchBase * this->PitchBend, pKillEvent);
640      #if ENABLE_FILTER      #if ENABLE_FILTER
641          pEG2->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);          pEG2->Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->PitchBase * this->PitchBend);
642      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
# Line 535  namespace LinuxSampler { namespace gig { Line 648  namespace LinuxSampler { namespace gig {
648          pLFO3->Process(Samples);          pLFO3->Process(Samples);
649    
650    
651        #if ENABLE_FILTER
652            CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters
653        #endif // ENABLE_FILTER
654    
655    
656          switch (this->PlaybackState) {          switch (this->PlaybackState) {
657    
658              case playback_state_ram: {              case playback_state_ram: {
# Line 559  namespace LinuxSampler { namespace gig { Line 677  namespace LinuxSampler { namespace gig {
677                          DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);                          DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
678                          if (!DiskStreamRef.pStream) {                          if (!DiskStreamRef.pStream) {
679                              std::cout << stderr << "Disk stream not available in time!" << std::endl << std::flush;                              std::cout << stderr << "Disk stream not available in time!" << std::endl << std::flush;
680                              Kill();                              KillImmediately();
681                              return;                              return;
682                          }                          }
683                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (RTMath::DoubleToInt(Pos) - MaxRAMPos));                          DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (RTMath::DoubleToInt(Pos) - MaxRAMPos));
# Line 567  namespace LinuxSampler { namespace gig { Line 685  namespace LinuxSampler { namespace gig {
685                      }                      }
686    
687                      // add silence sample at the end if we reached the end of the stream (for the interpolator)                      // add silence sample at the end if we reached the end of the stream (for the interpolator)
688                      if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) {                      if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) {
689                          DiskStreamRef.pStream->WriteSilence((MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);                          DiskStreamRef.pStream->WriteSilence((pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);
690                          this->PlaybackState = playback_state_end;                          this->PlaybackState = playback_state_end;
691                      }                      }
692    
# Line 580  namespace LinuxSampler { namespace gig { Line 698  namespace LinuxSampler { namespace gig {
698                  break;                  break;
699    
700              case playback_state_end:              case playback_state_end:
701                  Kill(); // free voice                  KillImmediately(); // free voice
702                  break;                  break;
703          }          }
704    
705    
     #if ENABLE_FILTER  
706          // Reset synthesis event lists (except VCO, as VCO events apply channel wide currently)          // Reset synthesis event lists (except VCO, as VCO events apply channel wide currently)
707            pEngine->pSynthesisEvents[Event::destination_vca]->clear();
708        #if ENABLE_FILTER
709          pEngine->pSynthesisEvents[Event::destination_vcfc]->clear();          pEngine->pSynthesisEvents[Event::destination_vcfc]->clear();
710          pEngine->pSynthesisEvents[Event::destination_vcfr]->clear();          pEngine->pSynthesisEvents[Event::destination_vcfr]->clear();
711      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
# Line 650  namespace LinuxSampler { namespace gig { Line 769  namespace LinuxSampler { namespace gig {
769                  if (pCCEvent->Controller == pLFO3->ExtController) {                  if (pCCEvent->Controller == pLFO3->ExtController) {
770                      pLFO3->SendEvent(pCCEvent);                      pLFO3->SendEvent(pCCEvent);
771                  }                  }
772                    if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange &&
773                        pCCEvent->Controller == pDimRgn->AttenuationController.controller_number) { // if crossfade event
774                        pEngine->pSynthesisEvents[Event::destination_vca]->alloc_assign(*pCCEvent);
775                    }
776              }              }
777    
778              pCCEvent = pEngine->pCCEvents->next();              pCCEvent = pEngine->pCCEvents->next();
# Line 689  namespace LinuxSampler { namespace gig { Line 812  namespace LinuxSampler { namespace gig {
812              if (pVCOEventList->last()) this->PitchBend = pitch;              if (pVCOEventList->last()) this->PitchBend = pitch;
813          }          }
814    
815            // process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !)
816            {
817                RTEList<Event>* pVCAEventList = pEngine->pSynthesisEvents[Event::destination_vca];
818                Event* pVCAEvent = pVCAEventList->first();
819                if (Delay) { // skip events that happened before this voice was triggered
820                    while (pVCAEvent && pVCAEvent->FragmentPos() <= Delay) pVCAEvent = pVCAEventList->next();
821                }
822                float crossfadevolume;
823                while (pVCAEvent) {
824                    Event* pNextVCAEvent = pVCAEventList->next();
825    
826                    // calculate the influence length of this event (in sample points)
827                    uint end = (pNextVCAEvent) ? pNextVCAEvent->FragmentPos() : Samples;
828    
829                    crossfadevolume = CrossfadeAttenuation(pVCAEvent->Value);
830    
831                    float effective_volume = crossfadevolume * this->Volume * pEngine->GlobalVolume;
832    
833                    // apply volume value to the volume parameter sequence
834                    for (uint i = pVCAEvent->FragmentPos(); i < end; i++) {
835                        pEngine->pSynthesisParameters[Event::destination_vca][i] = effective_volume;
836                    }
837    
838                    pVCAEvent = pNextVCAEvent;
839                }
840                if (pVCAEventList->last()) this->CrossfadeVolume = crossfadevolume;
841            }
842    
843      #if ENABLE_FILTER      #if ENABLE_FILTER
844          // process filter cutoff events          // process filter cutoff events
# Line 748  namespace LinuxSampler { namespace gig { Line 898  namespace LinuxSampler { namespace gig {
898      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
899      }      }
900    
901        #if ENABLE_FILTER
902        /**
903         * Calculate all necessary, final biquad filter parameters.
904         *
905         * @param Samples - number of samples to be rendered in this audio fragment cycle
906         */
907        void Voice::CalculateBiquadParameters(uint Samples) {
908            if (!FilterLeft.Enabled) return;
909    
910            biquad_param_t bqbase;
911            biquad_param_t bqmain;
912            float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0];
913            float prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][0];
914            FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
915            pEngine->pBasicFilterParameters[0] = bqbase;
916            pEngine->pMainFilterParameters[0]  = bqmain;
917    
918            float* bq;
919            for (int i = 1; i < Samples; i++) {
920                // recalculate biquad parameters if cutoff or resonance differ from previous sample point
921                if (!(i & FILTER_UPDATE_MASK)) if (pEngine->pSynthesisParameters[Event::destination_vcfr][i] != prev_res ||
922                                                   pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff) {
923                    prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i];
924                    prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][i];
925                    FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
926                }
927    
928                //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'
929                bq    = (float*) &pEngine->pBasicFilterParameters[i];
930                bq[0] = bqbase.a1;
931                bq[1] = bqbase.a2;
932                bq[2] = bqbase.b0;
933                bq[3] = bqbase.b1;
934                bq[4] = bqbase.b2;
935    
936                // same as 'pEngine->pMainFilterParameters[i] = bqmain;'
937                bq    = (float*) &pEngine->pMainFilterParameters[i];
938                bq[0] = bqmain.a1;
939                bq[1] = bqmain.a2;
940                bq[2] = bqmain.b0;
941                bq[3] = bqmain.b1;
942                bq[4] = bqmain.b2;
943            }
944        }
945        #endif // ENABLE_FILTER
946    
947      /**      /**
948       *  Interpolates the input audio data (no loop).       *  Interpolates the input audio data (no loop).
949       *       *
# Line 765  namespace LinuxSampler { namespace gig { Line 961  namespace LinuxSampler { namespace gig {
961                  InterpolateOneStep_Stereo(pSrc, i,                  InterpolateOneStep_Stereo(pSrc, i,
962                                            pEngine->pSynthesisParameters[Event::destination_vca][i],                                            pEngine->pSynthesisParameters[Event::destination_vca][i],
963                                            pEngine->pSynthesisParameters[Event::destination_vco][i],                                            pEngine->pSynthesisParameters[Event::destination_vco][i],
964                                            pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                            pEngine->pBasicFilterParameters[i],
965                                            pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                            pEngine->pMainFilterParameters[i]);
966              }              }
967          }          }
968          else { // Mono Sample          else { // Mono Sample
# Line 774  namespace LinuxSampler { namespace gig { Line 970  namespace LinuxSampler { namespace gig {
970                  InterpolateOneStep_Mono(pSrc, i,                  InterpolateOneStep_Mono(pSrc, i,
971                                          pEngine->pSynthesisParameters[Event::destination_vca][i],                                          pEngine->pSynthesisParameters[Event::destination_vca][i],
972                                          pEngine->pSynthesisParameters[Event::destination_vco][i],                                          pEngine->pSynthesisParameters[Event::destination_vco][i],
973                                          pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                          pEngine->pBasicFilterParameters[i],
974                                          pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                          pEngine->pMainFilterParameters[i]);
975              }              }
976          }          }
977      }      }
# Line 799  namespace LinuxSampler { namespace gig { Line 995  namespace LinuxSampler { namespace gig {
995                      InterpolateOneStep_Stereo(pSrc, i,                      InterpolateOneStep_Stereo(pSrc, i,
996                                                pEngine->pSynthesisParameters[Event::destination_vca][i],                                                pEngine->pSynthesisParameters[Event::destination_vca][i],
997                                                pEngine->pSynthesisParameters[Event::destination_vco][i],                                                pEngine->pSynthesisParameters[Event::destination_vco][i],
998                                                pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                                pEngine->pBasicFilterParameters[i],
999                                                pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                                pEngine->pMainFilterParameters[i]);
1000                      if (Pos > pSample->LoopEnd) {                      if (Pos > pSample->LoopEnd) {
1001                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
1002                          LoopCyclesLeft--;                          LoopCyclesLeft--;
# Line 811  namespace LinuxSampler { namespace gig { Line 1007  namespace LinuxSampler { namespace gig {
1007                      InterpolateOneStep_Stereo(pSrc, i,                      InterpolateOneStep_Stereo(pSrc, i,
1008                                                pEngine->pSynthesisParameters[Event::destination_vca][i],                                                pEngine->pSynthesisParameters[Event::destination_vca][i],
1009                                                pEngine->pSynthesisParameters[Event::destination_vco][i],                                                pEngine->pSynthesisParameters[Event::destination_vco][i],
1010                                                pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                                pEngine->pBasicFilterParameters[i],
1011                                                pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                                pEngine->pMainFilterParameters[i]);
1012                  }                  }
1013              }              }
1014              else { // render loop (endless loop)              else { // render loop (endless loop)
# Line 820  namespace LinuxSampler { namespace gig { Line 1016  namespace LinuxSampler { namespace gig {
1016                      InterpolateOneStep_Stereo(pSrc, i,                      InterpolateOneStep_Stereo(pSrc, i,
1017                                                pEngine->pSynthesisParameters[Event::destination_vca][i],                                                pEngine->pSynthesisParameters[Event::destination_vca][i],
1018                                                pEngine->pSynthesisParameters[Event::destination_vco][i],                                                pEngine->pSynthesisParameters[Event::destination_vco][i],
1019                                                pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                                pEngine->pBasicFilterParameters[i],
1020                                                pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                                pEngine->pMainFilterParameters[i]);
1021                      if (Pos > pSample->LoopEnd) {                      if (Pos > pSample->LoopEnd) {
1022                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
1023                      }                      }
# Line 835  namespace LinuxSampler { namespace gig { Line 1031  namespace LinuxSampler { namespace gig {
1031                      InterpolateOneStep_Mono(pSrc, i,                      InterpolateOneStep_Mono(pSrc, i,
1032                                              pEngine->pSynthesisParameters[Event::destination_vca][i],                                              pEngine->pSynthesisParameters[Event::destination_vca][i],
1033                                              pEngine->pSynthesisParameters[Event::destination_vco][i],                                              pEngine->pSynthesisParameters[Event::destination_vco][i],
1034                                              pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                              pEngine->pBasicFilterParameters[i],
1035                                              pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                              pEngine->pMainFilterParameters[i]);
1036                      if (Pos > pSample->LoopEnd) {                      if (Pos > pSample->LoopEnd) {
1037                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
1038                          LoopCyclesLeft--;                          LoopCyclesLeft--;
# Line 847  namespace LinuxSampler { namespace gig { Line 1043  namespace LinuxSampler { namespace gig {
1043                      InterpolateOneStep_Mono(pSrc, i,                      InterpolateOneStep_Mono(pSrc, i,
1044                                              pEngine->pSynthesisParameters[Event::destination_vca][i],                                              pEngine->pSynthesisParameters[Event::destination_vca][i],
1045                                              pEngine->pSynthesisParameters[Event::destination_vco][i],                                              pEngine->pSynthesisParameters[Event::destination_vco][i],
1046                                              pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                              pEngine->pBasicFilterParameters[i],
1047                                              pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                              pEngine->pMainFilterParameters[i]);
1048                  }                  }
1049              }              }
1050              else { // render loop (endless loop)              else { // render loop (endless loop)
# Line 856  namespace LinuxSampler { namespace gig { Line 1052  namespace LinuxSampler { namespace gig {
1052                      InterpolateOneStep_Mono(pSrc, i,                      InterpolateOneStep_Mono(pSrc, i,
1053                                              pEngine->pSynthesisParameters[Event::destination_vca][i],                                              pEngine->pSynthesisParameters[Event::destination_vca][i],
1054                                              pEngine->pSynthesisParameters[Event::destination_vco][i],                                              pEngine->pSynthesisParameters[Event::destination_vco][i],
1055                                              pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                              pEngine->pBasicFilterParameters[i],
1056                                              pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                              pEngine->pMainFilterParameters[i]);
1057                      if (Pos > pSample->LoopEnd) {                      if (Pos > pSample->LoopEnd) {
1058                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
1059                      }                      }
# Line 867  namespace LinuxSampler { namespace gig { Line 1063  namespace LinuxSampler { namespace gig {
1063      }      }
1064    
1065      /**      /**
1066       *  Immediately kill the voice.       *  Immediately kill the voice. This method should not be used to kill
1067         *  a normal, active voice, because it doesn't take care of things like
1068         *  fading down the volume level to avoid clicks and regular processing
1069         *  until the kill event actually occured!
1070         *
1071         *  @see Kill()
1072       */       */
1073      void Voice::Kill() {      void Voice::KillImmediately() {
1074          if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {          if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
1075              pDiskThread->OrderDeletionOfStream(&DiskStreamRef);              pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
1076          }          }
1077          Reset();          Reset();
1078      }      }
1079    
1080        /**
1081         *  Kill the voice in regular sense. Let the voice render audio until
1082         *  the kill event actually occured and then fade down the volume level
1083         *  very quickly and let the voice die finally. Unlike a normal release
1084         *  of a voice, a kill process cannot be cancalled and is therefore
1085         *  usually used for voice stealing and key group conflicts.
1086         *
1087         *  @param pKillEvent - event which caused the voice to be killed
1088         */
1089        void Voice::Kill(Event* pKillEvent) {
1090            if (pTriggerEvent && pKillEvent->FragmentPos() <= pTriggerEvent->FragmentPos()) return;
1091            this->pKillEvent = pKillEvent;
1092        }
1093    
1094  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.56  
changed lines
  Added in v.242

  ViewVC Help
Powered by ViewVC