/[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 2012 - (hide annotations) (download)
Fri Oct 23 17:53:17 2009 UTC (14 years, 6 months ago) by iliev
File size: 10896 byte(s)
* Refactoring: moved the independent code from
  the Gigasampler format engine to base classes
* SFZ format engine: experimental code (not usable yet)
* SoundFont format engine: experimental code (not usable yet)
* Fixed crash which may occur when MIDI key + transpose is out of range

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     * Copyright (C) 2009 Grigor Iliev *
8     * *
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    
31     /**
32     * Reacts on supported control change commands (e.g. pitch bend wheel,
33     * modulation wheel, aftertouch).
34     *
35     * @param pEngineChannel - engine channel on which this event occured on
36     * @param itControlChangeEvent - controller, value and time stamp of the event
37     */
38     void Engine::ProcessControlChange (
39     LinuxSampler::EngineChannel* pEngineChannel,
40     Pool<Event>::Iterator& itControlChangeEvent
41     ) {
42     dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));
43    
44     EngineChannel* pChannel = dynamic_cast<EngineChannel*>(pEngineChannel);
45     // handle the "control triggered" MIDI rule: a control change
46     // event can trigger a new note on or note off event
47     if (pChannel->pInstrument) {
48    
49     // TODO:
50     }
51    
52     // update controller value in the engine channel's controller table
53     pChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
54    
55     ProcessHardcodedControllers(pEngineChannel, itControlChangeEvent);
56    
57     // handle FX send controllers
58     ProcessFxSendControllers(pChannel, itControlChangeEvent);
59     }
60    
61     DiskThread* Engine::CreateDiskThread() {
62     return new DiskThread (
63     iMaxDiskStreams,
64     ((pAudioOutputDevice->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo
65     &instruments
66     );
67     }
68    
69     void Engine::TriggerNewVoices (
70     LinuxSampler::EngineChannel* pEngineChannel,
71     RTList<Event>::Iterator& itNoteOnEvent,
72     bool HandleKeyGroupConflicts
73     ) {
74     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
75    
76     uint8_t chan = pChannel->MidiChannel();
77     int key = itNoteOnEvent->Param.Note.Key;
78     uint8_t vel = itNoteOnEvent->Param.Note.Velocity;
79     int bend = pChannel->Pitch;
80     uint8_t chanaft = pChannel->ControllerTable[128];
81     uint8_t* cc = pChannel->ControllerTable;
82     ::sfz::trigger_t trig = TRIGGER_ATTACK;
83    
84     pChannel->regionsTemp = pChannel->pInstrument->GetRegionsOnKey (
85     chan, key, vel, bend, 0, chanaft, 0, 0, 0, trig, cc,
86     0.0f, 1, pChannel->PressedKeys, pChannel->LastKeySwitch, pChannel->LastKey
87     );
88    
89     for (int i = 0; i < pChannel->regionsTemp.size(); i++) {
90     if (!RegionSuspended(pChannel->regionsTemp[i])) {
91     LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);
92     }
93     }
94     }
95    
96     void Engine::TriggerReleaseVoices (
97     LinuxSampler::EngineChannel* pEngineChannel,
98     RTList<Event>::Iterator& itNoteOffEvent
99     ) {
100     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
101     uint8_t chan = pChannel->MidiChannel();
102     int key = itNoteOffEvent->Param.Note.Key;
103     uint8_t vel = itNoteOffEvent->Param.Note.Velocity;
104     int bend = pChannel->Pitch;
105     uint8_t chanaft = pChannel->ControllerTable[128];
106     uint8_t* cc = pChannel->ControllerTable;
107     ::sfz::trigger_t trig = TRIGGER_RELEASE;
108    
109     pChannel->regionsTemp = pChannel->pInstrument->GetRegionsOnKey (
110     chan, key, vel, bend, 0, chanaft, 0, 0, 0, trig, cc, 0.0f, 0, NULL, 0, 0
111     );
112    
113     // now launch the required amount of voices
114     for (int i = 0; i < pChannel->regionsTemp.size(); i++) {
115     LaunchVoice(pChannel, itNoteOffEvent, i, true, false, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples
116     }
117     }
118    
119     Pool<Voice>::Iterator Engine::LaunchVoice (
120     LinuxSampler::EngineChannel* pEngineChannel,
121     Pool<Event>::Iterator& itNoteOnEvent,
122     int iLayer,
123     bool ReleaseTriggerVoice,
124     bool VoiceStealing,
125     bool HandleKeyGroupConflicts
126     ) {
127     EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
128     int key = itNoteOnEvent->Param.Note.Key;
129     EngineChannel::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
130     /*::gig::Region* pRegion = pChannel->pInstrument->GetRegion(MIDIKey);
131    
132     // if nothing defined for this key
133     if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
134    
135     // only mark the first voice of a layered voice (group) to be in a
136     // key group, so the layered voices won't kill each other
137     int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;
138    
139     // handle key group (a.k.a. exclusive group) conflicts
140     if (HandleKeyGroupConflicts) {
141     if (iKeyGroup) { // if this voice / key belongs to a key group
142     uint** ppKeyGroup = &pChannel->ActiveKeyGroups[iKeyGroup];
143     if (*ppKeyGroup) { // if there's already an active key in that key group
144     EngineChannel::MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[**ppKeyGroup];
145     // kill all voices on the (other) key
146     RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
147     RTList<Voice>::Iterator end = pOtherKey->pActiveVoices->end();
148     for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
149     if (itVoiceToBeKilled->Type != Voice::type_release_trigger) {
150     itVoiceToBeKilled->Kill(itNoteOnEvent);
151     --VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict
152     }
153     }
154     }
155     }
156     }*/ // TODO: ^^^
157    
158     Voice::type_t VoiceType = Voice::type_normal;
159    
160     Pool<Voice>::Iterator itNewVoice;
161     ::sfz::Region* pRgn = pChannel->regionsTemp[iLayer];
162    
163     // no need to process if sample is silent
164     if (!pRgn->GetSample() || !pRgn->GetSample()->GetTotalFrameCount()) itNewVoice;
165    
166     // allocate a new voice for the key
167     itNewVoice = pKey->pActiveVoices->allocAppend();
168     if (itNewVoice) {
169     // launch the new voice
170     if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRgn, VoiceType, 0 /* iKeyGroup */) < 0) {
171     dmsg(4,("Voice not triggered\n"));
172     pKey->pActiveVoices->free(itNewVoice);
173     }
174     else { // on success
175     --VoiceSpawnsLeft;
176     if (!pKey->Active) { // mark as active key
177     pKey->Active = true;
178     pKey->itSelf = pChannel->pActiveKeys->allocAppend();
179     *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
180     }
181     if (itNewVoice->KeyGroup) {
182     uint** ppKeyGroup = &pChannel->ActiveKeyGroups[itNewVoice->KeyGroup];
183     *ppKeyGroup = &*pKey->itSelf; // put key as the (new) active key to its key group
184     }
185     if (itNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
186     return itNewVoice; // success
187     }
188     }
189     else if (VoiceStealing) {
190     // try to steal one voice
191     int result = StealVoice(pChannel, itNoteOnEvent);
192     if (!result) { // voice stolen successfully
193     // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
194     RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
195     if (itStealEvent) {
196     *itStealEvent = *itNoteOnEvent; // copy event
197     itStealEvent->Param.Note.Layer = iLayer;
198     itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
199     pKey->VoiceTheftsQueued++;
200     }
201     else dmsg(1,("Voice stealing queue full!\n"));
202     }
203     }
204    
205     // return if this is a release triggered voice and there is no
206     // releasetrigger dimension (could happen if an instrument
207     // change has occured between note on and off)
208     //if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
209    
210    
211    
212     return itNewVoice;
213     }
214    
215     bool Engine::DiskStreamSupported() {
216     return true;
217     }
218    
219     String Engine::Description() {
220     return "SFZ Format Engine";
221     }
222    
223     String Engine::Version() {
224     String s = "$Revision: 1.1 $";
225     return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
226     }
227    
228     }} // namespace LinuxSampler::sfz

  ViewVC Help
Powered by ViewVC