/[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 3082 by schoenebeck, Mon Jan 9 18:39:35 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));
82    
83          EngineChannel* pChannel = dynamic_cast<EngineChannel*>(pEngineChannel);          EngineChannel* pChannel = static_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) {  
   
             // TODO:  
         }  
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 72  namespace LinuxSampler { namespace sfz { Line 164  namespace LinuxSampler { namespace sfz {
164          bool                         HandleKeyGroupConflicts          bool                         HandleKeyGroupConflicts
165      ) {      ) {
166          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
167            //MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
168            ::sfz::Query q;
169            q.chan        = itNoteOnEvent->Param.Note.Channel + 1;
170            q.key         = itNoteOnEvent->Param.Note.Key;
171            q.vel         = itNoteOnEvent->Param.Note.Velocity;
172            q.bend        = pChannel->Pitch;
173            q.bpm         = 0;
174            q.chanaft     = pChannel->ControllerTable[128];
175            q.polyaft     = 0;
176            q.prog        = 0;
177            q.rand        = Random();
178            q.cc          = pChannel->ControllerTable;
179            q.timer       = 0;
180            q.sw          = pChannel->PressedKeys;
181            q.last_sw_key = pChannel->LastKeySwitch;
182            q.prev_sw_key = pChannel->LastKey;
183            q.trig        = TRIGGER_ATTACK |
184                ((pChannel->LastKey != -1 &&
185                  pChannel->PressedKeys[pChannel->LastKey] &&
186                  pChannel->LastKey != q.key) ?
187                 TRIGGER_LEGATO : TRIGGER_FIRST);
188    
189            q.search(pChannel->pInstrument);
190    
191            NoteIterator itNote = GetNotePool()->fromID(itNoteOnEvent->Param.Note.ID);
192            if (!itNote) {
193                dmsg(1,("sfz::Engine: No Note object for triggering new voices!\n"));
194                return;
195            }
196    
197          uint8_t  chan     = pChannel->MidiChannel();          int i = 0;
198          int      key      = itNoteOnEvent->Param.Note.Key;          while (::sfz::Region* region = q.next()) {
199          uint8_t  vel      = itNoteOnEvent->Param.Note.Velocity;              if (!RegionSuspended(region)) {
200          int      bend     = pChannel->Pitch;                  itNoteOnEvent->Param.Note.pRegion = region;
201          uint8_t  chanaft  = pChannel->ControllerTable[128];                  VoiceIterator itNewVoice =
202          uint8_t* cc       = pChannel->ControllerTable;                      LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);
203          ::sfz::trigger_t trig = TRIGGER_ATTACK |                  if (itNewVoice)
204                ((pChannel->LastKey != -1 &&                      itNewVoice.moveToEndOf(itNote->pActiveVoices);
                 pChannel->PressedKeys[pChannel->LastKey] &&  
                 pChannel->LastKey != key) ?  
                TRIGGER_LEGATO : TRIGGER_FIRST);  
   
         pChannel->regionsTemp = pChannel->pInstrument->GetRegionsOnKey (  
             chan, key, vel, bend, 0, chanaft, 0, 0, Random(), trig, cc,  
             0.0f, pChannel->PressedKeys, pChannel->LastKeySwitch, pChannel->LastKey  
         );  
   
         for (int i = 0; i < pChannel->regionsTemp.size(); i++) {  
             if (!RegionSuspended(pChannel->regionsTemp[i])) {  
                 LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);  
205              }              }
206                i++;
207          }          }
208      }      }
209    
# Line 102  namespace LinuxSampler { namespace sfz { Line 212  namespace LinuxSampler { namespace sfz {
212          RTList<Event>::Iterator&      itNoteOffEvent          RTList<Event>::Iterator&      itNoteOffEvent
213      ) {      ) {
214          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
215          uint8_t  chan     = pChannel->MidiChannel();          ::sfz::Query q;
216          int      key      = itNoteOffEvent->Param.Note.Key;          q.chan        = itNoteOffEvent->Param.Note.Channel + 1;
217            q.key         = itNoteOffEvent->Param.Note.Key;
218    
219          // MIDI note-on velocity is used instead of note-off velocity          // MIDI note-on velocity is used instead of note-off velocity
220          uint8_t  vel      = pChannel->pMIDIKeyInfo[key].Velocity;          q.vel         = pChannel->pMIDIKeyInfo[q.key].Velocity;
221          itNoteOffEvent->Param.Note.Velocity = vel;          itNoteOffEvent->Param.Note.Velocity = q.vel;
222    
223          int      bend     = pChannel->Pitch;          q.bend        = pChannel->Pitch;
224          uint8_t  chanaft  = pChannel->ControllerTable[128];          q.bpm         = 0;
225          uint8_t* cc       = pChannel->ControllerTable;          q.chanaft     = pChannel->ControllerTable[128];
226          ::sfz::trigger_t trig = TRIGGER_RELEASE;          q.polyaft     = 0;
227            q.prog        = 0;
228          pChannel->regionsTemp = pChannel->pInstrument->GetRegionsOnKey (          q.rand        = Random();
229              chan, key, vel, bend, 0, chanaft, 0, 0, Random(), trig, cc,          q.cc          = pChannel->ControllerTable;
230              0.0f, pChannel->PressedKeys, pChannel->LastKeySwitch, pChannel->LastKey          q.timer       = 0;
231          );          q.sw          = pChannel->PressedKeys;
232            q.last_sw_key = pChannel->LastKeySwitch;
233            q.prev_sw_key = pChannel->LastKey;
234            q.trig        = TRIGGER_RELEASE;
235    
236            q.search(pChannel->pInstrument);
237    
238            NoteIterator itNote = GetNotePool()->fromID(itNoteOffEvent->Param.Note.ID);
239            if (!itNote) {
240                dmsg(1,("sfz::Engine: No Note object for triggering new release voices!\n"));
241                return;
242            }
243    
244          // now launch the required amount of voices          // now launch the required amount of voices
245          for (int i = 0; i < pChannel->regionsTemp.size(); i++) {          int i = 0;
246              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()) {
247                itNoteOffEvent->Param.Note.pRegion = region;
248                VoiceIterator itNewVoice =
249                    LaunchVoice(pChannel, itNoteOffEvent, i, true, false, true); //FIXME: for the moment we don't perform voice stealing for release triggered samples
250                if (itNewVoice)
251                    itNewVoice.moveToEndOf(itNote->pActiveVoices);
252                i++;
253          }          }
254      }      }
255    
# Line 134  namespace LinuxSampler { namespace sfz { Line 262  namespace LinuxSampler { namespace sfz {
262          bool                          HandleKeyGroupConflicts          bool                          HandleKeyGroupConflicts
263      ) {      ) {
264          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
265          int key = itNoteOnEvent->Param.Note.Key;          //int key = itNoteOnEvent->Param.Note.Key;
266          EngineChannel::MidiKey* pKey  = &pChannel->pMIDIKeyInfo[key];          //EngineChannel::MidiKey* pKey  = &pChannel->pMIDIKeyInfo[key];
267          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);
268    
269            Voice::type_t VoiceType =
270                itNoteOnEvent->Type == Event::type_control_change ? Voice::type_controller_triggered :
271                ReleaseTriggerVoice ? Voice::type_release_trigger :
272                iLayer == 0 ? Voice::type_release_trigger_required :
273                Voice::type_normal;
274            if (pRgn->loop_mode == ::sfz::ONE_SHOT) VoiceType |= Voice::type_one_shot;
275    
276          Pool<Voice>::Iterator itNewVoice;          Pool<Voice>::Iterator itNewVoice;
         ::sfz::Region* pRgn = pChannel->regionsTemp[iLayer];  
277    
278          // 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();  
279    
280          // only mark the first voice of a layered voice (group) to be in a          // no need to process if sample is silent
281          // 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);  
282    
283          // allocate a new voice for the key          // allocate a new voice for the key
284          itNewVoice = pKey->pActiveVoices->allocAppend();          itNewVoice = GetVoicePool()->allocAppend();
285          int res = InitNewVoice (          int res = InitNewVoice (
286                  pChannel, pRgn, itNoteOnEvent, VoiceType, iLayer,                  pChannel, pRgn, itNoteOnEvent, VoiceType, iLayer,
287                  iKeyGroup, ReleaseTriggerVoice, VoiceStealing, itNewVoice                  pRgn->off_by, ReleaseTriggerVoice, VoiceStealing, itNewVoice
288          );          );
289          if (!res) return itNewVoice;          if (!res) return itNewVoice;
290    
# Line 174  namespace LinuxSampler { namespace sfz { Line 305  namespace LinuxSampler { namespace sfz {
305      }      }
306    
307      String Engine::Version() {      String Engine::Version() {
308          String s = "$Revision: 1.7 $";          String s = "$Revision$";
309          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
310      }      }
311    

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

  ViewVC Help
Powered by ViewVC