/[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 2879 - (hide annotations) (download)
Tue Apr 19 14:07:53 2016 UTC (8 years ago) by schoenebeck
File size: 13070 byte(s)
* All engines: Active voices are now internally grouped to "Note" objects,
  instead of being directly assigned to a keyboard key. This allows more
  fine graded processing of voices, which is i.e. required for certain
  instrument script features.
* Built-in script function "play_note()": Added support for passing
  special value -1 for "duration-us" argument, which will cause the
  triggered note to be released once the original note was released.
* Bumped version (2.0.0.svn3).

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 schoenebeck 2879 NoteIterator itNewNote;
110    
111 persson 2115 int i = 0;
112     while (::sfz::Region* region = q.next()) {
113     if (!RegionSuspended(region)) {
114     itControlChangeEvent->Param.Note.Key = 60;
115     itControlChangeEvent->Param.Note.Velocity = 127;
116     itControlChangeEvent->Param.Note.pRegion = region;
117 schoenebeck 2879 if (!itNewNote) {
118     const note_id_t noteID = LaunchNewNote(pEngineChannel, &*itControlChangeEvent);
119     itNewNote = GetNotePool()->fromID(noteID);
120     if (!itNewNote) {
121     dmsg(1,("sfz::Engine: Note pool empty!\n"));
122     return;
123     }
124     }
125     VoiceIterator itNewVoice =
126     LaunchVoice(pChannel, itControlChangeEvent, i, false, false, true);
127     if (itNewVoice)
128     itNewVoice.moveToEndOf(itNewNote->pActiveVoices);
129 persson 2115 }
130     i++;
131     }
132     }
133 iliev 2012 }
134    
135 schoenebeck 2559 void Engine::ProcessChannelPressure(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itChannelPressureEvent) {
136     // if required: engine global aftertouch handling (apart from the per voice handling)
137     }
138    
139     void Engine::ProcessPolyphonicKeyPressure(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNotePressureEvent) {
140     // if required: engine global aftertouch handling (apart from the per voice handling)
141     }
142    
143 iliev 2012 DiskThread* Engine::CreateDiskThread() {
144     return new DiskThread (
145     iMaxDiskStreams,
146     ((pAudioOutputDevice->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
147     &instruments
148     );
149     }
150    
151     void Engine::TriggerNewVoices (
152     LinuxSampler::EngineChannel* pEngineChannel,
153     RTList<Event>::Iterator& itNoteOnEvent,
154     bool HandleKeyGroupConflicts
155     ) {
156     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
157 schoenebeck 2879 MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
158 persson 2106 ::sfz::Query q;
159 persson 2317 q.chan = itNoteOnEvent->Param.Note.Channel + 1;
160 persson 2101 q.key = itNoteOnEvent->Param.Note.Key;
161     q.vel = itNoteOnEvent->Param.Note.Velocity;
162     q.bend = pChannel->Pitch;
163     q.bpm = 0;
164     q.chanaft = pChannel->ControllerTable[128];
165     q.polyaft = 0;
166     q.prog = 0;
167     q.rand = Random();
168     q.cc = pChannel->ControllerTable;
169     q.timer = 0;
170     q.sw = pChannel->PressedKeys;
171     q.last_sw_key = pChannel->LastKeySwitch;
172     q.prev_sw_key = pChannel->LastKey;
173     q.trig = TRIGGER_ATTACK |
174     ((pChannel->LastKey != -1 &&
175     pChannel->PressedKeys[pChannel->LastKey] &&
176     pChannel->LastKey != q.key) ?
177     TRIGGER_LEGATO : TRIGGER_FIRST);
178 iliev 2012
179 persson 2106 q.search(pChannel->pInstrument);
180    
181 schoenebeck 2879 NoteIterator itNote = GetNotePool()->fromID(itNoteOnEvent->Param.Note.ID);
182     if (!itNote) {
183     dmsg(1,("sfz::Engine: No Note object for triggering new voices!\n"));
184     return;
185     }
186    
187 persson 2101 int i = 0;
188     while (::sfz::Region* region = q.next()) {
189     if (!RegionSuspended(region)) {
190     itNoteOnEvent->Param.Note.pRegion = region;
191 schoenebeck 2879 VoiceIterator itNewVoice =
192     LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);
193     if (itNewVoice)
194     itNewVoice.moveToEndOf(itNote->pActiveVoices);
195 iliev 2012 }
196 persson 2101 i++;
197 iliev 2012 }
198     }
199    
200     void Engine::TriggerReleaseVoices (
201     LinuxSampler::EngineChannel* pEngineChannel,
202     RTList<Event>::Iterator& itNoteOffEvent
203     ) {
204     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
205 persson 2106 ::sfz::Query q;
206 persson 2317 q.chan = itNoteOffEvent->Param.Note.Channel + 1;
207 persson 2101 q.key = itNoteOffEvent->Param.Note.Key;
208 persson 2061
209     // MIDI note-on velocity is used instead of note-off velocity
210 persson 2101 q.vel = pChannel->pMIDIKeyInfo[q.key].Velocity;
211     itNoteOffEvent->Param.Note.Velocity = q.vel;
212 persson 2061
213 persson 2101 q.bend = pChannel->Pitch;
214     q.bpm = 0;
215     q.chanaft = pChannel->ControllerTable[128];
216     q.polyaft = 0;
217     q.prog = 0;
218     q.rand = Random();
219     q.cc = pChannel->ControllerTable;
220     q.timer = 0;
221     q.sw = pChannel->PressedKeys;
222     q.last_sw_key = pChannel->LastKeySwitch;
223     q.prev_sw_key = pChannel->LastKey;
224     q.trig = TRIGGER_RELEASE;
225 iliev 2012
226 persson 2106 q.search(pChannel->pInstrument);
227    
228 schoenebeck 2879 NoteIterator itNote = GetNotePool()->fromID(itNoteOffEvent->Param.Note.ID);
229     if (!itNote) {
230     dmsg(1,("sfz::Engine: No Note object for triggering new release voices!\n"));
231     return;
232     }
233    
234 iliev 2012 // now launch the required amount of voices
235 persson 2101 int i = 0;
236     while (::sfz::Region* region = q.next()) {
237     itNoteOffEvent->Param.Note.pRegion = region;
238 schoenebeck 2879 VoiceIterator itNewVoice =
239     LaunchVoice(pChannel, itNoteOffEvent, i, true, false, true); //FIXME: for the moment we don't perform voice stealing for release triggered samples
240     if (itNewVoice)
241     itNewVoice.moveToEndOf(itNote->pActiveVoices);
242 persson 2101 i++;
243 iliev 2012 }
244     }
245    
246     Pool<Voice>::Iterator Engine::LaunchVoice (
247     LinuxSampler::EngineChannel* pEngineChannel,
248     Pool<Event>::Iterator& itNoteOnEvent,
249     int iLayer,
250     bool ReleaseTriggerVoice,
251     bool VoiceStealing,
252     bool HandleKeyGroupConflicts
253     ) {
254     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
255     int key = itNoteOnEvent->Param.Note.Key;
256 schoenebeck 2879 //EngineChannel::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
257 persson 2115 ::sfz::Region* pRgn = static_cast< ::sfz::Region*>(itNoteOnEvent->Param.Note.pRegion);
258 iliev 2012
259 persson 2115 Voice::type_t VoiceType =
260     itNoteOnEvent->Type == Event::type_control_change ? Voice::type_controller_triggered :
261     ReleaseTriggerVoice ? Voice::type_release_trigger :
262     iLayer == 0 ? Voice::type_release_trigger_required :
263     Voice::type_normal;
264     if (pRgn->loop_mode == ::sfz::ONE_SHOT) VoiceType |= Voice::type_one_shot;
265    
266 iliev 2012 Pool<Voice>::Iterator itNewVoice;
267    
268 persson 2317 if (HandleKeyGroupConflicts) pChannel->HandleKeyGroupConflicts(pRgn->group, itNoteOnEvent);
269    
270 iliev 2012 // no need to process if sample is silent
271 persson 2317 if (!pRgn->GetSample(false) || !pRgn->GetSample()->GetTotalFrameCount()) return Pool<Voice>::Iterator();
272 iliev 2012
273     // allocate a new voice for the key
274 schoenebeck 2879 itNewVoice = GetVoicePool()->allocAppend();
275 iliev 2027 int res = InitNewVoice (
276     pChannel, pRgn, itNoteOnEvent, VoiceType, iLayer,
277 persson 2114 pRgn->off_by, ReleaseTriggerVoice, VoiceStealing, itNewVoice
278 iliev 2027 );
279     if (!res) return itNewVoice;
280 iliev 2012
281     // return if this is a release triggered voice and there is no
282     // releasetrigger dimension (could happen if an instrument
283     // change has occured between note on and off)
284     //if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
285    
286 iliev 2027 return Pool<Voice>::Iterator(); // no free voice or error
287 iliev 2012 }
288    
289     bool Engine::DiskStreamSupported() {
290     return true;
291     }
292    
293     String Engine::Description() {
294     return "SFZ Format Engine";
295     }
296    
297     String Engine::Version() {
298 schoenebeck 2494 String s = "$Revision$";
299 iliev 2012 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
300     }
301    
302     }} // namespace LinuxSampler::sfz

Properties

Name Value
svn:keywords Revision

  ViewVC Help
Powered by ViewVC