/[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 2115 - (show annotations) (download)
Thu Aug 12 15:36:15 2010 UTC (13 years, 8 months ago) by persson
File size: 9950 byte(s)
* sfz engine: added support for controller triggered regions
  (on_locc/on_hicc)
* sfz engine: added support for loop_mode=one_shot

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-2010 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 /**
32 * Reacts on supported control change commands (e.g. pitch bend wheel,
33 * modulation wheel, aftertouch).
34 *
35 * @param pEngineChannel - engine channel on which this event occured on
36 * @param itControlChangeEvent - controller, value and time stamp of the event
37 */
38 void Engine::ProcessControlChange (
39 LinuxSampler::EngineChannel* pEngineChannel,
40 Pool<Event>::Iterator& itControlChangeEvent
41 ) {
42 uint8_t cc = itControlChangeEvent->Param.CC.Controller;
43 dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", cc, itControlChangeEvent->Param.CC.Value));
44
45 EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
46
47 // update controller value in the engine channel's controller table
48 pChannel->ControllerTable[cc] = itControlChangeEvent->Param.CC.Value;
49
50 ProcessHardcodedControllers(pEngineChannel, itControlChangeEvent);
51
52 // handle FX send controllers
53 ProcessFxSendControllers(pChannel, itControlChangeEvent);
54
55 // handle control triggered regions: a control change event
56 // can trigger a new voice
57 if (pChannel->pInstrument && cc < 128) {
58
59 ::sfz::Query q;
60 q.chan = pChannel->MidiChannel();
61 q.key = 60;
62 q.vel = 127;
63 q.bend = pChannel->Pitch;
64 q.bpm = 0;
65 q.chanaft = pChannel->ControllerTable[128];
66 q.polyaft = 0;
67 q.prog = 0;
68 q.rand = Random();
69 q.cc = pChannel->ControllerTable;
70 q.timer = 0;
71 q.sw = pChannel->PressedKeys;
72 q.last_sw_key = pChannel->LastKeySwitch;
73 q.prev_sw_key = pChannel->LastKey;
74 q.trig = TRIGGER_ATTACK | TRIGGER_FIRST;
75
76 q.search(pChannel->pInstrument, cc);
77
78 int i = 0;
79 while (::sfz::Region* region = q.next()) {
80 if (!RegionSuspended(region)) {
81 itControlChangeEvent->Param.Note.Key = 60;
82 itControlChangeEvent->Param.Note.Velocity = 127;
83 itControlChangeEvent->Param.Note.pRegion = region;
84 LaunchVoice(pChannel, itControlChangeEvent, i, false, false, true);
85 }
86 i++;
87 }
88 }
89 }
90
91 DiskThread* Engine::CreateDiskThread() {
92 return new DiskThread (
93 iMaxDiskStreams,
94 ((pAudioOutputDevice->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
95 &instruments
96 );
97 }
98
99 void Engine::TriggerNewVoices (
100 LinuxSampler::EngineChannel* pEngineChannel,
101 RTList<Event>::Iterator& itNoteOnEvent,
102 bool HandleKeyGroupConflicts
103 ) {
104 EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
105 ::sfz::Query q;
106 q.chan = pChannel->MidiChannel();
107 q.key = itNoteOnEvent->Param.Note.Key;
108 q.vel = itNoteOnEvent->Param.Note.Velocity;
109 q.bend = pChannel->Pitch;
110 q.bpm = 0;
111 q.chanaft = pChannel->ControllerTable[128];
112 q.polyaft = 0;
113 q.prog = 0;
114 q.rand = Random();
115 q.cc = pChannel->ControllerTable;
116 q.timer = 0;
117 q.sw = pChannel->PressedKeys;
118 q.last_sw_key = pChannel->LastKeySwitch;
119 q.prev_sw_key = pChannel->LastKey;
120 q.trig = TRIGGER_ATTACK |
121 ((pChannel->LastKey != -1 &&
122 pChannel->PressedKeys[pChannel->LastKey] &&
123 pChannel->LastKey != q.key) ?
124 TRIGGER_LEGATO : TRIGGER_FIRST);
125
126 q.search(pChannel->pInstrument);
127
128 int i = 0;
129 while (::sfz::Region* region = q.next()) {
130 if (!RegionSuspended(region)) {
131 itNoteOnEvent->Param.Note.pRegion = region;
132 LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);
133 }
134 i++;
135 }
136 }
137
138 void Engine::TriggerReleaseVoices (
139 LinuxSampler::EngineChannel* pEngineChannel,
140 RTList<Event>::Iterator& itNoteOffEvent
141 ) {
142 EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
143 ::sfz::Query q;
144 q.chan = pChannel->MidiChannel();
145 q.key = itNoteOffEvent->Param.Note.Key;
146
147 // MIDI note-on velocity is used instead of note-off velocity
148 q.vel = pChannel->pMIDIKeyInfo[q.key].Velocity;
149 itNoteOffEvent->Param.Note.Velocity = q.vel;
150
151 q.bend = pChannel->Pitch;
152 q.bpm = 0;
153 q.chanaft = pChannel->ControllerTable[128];
154 q.polyaft = 0;
155 q.prog = 0;
156 q.rand = Random();
157 q.cc = pChannel->ControllerTable;
158 q.timer = 0;
159 q.sw = pChannel->PressedKeys;
160 q.last_sw_key = pChannel->LastKeySwitch;
161 q.prev_sw_key = pChannel->LastKey;
162 q.trig = TRIGGER_RELEASE;
163
164 q.search(pChannel->pInstrument);
165
166 // now launch the required amount of voices
167 int i = 0;
168 while (::sfz::Region* region = q.next()) {
169 itNoteOffEvent->Param.Note.pRegion = region;
170 LaunchVoice(pChannel, itNoteOffEvent, i, true, false, true); //FIXME: for the moment we don't perform voice stealing for release triggered samples
171 i++;
172 }
173 }
174
175 Pool<Voice>::Iterator Engine::LaunchVoice (
176 LinuxSampler::EngineChannel* pEngineChannel,
177 Pool<Event>::Iterator& itNoteOnEvent,
178 int iLayer,
179 bool ReleaseTriggerVoice,
180 bool VoiceStealing,
181 bool HandleKeyGroupConflicts
182 ) {
183 EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
184 int key = itNoteOnEvent->Param.Note.Key;
185 EngineChannel::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
186 ::sfz::Region* pRgn = static_cast< ::sfz::Region*>(itNoteOnEvent->Param.Note.pRegion);
187
188 Voice::type_t VoiceType =
189 itNoteOnEvent->Type == Event::type_control_change ? Voice::type_controller_triggered :
190 ReleaseTriggerVoice ? Voice::type_release_trigger :
191 iLayer == 0 ? Voice::type_release_trigger_required :
192 Voice::type_normal;
193 if (pRgn->loop_mode == ::sfz::ONE_SHOT) VoiceType |= Voice::type_one_shot;
194
195 Pool<Voice>::Iterator itNewVoice;
196
197 // no need to process if sample is silent
198 if (!pRgn->GetSample() || !pRgn->GetSample()->GetTotalFrameCount()) return Pool<Voice>::Iterator();
199
200 if (HandleKeyGroupConflicts) pChannel->HandleKeyGroupConflicts(pRgn->group, itNoteOnEvent);
201
202 // allocate a new voice for the key
203 itNewVoice = pKey->pActiveVoices->allocAppend();
204 int res = InitNewVoice (
205 pChannel, pRgn, itNoteOnEvent, VoiceType, iLayer,
206 pRgn->off_by, ReleaseTriggerVoice, VoiceStealing, itNewVoice
207 );
208 if (!res) return itNewVoice;
209
210 // return if this is a release triggered voice and there is no
211 // releasetrigger dimension (could happen if an instrument
212 // change has occured between note on and off)
213 //if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
214
215 return Pool<Voice>::Iterator(); // no free voice or error
216 }
217
218 bool Engine::DiskStreamSupported() {
219 return true;
220 }
221
222 String Engine::Description() {
223 return "SFZ Format Engine";
224 }
225
226 String Engine::Version() {
227 String s = "$Revision: 1.11 $";
228 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
229 }
230
231 }} // namespace LinuxSampler::sfz

  ViewVC Help
Powered by ViewVC