/[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 3219 - (hide annotations) (download)
Thu May 25 21:49:40 2017 UTC (6 years, 10 months ago) by schoenebeck
File size: 13932 byte(s)
* NKSP Fix: built-in script function "change_note()" did not
  (re)select the correct expected region.
* NKSP Fix: built-in script function "change_velo()" did not
  (re)select the correct subregion/dimension region
  (whatever term you are using for the sampler format of
   your choice).
* Bumped version (2.0.0.svn51).

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

Properties

Name Value
svn:keywords Revision

  ViewVC Help
Powered by ViewVC