/[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 239 by schoenebeck, Sun Sep 12 14:48:19 2004 UTC
# Line 27  Line 27 
27    
28  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
29    
30      // FIXME: no support for layers (nor crossfades) yet      // TODO: no support for crossfades yet
31    
32      const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff());      const float Voice::FILTER_CUTOFF_COEFF(CalculateFilterCutoffCoeff());
33    
34        const int Voice::FILTER_UPDATE_MASK(CalculateFilterUpdateMask());
35    
36      float Voice::CalculateFilterCutoffCoeff() {      float Voice::CalculateFilterCutoffCoeff() {
37          return log(FILTER_CUTOFF_MIN / FILTER_CUTOFF_MAX);          return log(FILTER_CUTOFF_MIN / FILTER_CUTOFF_MAX);
38      }      }
39    
40        int Voice::CalculateFilterUpdateMask() {
41            if (FILTER_UPDATE_PERIOD <= 0) return 0;
42            int power_of_two;
43            for (power_of_two = 0; 1<<power_of_two < FILTER_UPDATE_PERIOD; power_of_two++);
44            return (1 << power_of_two) - 1;
45        }
46    
47      Voice::Voice() {      Voice::Voice() {
48          pEngine     = NULL;          pEngine     = NULL;
49          pDiskThread = NULL;          pDiskThread = NULL;
# Line 48  namespace LinuxSampler { namespace gig { Line 57  namespace LinuxSampler { namespace gig {
57          pLFO1  = NULL;          pLFO1  = NULL;
58          pLFO2  = NULL;          pLFO2  = NULL;
59          pLFO3  = NULL;          pLFO3  = NULL;
60            KeyGroup = 0;
61      }      }
62    
63      Voice::~Voice() {      Voice::~Voice() {
# Line 62  namespace LinuxSampler { namespace gig { Line 72  namespace LinuxSampler { namespace gig {
72          if (pVCOManipulator)  delete pVCOManipulator;          if (pVCOManipulator)  delete pVCOManipulator;
73      }      }
74    
     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();  
     }  
   
75      void Voice::SetEngine(Engine* pEngine) {      void Voice::SetEngine(Engine* pEngine) {
76          this->pEngine = pEngine;          this->pEngine = pEngine;
77    
# Line 95  namespace LinuxSampler { namespace gig { Line 98  namespace LinuxSampler { namespace gig {
98          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.
99    
100          this->pDiskThread = pEngine->pDiskThread;          this->pDiskThread = pEngine->pDiskThread;
101          dmsg(1,("Voice::SetEngine()\n"));          dmsg(6,("Voice::SetEngine()\n"));
102      }      }
103    
104      /**      /**
# Line 105  namespace LinuxSampler { namespace gig { Line 108  namespace LinuxSampler { namespace gig {
108       *  @param pNoteOnEvent - event that caused triggering of this voice       *  @param pNoteOnEvent - event that caused triggering of this voice
109       *  @param PitchBend    - MIDI detune factor (-8192 ... +8191)       *  @param PitchBend    - MIDI detune factor (-8192 ... +8191)
110       *  @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
111         *  @param iLayer       - layer number this voice refers to (only if this is a layered sound of course)
112       *  @returns            0 on success, a value < 0 if something failed       *  @returns            0 on success, a value < 0 if something failed
113       */       */
114      int Voice::Trigger(Event* pNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument) {      int Voice::Trigger(Event* pNoteOnEvent, int PitchBend, ::gig::Instrument* pInstrument, int iLayer) {
115          if (!pInstrument) {          if (!pInstrument) {
116             dmsg(1,("voice::trigger: !pInstrument\n"));             dmsg(1,("voice::trigger: !pInstrument\n"));
117             exit(EXIT_FAILURE);             exit(EXIT_FAILURE);
# Line 117  namespace LinuxSampler { namespace gig { Line 121  namespace LinuxSampler { namespace gig {
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);
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                        DimValues[i] = 0; //TODO: we currently ignore this dimension
159                        break;
160                    case ::gig::dimension_keyboard:
161                        DimValues[i] = (uint) pNoteOnEvent->Key;
162                        break;
163                    case ::gig::dimension_modwheel:
164                        DimValues[i] = pEngine->ControllerTable[1];
165                        break;
166                    case ::gig::dimension_breath:
167                        DimValues[i] = pEngine->ControllerTable[2];
168                        break;
169                    case ::gig::dimension_foot:
170                        DimValues[i] = pEngine->ControllerTable[4];
171                        break;
172                    case ::gig::dimension_portamentotime:
173                        DimValues[i] = pEngine->ControllerTable[5];
174                        break;
175                    case ::gig::dimension_effect1:
176                        DimValues[i] = pEngine->ControllerTable[12];
177                        break;
178                    case ::gig::dimension_effect2:
179                        DimValues[i] = pEngine->ControllerTable[13];
180                        break;
181                    case ::gig::dimension_genpurpose1:
182                        DimValues[i] = pEngine->ControllerTable[16];
183                        break;
184                    case ::gig::dimension_genpurpose2:
185                        DimValues[i] = pEngine->ControllerTable[17];
186                        break;
187                    case ::gig::dimension_genpurpose3:
188                        DimValues[i] = pEngine->ControllerTable[18];
189                        break;
190                    case ::gig::dimension_genpurpose4:
191                        DimValues[i] = pEngine->ControllerTable[19];
192                        break;
193                    case ::gig::dimension_sustainpedal:
194                        DimValues[i] = pEngine->ControllerTable[64];
195                        break;
196                    case ::gig::dimension_portamento:
197                        DimValues[i] = pEngine->ControllerTable[65];
198                        break;
199                    case ::gig::dimension_sostenutopedal:
200                        DimValues[i] = pEngine->ControllerTable[66];
201                        break;
202                    case ::gig::dimension_softpedal:
203                        DimValues[i] = pEngine->ControllerTable[67];
204                        break;
205                    case ::gig::dimension_genpurpose5:
206                        DimValues[i] = pEngine->ControllerTable[80];
207                        break;
208                    case ::gig::dimension_genpurpose6:
209                        DimValues[i] = pEngine->ControllerTable[81];
210                        break;
211                    case ::gig::dimension_genpurpose7:
212                        DimValues[i] = pEngine->ControllerTable[82];
213                        break;
214                    case ::gig::dimension_genpurpose8:
215                        DimValues[i] = pEngine->ControllerTable[83];
216                        break;
217                    case ::gig::dimension_effect1depth:
218                        DimValues[i] = pEngine->ControllerTable[91];
219                        break;
220                    case ::gig::dimension_effect2depth:
221                        DimValues[i] = pEngine->ControllerTable[92];
222                        break;
223                    case ::gig::dimension_effect3depth:
224                        DimValues[i] = pEngine->ControllerTable[93];
225                        break;
226                    case ::gig::dimension_effect4depth:
227                        DimValues[i] = pEngine->ControllerTable[94];
228                        break;
229                    case ::gig::dimension_effect5depth:
230                        DimValues[i] = pEngine->ControllerTable[95];
231                        break;
232                    case ::gig::dimension_none:
233                        std::cerr << "gig::Voice::Trigger() Error: dimension=none\n" << std::flush;
234                        break;
235                    default:
236                        std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush;
237              }              }
238          }          }
239          if (!pDimRgn) { // if there was no velocity split          pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);
240              pDimRgn = pRegion->GetDimensionRegionByValue(0,0,0,0,0);  
241            // get starting crossfade volume level
242            switch (pDimRgn->AttenuationController.type) {
243                case ::gig::attenuation_ctrl_t::type_channelaftertouch:
244                    CrossfadeVolume = 1.0f; //TODO: aftertouch not supported yet
245                    break;
246                case ::gig::attenuation_ctrl_t::type_velocity:
247                    CrossfadeVolume = CrossfadeAttenuation(pNoteOnEvent->Velocity);
248                    break;
249                case ::gig::attenuation_ctrl_t::type_controlchange: //FIXME: currently not sample accurate
250                    CrossfadeVolume = CrossfadeAttenuation(pEngine->ControllerTable[pDimRgn->AttenuationController.controller_number]);
251                    break;
252                case ::gig::attenuation_ctrl_t::type_none: // no crossfade defined
253                default:
254                    CrossfadeVolume = 1.0f;
255          }          }
256    
257          pSample = pDimRgn->pSample; // sample won't change until the voice is finished          pSample = pDimRgn->pSample; // sample won't change until the voice is finished
258    
259            Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
260    
261          // 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
262          long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;          long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
263          DiskVoice          = cachedsamples < pSample->SamplesTotal;          DiskVoice          = cachedsamples < pSample->SamplesTotal;
264    
265          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
266              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)
267    
268              // 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
269              if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {              if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
# Line 159  namespace LinuxSampler { namespace gig { Line 274  namespace LinuxSampler { namespace gig {
274    
275              if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {              if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {
276                  dmsg(1,("Disk stream order failed!\n"));                  dmsg(1,("Disk stream order failed!\n"));
277                  Kill();                  KillImmediately();
278                  return -1;                  return -1;
279              }              }
280              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 294  namespace LinuxSampler { namespace gig {
294          {          {
295              double pitchbasecents = pDimRgn->FineTune * 10;              double pitchbasecents = pDimRgn->FineTune * 10;
296              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;
297              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents);              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate()));
298              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
299          }          }
300    
# Line 305  namespace LinuxSampler { namespace gig { Line 420  namespace LinuxSampler { namespace gig {
420                            pDimRgn->LFO1ControlDepth,                            pDimRgn->LFO1ControlDepth,
421                            pEngine->ControllerTable[pLFO1->ExtController],                            pEngine->ControllerTable[pLFO1->ExtController],
422                            pDimRgn->LFO1FlipPhase,                            pDimRgn->LFO1FlipPhase,
423                            this->SampleRate,                            pEngine->SampleRate,
424                            Delay);                            Delay);
425          }          }
426    
# Line 343  namespace LinuxSampler { namespace gig { Line 458  namespace LinuxSampler { namespace gig {
458                            pDimRgn->LFO2ControlDepth,                            pDimRgn->LFO2ControlDepth,
459                            pEngine->ControllerTable[pLFO2->ExtController],                            pEngine->ControllerTable[pLFO2->ExtController],
460                            pDimRgn->LFO2FlipPhase,                            pDimRgn->LFO2FlipPhase,
461                              pEngine->SampleRate,
462                            Delay);                            Delay);
463          }          }
464      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
# Line 380  namespace LinuxSampler { namespace gig { Line 496  namespace LinuxSampler { namespace gig {
496                            pDimRgn->LFO3ControlDepth,                            pDimRgn->LFO3ControlDepth,
497                            pEngine->ControllerTable[pLFO3->ExtController],                            pEngine->ControllerTable[pLFO3->ExtController],
498                            false,                            false,
499                            this->SampleRate,                            pEngine->SampleRate,
500                            Delay);                            Delay);
501          }          }
502    
# Line 478  namespace LinuxSampler { namespace gig { Line 594  namespace LinuxSampler { namespace gig {
594              VCFCutoffCtrl.fvalue    = cutoff - FILTER_CUTOFF_MIN;              VCFCutoffCtrl.fvalue    = cutoff - FILTER_CUTOFF_MIN;
595              VCFResonanceCtrl.fvalue = resonance;              VCFResonanceCtrl.fvalue = resonance;
596    
597              FilterLeft.SetParameters(cutoff,  resonance, SampleRate);              FilterLeft.SetParameters(cutoff,  resonance, pEngine->SampleRate);
598              FilterRight.SetParameters(cutoff, resonance, SampleRate);              FilterRight.SetParameters(cutoff, resonance, pEngine->SampleRate);
599    
600              FilterUpdateCounter = -1;              FilterUpdateCounter = -1;
601          }          }
# Line 489  namespace LinuxSampler { namespace gig { Line 605  namespace LinuxSampler { namespace gig {
605          }          }
606      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
607    
         // ************************************************  
         // TODO: ARTICULATION DATA HANDLING IS MISSING HERE  
         // ************************************************  
   
608          return 0; // success          return 0; // success
609      }      }
610    
# Line 510  namespace LinuxSampler { namespace gig { Line 622  namespace LinuxSampler { namespace gig {
622      void Voice::Render(uint Samples) {      void Voice::Render(uint Samples) {
623    
624          // Reset the synthesis parameter matrix          // Reset the synthesis parameter matrix
625          pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume);          pEngine->ResetSynthesisParameters(Event::destination_vca, this->Volume * this->CrossfadeVolume * pEngine->GlobalVolume);
626          pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);          pEngine->ResetSynthesisParameters(Event::destination_vco, this->PitchBase);
627      #if ENABLE_FILTER      #if ENABLE_FILTER
628          pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);          pEngine->ResetSynthesisParameters(Event::destination_vcfc, VCFCutoffCtrl.fvalue);
# Line 523  namespace LinuxSampler { namespace gig { Line 635  namespace LinuxSampler { namespace gig {
635    
636    
637          // 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
638          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);
639      #if ENABLE_FILTER      #if ENABLE_FILTER
640          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);
641      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
# Line 535  namespace LinuxSampler { namespace gig { Line 647  namespace LinuxSampler { namespace gig {
647          pLFO3->Process(Samples);          pLFO3->Process(Samples);
648    
649    
650        #if ENABLE_FILTER
651            CalculateBiquadParameters(Samples); // calculate the final biquad filter parameters
652        #endif // ENABLE_FILTER
653    
654    
655          switch (this->PlaybackState) {          switch (this->PlaybackState) {
656    
657              case playback_state_ram: {              case playback_state_ram: {
# Line 559  namespace LinuxSampler { namespace gig { Line 676  namespace LinuxSampler { namespace gig {
676                          DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);                          DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
677                          if (!DiskStreamRef.pStream) {                          if (!DiskStreamRef.pStream) {
678                              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;
679                              Kill();                              KillImmediately();
680                              return;                              return;
681                          }                          }
682                          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 684  namespace LinuxSampler { namespace gig {
684                      }                      }
685    
686                      // 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)
687                      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) {
688                          DiskStreamRef.pStream->WriteSilence((MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);                          DiskStreamRef.pStream->WriteSilence((pEngine->MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);
689                          this->PlaybackState = playback_state_end;                          this->PlaybackState = playback_state_end;
690                      }                      }
691    
# Line 580  namespace LinuxSampler { namespace gig { Line 697  namespace LinuxSampler { namespace gig {
697                  break;                  break;
698    
699              case playback_state_end:              case playback_state_end:
700                  Kill(); // free voice                  KillImmediately(); // free voice
701                  break;                  break;
702          }          }
703    
704    
     #if ENABLE_FILTER  
705          // 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)
706            pEngine->pSynthesisEvents[Event::destination_vca]->clear();
707        #if ENABLE_FILTER
708          pEngine->pSynthesisEvents[Event::destination_vcfc]->clear();          pEngine->pSynthesisEvents[Event::destination_vcfc]->clear();
709          pEngine->pSynthesisEvents[Event::destination_vcfr]->clear();          pEngine->pSynthesisEvents[Event::destination_vcfr]->clear();
710      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
# Line 650  namespace LinuxSampler { namespace gig { Line 768  namespace LinuxSampler { namespace gig {
768                  if (pCCEvent->Controller == pLFO3->ExtController) {                  if (pCCEvent->Controller == pLFO3->ExtController) {
769                      pLFO3->SendEvent(pCCEvent);                      pLFO3->SendEvent(pCCEvent);
770                  }                  }
771                    if (pDimRgn->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange &&
772                        pCCEvent->Controller == pDimRgn->AttenuationController.controller_number) { // if crossfade event
773                        pEngine->pSynthesisEvents[Event::destination_vca]->alloc_assign(*pCCEvent);
774                    }
775              }              }
776    
777              pCCEvent = pEngine->pCCEvents->next();              pCCEvent = pEngine->pCCEvents->next();
# Line 689  namespace LinuxSampler { namespace gig { Line 811  namespace LinuxSampler { namespace gig {
811              if (pVCOEventList->last()) this->PitchBend = pitch;              if (pVCOEventList->last()) this->PitchBend = pitch;
812          }          }
813    
814            // process volume / attenuation events (TODO: we only handle and _expect_ crossfade events here ATM !)
815            {
816                RTEList<Event>* pVCAEventList = pEngine->pSynthesisEvents[Event::destination_vca];
817                Event* pVCAEvent = pVCAEventList->first();
818                if (Delay) { // skip events that happened before this voice was triggered
819                    while (pVCAEvent && pVCAEvent->FragmentPos() <= Delay) pVCAEvent = pVCAEventList->next();
820                }
821                float crossfadevolume;
822                while (pVCAEvent) {
823                    Event* pNextVCAEvent = pVCAEventList->next();
824    
825                    // calculate the influence length of this event (in sample points)
826                    uint end = (pNextVCAEvent) ? pNextVCAEvent->FragmentPos() : Samples;
827    
828                    crossfadevolume = CrossfadeAttenuation(pVCAEvent->Value);
829    
830                    float effective_volume = crossfadevolume * this->Volume * pEngine->GlobalVolume;
831    
832                    // apply volume value to the volume parameter sequence
833                    for (uint i = pVCAEvent->FragmentPos(); i < end; i++) {
834                        pEngine->pSynthesisParameters[Event::destination_vca][i] = effective_volume;
835                    }
836    
837                    pVCAEvent = pNextVCAEvent;
838                }
839                if (pVCAEventList->last()) this->CrossfadeVolume = crossfadevolume;
840            }
841    
842      #if ENABLE_FILTER      #if ENABLE_FILTER
843          // process filter cutoff events          // process filter cutoff events
# Line 748  namespace LinuxSampler { namespace gig { Line 897  namespace LinuxSampler { namespace gig {
897      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
898      }      }
899    
900        #if ENABLE_FILTER
901        /**
902         * Calculate all necessary, final biquad filter parameters.
903         *
904         * @param Samples - number of samples to be rendered in this audio fragment cycle
905         */
906        void Voice::CalculateBiquadParameters(uint Samples) {
907            if (!FilterLeft.Enabled) return;
908    
909            biquad_param_t bqbase;
910            biquad_param_t bqmain;
911            float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0];
912            float prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][0];
913            FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
914            pEngine->pBasicFilterParameters[0] = bqbase;
915            pEngine->pMainFilterParameters[0]  = bqmain;
916    
917            float* bq;
918            for (int i = 1; i < Samples; i++) {
919                // recalculate biquad parameters if cutoff or resonance differ from previous sample point
920                if (!(i & FILTER_UPDATE_MASK)) if (pEngine->pSynthesisParameters[Event::destination_vcfr][i] != prev_res ||
921                                                   pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff) {
922                    prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i];
923                    prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][i];
924                    FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
925                }
926    
927                //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'
928                bq    = (float*) &pEngine->pBasicFilterParameters[i];
929                bq[0] = bqbase.a1;
930                bq[1] = bqbase.a2;
931                bq[2] = bqbase.b0;
932                bq[3] = bqbase.b1;
933                bq[4] = bqbase.b2;
934    
935                // same as 'pEngine->pMainFilterParameters[i] = bqmain;'
936                bq    = (float*) &pEngine->pMainFilterParameters[i];
937                bq[0] = bqmain.a1;
938                bq[1] = bqmain.a2;
939                bq[2] = bqmain.b0;
940                bq[3] = bqmain.b1;
941                bq[4] = bqmain.b2;
942            }
943        }
944        #endif // ENABLE_FILTER
945    
946      /**      /**
947       *  Interpolates the input audio data (no loop).       *  Interpolates the input audio data (no loop).
948       *       *
# Line 765  namespace LinuxSampler { namespace gig { Line 960  namespace LinuxSampler { namespace gig {
960                  InterpolateOneStep_Stereo(pSrc, i,                  InterpolateOneStep_Stereo(pSrc, i,
961                                            pEngine->pSynthesisParameters[Event::destination_vca][i],                                            pEngine->pSynthesisParameters[Event::destination_vca][i],
962                                            pEngine->pSynthesisParameters[Event::destination_vco][i],                                            pEngine->pSynthesisParameters[Event::destination_vco][i],
963                                            pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                            pEngine->pBasicFilterParameters[i],
964                                            pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                            pEngine->pMainFilterParameters[i]);
965              }              }
966          }          }
967          else { // Mono Sample          else { // Mono Sample
# Line 774  namespace LinuxSampler { namespace gig { Line 969  namespace LinuxSampler { namespace gig {
969                  InterpolateOneStep_Mono(pSrc, i,                  InterpolateOneStep_Mono(pSrc, i,
970                                          pEngine->pSynthesisParameters[Event::destination_vca][i],                                          pEngine->pSynthesisParameters[Event::destination_vca][i],
971                                          pEngine->pSynthesisParameters[Event::destination_vco][i],                                          pEngine->pSynthesisParameters[Event::destination_vco][i],
972                                          pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                          pEngine->pBasicFilterParameters[i],
973                                          pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                          pEngine->pMainFilterParameters[i]);
974              }              }
975          }          }
976      }      }
# Line 799  namespace LinuxSampler { namespace gig { Line 994  namespace LinuxSampler { namespace gig {
994                      InterpolateOneStep_Stereo(pSrc, i,                      InterpolateOneStep_Stereo(pSrc, i,
995                                                pEngine->pSynthesisParameters[Event::destination_vca][i],                                                pEngine->pSynthesisParameters[Event::destination_vca][i],
996                                                pEngine->pSynthesisParameters[Event::destination_vco][i],                                                pEngine->pSynthesisParameters[Event::destination_vco][i],
997                                                pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                                pEngine->pBasicFilterParameters[i],
998                                                pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                                pEngine->pMainFilterParameters[i]);
999                      if (Pos > pSample->LoopEnd) {                      if (Pos > pSample->LoopEnd) {
1000                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
1001                          LoopCyclesLeft--;                          LoopCyclesLeft--;
# Line 811  namespace LinuxSampler { namespace gig { Line 1006  namespace LinuxSampler { namespace gig {
1006                      InterpolateOneStep_Stereo(pSrc, i,                      InterpolateOneStep_Stereo(pSrc, i,
1007                                                pEngine->pSynthesisParameters[Event::destination_vca][i],                                                pEngine->pSynthesisParameters[Event::destination_vca][i],
1008                                                pEngine->pSynthesisParameters[Event::destination_vco][i],                                                pEngine->pSynthesisParameters[Event::destination_vco][i],
1009                                                pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                                pEngine->pBasicFilterParameters[i],
1010                                                pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                                pEngine->pMainFilterParameters[i]);
1011                  }                  }
1012              }              }
1013              else { // render loop (endless loop)              else { // render loop (endless loop)
# Line 820  namespace LinuxSampler { namespace gig { Line 1015  namespace LinuxSampler { namespace gig {
1015                      InterpolateOneStep_Stereo(pSrc, i,                      InterpolateOneStep_Stereo(pSrc, i,
1016                                                pEngine->pSynthesisParameters[Event::destination_vca][i],                                                pEngine->pSynthesisParameters[Event::destination_vca][i],
1017                                                pEngine->pSynthesisParameters[Event::destination_vco][i],                                                pEngine->pSynthesisParameters[Event::destination_vco][i],
1018                                                pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                                pEngine->pBasicFilterParameters[i],
1019                                                pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                                pEngine->pMainFilterParameters[i]);
1020                      if (Pos > pSample->LoopEnd) {                      if (Pos > pSample->LoopEnd) {
1021                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
1022                      }                      }
# Line 835  namespace LinuxSampler { namespace gig { Line 1030  namespace LinuxSampler { namespace gig {
1030                      InterpolateOneStep_Mono(pSrc, i,                      InterpolateOneStep_Mono(pSrc, i,
1031                                              pEngine->pSynthesisParameters[Event::destination_vca][i],                                              pEngine->pSynthesisParameters[Event::destination_vca][i],
1032                                              pEngine->pSynthesisParameters[Event::destination_vco][i],                                              pEngine->pSynthesisParameters[Event::destination_vco][i],
1033                                              pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                              pEngine->pBasicFilterParameters[i],
1034                                              pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                              pEngine->pMainFilterParameters[i]);
1035                      if (Pos > pSample->LoopEnd) {                      if (Pos > pSample->LoopEnd) {
1036                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
1037                          LoopCyclesLeft--;                          LoopCyclesLeft--;
# Line 847  namespace LinuxSampler { namespace gig { Line 1042  namespace LinuxSampler { namespace gig {
1042                      InterpolateOneStep_Mono(pSrc, i,                      InterpolateOneStep_Mono(pSrc, i,
1043                                              pEngine->pSynthesisParameters[Event::destination_vca][i],                                              pEngine->pSynthesisParameters[Event::destination_vca][i],
1044                                              pEngine->pSynthesisParameters[Event::destination_vco][i],                                              pEngine->pSynthesisParameters[Event::destination_vco][i],
1045                                              pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                              pEngine->pBasicFilterParameters[i],
1046                                              pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                              pEngine->pMainFilterParameters[i]);
1047                  }                  }
1048              }              }
1049              else { // render loop (endless loop)              else { // render loop (endless loop)
# Line 856  namespace LinuxSampler { namespace gig { Line 1051  namespace LinuxSampler { namespace gig {
1051                      InterpolateOneStep_Mono(pSrc, i,                      InterpolateOneStep_Mono(pSrc, i,
1052                                              pEngine->pSynthesisParameters[Event::destination_vca][i],                                              pEngine->pSynthesisParameters[Event::destination_vca][i],
1053                                              pEngine->pSynthesisParameters[Event::destination_vco][i],                                              pEngine->pSynthesisParameters[Event::destination_vco][i],
1054                                              pEngine->pSynthesisParameters[Event::destination_vcfc][i],                                              pEngine->pBasicFilterParameters[i],
1055                                              pEngine->pSynthesisParameters[Event::destination_vcfr][i]);                                              pEngine->pMainFilterParameters[i]);
1056                      if (Pos > pSample->LoopEnd) {                      if (Pos > pSample->LoopEnd) {
1057                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;                          Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
1058                      }                      }
# Line 867  namespace LinuxSampler { namespace gig { Line 1062  namespace LinuxSampler { namespace gig {
1062      }      }
1063    
1064      /**      /**
1065       *  Immediately kill the voice.       *  Immediately kill the voice. This method should not be used to kill
1066         *  a normal, active voice, because it doesn't take care of things like
1067         *  fading down the volume level to avoid clicks and regular processing
1068         *  until the kill event actually occured!
1069         *
1070         *  @see Kill()
1071       */       */
1072      void Voice::Kill() {      void Voice::KillImmediately() {
1073          if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {          if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
1074              pDiskThread->OrderDeletionOfStream(&DiskStreamRef);              pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
1075          }          }
1076          Reset();          Reset();
1077      }      }
1078    
1079        /**
1080         *  Kill the voice in regular sense. Let the voice render audio until
1081         *  the kill event actually occured and then fade down the volume level
1082         *  very quickly and let the voice die finally. Unlike a normal release
1083         *  of a voice, a kill process cannot be cancalled and is therefore
1084         *  usually used for voice stealing and key group conflicts.
1085         *
1086         *  @param pKillEvent - event which caused the voice to be killed
1087         */
1088        void Voice::Kill(Event* pKillEvent) {
1089            this->pKillEvent = pKillEvent;
1090        }
1091    
1092  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

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

  ViewVC Help
Powered by ViewVC