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 * |
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); |
183 |
|
|
184 |
// calculate initial pitch value |
// calculate initial pitch value |
185 |
{ |
{ |
186 |
double pitchbasecents = pDimRgn->FineTune + (int) pEngine->ScaleTuning[MIDIKey % 12]; |
double pitchbasecents = pEngineChannel->pInstrument->FineTune + pDimRgn->FineTune + pEngine->ScaleTuning[MIDIKey % 12]; |
187 |
if (pDimRgn->PitchTrack) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100; |
|
188 |
|
// GSt behaviour: maximum transpose up is 40 semitones. If |
189 |
|
// MIDI key is more than 40 semitones above unity note, |
190 |
|
// the transpose is not done. |
191 |
|
if (pDimRgn->PitchTrack && (MIDIKey - (int) pDimRgn->UnityNote) < 40) pitchbasecents += (MIDIKey - (int) pDimRgn->UnityNote) * 100; |
192 |
|
|
193 |
this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->SampleRate)); |
this->PitchBase = RTMath::CentsToFreqRatio(pitchbasecents) * (double(pSample->SamplesPerSecond) / double(pEngine->SampleRate)); |
194 |
this->PitchBend = RTMath::CentsToFreqRatio(((double) PitchBend / 8192.0) * 200.0); // pitchbend wheel +-2 semitones = 200 cents |
this->PitchBend = RTMath::CentsToFreqRatio(PitchBend / 8192.0 * 100.0 * pEngineChannel->pInstrument->PitchbendRange); |
195 |
} |
} |
196 |
|
|
197 |
// 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 |
520 |
finalSynthesisParameters.filterLeft.SetType(pDimRgn->VCFType); |
finalSynthesisParameters.filterLeft.SetType(pDimRgn->VCFType); |
521 |
finalSynthesisParameters.filterRight.SetType(pDimRgn->VCFType); |
finalSynthesisParameters.filterRight.SetType(pDimRgn->VCFType); |
522 |
#else // override filter type |
#else // override filter type |
523 |
FilterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
finalSynthesisParameters.filterLeft.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
524 |
FilterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
finalSynthesisParameters.filterRight.SetType(CONFIG_OVERRIDE_FILTER_TYPE); |
525 |
#endif // CONFIG_OVERRIDE_FILTER_TYPE |
#endif // CONFIG_OVERRIDE_FILTER_TYPE |
526 |
|
|
527 |
VCFCutoffCtrl.value = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller]; |
VCFCutoffCtrl.value = pEngineChannel->ControllerTable[VCFCutoffCtrl.controller]; |
737 |
} |
} |
738 |
|
|
739 |
void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) { |
void Voice::processPitchEvent(RTList<Event>::Iterator& itEvent) { |
740 |
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; |
|
741 |
} |
} |
742 |
|
|
743 |
void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) { |
void Voice::processCutoffEvent(RTList<Event>::Iterator& itEvent) { |
779 |
RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first(); |
RTList<Event>::Iterator itCCEvent = pEngineChannel->pEvents->first(); |
780 |
RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first(); |
RTList<Event>::Iterator itNoteEvent = pEngineChannel->pMIDIKeyInfo[MIDIKey].pEvents->first(); |
781 |
|
|
782 |
if (Skip) { // skip events that happened before this voice was triggered |
if (itTriggerEvent) { // skip events that happened before this voice was triggered |
783 |
while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent; |
while (itCCEvent && itCCEvent->FragmentPos() <= Skip) ++itCCEvent; |
784 |
while (itNoteEvent && itNoteEvent->FragmentPos() <= Skip) ++itNoteEvent; |
// we can't simply compare the timestamp here, because note events |
785 |
|
// might happen on the same time stamp, so we have to deal on the |
786 |
|
// actual sequence the note events arrived instead (see bug #112) |
787 |
|
for (; itNoteEvent; ++itNoteEvent) { |
788 |
|
if (itTriggerEvent == itNoteEvent) { |
789 |
|
++itNoteEvent; |
790 |
|
break; |
791 |
|
} |
792 |
|
} |
793 |
} |
} |
794 |
|
|
795 |
uint killPos; |
uint killPos; |
796 |
if (itKillEvent) killPos = RTMath::Min(itKillEvent->FragmentPos(), pEngine->MaxFadeOutPos); |
if (itKillEvent) { |
797 |
|
int maxFadeOutPos = Samples - pEngine->MinFadeOutSamples; |
798 |
|
if (maxFadeOutPos < 0) { |
799 |
|
// There's not enough space in buffer to do a fade out |
800 |
|
// from max volume (this can only happen for audio |
801 |
|
// drivers that use Samples < MaxSamplesPerCycle). |
802 |
|
// End the EG1 here, at pos 0, with a shorter max fade |
803 |
|
// out time. |
804 |
|
EG1.enterFadeOutStage(Samples / CONFIG_DEFAULT_SUBFRAGMENT_SIZE); |
805 |
|
itKillEvent = Pool<Event>::Iterator(); |
806 |
|
} else { |
807 |
|
killPos = RTMath::Min(itKillEvent->FragmentPos(), maxFadeOutPos); |
808 |
|
} |
809 |
|
} |
810 |
|
|
811 |
uint i = Skip; |
uint i = Skip; |
812 |
while (i < Samples) { |
while (i < Samples) { |
813 |
int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples); |
int iSubFragmentEnd = RTMath::Min(i + CONFIG_DEFAULT_SUBFRAGMENT_SIZE, Samples); |
814 |
|
|
815 |
// initialize all final synthesis parameters |
// initialize all final synthesis parameters |
|
finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend; |
|
816 |
fFinalCutoff = VCFCutoffCtrl.fvalue; |
fFinalCutoff = VCFCutoffCtrl.fvalue; |
817 |
fFinalResonance = VCFResonanceCtrl.fvalue; |
fFinalResonance = VCFResonanceCtrl.fvalue; |
818 |
|
|
819 |
// process MIDI control change and pitchbend events for this subfragment |
// process MIDI control change and pitchbend events for this subfragment |
820 |
processCCEvents(itCCEvent, iSubFragmentEnd); |
processCCEvents(itCCEvent, iSubFragmentEnd); |
821 |
|
|
822 |
|
finalSynthesisParameters.fFinalPitch = PitchBase * PitchBend; |
823 |
float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render(); |
float fFinalVolume = VolumeSmoother.render() * CrossfadeSmoother.render(); |
824 |
#ifdef CONFIG_PROCESS_MUTED_CHANNELS |
#ifdef CONFIG_PROCESS_MUTED_CHANNELS |
825 |
if (pEngineChannel->GetMute()) fFinalVolume = 0; |
if (pEngineChannel->GetMute()) fFinalVolume = 0; |
945 |
* fading down the volume level to avoid clicks and regular processing |
* fading down the volume level to avoid clicks and regular processing |
946 |
* until the kill event actually occured! |
* until the kill event actually occured! |
947 |
* |
* |
948 |
* @see Kill() |
* If it's necessary to know when the voice's disk stream was actually |
949 |
|
* deleted, then one can set the optional @a bRequestNotification |
950 |
|
* parameter and this method will then return the handle of the disk |
951 |
|
* stream (unique identifier) and one can use this handle to poll the |
952 |
|
* disk thread if this stream has been deleted. In any case this method |
953 |
|
* will return immediately and will not block until the stream actually |
954 |
|
* was deleted. |
955 |
|
* |
956 |
|
* @param bRequestNotification - (optional) whether the disk thread shall |
957 |
|
* provide a notification once it deleted |
958 |
|
* the respective disk stream |
959 |
|
* (default=false) |
960 |
|
* @returns handle to the voice's disk stream or @c Stream::INVALID_HANDLE |
961 |
|
* if the voice did not use a disk stream at all |
962 |
|
* @see Kill() |
963 |
*/ |
*/ |
964 |
void Voice::KillImmediately() { |
Stream::Handle Voice::KillImmediately(bool bRequestNotification) { |
965 |
|
Stream::Handle hStream = Stream::INVALID_HANDLE; |
966 |
if (DiskVoice && DiskStreamRef.State != Stream::state_unused) { |
if (DiskVoice && DiskStreamRef.State != Stream::state_unused) { |
967 |
pDiskThread->OrderDeletionOfStream(&DiskStreamRef); |
pDiskThread->OrderDeletionOfStream(&DiskStreamRef, bRequestNotification); |
968 |
|
hStream = DiskStreamRef.hStream; |
969 |
} |
} |
970 |
Reset(); |
Reset(); |
971 |
|
return hStream; |
972 |
} |
} |
973 |
|
|
974 |
/** |
/** |