/[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 225 by schoenebeck, Sun Aug 22 14:46:47 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 107  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 119  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;
# Line 181  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 513  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->GlobalVolume);          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 593  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 658  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 697  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

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

  ViewVC Help
Powered by ViewVC