/[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 2611 - (hide annotations) (download)
Mon Jun 9 19:20:37 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 17989 byte(s)
* Fixed crash when loading an instrument script.
* Fixed "init" script handler only to be executed once:
  when the script was loaded.
* Fixed aftertouch script event which always had value zero
  and controller number was set to aftertouch value instead.
* gig Engine: Fixed handling of "smartmidi" dimension, which
  was recognized as "unknown" dimension.
* Fixed script function gig_set_dim_zone(): was accessing
  wrong event.
* ls_instr_script command line tool: is now not limited to
  core language scripts, but can now also parse sampler format
  dependent instrument scripts, with the respective specific
  built-in script variables and functions.
* ScriptVM: Fixed runtime behavior of "and" and "or" binary
  script expressions, which also evaluated the right hand side
  of the expression even if the left hand side already failed
  the overall expression semantic to become true.
* Bumped version (1.0.0.svn46).

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

Properties

Name Value
svn:keywords Revision

  ViewVC Help
Powered by ViewVC