/[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 2600 - (hide annotations) (download)
Sat Jun 7 00:16:03 2014 UTC (9 years, 10 months ago) by schoenebeck
File size: 17675 byte(s)
* Implemented built-in instrument script function "set_controller()".
* Fixed built-in script functions "ignore_event()" and
  "ignore_controller()".
* Added extended instrument script VM for the Gigasampler/GigaStudio format
  sampler engine, which extends the general instrument script VM with Giga
  format specific variables and functions.
* Giga format instrument scripts: added built-in script int constant
  variables $GIG_DIM_CHANNEL, $GIG_DIM_LAYER, $GIG_DIM_VELOCITY,
  $GIG_DIM_AFTERTOUCH, $GIG_DIM_RELEASE, $GIG_DIM_KEYBOARD,
  $GIG_DIM_ROUNDROBIN, $GIG_DIM_RANDOM, $GIG_DIM_SMARTMIDI,
  $GIG_DIM_ROUNDROBINKEY, $GIG_DIM_MODWHEEL, $GIG_DIM_BREATH,
  $GIG_DIM_FOOT, $GIG_DIM_PORTAMENTOTIME, $GIG_DIM_EFFECT1,
  $GIG_DIM_EFFECT2, $GIG_DIM_GENPURPOSE1, $GIG_DIM_GENPURPOSE2,
  $GIG_DIM_GENPURPOSE3, $GIG_DIM_GENPURPOSE4, $GIG_DIM_SUSTAIN,
  $GIG_DIM_PORTAMENTO, $GIG_DIM_SOSTENUTO, $GIG_DIM_SOFT,
  $GIG_DIM_GENPURPOSE5, $GIG_DIM_GENPURPOSE6, $GIG_DIM_GENPURPOSE7,
  $GIG_DIM_GENPURPOSE8, $GIG_DIM_EFFECT1DEPTH, $GIG_DIM_EFFECT2DEPTH,
  $GIG_DIM_EFFECT3DEPTH, $GIG_DIM_EFFECT4DEPTH, $GIG_DIM_EFFECT5DEPTH.
* Giga format instrument scripts: Implemented built-in script function
  "gig_set_dim_zone(event_id, dimension, zone)", which allows to override
  dimension zone(s) for new voices.
* Bumped version (1.0.0.svn45).

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

Properties

Name Value
svn:keywords Revision

  ViewVC Help
Powered by ViewVC