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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2086 by persson, Sun Apr 25 12:51:30 2010 UTC revision 3219 by schoenebeck, Thu May 25 21:49:40 2017 UTC
# Line 4  Line 4 
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2009 Christian Schoenebeck                         *   *   Copyright (C) 2005-2009 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2010 Grigor Iliev                                  *   *   Copyright (C) 2009-2012 Grigor Iliev                                  *
8   *                                                                         *   *                                                                         *
9   *   This program is free software; you can redistribute it and/or modify  *   *   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  *   *   it under the terms of the GNU General Public License as published by  *
# Line 24  Line 24 
24    
25  #include "Engine.h"  #include "Engine.h"
26  #include "EngineChannel.h"  #include "EngineChannel.h"
27    #include "InstrumentScriptVM.h"
28    
29  namespace LinuxSampler { namespace sfz {  namespace LinuxSampler { namespace sfz {
30      Engine::Format Engine::GetEngineFormat() { return SFZ; }      Engine::Format Engine::GetEngineFormat() { return SFZ; }
31    
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        
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    
69      /**      /**
70       *  Reacts on supported control change commands (e.g. pitch bend wheel,       *  Reacts on supported control change commands (e.g. pitch bend wheel,
71       *  modulation wheel, aftertouch).       *  modulation wheel, aftertouch).
# Line 39  namespace LinuxSampler { namespace sfz { Line 77  namespace LinuxSampler { namespace sfz {
77          LinuxSampler::EngineChannel*  pEngineChannel,          LinuxSampler::EngineChannel*  pEngineChannel,
78          Pool<Event>::Iterator&        itControlChangeEvent          Pool<Event>::Iterator&        itControlChangeEvent
79      ) {      ) {
80          dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));          uint8_t cc = itControlChangeEvent->Param.CC.Controller;
81            dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", cc, itControlChangeEvent->Param.CC.Value));
         EngineChannel* pChannel = dynamic_cast<EngineChannel*>(pEngineChannel);  
         // handle the "control triggered" MIDI rule: a control change  
         // event can trigger a new note on or note off event  
         if (pChannel->pInstrument) {  
82    
83              // TODO:          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
         }  
84    
85          // update controller value in the engine channel's controller table          // update controller value in the engine channel's controller table
86          pChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;          pChannel->ControllerTable[cc] = itControlChangeEvent->Param.CC.Value;
87    
88          ProcessHardcodedControllers(pEngineChannel, itControlChangeEvent);          ProcessHardcodedControllers(pEngineChannel, itControlChangeEvent);
89    
90          // handle FX send controllers          // handle FX send controllers
91          ProcessFxSendControllers(pChannel, itControlChangeEvent);          ProcessFxSendControllers(pChannel, itControlChangeEvent);
92    
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                q.chan        = itControlChangeEvent->Param.CC.Channel + 1;
99                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                NoteIterator itNewNote;
117    
118                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                        if (!itNewNote) {
125                            const note_id_t noteID = LaunchNewNote(pEngineChannel, itControlChangeEvent);
126                            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                    }
137                    i++;
138                }
139            }
140        }
141    
142        void Engine::ProcessChannelPressure(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itChannelPressureEvent) {
143            // forward this to the CC routine, so it updates the current aftertouch value
144            ProcessControlChange(pEngineChannel, itChannelPressureEvent);
145    
146            // 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      DiskThread* Engine::CreateDiskThread() {      DiskThread* Engine::CreateDiskThread() {
# Line 71  namespace LinuxSampler { namespace sfz { Line 163  namespace LinuxSampler { namespace sfz {
163          RTList<Event>::Iterator&     itNoteOnEvent,          RTList<Event>::Iterator&     itNoteOnEvent,
164          bool                         HandleKeyGroupConflicts          bool                         HandleKeyGroupConflicts
165      ) {      ) {
166            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          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
172            //MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
173          uint8_t  chan     = pChannel->MidiChannel();          ::sfz::Query q;
174          int      key      = itNoteOnEvent->Param.Note.Key;          q.chan        = itNoteOnEvent->Param.Note.Channel + 1;
175          uint8_t  vel      = itNoteOnEvent->Param.Note.Velocity;          q.key         = itNote->cause.Param.Note.Key; //itNoteOnEvent->Param.Note.Key; <- using note object instead, since note nr might been modified by script
176          int      bend     = pChannel->Pitch;          q.vel         = itNote->cause.Param.Note.Velocity; //itNoteOnEvent->Param.Note.Velocity; <- using note object instead, since velocity might been modified by script
177          uint8_t  chanaft  = pChannel->ControllerTable[128];          q.bend        = pChannel->Pitch;
178          uint8_t* cc       = pChannel->ControllerTable;          q.bpm         = 0;
179          ::sfz::trigger_t trig = TRIGGER_ATTACK |          q.chanaft     = pChannel->ControllerTable[128];
180                ((pChannel->LastKey != -1 &&          q.polyaft     = 0;
181                  pChannel->PressedKeys[pChannel->LastKey] &&          q.prog        = 0;
182                  pChannel->LastKey != key) ?          q.rand        = Random();
183                 TRIGGER_LEGATO : TRIGGER_FIRST);          q.cc          = pChannel->ControllerTable;
184            q.timer       = 0;
185          pChannel->regionsTemp = pChannel->pInstrument->GetRegionsOnKey (          q.sw          = pChannel->PressedKeys;
186              chan, key, vel, bend, 0, chanaft, 0, 0, Random(), trig, cc,          q.last_sw_key = pChannel->LastKeySwitch;
187              0.0f, pChannel->PressedKeys, pChannel->LastKeySwitch, pChannel->LastKey          q.prev_sw_key = pChannel->LastKey;
188          );          q.trig        = TRIGGER_ATTACK |
189                ((pChannel->LastKey != -1 &&
190          for (int i = 0; i < pChannel->regionsTemp.size(); i++) {                pChannel->PressedKeys[pChannel->LastKey] &&
191              if (!RegionSuspended(pChannel->regionsTemp[i])) {                pChannel->LastKey != q.key) ?
192                  LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);               TRIGGER_LEGATO : TRIGGER_FIRST);
193    
194            q.search(pChannel->pInstrument);
195    
196            int i = 0;
197            while (::sfz::Region* region = q.next()) {
198                if (!RegionSuspended(region)) {
199                    itNoteOnEvent->Param.Note.pRegion = region;
200                    VoiceIterator itNewVoice =
201                        LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);
202                    if (itNewVoice)
203                        itNewVoice.moveToEndOf(itNote->pActiveVoices);
204              }              }
205                i++;
206          }          }
207      }      }
208    
# Line 101  namespace LinuxSampler { namespace sfz { Line 210  namespace LinuxSampler { namespace sfz {
210          LinuxSampler::EngineChannel*  pEngineChannel,          LinuxSampler::EngineChannel*  pEngineChannel,
211          RTList<Event>::Iterator&      itNoteOffEvent          RTList<Event>::Iterator&      itNoteOffEvent
212      ) {      ) {
213            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          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
219          uint8_t  chan     = pChannel->MidiChannel();          ::sfz::Query q;
220          int      key      = itNoteOffEvent->Param.Note.Key;          q.chan        = itNoteOffEvent->Param.Note.Channel + 1;
221            q.key         = itNote->cause.Param.Note.Key; //itNoteOffEvent->Param.Note.Key; <- using note object instead, since note nr might been modified by script
222    
223          // MIDI note-on velocity is used instead of note-off velocity          // MIDI note-on velocity is used instead of note-off velocity
224          uint8_t  vel      = pChannel->pMIDIKeyInfo[key].Velocity;          q.vel         = itNote->cause.Param.Note.Velocity; //pChannel->pMIDIKeyInfo[q.key].Velocity; <- using note object instead, since velocity might been modified by script
225          itNoteOffEvent->Param.Note.Velocity = vel;          itNoteOffEvent->Param.Note.Velocity = q.vel;
226    
227          int      bend     = pChannel->Pitch;          q.bend        = pChannel->Pitch;
228          uint8_t  chanaft  = pChannel->ControllerTable[128];          q.bpm         = 0;
229          uint8_t* cc       = pChannel->ControllerTable;          q.chanaft     = pChannel->ControllerTable[128];
230          ::sfz::trigger_t trig = TRIGGER_RELEASE;          q.polyaft     = 0;
231            q.prog        = 0;
232          pChannel->regionsTemp = pChannel->pInstrument->GetRegionsOnKey (          q.rand        = Random();
233              chan, key, vel, bend, 0, chanaft, 0, 0, Random(), trig, cc,          q.cc          = pChannel->ControllerTable;
234              0.0f, pChannel->PressedKeys, pChannel->LastKeySwitch, pChannel->LastKey          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    
240            q.search(pChannel->pInstrument);
241    
242          // now launch the required amount of voices          // now launch the required amount of voices
243          for (int i = 0; i < pChannel->regionsTemp.size(); i++) {          int i = 0;
244              LaunchVoice(pChannel, itNoteOffEvent, i, true, false, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples          while (::sfz::Region* region = q.next()) {
245                itNoteOffEvent->Param.Note.pRegion = region;
246                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                i++;
251          }          }
252      }      }
253    
# Line 134  namespace LinuxSampler { namespace sfz { Line 260  namespace LinuxSampler { namespace sfz {
260          bool                          HandleKeyGroupConflicts          bool                          HandleKeyGroupConflicts
261      ) {      ) {
262          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
263          int key = itNoteOnEvent->Param.Note.Key;          //int key = itNoteOnEvent->Param.Note.Key;
264          EngineChannel::MidiKey* pKey  = &pChannel->pMIDIKeyInfo[key];          //EngineChannel::MidiKey* pKey  = &pChannel->pMIDIKeyInfo[key];
265          Voice::type_t VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;          ::sfz::Region* pRgn = static_cast< ::sfz::Region*>(itNoteOnEvent->Param.Note.pRegion);
266    
267            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          Pool<Voice>::Iterator itNewVoice;          Pool<Voice>::Iterator itNewVoice;
         ::sfz::Region* pRgn = pChannel->regionsTemp[iLayer];  
275    
276          // no need to process if sample is silent          if (HandleKeyGroupConflicts) pChannel->HandleKeyGroupConflicts(pRgn->group, itNoteOnEvent);
         if (!pRgn->GetSample() || !pRgn->GetSample()->GetTotalFrameCount()) return Pool<Voice>::Iterator();  
277    
278          // only mark the first voice of a layered voice (group) to be in a          // no need to process if sample is silent
279          // key group, so the layered voices won't kill each other          if (!pRgn->GetSample(false) || !pRgn->GetSample()->GetTotalFrameCount()) return Pool<Voice>::Iterator();
         int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRgn->group : 0;  
         if (HandleKeyGroupConflicts) pChannel->HandleKeyGroupConflicts(iKeyGroup, itNoteOnEvent, pRgn->off_mode == ::sfz::OFF_NORMAL);  
280    
281          // allocate a new voice for the key          // allocate a new voice for the key
282          itNewVoice = pKey->pActiveVoices->allocAppend();          itNewVoice = GetVoicePool()->allocAppend();
283          int res = InitNewVoice (          int res = InitNewVoice (
284                  pChannel, pRgn, itNoteOnEvent, VoiceType, iLayer,                  pChannel, pRgn, itNoteOnEvent, VoiceType, iLayer,
285                  iKeyGroup, ReleaseTriggerVoice, VoiceStealing, itNewVoice                  pRgn->off_by, ReleaseTriggerVoice, VoiceStealing, itNewVoice
286          );          );
287          if (!res) return itNewVoice;          if (!res) return itNewVoice;
288    
# Line 174  namespace LinuxSampler { namespace sfz { Line 303  namespace LinuxSampler { namespace sfz {
303      }      }
304    
305      String Engine::Version() {      String Engine::Version() {
306          String s = "$Revision: 1.7 $";          String s = "$Revision$";
307          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
308      }      }
309    

Legend:
Removed from v.2086  
changed lines
  Added in v.3219

  ViewVC Help
Powered by ViewVC