/[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 84 by schoenebeck, Sun May 23 20:17:31 2004 UTC revision 236 by schoenebeck, Thu Sep 9 18:44:18 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    
# Line 71  namespace LinuxSampler { namespace gig { Line 71  namespace LinuxSampler { namespace gig {
71          if (pVCOManipulator)  delete pVCOManipulator;          if (pVCOManipulator)  delete pVCOManipulator;
72      }      }
73    
     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();  
     }  
   
74      void Voice::SetEngine(Engine* pEngine) {      void Voice::SetEngine(Engine* pEngine) {
75          this->pEngine = pEngine;          this->pEngine = pEngine;
76    
# Line 114  namespace LinuxSampler { namespace gig { Line 107  namespace LinuxSampler { namespace gig {
107       *  @param pNoteOnEvent - event that caused triggering of this voice       *  @param pNoteOnEvent - event that caused triggering of this voice
108       *  @param PitchBend    - MIDI detune factor (-8192 ... +8191)       *  @param PitchBend    - MIDI detune factor (-8192 ... +8191)
109       *  @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
110         *  @param iLayer       - layer number this voice refers to (only if this is a layered sound of course)
111       *  @returns            0 on success, a value < 0 if something failed       *  @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) {
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);
# Line 126  namespace LinuxSampler { namespace gig { Line 120  namespace LinuxSampler { namespace gig {
120          MIDIKey         = pNoteOnEvent->Key;          MIDIKey         = pNoteOnEvent->Key;
121          pRegion         = pInstrument->GetRegion(MIDIKey);          pRegion         = pInstrument->GetRegion(MIDIKey);
122          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;  
123          Delay           = pNoteOnEvent->FragmentPos();          Delay           = pNoteOnEvent->FragmentPos();
124          pTriggerEvent   = pNoteOnEvent;          pTriggerEvent   = pNoteOnEvent;
125    
126          if (!pRegion) {          if (!pRegion) {
127              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;
128              Kill();              Kill();
129              return -1;              return -1;
130          }          }
131    
132          //TODO: current MIDI controller values are not taken into account yet          // get current dimension values to select the right dimension region
133          ::gig::DimensionRegion* pDimRgn = NULL;          //FIXME: controller values for selecting the dimension region here are currently not sample accurate
134          for (int i = pRegion->Dimensions - 1; i >= 0; i--) { // Check if instrument has a velocity split          uint DimValues[5] = {0,0,0,0,0};
135              if (pRegion->pDimensionDefinitions[i].dimension == ::gig::dimension_velocity) {          for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
136                  uint DimValues[5] = {0,0,0,0,0};              switch (pRegion->pDimensionDefinitions[i].dimension) {
137                    case ::gig::dimension_samplechannel:
138                        DimValues[i] = 0; //TODO: we currently ignore this dimension
139                        break;
140                    case ::gig::dimension_layer:
141                        DimValues[i] = iLayer;
142                        // if this is the 1st layer then spawn further voices for all the other layers
143                        if (iLayer == 0)
144                            for (int iNewLayer = 1; iNewLayer < pRegion->pDimensionDefinitions[i].zones; iNewLayer++)
145                                pEngine->LaunchVoice(pNoteOnEvent, iNewLayer);
146                        break;
147                    case ::gig::dimension_velocity:
148                      DimValues[i] = pNoteOnEvent->Velocity;                      DimValues[i] = pNoteOnEvent->Velocity;
149                  pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);                      break;
150                  break;                  case ::gig::dimension_channelaftertouch:
151                        DimValues[i] = 0; //TODO: we currently ignore this dimension
152                        break;
153                    case ::gig::dimension_releasetrigger:
154                        DimValues[i] = 0; //TODO: we currently ignore this dimension
155                        break;
156                    case ::gig::dimension_keyboard:
157                        DimValues[i] = (uint) pNoteOnEvent->Key;
158                        break;
159                    case ::gig::dimension_modwheel:
160                        DimValues[i] = pEngine->ControllerTable[1];
161                        break;
162                    case ::gig::dimension_breath:
163                        DimValues[i] = pEngine->ControllerTable[2];
164                        break;
165                    case ::gig::dimension_foot:
166                        DimValues[i] = pEngine->ControllerTable[4];
167                        break;
168                    case ::gig::dimension_portamentotime:
169                        DimValues[i] = pEngine->ControllerTable[5];
170                        break;
171                    case ::gig::dimension_effect1:
172                        DimValues[i] = pEngine->ControllerTable[12];
173                        break;
174                    case ::gig::dimension_effect2:
175                        DimValues[i] = pEngine->ControllerTable[13];
176                        break;
177                    case ::gig::dimension_genpurpose1:
178                        DimValues[i] = pEngine->ControllerTable[16];
179                        break;
180                    case ::gig::dimension_genpurpose2:
181                        DimValues[i] = pEngine->ControllerTable[17];
182                        break;
183                    case ::gig::dimension_genpurpose3:
184                        DimValues[i] = pEngine->ControllerTable[18];
185                        break;
186                    case ::gig::dimension_genpurpose4:
187                        DimValues[i] = pEngine->ControllerTable[19];
188                        break;
189                    case ::gig::dimension_sustainpedal:
190                        DimValues[i] = pEngine->ControllerTable[64];
191                        break;
192                    case ::gig::dimension_portamento:
193                        DimValues[i] = pEngine->ControllerTable[65];
194                        break;
195                    case ::gig::dimension_sostenutopedal:
196                        DimValues[i] = pEngine->ControllerTable[66];
197                        break;
198                    case ::gig::dimension_softpedal:
199                        DimValues[i] = pEngine->ControllerTable[67];
200                        break;
201                    case ::gig::dimension_genpurpose5:
202                        DimValues[i] = pEngine->ControllerTable[80];
203                        break;
204                    case ::gig::dimension_genpurpose6:
205                        DimValues[i] = pEngine->ControllerTable[81];
206                        break;
207                    case ::gig::dimension_genpurpose7:
208                        DimValues[i] = pEngine->ControllerTable[82];
209                        break;
210                    case ::gig::dimension_genpurpose8:
211                        DimValues[i] = pEngine->ControllerTable[83];
212                        break;
213                    case ::gig::dimension_effect1depth:
214                        DimValues[i] = pEngine->ControllerTable[91];
215                        break;
216                    case ::gig::dimension_effect2depth:
217                        DimValues[i] = pEngine->ControllerTable[92];
218                        break;
219                    case ::gig::dimension_effect3depth:
220                        DimValues[i] = pEngine->ControllerTable[93];
221                        break;
222                    case ::gig::dimension_effect4depth:
223                        DimValues[i] = pEngine->ControllerTable[94];
224                        break;
225                    case ::gig::dimension_effect5depth:
226                        DimValues[i] = pEngine->ControllerTable[95];
227                        break;
228                    case ::gig::dimension_none:
229                        std::cerr << "gig::Voice::Trigger() Error: dimension=none\n" << std::flush;
230                        break;
231                    default:
232                        std::cerr << "gig::Voice::Trigger() Error: Unknown dimension\n" << std::flush;
233              }              }
234          }          }
235          if (!pDimRgn) { // if there was no velocity split          pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);
236              pDimRgn = pRegion->GetDimensionRegionByValue(0,0,0,0,0);  
237            // get starting crossfade volume level
238            switch (pDimRgn->AttenuationController.type) {
239                case ::gig::attenuation_ctrl_t::type_channelaftertouch:
240                    CrossfadeVolume = 1.0f; //TODO: aftertouch not supported yet
241                    break;
242                case ::gig::attenuation_ctrl_t::type_velocity:
243                    CrossfadeVolume = CrossfadeAttenuation(pNoteOnEvent->Velocity);
244                    break;
245                case ::gig::attenuation_ctrl_t::type_controlchange: //FIXME: currently not sample accurate
246                    CrossfadeVolume = CrossfadeAttenuation(pEngine->ControllerTable[pDimRgn->AttenuationController.controller_number]);
247                    break;
248                case ::gig::attenuation_ctrl_t::type_none: // no crossfade defined
249                default:
250                    CrossfadeVolume = 1.0f;
251          }          }
252    
253          pSample = pDimRgn->pSample; // sample won't change until the voice is finished          pSample = pDimRgn->pSample; // sample won't change until the voice is finished
254    
255            Pos = pDimRgn->SampleStartOffset; // offset where we should start playback of sample (0 - 2000 sample points)
256    
257          // 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
258          long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;          long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
259          DiskVoice          = cachedsamples < pSample->SamplesTotal;          DiskVoice          = cachedsamples < pSample->SamplesTotal;
260    
261          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
262              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)
263    
264              // 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
265              if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {              if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
# Line 188  namespace LinuxSampler { namespace gig { Line 290  namespace LinuxSampler { namespace gig {
290          {          {
291              double pitchbasecents = pDimRgn->FineTune * 10;              double pitchbasecents = pDimRgn->FineTune * 10;
292              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;
293              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents);              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->pAudioOutputDevice->SampleRate()));
294              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
295          }          }
296    
# Line 314  namespace LinuxSampler { namespace gig { Line 416  namespace LinuxSampler { namespace gig {
416                            pDimRgn->LFO1ControlDepth,                            pDimRgn->LFO1ControlDepth,
417                            pEngine->ControllerTable[pLFO1->ExtController],                            pEngine->ControllerTable[pLFO1->ExtController],
418                            pDimRgn->LFO1FlipPhase,                            pDimRgn->LFO1FlipPhase,
419                            this->SampleRate,                            pEngine->SampleRate,
420                            Delay);                            Delay);
421          }          }
422    
# Line 352  namespace LinuxSampler { namespace gig { Line 454  namespace LinuxSampler { namespace gig {
454                            pDimRgn->LFO2ControlDepth,                            pDimRgn->LFO2ControlDepth,
455                            pEngine->ControllerTable[pLFO2->ExtController],                            pEngine->ControllerTable[pLFO2->ExtController],
456                            pDimRgn->LFO2FlipPhase,                            pDimRgn->LFO2FlipPhase,
457                            this->SampleRate,                            pEngine->SampleRate,
458                            Delay);                            Delay);
459          }          }
460      #endif // ENABLE_FILTER      #endif // ENABLE_FILTER
# Line 390  namespace LinuxSampler { namespace gig { Line 492  namespace LinuxSampler { namespace gig {
492                            pDimRgn->LFO3ControlDepth,                            pDimRgn->LFO3ControlDepth,
493                            pEngine->ControllerTable[pLFO3->ExtController],                            pEngine->ControllerTable[pLFO3->ExtController],
494                            false,                            false,
495                            this->SampleRate,                            pEngine->SampleRate,
496                            Delay);                            Delay);
497          }          }
498    
# Line 488  namespace LinuxSampler { namespace gig { Line 590  namespace LinuxSampler { namespace gig {
590              VCFCutoffCtrl.fvalue    = cutoff - FILTER_CUTOFF_MIN;              VCFCutoffCtrl.fvalue    = cutoff - FILTER_CUTOFF_MIN;
591              VCFResonanceCtrl.fvalue = resonance;              VCFResonanceCtrl.fvalue = resonance;
592    
593              FilterLeft.SetParameters(cutoff,  resonance, SampleRate);              FilterLeft.SetParameters(cutoff,  resonance, pEngine->SampleRate);
594              FilterRight.SetParameters(cutoff, resonance, SampleRate);              FilterRight.SetParameters(cutoff, resonance, pEngine->SampleRate);
595    
596              FilterUpdateCounter = -1;              FilterUpdateCounter = -1;
597          }          }
# Line 520  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 582  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 600  namespace LinuxSampler { namespace gig { Line 702  namespace LinuxSampler { namespace gig {
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 665  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 704  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 776  namespace LinuxSampler { namespace gig { Line 910  namespace LinuxSampler { namespace gig {
910          biquad_param_t bqmain;          biquad_param_t bqmain;
911          float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0];          float prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][0];
912          float prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][0];          float prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][0];
913          FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, SampleRate);          FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
914          pEngine->pBasicFilterParameters[0] = bqbase;          pEngine->pBasicFilterParameters[0] = bqbase;
915          pEngine->pMainFilterParameters[0]  = bqmain;          pEngine->pMainFilterParameters[0]  = bqmain;
916    
# Line 787  namespace LinuxSampler { namespace gig { Line 921  namespace LinuxSampler { namespace gig {
921                                                 pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff) {                                                 pEngine->pSynthesisParameters[Event::destination_vcfc][i] != prev_cutoff) {
922                  prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i];                  prev_cutoff = pEngine->pSynthesisParameters[Event::destination_vcfc][i];
923                  prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][i];                  prev_res    = pEngine->pSynthesisParameters[Event::destination_vcfr][i];
924                  FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, SampleRate);                  FilterLeft.SetParameters(&bqbase, &bqmain, prev_cutoff, prev_res, pEngine->SampleRate);
925              }              }
926    
927              //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'              //same as 'pEngine->pBasicFilterParameters[i] = bqbase;'

Legend:
Removed from v.84  
changed lines
  Added in v.236

  ViewVC Help
Powered by ViewVC