/[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 2559 - (hide annotations) (download)
Sun May 18 17:38:25 2014 UTC (9 years, 11 months ago) by schoenebeck
File size: 16889 byte(s)
* Aftertouch: extended API to explicitly handle channel pressure and
  polyphonic key pressure events (so far polyphonic pressure was not
  supported at all, and channel pressure was rerouted as CC128 but not
  used so far).
* Gig Engine: Fixed support for 'aftertouch' attenuation controller.
* Bumped version (1.0.0.svn39).

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    
305     // no need to continue if sample is silent
306     if (!pDimRgn->pSample || !pDimRgn->pSample->SamplesTotal) return Pool<Voice>::Iterator();
307    
308 schoenebeck 233 // allocate a new voice for the key
309 schoenebeck 271 Pool<Voice>::Iterator itNewVoice = pKey->pActiveVoices->allocAppend();
310 schoenebeck 285
311 iliev 2027 int res = InitNewVoice (
312     pChannel, pDimRgn, itNoteOnEvent, VoiceType, iLayer,
313     iKeyGroup, ReleaseTriggerVoice, VoiceStealing, itNewVoice
314     );
315     if (!res) return itNewVoice;
316    
317 schoenebeck 271 return Pool<Voice>::Iterator(); // no free voice or error
318 schoenebeck 233 }
319    
320 schoenebeck 53 bool Engine::DiskStreamSupported() {
321     return true;
322     }
323    
324     String Engine::Description() {
325 iliev 2012 return "GigaSampler Format Engine";
326 schoenebeck 53 }
327    
328     String Engine::Version() {
329 schoenebeck 2494 String s = "$Revision$";
330 schoenebeck 123 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
331 schoenebeck 53 }
332    
333     }} // namespace LinuxSampler::gig

Properties

Name Value
svn:keywords Revision

  ViewVC Help
Powered by ViewVC