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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2565 - (show 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 /***************************************************************************
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-2010 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 "Engine.h"
26 #include "EngineChannel.h"
27
28 namespace LinuxSampler { namespace gig {
29 Engine::Format Engine::GetEngineFormat() { return GIG; }
30
31 /**
32 * Reacts on supported control change commands (e.g. pitch bend wheel,
33 * modulation wheel, aftertouch).
34 *
35 * @param pEngineChannel - engine channel on which this event occured on
36 * @param itControlChangeEvent - controller, value and time stamp of the event
37 */
38 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
44 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
49 ::gig::MidiRule* rule;
50 for (int i = 0 ; (rule = pChannel->pInstrument->GetMidiRule(i)) ; i++) {
51
52 if (::gig::MidiRuleCtrlTrigger* ctrlTrigger =
53 dynamic_cast< ::gig::MidiRuleCtrlTrigger*>(rule)) {
54 if (itControlChangeEvent->Param.CC.Controller ==
55 ctrlTrigger->ControllerNumber) {
56
57 uint8_t oldCCValue = pChannel->ControllerTable[
58 itControlChangeEvent->Param.CC.Controller];
59 uint8_t newCCValue = itControlChangeEvent->Param.CC.Value;
60
61 for (int i = 0 ; i < ctrlTrigger->Triggers ; i++) {
62 ::gig::MidiRuleCtrlTrigger::trigger_t* pTrigger =
63 &ctrlTrigger->pTriggers[i];
64
65 // 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
74 RTList<Event>::Iterator itNewEvent = pGlobalEvents->allocAppend();
75 if (itNewEvent) {
76 *itNewEvent = *itControlChangeEvent;
77 itNewEvent->Param.Note.Key = pTrigger->Key;
78
79 if (pTrigger->NoteOff || pTrigger->Velocity == 0) {
80 itNewEvent->Type = Event::type_note_off;
81 itNewEvent->Param.Note.Velocity = 100;
82
83 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
92 ProcessNoteOn(pEngineChannel, itNewEvent);
93 }
94 }
95 else dmsg(1,("Event pool emtpy!\n"));
96 }
97 }
98 }
99 }
100 }
101 }
102
103 // update controller value in the engine channel's controller table
104 pChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
105
106 ProcessHardcodedControllers(pEngineChannel, itControlChangeEvent);
107
108 // handle FX send controllers
109 ProcessFxSendControllers(pChannel, itControlChangeEvent);
110 }
111
112 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 DiskThread* Engine::CreateDiskThread() {
121 return new DiskThread (
122 iMaxDiskStreams,
123 ((pAudioOutputDevice->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
124 &instruments
125 );
126 }
127
128 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 }
142 }
143
144 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
155 // MIDI note-on velocity is used instead of note-off velocity
156 itNoteOffEvent->Param.Note.Velocity = pKey->Velocity;
157
158 // 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 }
162 }
163
164 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
177 // if nothing defined for this key
178 if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
179
180 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
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 DimValues[i] = pChannel->ControllerTable[128];
204 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 DimValues[i] = (uint) (pChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones);
211 break;
212 case ::gig::dimension_roundrobin:
213 DimValues[i] = uint(*pChannel->pMIDIKeyInfo[MIDIKey].pRoundRobinIndex % pRegion->pDimensionDefinitions[i].zones); // RoundRobinIndex is incremented for each note on in this Region
214 break;
215 case ::gig::dimension_roundrobinkeyboard:
216 DimValues[i] = uint(pChannel->RoundRobinIndex % pRegion->pDimensionDefinitions[i].zones); // RoundRobinIndex is incremented for each note on
217 break;
218 case ::gig::dimension_random:
219 DimValues[i] = uint(Random() * pRegion->pDimensionDefinitions[i].zones);
220 break;
221 case ::gig::dimension_modwheel:
222 DimValues[i] = pChannel->ControllerTable[1];
223 break;
224 case ::gig::dimension_breath:
225 DimValues[i] = pChannel->ControllerTable[2];
226 break;
227 case ::gig::dimension_foot:
228 DimValues[i] = pChannel->ControllerTable[4];
229 break;
230 case ::gig::dimension_portamentotime:
231 DimValues[i] = pChannel->ControllerTable[5];
232 break;
233 case ::gig::dimension_effect1:
234 DimValues[i] = pChannel->ControllerTable[12];
235 break;
236 case ::gig::dimension_effect2:
237 DimValues[i] = pChannel->ControllerTable[13];
238 break;
239 case ::gig::dimension_genpurpose1:
240 DimValues[i] = pChannel->ControllerTable[16];
241 break;
242 case ::gig::dimension_genpurpose2:
243 DimValues[i] = pChannel->ControllerTable[17];
244 break;
245 case ::gig::dimension_genpurpose3:
246 DimValues[i] = pChannel->ControllerTable[18];
247 break;
248 case ::gig::dimension_genpurpose4:
249 DimValues[i] = pChannel->ControllerTable[19];
250 break;
251 case ::gig::dimension_sustainpedal:
252 DimValues[i] = pChannel->ControllerTable[64];
253 break;
254 case ::gig::dimension_portamento:
255 DimValues[i] = pChannel->ControllerTable[65];
256 break;
257 case ::gig::dimension_sostenutopedal:
258 DimValues[i] = pChannel->ControllerTable[66];
259 break;
260 case ::gig::dimension_softpedal:
261 DimValues[i] = pChannel->ControllerTable[67];
262 break;
263 case ::gig::dimension_genpurpose5:
264 DimValues[i] = pChannel->ControllerTable[80];
265 break;
266 case ::gig::dimension_genpurpose6:
267 DimValues[i] = pChannel->ControllerTable[81];
268 break;
269 case ::gig::dimension_genpurpose7:
270 DimValues[i] = pChannel->ControllerTable[82];
271 break;
272 case ::gig::dimension_genpurpose8:
273 DimValues[i] = pChannel->ControllerTable[83];
274 break;
275 case ::gig::dimension_effect1depth:
276 DimValues[i] = pChannel->ControllerTable[91];
277 break;
278 case ::gig::dimension_effect2depth:
279 DimValues[i] = pChannel->ControllerTable[92];
280 break;
281 case ::gig::dimension_effect3depth:
282 DimValues[i] = pChannel->ControllerTable[93];
283 break;
284 case ::gig::dimension_effect4depth:
285 DimValues[i] = pChannel->ControllerTable[94];
286 break;
287 case ::gig::dimension_effect5depth:
288 DimValues[i] = pChannel->ControllerTable[95];
289 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
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 if (ReleaseTriggerVoice && !(VoiceType & Voice::type_release_trigger)) return Pool<Voice>::Iterator();
302
303 ::gig::DimensionRegion* pDimRgn = pRegion->GetDimensionRegionByValue(DimValues);
304 if (!pDimRgn) return Pool<Voice>::Iterator(); // error (could not resolve dimension region)
305
306 // no need to continue if sample is silent
307 if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();
308
309 // allocate a new voice for the key
310 Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();
311
312 int res = InitNewVoice (
313 pChannel, pDimRgn, itNoteOnEvent, VoiceType, iLayer,
314 iKeyGroup, ReleaseTriggerVoice, VoiceStealing, itNewVoice
315 );
316 if (!res) return itNewVoice;
317
318 return Pool<Voice>::Iterator(); // no free voice or error
319 }
320
321 bool Engine::DiskStreamSupported() {
322 return true;
323 }
324
325 String Engine::Description() {
326 return "GigaSampler Format Engine";
327 }
328
329 String Engine::Version() {
330 String s = "$Revision$";
331 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
332 }
333
334 }} // namespace LinuxSampler::gig

Properties

Name Value
svn:keywords Revision

  ViewVC Help
Powered by ViewVC