/[svn]/linuxsampler/trunk/src/engines/gig/Engine.cpp
ViewVC logotype

Annotation of /linuxsampler/trunk/src/engines/gig/Engine.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2012 - (hide annotations) (download)
Fri Oct 23 17:53:17 2009 UTC (14 years, 6 months ago) by iliev
File size: 19005 byte(s)
* Refactoring: moved the independent code from
  the Gigasampler format engine to base classes
* SFZ format engine: experimental code (not usable yet)
* SoundFont format engine: experimental code (not usable yet)
* Fixed crash which may occur when MIDI key + transpose is out of range

1 schoenebeck 53 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 persson 1644 * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 1860 * Copyright (C) 2005-2009 Christian Schoenebeck *
7 iliev 2012 * Copyright (C) 2009 Grigor Iliev *
8 schoenebeck 53 * *
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 "Engine.h"
26 iliev 2012 #include "EngineChannel.h"
27 schoenebeck 53
28     namespace LinuxSampler { namespace gig {
29 iliev 2012 Engine::Format Engine::GetEngineFormat() { return GIG; }
30 schoenebeck 53
31 schoenebeck 412 /**
32 iliev 2012 * Reacts on supported control change commands (e.g. pitch bend wheel,
33     * modulation wheel, aftertouch).
34 schoenebeck 412 *
35 iliev 2012 * @param pEngineChannel - engine channel on which this event occured on
36     * @param itControlChangeEvent - controller, value and time stamp of the event
37 schoenebeck 412 */
38 iliev 2012 void Engine::ProcessControlChange (
39     LinuxSampler::EngineChannel* pEngineChannel,
40     Pool<Event>::Iterator& itControlChangeEvent
41     ) {
42     dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));
43 persson 1039
44 iliev 2012 EngineChannel* pChannel = dynamic_cast<EngineChannel*>(pEngineChannel);
45     // handle the "control triggered" MIDI rule: a control change
46     // event can trigger a new note on or note off event
47     if (pChannel->pInstrument) {
48 schoenebeck 411
49 iliev 2012 ::gig::MidiRule* rule;
50     for (int i = 0 ; (rule = pChannel->pInstrument->GetMidiRule(i)) ; i++) {
51 schoenebeck 411
52 iliev 2012 if (::gig::MidiRuleCtrlTrigger* ctrlTrigger =
53     dynamic_cast< ::gig::MidiRuleCtrlTrigger*>(rule)) {
54     if (itControlChangeEvent->Param.CC.Controller ==
55     ctrlTrigger->ControllerNumber) {
56 persson 1038
57 iliev 2012 uint8_t oldCCValue = pChannel->ControllerTable[
58     itControlChangeEvent->Param.CC.Controller];
59     uint8_t newCCValue = itControlChangeEvent->Param.CC.Value;
60 schoenebeck 53
61 iliev 2012 for (int i = 0 ; i < ctrlTrigger->Triggers ; i++) {
62     ::gig::MidiRuleCtrlTrigger::trigger_t* pTrigger =
63     &ctrlTrigger->pTriggers[i];
64 schoenebeck 53
65 iliev 2012 // check if the controller has passed the
66     // trigger point in the right direction
67     if ((pTrigger->Descending &&
68     oldCCValue > pTrigger->TriggerPoint &&
69     newCCValue <= pTrigger->TriggerPoint) ||
70     (!pTrigger->Descending &&
71     oldCCValue < pTrigger->TriggerPoint &&
72     newCCValue >= pTrigger->TriggerPoint)) {
73 schoenebeck 53
74 iliev 2012 RTList<Event>::Iterator itNewEvent = pGlobalEvents->allocAppend();
75     if (itNewEvent) {
76     *itNewEvent = *itControlChangeEvent;
77     itNewEvent->Param.Note.Key = pTrigger->Key;
78 schoenebeck 53
79 iliev 2012 if (pTrigger->NoteOff || pTrigger->Velocity == 0) {
80     itNewEvent->Type = Event::type_note_off;
81     itNewEvent->Param.Note.Velocity = 100;
82 schoenebeck 53
83 iliev 2012 ProcessNoteOff(pEngineChannel, itNewEvent);
84     } else {
85     itNewEvent->Type = Event::type_note_on;
86     //TODO: if Velocity is 255, the triggered velocity should
87     // depend on how fast the controller is moving
88     itNewEvent->Param.Note.Velocity =
89     pTrigger->Velocity == 255 ? 100 :
90     pTrigger->Velocity;
91 schoenebeck 53
92 iliev 2012 ProcessNoteOn(pEngineChannel, itNewEvent);
93     }
94     }
95     else dmsg(1,("Event pool emtpy!\n"));
96     }
97 schoenebeck 1321 }
98     }
99     }
100     }
101     }
102    
103 iliev 2012 // update controller value in the engine channel's controller table
104     pChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
105 schoenebeck 1321
106 iliev 2012 ProcessHardcodedControllers(pEngineChannel, itControlChangeEvent);
107 schoenebeck 1321
108 iliev 2012 // handle FX send controllers
109     ProcessFxSendControllers(pChannel, itControlChangeEvent);
110 schoenebeck 1321 }
111    
112 iliev 2012 DiskThread* Engine::CreateDiskThread() {
113     return new DiskThread (
114     iMaxDiskStreams,
115     ((pAudioOutputDevice->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
116     &instruments
117     );
118 schoenebeck 412 }
119    
120 iliev 2012 void Engine::TriggerNewVoices (
121     LinuxSampler::EngineChannel* pEngineChannel,
122     RTList<Event>::Iterator& itNoteOnEvent,
123     bool HandleKeyGroupConflicts
124     ) {
125     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
126     // first, get total amount of required voices (dependant on amount of layers)
127     ::gig::Region* pRegion = pChannel->pInstrument->GetRegion(itNoteOnEvent->Param.Note.Key);
128     if (pRegion && !RegionSuspended(pRegion)) {
129     int voicesRequired = pRegion->Layers;
130     // now launch the required amount of voices
131     for (int i = 0; i < voicesRequired; i++)
132     LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);
133 schoenebeck 412 }
134 persson 438 }
135 schoenebeck 412
136 iliev 2012 void Engine::TriggerReleaseVoices (
137     LinuxSampler::EngineChannel* pEngineChannel,
138     RTList<Event>::Iterator& itNoteOffEvent
139     ) {
140     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
141     MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key];
142     // first, get total amount of required voices (dependant on amount of layers)
143     ::gig::Region* pRegion = pChannel->pInstrument->GetRegion(itNoteOffEvent->Param.Note.Key);
144     if (pRegion) {
145     int voicesRequired = pRegion->Layers;
146 schoenebeck 53
147 iliev 2012 // MIDI note-on velocity is used instead of note-off velocity
148     itNoteOffEvent->Param.Note.Velocity = pKey->Velocity;
149 schoenebeck 53
150 iliev 2012 // now launch the required amount of voices
151     for (int i = 0; i < voicesRequired; i++)
152     LaunchVoice(pChannel, itNoteOffEvent, i, true, false, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples
153 schoenebeck 53 }
154 schoenebeck 412 }
155    
156 iliev 2012 Pool<Voice>::Iterator Engine::LaunchVoice (
157     LinuxSampler::EngineChannel* pEngineChannel,
158     Pool<Event>::Iterator& itNoteOnEvent,
159     int iLayer,
160     bool ReleaseTriggerVoice,
161     bool VoiceStealing,
162     bool HandleKeyGroupConflicts
163     ) {
164     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
165     int MIDIKey = itNoteOnEvent->Param.Note.Key;
166     EngineChannel::MidiKey* pKey = &pChannel->pMIDIKeyInfo[MIDIKey];
167     ::gig::Region* pRegion = pChannel->pInstrument->GetRegion(MIDIKey);
168 schoenebeck 53
169 schoenebeck 668 // if nothing defined for this key
170     if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
171    
172 schoenebeck 669 // only mark the first voice of a layered voice (group) to be in a
173     // key group, so the layered voices won't kill each other
174     int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;
175    
176 schoenebeck 668 // handle key group (a.k.a. exclusive group) conflicts
177     if (HandleKeyGroupConflicts) {
178     if (iKeyGroup) { // if this voice / key belongs to a key group
179 iliev 2012 uint** ppKeyGroup = &pChannel->ActiveKeyGroups[iKeyGroup];
180 schoenebeck 668 if (*ppKeyGroup) { // if there's already an active key in that key group
181 iliev 2012 EngineChannel::MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[**ppKeyGroup];
182 schoenebeck 668 // kill all voices on the (other) key
183     RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
184     RTList<Voice>::Iterator end = pOtherKey->pActiveVoices->end();
185     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
186     if (itVoiceToBeKilled->Type != Voice::type_release_trigger) {
187     itVoiceToBeKilled->Kill(itNoteOnEvent);
188     --VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict
189     }
190     }
191     }
192     }
193     }
194    
195 schoenebeck 669 Voice::type_t VoiceType = Voice::type_normal;
196    
197     // get current dimension values to select the right dimension region
198     //TODO: for stolen voices this dimension region selection block is processed twice, this should be changed
199     //FIXME: controller values for selecting the dimension region here are currently not sample accurate
200     uint DimValues[8] = { 0 };
201     for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
202     switch (pRegion->pDimensionDefinitions[i].dimension) {
203     case ::gig::dimension_samplechannel:
204     DimValues[i] = 0; //TODO: we currently ignore this dimension
205     break;
206     case ::gig::dimension_layer:
207     DimValues[i] = iLayer;
208     break;
209     case ::gig::dimension_velocity:
210     DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
211     break;
212     case ::gig::dimension_channelaftertouch:
213 iliev 2012 DimValues[i] = pChannel->ControllerTable[128];
214 schoenebeck 669 break;
215     case ::gig::dimension_releasetrigger:
216     VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;
217     DimValues[i] = (uint) ReleaseTriggerVoice;
218     break;
219     case ::gig::dimension_keyboard:
220 iliev 2012 DimValues[i] = (uint) (pChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);
221 schoenebeck 669 break;
222     case ::gig::dimension_roundrobin:
223 iliev 2012 DimValues[i] = (uint) pChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on
224 schoenebeck 669 break;
225     case ::gig::dimension_random:
226     RandomSeed = RandomSeed * 1103515245 + 12345; // classic pseudo random number generator
227     DimValues[i] = (uint) RandomSeed >> (32 - pRegion->pDimensionDefinitions[i].bits); // highest bits are most random
228     break;
229     case ::gig::dimension_modwheel:
230 iliev 2012 DimValues[i] = pChannel->ControllerTable[1];
231 schoenebeck 669 break;
232     case ::gig::dimension_breath:
233 iliev 2012 DimValues[i] = pChannel->ControllerTable[2];
234 schoenebeck 669 break;
235     case ::gig::dimension_foot:
236 iliev 2012 DimValues[i] = pChannel->ControllerTable[4];
237 schoenebeck 669 break;
238     case ::gig::dimension_portamentotime:
239 iliev 2012 DimValues[i] = pChannel->ControllerTable[5];
240 schoenebeck 669 break;
241     case ::gig::dimension_effect1:
242 iliev 2012 DimValues[i] = pChannel->ControllerTable[12];
243 schoenebeck 669 break;
244     case ::gig::dimension_effect2:
245 iliev 2012 DimValues[i] = pChannel->ControllerTable[13];
246 schoenebeck 669 break;
247     case ::gig::dimension_genpurpose1:
248 iliev 2012 DimValues[i] = pChannel->ControllerTable[16];
249 schoenebeck 669 break;
250     case ::gig::dimension_genpurpose2:
251 iliev 2012 DimValues[i] = pChannel->ControllerTable[17];
252 schoenebeck 669 break;
253     case ::gig::dimension_genpurpose3:
254 iliev 2012 DimValues[i] = pChannel->ControllerTable[18];
255 schoenebeck 669 break;
256     case ::gig::dimension_genpurpose4:
257 iliev 2012 DimValues[i] = pChannel->ControllerTable[19];
258 schoenebeck 669 break;
259     case ::gig::dimension_sustainpedal:
260 iliev 2012 DimValues[i] = pChannel->ControllerTable[64];
261 schoenebeck 669 break;
262     case ::gig::dimension_portamento:
263 iliev 2012 DimValues[i] = pChannel->ControllerTable[65];
264 schoenebeck 669 break;
265     case ::gig::dimension_sostenutopedal:
266 iliev 2012 DimValues[i] = pChannel->ControllerTable[66];
267 schoenebeck 669 break;
268     case ::gig::dimension_softpedal:
269 iliev 2012 DimValues[i] = pChannel->ControllerTable[67];
270 schoenebeck 669 break;
271     case ::gig::dimension_genpurpose5:
272 iliev 2012 DimValues[i] = pChannel->ControllerTable[80];
273 schoenebeck 669 break;
274     case ::gig::dimension_genpurpose6:
275 iliev 2012 DimValues[i] = pChannel->ControllerTable[81];
276 schoenebeck 669 break;
277     case ::gig::dimension_genpurpose7:
278 iliev 2012 DimValues[i] = pChannel->ControllerTable[82];
279 schoenebeck 669 break;
280     case ::gig::dimension_genpurpose8:
281 iliev 2012 DimValues[i] = pChannel->ControllerTable[83];
282 schoenebeck 669 break;
283     case ::gig::dimension_effect1depth:
284 iliev 2012 DimValues[i] = pChannel->ControllerTable[91];
285 schoenebeck 669 break;
286     case ::gig::dimension_effect2depth:
287 iliev 2012 DimValues[i] = pChannel->ControllerTable[92];
288 schoenebeck 669 break;
289     case ::gig::dimension_effect3depth:
290 iliev 2012 DimValues[i] = pChannel->ControllerTable[93];
291 schoenebeck 669 break;
292     case ::gig::dimension_effect4depth:
293 iliev 2012 DimValues[i] = pChannel->ControllerTable[94];
294 schoenebeck 669 break;
295     case ::gig::dimension_effect5depth:
296 iliev 2012 DimValues[i] = pChannel->ControllerTable[95];
297 schoenebeck 669 break;
298     case ::gig::dimension_none:
299     std::cerr << "gig::Engine::LaunchVoice() Error: dimension=none\n" << std::flush;
300     break;
301     default:
302     std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
303     }
304     }
305 persson 1038
306     // return if this is a release triggered voice and there is no
307     // releasetrigger dimension (could happen if an instrument
308     // change has occured between note on and off)
309     if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
310    
311 schoenebeck 669 ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
312    
313     // no need to continue if sample is silent
314     if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();
315    
316 schoenebeck 233 // allocate a new voice for the key
317 schoenebeck 271 Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();
318     if (itNewVoice) {
319 schoenebeck 233 // launch the new voice
320 iliev 2012 if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pDimRgn, VoiceType, iKeyGroup) < 0) {
321 schoenebeck 354 dmsg(4,("Voice not triggered\n"));
322 schoenebeck 271 pKey->pActiveVoices->free(itNewVoice);
323 schoenebeck 233 }
324 schoenebeck 239 else { // on success
325 schoenebeck 663 --VoiceSpawnsLeft;
326 schoenebeck 239 if (!pKey->Active) { // mark as active key
327     pKey->Active = true;
328 iliev 2012 pKey->itSelf = pChannel->pActiveKeys->allocAppend();
329 schoenebeck 271 *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
330 schoenebeck 239 }
331 schoenebeck 271 if (itNewVoice->KeyGroup) {
332 iliev 2012 uint** ppKeyGroup = &pChannel->ActiveKeyGroups[itNewVoice->KeyGroup];
333 schoenebeck 271 *ppKeyGroup = &*pKey->itSelf; // put key as the (new) active key to its key group
334 schoenebeck 239 }
335 schoenebeck 271 if (itNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
336     return itNewVoice; // success
337 schoenebeck 233 }
338     }
339 schoenebeck 285 else if (VoiceStealing) {
340 schoenebeck 460 // try to steal one voice
341 iliev 2012 int result = StealVoice(pChannel, itNoteOnEvent);
342 schoenebeck 473 if (!result) { // voice stolen successfully
343     // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
344     RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
345     if (itStealEvent) {
346     *itStealEvent = *itNoteOnEvent; // copy event
347     itStealEvent->Param.Note.Layer = iLayer;
348     itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
349     pKey->VoiceTheftsQueued++;
350     }
351     else dmsg(1,("Voice stealing queue full!\n"));
352 schoenebeck 285 }
353     }
354    
355 schoenebeck 271 return Pool<Voice>::Iterator(); // no free voice or error
356 schoenebeck 233 }
357    
358 schoenebeck 53 bool Engine::DiskStreamSupported() {
359     return true;
360     }
361    
362     String Engine::Description() {
363 iliev 2012 return "GigaSampler Format Engine";
364 schoenebeck 53 }
365    
366     String Engine::Version() {
367 iliev 2012 String s = "$Revision: 1.105 $";
368 schoenebeck 123 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
369 schoenebeck 53 }
370    
371     }} // namespace LinuxSampler::gig

  ViewVC Help
Powered by ViewVC