/[svn]/linuxsampler/trunk/src/engines/sfz/Voice.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/sfz/Voice.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2559 - (show annotations) (download)
Sun May 18 17:38:25 2014 UTC (9 years, 11 months ago) by schoenebeck
File size: 13542 byte(s)
* Aftertouch: extended API to explicitly handle channel pressure and
  polyphonic key pressure events (so far polyphonic pressure was not
  supported at all, and channel pressure was rerouted as CC128 but not
  used so far).
* Gig Engine: Fixed support for 'aftertouch' attenuation controller.
* Bumped version (1.0.0.svn39).

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2008 Christian Schoenebeck *
7 * Copyright (C) 2009 - 2013 Christian Schoenebeck and Grigor Iliev *
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 * This program is distributed in the hope that it will be useful, *
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17 * GNU General Public License for more details. *
18 * *
19 * You should have received a copy of the GNU General Public License *
20 * along with this program; if not, write to the Free Software *
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
22 * MA 02111-1307 USA *
23 ***************************************************************************/
24
25 #include "Voice.h"
26
27 #include "Engine.h"
28 #include "EngineChannel.h"
29
30 #define LN_10_DIV_20 0.115129254649702
31
32 namespace LinuxSampler { namespace sfz {
33
34 typedef LinuxSampler::VoiceBase<EngineChannel, ::sfz::Region, Sample, DiskThread> SfzVoice;
35 Voice::Voice(): SignalRack(this), SfzVoice(&SignalRack) {
36 pEngine = NULL;
37 bEqSupport = true;
38 }
39
40 Voice::~Voice() {
41
42 }
43
44 EngineChannel* Voice::GetSfzEngineChannel() {
45 return static_cast<EngineChannel*>(pEngineChannel);
46 }
47
48 void Voice::SetEngine(LinuxSampler::Engine* pEngine) {
49 Engine* engine = static_cast<Engine*>(pEngine);
50 this->pEngine = engine;
51 this->pDiskThread = engine->pDiskThread;
52 dmsg(6,("Voice::SetEngine()\n"));
53 }
54
55 Voice::SampleInfo Voice::GetSampleInfo() {
56 SampleInfo si;
57 si.SampleRate = pSample->GetSampleRate();
58 si.ChannelCount = pSample->GetChannelCount();
59 si.FrameSize = pSample->GetFrameSize();
60 si.BitDepth = (pSample->GetFrameSize() / pSample->GetChannelCount()) * 8;
61 si.TotalFrameCount = pSample->GetTotalFrameCount();
62
63 si.HasLoops = pRegion->HasLoop();
64 si.LoopStart = pRegion->GetLoopStart();
65 si.LoopLength = pRegion->GetLoopEnd() - pRegion->GetLoopStart();
66 si.LoopPlayCount = pRegion->GetLoopCount();
67 si.Unpitched = pRegion->pitch_keytrack == 0;
68 return si;
69 }
70
71 Voice::RegionInfo Voice::GetRegionInfo() {
72 RegionInfo ri;
73 ri.UnityNote = pRegion->pitch_keycenter;
74 ri.FineTune = pRegion->tune + pRegion->transpose * 100;
75 ri.Pan = int(pRegion->pan * 0.63); // convert from -100..100 to -64..63
76 ri.SampleStartOffset = pRegion->offset ? *(pRegion->offset) : 0;
77
78 ri.VCFEnabled = pRegion->cutoff;
79 switch (pRegion->fil_type) {
80 case ::sfz::LPF_1P:
81 ri.VCFType = Filter::vcf_type_1p_lowpass;
82 break;
83 case ::sfz::LPF_2P:
84 ri.VCFType = Filter::vcf_type_2p_lowpass;
85 break;
86 case ::sfz::LPF_4P:
87 ri.VCFType = Filter::vcf_type_4p_lowpass;
88 break;
89 case ::sfz::LPF_6P:
90 ri.VCFType = Filter::vcf_type_6p_lowpass;
91 break;
92 case ::sfz::HPF_1P:
93 ri.VCFType = Filter::vcf_type_1p_highpass;
94 break;
95 case ::sfz::HPF_2P:
96 ri.VCFType = Filter::vcf_type_2p_highpass;
97 break;
98 case ::sfz::HPF_4P:
99 ri.VCFType = Filter::vcf_type_4p_highpass;
100 break;
101 case ::sfz::HPF_6P:
102 ri.VCFType = Filter::vcf_type_6p_highpass;
103 break;
104 case ::sfz::BPF_1P:
105 case ::sfz::BPF_2P:
106 ri.VCFType = Filter::vcf_type_2p_bandpass;
107 break;
108 case ::sfz::BRF_1P:
109 case ::sfz::BRF_2P:
110 ri.VCFType = Filter::vcf_type_2p_bandreject;
111 break;
112 case ::sfz::APF_1P:
113 case ::sfz::PKF_2P:
114 default:
115 ri.VCFEnabled = false;
116 break;
117 }
118
119 ri.VCFResonance = pRegion->resonance;
120
121 // rt_decay is in dB. Precalculate a suitable value for exp in
122 // GetReleaseTriggerAttenuation: -ln(10) / 20 * rt_decay
123 ri.ReleaseTriggerDecay = -LN_10_DIV_20 * pRegion->rt_decay;
124
125 return ri;
126 }
127
128 Voice::InstrumentInfo Voice::GetInstrumentInfo() {
129 InstrumentInfo ii;
130 ii.FineTune = 0; // TODO:
131 ii.PitchbendRange = 2; // TODO:
132
133 return ii;
134 }
135
136 double Voice::GetSampleAttenuation() {
137 return exp(LN_10_DIV_20 * pRegion->volume) * pRegion->amplitude / 100;
138 }
139
140 double Voice::GetVelocityAttenuation(uint8_t MIDIKeyVelocity) {
141 float offset = -pRegion->amp_veltrack;
142 if (offset <= 0) offset += 100;
143 return (offset + pRegion->amp_veltrack * pRegion->amp_velcurve[MIDIKeyVelocity]) / 100;
144 }
145
146 double Voice::GetVelocityRelease(uint8_t MIDIKeyVelocity) {
147 return 127.0 / MIDIKeyVelocity;
148 }
149
150 void Voice::ProcessCCEvent(RTList<Event>::Iterator& itEvent) {
151 /*if (itEvent->Type == Event::type_control_change && itEvent->Param.CC.Controller) { // if (valid) MIDI control change event
152 if (pRegion->AttenuationController.type == ::gig::attenuation_ctrl_t::type_controlchange &&
153 itEvent->Param.CC.Controller == pRegion->AttenuationController.controller_number) {
154 CrossfadeSmoother.update(AbstractEngine::CrossfadeCurve[CrossfadeAttenuation(itEvent->Param.CC.Value)]);
155 }
156 }*/ // TODO: ^^^
157 }
158
159 void Voice::ProcessChannelPressureEvent(RTList<Event>::Iterator& itEvent) {
160 //TODO: ...
161 }
162
163 void Voice::ProcessPolyphonicKeyPressureEvent(RTList<Event>::Iterator& itEvent) {
164 //TODO: ...
165 }
166
167 double Voice::CalculateCrossfadeVolume(uint8_t MIDIKeyVelocity) {
168 /*float crossfadeVolume;
169 switch (pRegion->AttenuationController.type) {
170 case ::gig::attenuation_ctrl_t::type_channelaftertouch:
171 crossfadeVolume = Engine::CrossfadeCurve[CrossfadeAttenuation(GetSfzEngineChannel()->ControllerTable[128])];
172 break;
173 case ::gig::attenuation_ctrl_t::type_velocity:
174 crossfadeVolume = Engine::CrossfadeCurve[CrossfadeAttenuation(MIDIKeyVelocity)];
175 break;
176 case ::gig::attenuation_ctrl_t::type_controlchange: //FIXME: currently not sample accurate
177 crossfadeVolume = Engine::CrossfadeCurve[CrossfadeAttenuation(GetSfzEngineChannel()->ControllerTable[pRegion->AttenuationController.controller_number])];
178 break;
179 case ::gig::attenuation_ctrl_t::type_none: // no crossfade defined
180 default:
181 crossfadeVolume = 1.0f;
182 }
183
184 return crossfadeVolume;*/ // TODO: ^^^
185 return 1.0f;
186 }
187
188 double Voice::GetEG1ControllerValue(uint8_t MIDIKeyVelocity) {
189 /*double eg1controllervalue = 0;
190 switch (pRegion->EG1Controller.type) {
191 case ::gig::eg1_ctrl_t::type_none: // no controller defined
192 eg1controllervalue = 0;
193 break;
194 case ::gig::eg1_ctrl_t::type_channelaftertouch:
195 eg1controllervalue = GetSfzEngineChannel()->ControllerTable[128];
196 break;
197 case ::gig::eg1_ctrl_t::type_velocity:
198 eg1controllervalue = MIDIKeyVelocity;
199 break;
200 case ::gig::eg1_ctrl_t::type_controlchange: // MIDI control change controller
201 eg1controllervalue = GetSfzEngineChannel()->ControllerTable[pRegion->EG1Controller.controller_number];
202 break;
203 }
204 if (pRegion->EG1ControllerInvert) eg1controllervalue = 127 - eg1controllervalue;
205
206 return eg1controllervalue;*/ // TODO: ^^^
207 return 0;
208 }
209
210 Voice::EGInfo Voice::CalculateEG1ControllerInfluence(double eg1ControllerValue) {
211 /*EGInfo eg;
212 // (eg1attack is different from the others)
213 eg.Attack = (pRegion->EG1ControllerAttackInfluence) ?
214 1 + 0.031 * (double) (pRegion->EG1ControllerAttackInfluence == 1 ?
215 1 : 1 << pRegion->EG1ControllerAttackInfluence) * eg1ControllerValue : 1.0;
216 eg.Decay = (pRegion->EG1ControllerDecayInfluence) ? 1 + 0.00775 * (double) (1 << pRegion->EG1ControllerDecayInfluence) * eg1ControllerValue : 1.0;
217 eg.Release = (pRegion->EG1ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pRegion->EG1ControllerReleaseInfluence) * eg1ControllerValue : 1.0;
218
219 return eg;*/ // TODO: ^^^
220 EGInfo eg;
221 eg.Attack = 1.0;
222 eg.Decay = 1.0;
223 eg.Release = 1.0;
224 return eg;
225 }
226
227 double Voice::GetEG2ControllerValue(uint8_t MIDIKeyVelocity) {
228 /*double eg2controllervalue = 0;
229 switch (pRegion->EG2Controller.type) {
230 case ::gig::eg2_ctrl_t::type_none: // no controller defined
231 eg2controllervalue = 0;
232 break;
233 case ::gig::eg2_ctrl_t::type_channelaftertouch:
234 eg2controllervalue = GetSfzEngineChannel()->ControllerTable[128];
235 break;
236 case ::gig::eg2_ctrl_t::type_velocity:
237 eg2controllervalue = MIDIKeyVelocity;
238 break;
239 case ::gig::eg2_ctrl_t::type_controlchange: // MIDI control change controller
240 eg2controllervalue = GetSfzEngineChannel()->ControllerTable[pRegion->EG2Controller.controller_number];
241 break;
242 }
243 if (pRegion->EG2ControllerInvert) eg2controllervalue = 127 - eg2controllervalue;
244
245 return eg2controllervalue;*/ // TODO: ^^^
246 return 0;
247 }
248
249 Voice::EGInfo Voice::CalculateEG2ControllerInfluence(double eg2ControllerValue) {
250 /*EGInfo eg;
251 eg.Attack = (pRegion->EG2ControllerAttackInfluence) ? 1 + 0.00775 * (double) (1 << pRegion->EG2ControllerAttackInfluence) * eg2ControllerValue : 1.0;
252 eg.Decay = (pRegion->EG2ControllerDecayInfluence) ? 1 + 0.00775 * (double) (1 << pRegion->EG2ControllerDecayInfluence) * eg2ControllerValue : 1.0;
253 eg.Release = (pRegion->EG2ControllerReleaseInfluence) ? 1 + 0.00775 * (double) (1 << pRegion->EG2ControllerReleaseInfluence) * eg2ControllerValue : 1.0;
254
255 return eg;*/ // TODO: ^^^
256 EGInfo eg;
257 eg.Attack = 1.0;
258 eg.Decay = 1.0;
259 eg.Release = 1.0;
260 return eg;
261 }
262
263 float Voice::CalculateCutoffBase(uint8_t MIDIKeyVelocity) {
264 float cutoff = *pRegion->cutoff;
265 cutoff *= RTMath::CentsToFreqRatioUnlimited(
266 MIDIKeyVelocity / 127.0f * pRegion->fil_veltrack +
267 (MIDIKey - pRegion->fil_keycenter) * pRegion->fil_keytrack);
268 return cutoff;
269 }
270
271 float Voice::CalculateFinalCutoff(float cutoffBase) {
272 float cutoff = cutoffBase;
273 if (cutoff > 0.49 * pEngine->SampleRate) cutoff = 0.49 * pEngine->SampleRate;
274 return cutoff;
275 }
276
277 float Voice::GetReleaseTriggerAttenuation(float noteLength) {
278 // pow(10, -rt_decay * noteLength / 20):
279 return expf(RgnInfo.ReleaseTriggerDecay * noteLength);
280 }
281
282 void Voice::ProcessGroupEvent(RTList<Event>::Iterator& itEvent) {
283 dmsg(4,("Voice %x processGroupEvents event type=%d", this, itEvent->Type));
284 if (itEvent->Type == Event::type_control_change ||
285 (Type & Voice::type_controller_triggered) ||
286 itEvent->Param.Note.Key != MIDIKey) {
287 dmsg(4,("Voice %x - kill", this));
288 if (pRegion->off_mode == ::sfz::OFF_NORMAL) {
289 // turn off the voice by entering release envelope stage
290 EnterReleaseStage();
291 } else {
292 // kill the voice fast
293 SignalRack.EnterFadeOutStage();
294 }
295 }
296 }
297
298 void Voice::SetSampleStartOffset() {
299 if (DiskVoice && RgnInfo.SampleStartOffset > pSample->MaxOffset) {
300 // The offset is applied to the RAM buffer
301 finalSynthesisParameters.dPos = 0;
302 Pos = 0;
303 } else {
304 finalSynthesisParameters.dPos = RgnInfo.SampleStartOffset; // offset where we should start playback of sample
305 Pos = RgnInfo.SampleStartOffset;
306 }
307 }
308
309 void Voice::CalculateFadeOutCoeff(float FadeOutTime, float SampleRate) {
310 SignalRack.CalculateFadeOutCoeff(FadeOutTime, SampleRate);
311 }
312
313 int Voice::CalculatePan(uint8_t pan) {
314 // the value isn't limited to [0, 127] here, as this is done
315 // later in SignalUnit.CalculatePan
316 return pan + RgnInfo.Pan;
317 }
318
319 }} // namespace LinuxSampler::sfz

  ViewVC Help
Powered by ViewVC