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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2559 - (show 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 /***************************************************************************
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 * Copyright (C) 2009-2012 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 sfz {
29 Engine::Format Engine::GetEngineFormat() { return SFZ; }
30
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
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 uint8_t cc = itControlChangeEvent->Param.CC.Controller;
74 dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", cc, itControlChangeEvent->Param.CC.Value));
75
76 EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
77
78 // update controller value in the engine channel's controller table
79 pChannel->ControllerTable[cc] = itControlChangeEvent->Param.CC.Value;
80
81 ProcessHardcodedControllers(pEngineChannel, itControlChangeEvent);
82
83 // handle FX send controllers
84 ProcessFxSendControllers(pChannel, itControlChangeEvent);
85
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 q.chan = itControlChangeEvent->Param.CC.Channel + 1;
92 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 }
121
122 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 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 ::sfz::Query q;
145 q.chan = itNoteOnEvent->Param.Note.Channel + 1;
146 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
165 q.search(pChannel->pInstrument);
166
167 int i = 0;
168 while (::sfz::Region* region = q.next()) {
169 if (!RegionSuspended(region)) {
170 itNoteOnEvent->Param.Note.pRegion = region;
171 LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);
172 }
173 i++;
174 }
175 }
176
177 void Engine::TriggerReleaseVoices (
178 LinuxSampler::EngineChannel* pEngineChannel,
179 RTList<Event>::Iterator& itNoteOffEvent
180 ) {
181 EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
182 ::sfz::Query q;
183 q.chan = itNoteOffEvent->Param.Note.Channel + 1;
184 q.key = itNoteOffEvent->Param.Note.Key;
185
186 // MIDI note-on velocity is used instead of note-off velocity
187 q.vel = pChannel->pMIDIKeyInfo[q.key].Velocity;
188 itNoteOffEvent->Param.Note.Velocity = q.vel;
189
190 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
203 q.search(pChannel->pInstrument);
204
205 // now launch the required amount of voices
206 int i = 0;
207 while (::sfz::Region* region = q.next()) {
208 itNoteOffEvent->Param.Note.pRegion = region;
209 LaunchVoice(pChannel, itNoteOffEvent, i, true, false, true); //FIXME: for the moment we don't perform voice stealing for release triggered samples
210 i++;
211 }
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 ::sfz::Region* pRgn = static_cast< ::sfz::Region*>(itNoteOnEvent->Param.Note.pRegion);
226
227 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 Pool<Voice>::Iterator itNewVoice;
235
236 if (HandleKeyGroupConflicts) pChannel->HandleKeyGroupConflicts(pRgn->group, itNoteOnEvent);
237
238 // no need to process if sample is silent
239 if (!pRgn->GetSample(false) || !pRgn->GetSample()->GetTotalFrameCount()) return Pool<Voice>::Iterator();
240
241 // allocate a new voice for the key
242 itNewVoice = pKey->pActiveVoices->allocAppend();
243 int res = InitNewVoice (
244 pChannel, pRgn, itNoteOnEvent, VoiceType, iLayer,
245 pRgn->off_by, ReleaseTriggerVoice, VoiceStealing, itNewVoice
246 );
247 if (!res) return itNewVoice;
248
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 return Pool<Voice>::Iterator(); // no free voice or error
255 }
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 String s = "$Revision$";
267 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