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

Annotation of /linuxsampler/trunk/src/engines/sfz/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: 11660 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 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6     * Copyright (C) 2005-2009 Christian Schoenebeck *
7 persson 2317 * Copyright (C) 2009-2012 Grigor Iliev *
8 iliev 2012 * *
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 sfz {
29     Engine::Format Engine::GetEngineFormat() { return SFZ; }
30 iliev 2244
31     Engine::Engine() {
32     pCCPool = new Pool<CCSignalUnit::CC>(GLOBAL_MAX_VOICES * MaxCCPerVoice);
33     pSmootherPool = new Pool<Smoother>(GLOBAL_MAX_VOICES * MaxCCPerVoice);
34     for (VoiceIterator iterVoice = GetVoicePool()->allocAppend(); iterVoice == GetVoicePool()->last(); iterVoice = GetVoicePool()->allocAppend()) {
35     (static_cast<SfzSignalUnitRack*>(iterVoice->pSignalUnitRack))->InitRTLists();
36     }
37     GetVoicePool()->clear();
38     }
39    
40     Engine::~Engine() {
41     if (pCCPool) {
42     pCCPool->clear();
43     delete pCCPool;
44     }
45    
46     if (pSmootherPool) {
47     pSmootherPool->clear();
48     delete pSmootherPool;
49     }
50     }
51    
52     void Engine::PostSetMaxVoices(int iVoices) {
53     pCCPool->resizePool(iVoices * MaxCCPerVoice);
54     pSmootherPool->resizePool(iVoices * MaxCCPerVoice);
55    
56     for (VoiceIterator iterVoice = GetVoicePool()->allocAppend(); iterVoice == GetVoicePool()->last(); iterVoice = GetVoicePool()->allocAppend()) {
57     (static_cast<SfzSignalUnitRack*>(iterVoice->pSignalUnitRack))->InitRTLists();
58     }
59     GetVoicePool()->clear();
60     }
61 iliev 2012
62     /**
63     * Reacts on supported control change commands (e.g. pitch bend wheel,
64     * modulation wheel, aftertouch).
65     *
66     * @param pEngineChannel - engine channel on which this event occured on
67     * @param itControlChangeEvent - controller, value and time stamp of the event
68     */
69     void Engine::ProcessControlChange (
70     LinuxSampler::EngineChannel* pEngineChannel,
71     Pool<Event>::Iterator& itControlChangeEvent
72     ) {
73 persson 2115 uint8_t cc = itControlChangeEvent->Param.CC.Controller;
74     dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", cc, itControlChangeEvent->Param.CC.Value));
75 iliev 2012
76 persson 2106 EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
77 iliev 2012
78     // update controller value in the engine channel's controller table
79 persson 2115 pChannel->ControllerTable[cc] = itControlChangeEvent->Param.CC.Value;
80 iliev 2012
81     ProcessHardcodedControllers(pEngineChannel, itControlChangeEvent);
82    
83     // handle FX send controllers
84     ProcessFxSendControllers(pChannel, itControlChangeEvent);
85 persson 2115
86     // handle control triggered regions: a control change event
87     // can trigger a new voice
88     if (pChannel->pInstrument && cc < 128) {
89    
90     ::sfz::Query q;
91 persson 2317 q.chan = itControlChangeEvent->Param.CC.Channel + 1;
92 persson 2115 q.key = 60;
93     q.vel = 127;
94     q.bend = pChannel->Pitch;
95     q.bpm = 0;
96     q.chanaft = pChannel->ControllerTable[128];
97     q.polyaft = 0;
98     q.prog = 0;
99     q.rand = Random();
100     q.cc = pChannel->ControllerTable;
101     q.timer = 0;
102     q.sw = pChannel->PressedKeys;
103     q.last_sw_key = pChannel->LastKeySwitch;
104     q.prev_sw_key = pChannel->LastKey;
105     q.trig = TRIGGER_ATTACK | TRIGGER_FIRST;
106    
107     q.search(pChannel->pInstrument, cc);
108    
109     int i = 0;
110     while (::sfz::Region* region = q.next()) {
111     if (!RegionSuspended(region)) {
112     itControlChangeEvent->Param.Note.Key = 60;
113     itControlChangeEvent->Param.Note.Velocity = 127;
114     itControlChangeEvent->Param.Note.pRegion = region;
115     LaunchVoice(pChannel, itControlChangeEvent, i, false, false, true);
116     }
117     i++;
118     }
119     }
120 iliev 2012 }
121    
122 schoenebeck 2559 void Engine::ProcessChannelPressure(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itChannelPressureEvent) {
123     // if required: engine global aftertouch handling (apart from the per voice handling)
124     }
125    
126     void Engine::ProcessPolyphonicKeyPressure(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNotePressureEvent) {
127     // if required: engine global aftertouch handling (apart from the per voice handling)
128     }
129    
130 iliev 2012 DiskThread* Engine::CreateDiskThread() {
131     return new DiskThread (
132     iMaxDiskStreams,
133     ((pAudioOutputDevice->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
134     &instruments
135     );
136     }
137    
138     void Engine::TriggerNewVoices (
139     LinuxSampler::EngineChannel* pEngineChannel,
140     RTList<Event>::Iterator& itNoteOnEvent,
141     bool HandleKeyGroupConflicts
142     ) {
143     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
144 persson 2106 ::sfz::Query q;
145 persson 2317 q.chan = itNoteOnEvent->Param.Note.Channel + 1;
146 persson 2101 q.key = itNoteOnEvent->Param.Note.Key;
147     q.vel = itNoteOnEvent->Param.Note.Velocity;
148     q.bend = pChannel->Pitch;
149     q.bpm = 0;
150     q.chanaft = pChannel->ControllerTable[128];
151     q.polyaft = 0;
152     q.prog = 0;
153     q.rand = Random();
154     q.cc = pChannel->ControllerTable;
155     q.timer = 0;
156     q.sw = pChannel->PressedKeys;
157     q.last_sw_key = pChannel->LastKeySwitch;
158     q.prev_sw_key = pChannel->LastKey;
159     q.trig = TRIGGER_ATTACK |
160     ((pChannel->LastKey != -1 &&
161     pChannel->PressedKeys[pChannel->LastKey] &&
162     pChannel->LastKey != q.key) ?
163     TRIGGER_LEGATO : TRIGGER_FIRST);
164 iliev 2012
165 persson 2106 q.search(pChannel->pInstrument);
166    
167 persson 2101 int i = 0;
168     while (::sfz::Region* region = q.next()) {
169     if (!RegionSuspended(region)) {
170     itNoteOnEvent->Param.Note.pRegion = region;
171 iliev 2012 LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);
172     }
173 persson 2101 i++;
174 iliev 2012 }
175     }
176    
177     void Engine::TriggerReleaseVoices (
178     LinuxSampler::EngineChannel* pEngineChannel,
179     RTList<Event>::Iterator& itNoteOffEvent
180     ) {
181     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
182 persson 2106 ::sfz::Query q;
183 persson 2317 q.chan = itNoteOffEvent->Param.Note.Channel + 1;
184 persson 2101 q.key = itNoteOffEvent->Param.Note.Key;
185 persson 2061
186     // MIDI note-on velocity is used instead of note-off velocity
187 persson 2101 q.vel = pChannel->pMIDIKeyInfo[q.key].Velocity;
188     itNoteOffEvent->Param.Note.Velocity = q.vel;
189 persson 2061
190 persson 2101 q.bend = pChannel->Pitch;
191     q.bpm = 0;
192     q.chanaft = pChannel->ControllerTable[128];
193     q.polyaft = 0;
194     q.prog = 0;
195     q.rand = Random();
196     q.cc = pChannel->ControllerTable;
197     q.timer = 0;
198     q.sw = pChannel->PressedKeys;
199     q.last_sw_key = pChannel->LastKeySwitch;
200     q.prev_sw_key = pChannel->LastKey;
201     q.trig = TRIGGER_RELEASE;
202 iliev 2012
203 persson 2106 q.search(pChannel->pInstrument);
204    
205 iliev 2012 // now launch the required amount of voices
206 persson 2101 int i = 0;
207     while (::sfz::Region* region = q.next()) {
208     itNoteOffEvent->Param.Note.pRegion = region;
209 persson 2114 LaunchVoice(pChannel, itNoteOffEvent, i, true, false, true); //FIXME: for the moment we don't perform voice stealing for release triggered samples
210 persson 2101 i++;
211 iliev 2012 }
212     }
213    
214     Pool<Voice>::Iterator Engine::LaunchVoice (
215     LinuxSampler::EngineChannel* pEngineChannel,
216     Pool<Event>::Iterator& itNoteOnEvent,
217     int iLayer,
218     bool ReleaseTriggerVoice,
219     bool VoiceStealing,
220     bool HandleKeyGroupConflicts
221     ) {
222     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
223     int key = itNoteOnEvent->Param.Note.Key;
224     EngineChannel::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
225 persson 2115 ::sfz::Region* pRgn = static_cast< ::sfz::Region*>(itNoteOnEvent->Param.Note.pRegion);
226 iliev 2012
227 persson 2115 Voice::type_t VoiceType =
228     itNoteOnEvent->Type == Event::type_control_change ? Voice::type_controller_triggered :
229     ReleaseTriggerVoice ? Voice::type_release_trigger :
230     iLayer == 0 ? Voice::type_release_trigger_required :
231     Voice::type_normal;
232     if (pRgn->loop_mode == ::sfz::ONE_SHOT) VoiceType |= Voice::type_one_shot;
233    
234 iliev 2012 Pool<Voice>::Iterator itNewVoice;
235    
236 persson 2317 if (HandleKeyGroupConflicts) pChannel->HandleKeyGroupConflicts(pRgn->group, itNoteOnEvent);
237    
238 iliev 2012 // no need to process if sample is silent
239 persson 2317 if (!pRgn->GetSample(false) || !pRgn->GetSample()->GetTotalFrameCount()) return Pool<Voice>::Iterator();
240 iliev 2012
241     // allocate a new voice for the key
242     itNewVoice = pKey->pActiveVoices->allocAppend();
243 iliev 2027 int res = InitNewVoice (
244     pChannel, pRgn, itNoteOnEvent, VoiceType, iLayer,
245 persson 2114 pRgn->off_by, ReleaseTriggerVoice, VoiceStealing, itNewVoice
246 iliev 2027 );
247     if (!res) return itNewVoice;
248 iliev 2012
249     // return if this is a release triggered voice and there is no
250     // releasetrigger dimension (could happen if an instrument
251     // change has occured between note on and off)
252     //if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
253    
254 iliev 2027 return Pool<Voice>::Iterator(); // no free voice or error
255 iliev 2012 }
256    
257     bool Engine::DiskStreamSupported() {
258     return true;
259     }
260    
261     String Engine::Description() {
262     return "SFZ Format Engine";
263     }
264    
265     String Engine::Version() {
266 schoenebeck 2494 String s = "$Revision$";
267 iliev 2012 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
268     }
269    
270     }} // namespace LinuxSampler::sfz

Properties

Name Value
svn:keywords Revision

  ViewVC Help
Powered by ViewVC