/[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 2061 by persson, Tue Feb 23 18:32:31 2010 UTC revision 3015 by schoenebeck, Tue Oct 18 20:13:08 2016 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 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 27  Line 27 
27    
28  namespace LinuxSampler { namespace sfz {  namespace LinuxSampler { namespace sfz {
29      Engine::Format Engine::GetEngineFormat() { return SFZ; }      Engine::Format Engine::GetEngineFormat() { return SFZ; }
30        
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    
62      /**      /**
63       *  Reacts on supported control change commands (e.g. pitch bend wheel,       *  Reacts on supported control change commands (e.g. pitch bend wheel,
# Line 39  namespace LinuxSampler { namespace sfz { Line 70  namespace LinuxSampler { namespace sfz {
70          LinuxSampler::EngineChannel*  pEngineChannel,          LinuxSampler::EngineChannel*  pEngineChannel,
71          Pool<Event>::Iterator&        itControlChangeEvent          Pool<Event>::Iterator&        itControlChangeEvent
72      ) {      ) {
73          dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));          uint8_t cc = itControlChangeEvent->Param.CC.Controller;
74            dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", cc, itControlChangeEvent->Param.CC.Value));
75    
76          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:  
         }  
77    
78          // update controller value in the engine channel's controller table          // update controller value in the engine channel's controller table
79          pChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;          pChannel->ControllerTable[cc] = itControlChangeEvent->Param.CC.Value;
80    
81          ProcessHardcodedControllers(pEngineChannel, itControlChangeEvent);          ProcessHardcodedControllers(pEngineChannel, itControlChangeEvent);
82    
83          // handle FX send controllers          // handle FX send controllers
84          ProcessFxSendControllers(pChannel, itControlChangeEvent);          ProcessFxSendControllers(pChannel, itControlChangeEvent);
85    
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                q.chan        = itControlChangeEvent->Param.CC.Channel + 1;
92                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                NoteIterator itNewNote;
110    
111                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                        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                    }
130                    i++;
131                }
132            }
133        }
134    
135        void Engine::ProcessChannelPressure(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itChannelPressureEvent) {
136            // forward this to the CC routine, so it updates the current aftertouch value
137            ProcessControlChange(pEngineChannel, itChannelPressureEvent);
138    
139            // if required: engine global aftertouch handling (apart from the per voice handling)
140        }
141    
142        void Engine::ProcessPolyphonicKeyPressure(LinuxSampler::EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNotePressureEvent) {
143            // if required: engine global aftertouch handling (apart from the per voice handling)
144      }      }
145    
146      DiskThread* Engine::CreateDiskThread() {      DiskThread* Engine::CreateDiskThread() {
# Line 72  namespace LinuxSampler { namespace sfz { Line 157  namespace LinuxSampler { namespace sfz {
157          bool                         HandleKeyGroupConflicts          bool                         HandleKeyGroupConflicts
158      ) {      ) {
159          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
160            MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
161            ::sfz::Query q;
162            q.chan        = itNoteOnEvent->Param.Note.Channel + 1;
163            q.key         = itNoteOnEvent->Param.Note.Key;
164            q.vel         = itNoteOnEvent->Param.Note.Velocity;
165            q.bend        = pChannel->Pitch;
166            q.bpm         = 0;
167            q.chanaft     = pChannel->ControllerTable[128];
168            q.polyaft     = 0;
169            q.prog        = 0;
170            q.rand        = Random();
171            q.cc          = pChannel->ControllerTable;
172            q.timer       = 0;
173            q.sw          = pChannel->PressedKeys;
174            q.last_sw_key = pChannel->LastKeySwitch;
175            q.prev_sw_key = pChannel->LastKey;
176            q.trig        = TRIGGER_ATTACK |
177                ((pChannel->LastKey != -1 &&
178                  pChannel->PressedKeys[pChannel->LastKey] &&
179                  pChannel->LastKey != q.key) ?
180                 TRIGGER_LEGATO : TRIGGER_FIRST);
181    
182            q.search(pChannel->pInstrument);
183    
184            NoteIterator itNote = GetNotePool()->fromID(itNoteOnEvent->Param.Note.ID);
185            if (!itNote) {
186                dmsg(1,("sfz::Engine: No Note object for triggering new voices!\n"));
187                return;
188            }
189    
190          uint8_t  chan     = pChannel->MidiChannel();          int i = 0;
191          int      key      = itNoteOnEvent->Param.Note.Key;          while (::sfz::Region* region = q.next()) {
192          uint8_t  vel      = itNoteOnEvent->Param.Note.Velocity;              if (!RegionSuspended(region)) {
193          int      bend     = pChannel->Pitch;                  itNoteOnEvent->Param.Note.pRegion = region;
194          uint8_t  chanaft  = pChannel->ControllerTable[128];                  VoiceIterator itNewVoice =
195          uint8_t* cc       = pChannel->ControllerTable;                      LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);
196          ::sfz::trigger_t trig = TRIGGER_ATTACK |                  if (itNewVoice)
197                ((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, 0, trig, cc,  
             0.0f, 1, 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);  
198              }              }
199                i++;
200          }          }
201      }      }
202    
# Line 102  namespace LinuxSampler { namespace sfz { Line 205  namespace LinuxSampler { namespace sfz {
205          RTList<Event>::Iterator&      itNoteOffEvent          RTList<Event>::Iterator&      itNoteOffEvent
206      ) {      ) {
207          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
208          uint8_t  chan     = pChannel->MidiChannel();          ::sfz::Query q;
209          int      key      = itNoteOffEvent->Param.Note.Key;          q.chan        = itNoteOffEvent->Param.Note.Channel + 1;
210            q.key         = itNoteOffEvent->Param.Note.Key;
211    
212          // MIDI note-on velocity is used instead of note-off velocity          // MIDI note-on velocity is used instead of note-off velocity
213          uint8_t  vel      = pChannel->pMIDIKeyInfo[key].Velocity;          q.vel         = pChannel->pMIDIKeyInfo[q.key].Velocity;
214          itNoteOffEvent->Param.Note.Velocity = vel;          itNoteOffEvent->Param.Note.Velocity = q.vel;
215    
216          int      bend     = pChannel->Pitch;          q.bend        = pChannel->Pitch;
217          uint8_t  chanaft  = pChannel->ControllerTable[128];          q.bpm         = 0;
218          uint8_t* cc       = pChannel->ControllerTable;          q.chanaft     = pChannel->ControllerTable[128];
219          ::sfz::trigger_t trig = TRIGGER_RELEASE;          q.polyaft     = 0;
220            q.prog        = 0;
221          pChannel->regionsTemp = pChannel->pInstrument->GetRegionsOnKey (          q.rand        = Random();
222              chan, key, vel, bend, 0, chanaft, 0, 0, 0, trig, cc, 0.0f, 1, NULL, 0, 0          q.cc          = pChannel->ControllerTable;
223          );          q.timer       = 0;
224            q.sw          = pChannel->PressedKeys;
225            q.last_sw_key = pChannel->LastKeySwitch;
226            q.prev_sw_key = pChannel->LastKey;
227            q.trig        = TRIGGER_RELEASE;
228    
229            q.search(pChannel->pInstrument);
230    
231            NoteIterator itNote = GetNotePool()->fromID(itNoteOffEvent->Param.Note.ID);
232            if (!itNote) {
233                dmsg(1,("sfz::Engine: No Note object for triggering new release voices!\n"));
234                return;
235            }
236    
237          // now launch the required amount of voices          // now launch the required amount of voices
238          for (int i = 0; i < pChannel->regionsTemp.size(); i++) {          int i = 0;
239              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()) {
240                itNoteOffEvent->Param.Note.pRegion = region;
241                VoiceIterator itNewVoice =
242                    LaunchVoice(pChannel, itNoteOffEvent, i, true, false, true); //FIXME: for the moment we don't perform voice stealing for release triggered samples
243                if (itNewVoice)
244                    itNewVoice.moveToEndOf(itNote->pActiveVoices);
245                i++;
246          }          }
247      }      }
248    
# Line 134  namespace LinuxSampler { namespace sfz { Line 256  namespace LinuxSampler { namespace sfz {
256      ) {      ) {
257          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);          EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
258          int key = itNoteOnEvent->Param.Note.Key;          int key = itNoteOnEvent->Param.Note.Key;
259          EngineChannel::MidiKey* pKey  = &pChannel->pMIDIKeyInfo[key];          //EngineChannel::MidiKey* pKey  = &pChannel->pMIDIKeyInfo[key];
260          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);
261    
262            Voice::type_t VoiceType =
263                itNoteOnEvent->Type == Event::type_control_change ? Voice::type_controller_triggered :
264                ReleaseTriggerVoice ? Voice::type_release_trigger :
265                iLayer == 0 ? Voice::type_release_trigger_required :
266                Voice::type_normal;
267            if (pRgn->loop_mode == ::sfz::ONE_SHOT) VoiceType |= Voice::type_one_shot;
268    
269          Pool<Voice>::Iterator itNewVoice;          Pool<Voice>::Iterator itNewVoice;
         ::sfz::Region* pRgn = pChannel->regionsTemp[iLayer];  
270    
271          // 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();  
272    
273          // only mark the first voice of a layered voice (group) to be in a          // no need to process if sample is silent
274          // 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);  
275    
276          // allocate a new voice for the key          // allocate a new voice for the key
277          itNewVoice = pKey->pActiveVoices->allocAppend();          itNewVoice = GetVoicePool()->allocAppend();
278          int res = InitNewVoice (          int res = InitNewVoice (
279                  pChannel, pRgn, itNoteOnEvent, VoiceType, iLayer,                  pChannel, pRgn, itNoteOnEvent, VoiceType, iLayer,
280                  iKeyGroup, ReleaseTriggerVoice, VoiceStealing, itNewVoice                  pRgn->off_by, ReleaseTriggerVoice, VoiceStealing, itNewVoice
281          );          );
282          if (!res) return itNewVoice;          if (!res) return itNewVoice;
283    
# Line 173  namespace LinuxSampler { namespace sfz { Line 298  namespace LinuxSampler { namespace sfz {
298      }      }
299    
300      String Engine::Version() {      String Engine::Version() {
301          String s = "$Revision: 1.4 $";          String s = "$Revision$";
302          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
303      }      }
304    

Legend:
Removed from v.2061  
changed lines
  Added in v.3015

  ViewVC Help
Powered by ViewVC