/[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 1038 by persson, Sat Feb 3 15:33:00 2007 UTC revision 1895 by persson, Sun May 3 12:15:40 2009 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *
6   *   Copyright (C) 2005, 2006 Christian Schoenebeck                        *   *   Copyright (C) 2005 - 2009 Christian Schoenebeck                       *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 38  namespace LinuxSampler { namespace gig { Line 38  namespace LinuxSampler { namespace gig {
38          pLFO3 = new LFOSigned(1200.0f); // pitch EG (-1200..+1200 range)          pLFO3 = new LFOSigned(1200.0f); // pitch EG (-1200..+1200 range)
39          KeyGroup = 0;          KeyGroup = 0;
40          SynthesisMode = 0; // set all mode bits to 0 first          SynthesisMode = 0; // set all mode bits to 0 first
41          // select synthesis implementation (currently either pure C++ or MMX+SSE(1))          // select synthesis implementation (asm core is not supported ATM)
42          #if CONFIG_ASM && ARCH_X86          #if 0 // CONFIG_ASM && ARCH_X86
43          SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE());          SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, Features::supportsMMX() && Features::supportsSSE());
44          #else          #else
45          SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false);          SYNTHESIS_MODE_SET_IMPLEMENTATION(SynthesisMode, false);
# Line 156  namespace LinuxSampler { namespace gig { Line 156  namespace LinuxSampler { namespace gig {
156          const DLS::sample_loop_t& loopinfo = pDimRgn->pSampleLoops[0];          const DLS::sample_loop_t& loopinfo = pDimRgn->pSampleLoops[0];
157    
158          if (DiskVoice) { // voice to be streamed from disk          if (DiskVoice) { // voice to be streamed from disk
159              MaxRAMPos = cachedsamples - (pEngine->MaxSamplesPerCycle << CONFIG_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)              if (cachedsamples > (pEngine->MaxSamplesPerCycle << CONFIG_MAX_PITCH)) {
160                    MaxRAMPos = cachedsamples - (pEngine->MaxSamplesPerCycle << CONFIG_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)
161                } else {
162                    // The cache is too small to fit a max sample buffer.
163                    // Setting MaxRAMPos to 0 will probably cause a click
164                    // in the audio, but it's better than not handling
165                    // this case at all, which would have caused the
166                    // unsigned MaxRAMPos to be set to a negative number.
167                    MaxRAMPos = 0;
168                }
169    
170              // 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
171              RAMLoop = (pDimRgn->SampleLoops && (loopinfo.LoopStart + loopinfo.LoopLength) <= MaxRAMPos);              RAMLoop = (pDimRgn->SampleLoops && (loopinfo.LoopStart + loopinfo.LoopLength) <= MaxRAMPos);
# Line 183  namespace LinuxSampler { namespace gig { Line 192  namespace LinuxSampler { namespace gig {
192    
193          // calculate initial pitch value          // calculate initial pitch value
194          {          {
195              double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12];              double pitchbasecents = pEngineChannel->pInstrument->FineTune + pDimRgn->FineTune + pEngine->ScaleTuning[MIDIKey % 12];
196              if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;  
197              this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->SampleRate));              // GSt behaviour: maximum transpose up is 40 semitones. If
198              this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents              // MIDI key is more than 40 semitones above unity note,
199                // the transpose is not done.
200                if (pDimRgn->PitchTrack && (MIDIKey - (int) pDimRgn->UnityNote) < 40) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100;
201    
202                this->PitchBase = RTMath::CentsToFreqRatioUnlimited(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->SampleRate));
203                this->PitchBend = RTMath::CentsToFreqRatio(PitchBend / 8192.0 * 100.0 * pEngineChannel->pInstrument->PitchbendRange);
204          }          }
205    
206          // the length of the decay and release curves are dependent on the velocity          // the length of the decay and release curves are dependent on the velocity
# Line 515  namespace LinuxSampler { namespace gig { Line 529  namespace LinuxSampler { namespace gig {
529              finalSynthesisParameters.filterLeft.SetType(pDimRgn->VCFType);              finalSynthesisParameters.filterLeft.SetType(pDimRgn->VCFType);
530              finalSynthesisParameters.filterRight.SetType(pDimRgn->VCFType);              finalSynthesisParameters.filterRight.SetType(pDimRgn->VCFType);
531              #else // override filter type              #else // override filter type
532              FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE);              finalSynthesisParameters.filterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE);
533              FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE);              finalSynthesisParameters.filterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE);
534              #endif // CONFIG_OVERRIDE_FILTER_TYPE              #endif // CONFIG_OVERRIDE_FILTER_TYPE
535    
536              VCFCutoffCtrl.value    = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller];              VCFCutoffCtrl.value    = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller];
# Line 732  namespace LinuxSampler { namespace gig { Line 746  namespace LinuxSampler { namespace gig {
746      }      }
747    
748      void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) {      void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) {
749          const float pitch = RTMath::CentsToFreqRatio(((double) itEvent->Param.Pitch.Pitch / 8192.0) * 200.0); // +-two semitones = +-200 cents          PitchBend = RTMath::CentsToFreqRatio(itEvent->Param.Pitch.Pitch / 8192.0 * 100.0 * pEngineChannel->pInstrument->PitchbendRange);
         finalSynthesisParameters.fFinalPitch *= pitch;  
         PitchBend = pitch;  
750      }      }
751    
752      void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) {      void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) {
# Line 776  namespace LinuxSampler { namespace gig { Line 788  namespace LinuxSampler { namespace gig {
788          RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first();          RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first();
789          RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first();          RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first();
790    
791          if (Skip) { // skip events that happened before this voice was triggered          if (itTriggerEvent) { // skip events that happened before this voice was triggered
792              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;              while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent;
793              while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent;              // we can't simply compare the timestamp here, because note events
794                // might happen on the same time stamp, so we have to deal on the
795                // actual sequence the note events arrived instead (see bug #112)
796                for (; itNoteEvent; ++itNoteEvent) {
797                    if (itTriggerEvent == itNoteEvent) {
798                        ++itNoteEvent;
799                        break;
800                    }
801                }
802          }          }
803    
804          uint killPos;          uint killPos;
805          if (itKillEvent) killPos = RTMath::Min(itKillEvent->FragmentPos(), pEngine->MaxFadeOutPos);          if (itKillEvent) {
806                int maxFadeOutPos = Samples - pEngine->MinFadeOutSamples;
807                if (maxFadeOutPos < 0) {
808                    // There's not enough space in buffer to do a fade out
809                    // from max volume (this can only happen for audio
810                    // drivers that use Samples < MaxSamplesPerCycle).
811                    // End the EG1 here, at pos 0, with a shorter max fade
812                    // out time.
813                    EG1.enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE);
814                    itKillEvent = Pool<Event>::Iterator();
815                } else {
816                    killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos);
817                }
818            }
819    
820          uint i = Skip;          uint i = Skip;
821          while (i < Samples) {          while (i < Samples) {
822              int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);              int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples);
823    
824              // initialize all final synthesis parameters              // initialize all final synthesis parameters
             finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend;  
825              fFinalCutoff    = VCFCutoffCtrl.fvalue;              fFinalCutoff    = VCFCutoffCtrl.fvalue;
826              fFinalResonance = VCFResonanceCtrl.fvalue;              fFinalResonance = VCFResonanceCtrl.fvalue;
827    
828              // process MIDI control change and pitchbend events for this subfragment              // process MIDI control change and pitchbend events for this subfragment
829              processCCEvents(itCCEvent, iSubFragmentEnd);              processCCEvents(itCCEvent, iSubFragmentEnd);
830    
831                finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend;
832              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();              float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render();
833  #ifdef CONFIG_PROCESS_MUTED_CHANNELS  #ifdef CONFIG_PROCESS_MUTED_CHANNELS
834              if (pEngineChannel->GetMute()) fFinalVolume = 0;              if (pEngineChannel->GetMute()) fFinalVolume = 0;
# Line 843  namespace LinuxSampler { namespace gig { Line 876  namespace LinuxSampler { namespace gig {
876              if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();              if (bLFO2Enabled) fFinalCutoff *= pLFO2->render();
877              if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());              if (bLFO3Enabled) finalSynthesisParameters.fFinalPitch *= RTMath::CentsToFreqRatio(pLFO3->render());
878    
879                // limit the pitch so we don't read outside the buffer
880                finalSynthesisParameters.fFinalPitch = RTMath::Min(finalSynthesisParameters.fFinalPitch, float(1 << CONFIG_MAX_PITCH));
881    
882              // if filter enabled then update filter coefficients              // if filter enabled then update filter coefficients
883              if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {              if (SYNTHESIS_MODE_GET_FILTER(SynthesisMode)) {
884                  finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);                  finalSynthesisParameters.filterLeft.SetParameters(fFinalCutoff, fFinalResonance, pEngine->SampleRate);
# Line 921  namespace LinuxSampler { namespace gig { Line 957  namespace LinuxSampler { namespace gig {
957       *  fading down the volume level to avoid clicks and regular processing       *  fading down the volume level to avoid clicks and regular processing
958       *  until the kill event actually occured!       *  until the kill event actually occured!
959       *       *
960       *  @see Kill()       * If it's necessary to know when the voice's disk stream was actually
961         * deleted, then one can set the optional @a bRequestNotification
962         * parameter and this method will then return the handle of the disk
963         * stream (unique identifier) and one can use this handle to poll the
964         * disk thread if this stream has been deleted. In any case this method
965         * will return immediately and will not block until the stream actually
966         * was deleted.
967         *
968         * @param bRequestNotification - (optional) whether the disk thread shall
969         *                                provide a notification once it deleted
970         *                               the respective disk stream
971         *                               (default=false)
972         * @returns handle to the voice's disk stream or @c Stream::INVALID_HANDLE
973         *          if the voice did not use a disk stream at all
974         * @see Kill()
975       */       */
976      void Voice::KillImmediately() {      Stream::Handle Voice::KillImmediately(bool bRequestNotification) {
977            Stream::Handle hStream = Stream::INVALID_HANDLE;
978          if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {          if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
979              pDiskThread->OrderDeletionOfStream(&DiskStreamRef);              pDiskThread->OrderDeletionOfStream(&DiskStreamRef, bRequestNotification);
980                hStream = DiskStreamRef.hStream;
981          }          }
982          Reset();          Reset();
983            return hStream;
984      }      }
985    
986      /**      /**

Legend:
Removed from v.1038  
changed lines
  Added in v.1895

  ViewVC Help
Powered by ViewVC