/[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 2565 - (hide annotations) (download)
Tue May 20 12:21:39 2014 UTC (9 years, 11 months ago) by schoenebeck
File size: 16989 byte(s)
* Giga format: Fixed crash that happened with velocity split sounds
  under certain conditions (see also previous commit on libgig).
* Bumped version to 1.0.0.svn40.

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 persson 2072 * Copyright (C) 2005-2008 Christian Schoenebeck *
7     * Copyright (C) 2009-2010 Christian Schoenebeck and 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 schoenebeck 2559 void Engine::ProcessChannelPressure(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itChannelPressureEvent) {
113     // if required: engine global aftertouch handling (apart from the per voice handling)
114     }
115    
116     void Engine::ProcessPolyphonicKeyPressure(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNotePressureEvent) {
117     // if required: engine global aftertouch handling (apart from the per voice handling)
118     }
119    
120 iliev 2012 DiskThread* Engine::CreateDiskThread() {
121     return new DiskThread (
122     iMaxDiskStreams,
123     ((pAudioOutputDevice->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
124     &instruments
125     );
126 schoenebeck 412 }
127    
128 iliev 2012 void Engine::TriggerNewVoices (
129     LinuxSampler::EngineChannel* pEngineChannel,
130     RTList<Event>::Iterator& itNoteOnEvent,
131     bool HandleKeyGroupConflicts
132     ) {
133     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
134     // first, get total amount of required voices (dependant on amount of layers)
135     ::gig::Region* pRegion = pChannel->pInstrument->GetRegion(itNoteOnEvent->Param.Note.Key);
136     if (pRegion && !RegionSuspended(pRegion)) {
137     int voicesRequired = pRegion->Layers;
138     // now launch the required amount of voices
139     for (int i = 0; i < voicesRequired; i++)
140     LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);
141 schoenebeck 412 }
142 persson 438 }
143 schoenebeck 412
144 iliev 2012 void Engine::TriggerReleaseVoices (
145     LinuxSampler::EngineChannel* pEngineChannel,
146     RTList<Event>::Iterator& itNoteOffEvent
147     ) {
148     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
149     MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNoteOffEvent->Param.Note.Key];
150     // first, get total amount of required voices (dependant on amount of layers)
151     ::gig::Region* pRegion = pChannel->pInstrument->GetRegion(itNoteOffEvent->Param.Note.Key);
152     if (pRegion) {
153     int voicesRequired = pRegion->Layers;
154 schoenebeck 53
155 iliev 2012 // MIDI note-on velocity is used instead of note-off velocity
156     itNoteOffEvent->Param.Note.Velocity = pKey->Velocity;
157 schoenebeck 53
158 iliev 2012 // now launch the required amount of voices
159     for (int i = 0; i < voicesRequired; i++)
160     LaunchVoice(pChannel, itNoteOffEvent, i, true, false, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples
161 schoenebeck 53 }
162 schoenebeck 412 }
163    
164 iliev 2012 Pool<Voice>::Iterator Engine::LaunchVoice (
165     LinuxSampler::EngineChannel* pEngineChannel,
166     Pool<Event>::Iterator& itNoteOnEvent,
167     int iLayer,
168     bool ReleaseTriggerVoice,
169     bool VoiceStealing,
170     bool HandleKeyGroupConflicts
171     ) {
172     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
173     int MIDIKey = itNoteOnEvent->Param.Note.Key;
174     EngineChannel::MidiKey* pKey = &pChannel->pMIDIKeyInfo[MIDIKey];
175     ::gig::Region* pRegion = pChannel->pInstrument->GetRegion(MIDIKey);
176 schoenebeck 53
177 schoenebeck 668 // if nothing defined for this key
178     if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
179    
180 persson 2114 int iKeyGroup = pRegion->KeyGroup;
181     // only need to send a group event from the first voice in a layered region,
182     // as all layers in a region always belongs to the same key group
183     if (HandleKeyGroupConflicts && iLayer == 0) pChannel->HandleKeyGroupConflicts(iKeyGroup, itNoteOnEvent);
184 schoenebeck 669
185     Voice::type_t VoiceType = Voice::type_normal;
186    
187     // get current dimension values to select the right dimension region
188     //TODO: for stolen voices this dimension region selection block is processed twice, this should be changed
189     //FIXME: controller values for selecting the dimension region here are currently not sample accurate
190     uint DimValues[8] = { 0 };
191     for (int i = pRegion->Dimensions - 1; i >= 0; i--) {
192     switch (pRegion->pDimensionDefinitions[i].dimension) {
193     case ::gig::dimension_samplechannel:
194     DimValues[i] = 0; //TODO: we currently ignore this dimension
195     break;
196     case ::gig::dimension_layer:
197     DimValues[i] = iLayer;
198     break;
199     case ::gig::dimension_velocity:
200     DimValues[i] = itNoteOnEvent->Param.Note.Velocity;
201     break;
202     case ::gig::dimension_channelaftertouch:
203 iliev 2012 DimValues[i] = pChannel->ControllerTable[128];
204 schoenebeck 669 break;
205     case ::gig::dimension_releasetrigger:
206     VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;
207     DimValues[i] = (uint) ReleaseTriggerVoice;
208     break;
209     case ::gig::dimension_keyboard:
210 iliev 2012 DimValues[i] = (uint) (pChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);
211 schoenebeck 669 break;
212     case ::gig::dimension_roundrobin:
213 persson 2043 DimValues[i] = uint(*pChannel->pMIDIKeyInfo[MIDIKey].pRoundRobinIndex % pRegion->pDimensionDefinitions[i].zones); // RoundRobinIndex is incremented for each note on in this Region
214 schoenebeck 669 break;
215 persson 2043 case ::gig::dimension_roundrobinkeyboard:
216     DimValues[i] = uint(pChannel->RoundRobinIndex % pRegion->pDimensionDefinitions[i].zones); // RoundRobinIndex is incremented for each note on
217     break;
218 schoenebeck 669 case ::gig::dimension_random:
219 persson 2072 DimValues[i] = uint(Random() * pRegion->pDimensionDefinitions[i].zones);
220 schoenebeck 669 break;
221     case ::gig::dimension_modwheel:
222 iliev 2012 DimValues[i] = pChannel->ControllerTable[1];
223 schoenebeck 669 break;
224     case ::gig::dimension_breath:
225 iliev 2012 DimValues[i] = pChannel->ControllerTable[2];
226 schoenebeck 669 break;
227     case ::gig::dimension_foot:
228 iliev 2012 DimValues[i] = pChannel->ControllerTable[4];
229 schoenebeck 669 break;
230     case ::gig::dimension_portamentotime:
231 iliev 2012 DimValues[i] = pChannel->ControllerTable[5];
232 schoenebeck 669 break;
233     case ::gig::dimension_effect1:
234 iliev 2012 DimValues[i] = pChannel->ControllerTable[12];
235 schoenebeck 669 break;
236     case ::gig::dimension_effect2:
237 iliev 2012 DimValues[i] = pChannel->ControllerTable[13];
238 schoenebeck 669 break;
239     case ::gig::dimension_genpurpose1:
240 iliev 2012 DimValues[i] = pChannel->ControllerTable[16];
241 schoenebeck 669 break;
242     case ::gig::dimension_genpurpose2:
243 iliev 2012 DimValues[i] = pChannel->ControllerTable[17];
244 schoenebeck 669 break;
245     case ::gig::dimension_genpurpose3:
246 iliev 2012 DimValues[i] = pChannel->ControllerTable[18];
247 schoenebeck 669 break;
248     case ::gig::dimension_genpurpose4:
249 iliev 2012 DimValues[i] = pChannel->ControllerTable[19];
250 schoenebeck 669 break;
251     case ::gig::dimension_sustainpedal:
252 iliev 2012 DimValues[i] = pChannel->ControllerTable[64];
253 schoenebeck 669 break;
254     case ::gig::dimension_portamento:
255 iliev 2012 DimValues[i] = pChannel->ControllerTable[65];
256 schoenebeck 669 break;
257     case ::gig::dimension_sostenutopedal:
258 iliev 2012 DimValues[i] = pChannel->ControllerTable[66];
259 schoenebeck 669 break;
260     case ::gig::dimension_softpedal:
261 iliev 2012 DimValues[i] = pChannel->ControllerTable[67];
262 schoenebeck 669 break;
263     case ::gig::dimension_genpurpose5:
264 iliev 2012 DimValues[i] = pChannel->ControllerTable[80];
265 schoenebeck 669 break;
266     case ::gig::dimension_genpurpose6:
267 iliev 2012 DimValues[i] = pChannel->ControllerTable[81];
268 schoenebeck 669 break;
269     case ::gig::dimension_genpurpose7:
270 iliev 2012 DimValues[i] = pChannel->ControllerTable[82];
271 schoenebeck 669 break;
272     case ::gig::dimension_genpurpose8:
273 iliev 2012 DimValues[i] = pChannel->ControllerTable[83];
274 schoenebeck 669 break;
275     case ::gig::dimension_effect1depth:
276 iliev 2012 DimValues[i] = pChannel->ControllerTable[91];
277 schoenebeck 669 break;
278     case ::gig::dimension_effect2depth:
279 iliev 2012 DimValues[i] = pChannel->ControllerTable[92];
280 schoenebeck 669 break;
281     case ::gig::dimension_effect3depth:
282 iliev 2012 DimValues[i] = pChannel->ControllerTable[93];
283 schoenebeck 669 break;
284     case ::gig::dimension_effect4depth:
285 iliev 2012 DimValues[i] = pChannel->ControllerTable[94];
286 schoenebeck 669 break;
287     case ::gig::dimension_effect5depth:
288 iliev 2012 DimValues[i] = pChannel->ControllerTable[95];
289 schoenebeck 669 break;
290     case ::gig::dimension_none:
291     std::cerr << "gig::Engine::LaunchVoice() Error: dimension=none\n" << std::flush;
292     break;
293     default:
294     std::cerr << "gig::Engine::LaunchVoice() Error: Unknown dimension\n" << std::flush;
295     }
296     }
297 persson 1038
298     // return if this is a release triggered voice and there is no
299     // releasetrigger dimension (could happen if an instrument
300     // change has occured between note on and off)
301 persson 2115 if (ReleaseTriggerVoice && !(VoiceType & Voice::type_release_trigger)) return Pool<Voice>::Iterator();
302 persson 1038
303 schoenebeck 669 ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
304 schoenebeck 2565 if (!pDimRgn) return Pool<Voice>::Iterator(); // error (could not resolve dimension region)
305 schoenebeck 669
306     // no need to continue if sample is silent
307     if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();
308    
309 schoenebeck 233 // allocate a new voice for the key
310 schoenebeck 271 Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();
311 schoenebeck 285
312 iliev 2027 int res = InitNewVoice (
313     pChannel, pDimRgn, itNoteOnEvent, VoiceType, iLayer,
314     iKeyGroup, ReleaseTriggerVoice, VoiceStealing, itNewVoice
315     );
316     if (!res) return itNewVoice;
317    
318 schoenebeck 271 return Pool<Voice>::Iterator(); // no free voice or error
319 schoenebeck 233 }
320    
321 schoenebeck 53 bool Engine::DiskStreamSupported() {
322     return true;
323     }
324    
325     String Engine::Description() {
326 iliev 2012 return "GigaSampler Format Engine";
327 schoenebeck 53 }
328    
329     String Engine::Version() {
330 schoenebeck 2494 String s = "$Revision$";
331 schoenebeck 123 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
332 schoenebeck 53 }
333    
334     }} // namespace LinuxSampler::gig

Properties

Name Value
svn:keywords Revision

  ViewVC Help
Powered by ViewVC