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

Contents of /linuxsampler/trunk/src/engines/sf2/Engine.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2012 - (show annotations) (download)
Fri Oct 23 17:53:17 2009 UTC (14 years, 6 months ago) by iliev
File size: 11077 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 /***************************************************************************
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 sf2 {
29 Engine::Format Engine::GetEngineFormat() { return SF2; }
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
83 std::vector< ::sf2::Region*> regs = pChannel->pInstrument->GetRegionsOnKey (
84 key, vel
85 );
86
87 pChannel->regionsTemp.clear();
88
89 bool preset = (dynamic_cast< ::sf2::Preset*>(pChannel->pInstrument)) != NULL;
90
91 if (preset) {
92 for (int i = 0; i < regs.size(); i++) {
93 // TODO: Generators in the PGEN sub-chunk are applied relative to generators in the IGEN sub-chunk in an additive manner. In
94 // other words, PGEN generators increase or decrease the value of an IGEN generator.
95 ::sf2::Instrument* sfInstr = regs[i]->pInstrument;
96
97 std::vector< ::sf2::Region*> subRegs = sfInstr->GetRegionsOnKey (
98 key, vel
99 );
100 for (int j = 0; j < subRegs.size(); j++) {
101 pChannel->regionsTemp.push_back(subRegs[j]);
102 }
103 }
104 } else {
105 pChannel->regionsTemp = pChannel->pInstrument->GetRegionsOnKey (
106 key, vel
107 );
108 }
109
110 for (int i = 0; i < pChannel->regionsTemp.size(); i++) {
111 ::sf2::Region* r = pChannel->regionsTemp[i];
112 //std::cout << r->GetSample()->GetName();
113 //std::cout << " loKey: " << r->loKey << " hiKey: " << r->hiKey << " minVel: " << r->minVel << " maxVel: " << r->maxVel << " Vel: " << ((int)vel) << std::endl << std::endl;
114 if (!RegionSuspended(pChannel->regionsTemp[i])) {
115 LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);
116 }
117 }
118 }
119
120 void Engine::TriggerReleaseVoices (
121 LinuxSampler::EngineChannel* pEngineChannel,
122 RTList<Event>::Iterator& itNoteOffEvent
123 ) {
124
125 }
126
127 Pool<Voice>::Iterator Engine::LaunchVoice (
128 LinuxSampler::EngineChannel* pEngineChannel,
129 Pool<Event>::Iterator& itNoteOnEvent,
130 int iLayer,
131 bool ReleaseTriggerVoice,
132 bool VoiceStealing,
133 bool HandleKeyGroupConflicts
134 ) {
135 EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
136 int key = itNoteOnEvent->Param.Note.Key;
137 EngineChannel::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
138 /*::gig::Region* pRegion = pChannel->pInstrument->GetRegion(MIDIKey);
139
140 // if nothing defined for this key
141 if (!pRegion) return Pool<Voice>::Iterator(); // nothing to do
142
143 // only mark the first voice of a layered voice (group) to be in a
144 // key group, so the layered voices won't kill each other
145 int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRegion->KeyGroup : 0;
146
147 // handle key group (a.k.a. exclusive group) conflicts
148 if (HandleKeyGroupConflicts) {
149 if (iKeyGroup) { // if this voice / key belongs to a key group
150 uint** ppKeyGroup = &pChannel->ActiveKeyGroups[iKeyGroup];
151 if (*ppKeyGroup) { // if there's already an active key in that key group
152 EngineChannel::MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[**ppKeyGroup];
153 // kill all voices on the (other) key
154 RTList<Voice>::Iterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();
155 RTList<Voice>::Iterator end = pOtherKey->pActiveVoices->end();
156 for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
157 if (itVoiceToBeKilled->Type != Voice::type_release_trigger) {
158 itVoiceToBeKilled->Kill(itNoteOnEvent);
159 --VoiceSpawnsLeft; //FIXME: just a hack, we should better check in StealVoice() if the voice was killed due to key conflict
160 }
161 }
162 }
163 }
164 }*/ // TODO: ^^^
165
166 Voice::type_t VoiceType = Voice::type_normal;
167
168 Pool<Voice>::Iterator itNewVoice;
169 ::sf2::Region* pRgn = pChannel->regionsTemp[iLayer];
170
171 // no need to process if sample is silent
172 if (!pRgn->GetSample() || !pRgn->GetSample()->GetTotalFrameCount()) itNewVoice; // TODO:
173
174 // allocate a new voice for the key
175 itNewVoice = pKey->pActiveVoices->allocAppend();
176 if (itNewVoice) {
177 // launch the new voice
178 if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRgn, VoiceType, 0 /* iKeyGroup */) < 0) {
179 dmsg(4,("Voice not triggered\n"));
180 pKey->pActiveVoices->free(itNewVoice);
181 }
182 else { // on success
183 --VoiceSpawnsLeft;
184 if (!pKey->Active) { // mark as active key
185 pKey->Active = true;
186 pKey->itSelf = pChannel->pActiveKeys->allocAppend();
187 *pKey->itSelf = itNoteOnEvent->Param.Note.Key;
188 }
189 if (itNewVoice->KeyGroup) {
190 uint** ppKeyGroup = &pChannel->ActiveKeyGroups[itNewVoice->KeyGroup];
191 *ppKeyGroup = &*pKey->itSelf; // put key as the (new) active key to its key group
192 }
193 if (itNewVoice->Type == Voice::type_release_trigger_required) pKey->ReleaseTrigger = true; // mark key for the need of release triggered voice(s)
194 return itNewVoice; // success
195 }
196 }
197 else if (VoiceStealing) {
198 // try to steal one voice
199 int result = StealVoice(pChannel, itNoteOnEvent);
200 if (!result) { // voice stolen successfully
201 // put note-on event into voice-stealing queue, so it will be reprocessed after killed voice died
202 RTList<Event>::Iterator itStealEvent = pVoiceStealingQueue->allocAppend();
203 if (itStealEvent) {
204 *itStealEvent = *itNoteOnEvent; // copy event
205 itStealEvent->Param.Note.Layer = iLayer;
206 itStealEvent->Param.Note.ReleaseTrigger = ReleaseTriggerVoice;
207 pKey->VoiceTheftsQueued++;
208 }
209 else dmsg(1,("Voice stealing queue full!\n"));
210 }
211 }
212
213 // return if this is a release triggered voice and there is no
214 // releasetrigger dimension (could happen if an instrument
215 // change has occured between note on and off)
216 //if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
217
218
219
220 return itNewVoice;
221 }
222
223 bool Engine::DiskStreamSupported() {
224 return true;
225 }
226
227 String Engine::Description() {
228 return "SoundFont Format Engine";
229 }
230
231 String Engine::Version() {
232 String s = "$Revision: 1.1 $";
233 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
234 }
235
236 }} // namespace LinuxSampler::sf2

  ViewVC Help
Powered by ViewVC