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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2101 - (show annotations) (download)
Sun May 30 11:40:31 2010 UTC (13 years, 10 months ago) by persson
File size: 8801 byte(s)
* sfz/sf2 engines: RT-safeness: avoid malloc in audio thread
* sfz/sf2 engines: fixed a bug that could cause voice stealing to fail

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-2010 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 ::sfz::Query q(*pChannel->pInstrument);
76 q.chan = pChannel->MidiChannel();
77 q.key = itNoteOnEvent->Param.Note.Key;
78 q.vel = itNoteOnEvent->Param.Note.Velocity;
79 q.bend = pChannel->Pitch;
80 q.bpm = 0;
81 q.chanaft = pChannel->ControllerTable[128];
82 q.polyaft = 0;
83 q.prog = 0;
84 q.rand = Random();
85 q.cc = pChannel->ControllerTable;
86 q.timer = 0;
87 q.sw = pChannel->PressedKeys;
88 q.last_sw_key = pChannel->LastKeySwitch;
89 q.prev_sw_key = pChannel->LastKey;
90 q.trig = TRIGGER_ATTACK |
91 ((pChannel->LastKey != -1 &&
92 pChannel->PressedKeys[pChannel->LastKey] &&
93 pChannel->LastKey != q.key) ?
94 TRIGGER_LEGATO : TRIGGER_FIRST);
95
96 int i = 0;
97 while (::sfz::Region* region = q.next()) {
98 if (!RegionSuspended(region)) {
99 itNoteOnEvent->Param.Note.pRegion = region;
100 LaunchVoice(pChannel, itNoteOnEvent, i, false, true, HandleKeyGroupConflicts);
101 }
102 i++;
103 }
104 }
105
106 void Engine::TriggerReleaseVoices (
107 LinuxSampler::EngineChannel* pEngineChannel,
108 RTList<Event>::Iterator& itNoteOffEvent
109 ) {
110 EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
111 ::sfz::Query q(*pChannel->pInstrument);
112 q.chan = pChannel->MidiChannel();
113 q.key = itNoteOffEvent->Param.Note.Key;
114
115 // MIDI note-on velocity is used instead of note-off velocity
116 q.vel = pChannel->pMIDIKeyInfo[q.key].Velocity;
117 itNoteOffEvent->Param.Note.Velocity = q.vel;
118
119 q.bend = pChannel->Pitch;
120 q.bpm = 0;
121 q.chanaft = pChannel->ControllerTable[128];
122 q.polyaft = 0;
123 q.prog = 0;
124 q.rand = Random();
125 q.cc = pChannel->ControllerTable;
126 q.timer = 0;
127 q.sw = pChannel->PressedKeys;
128 q.last_sw_key = pChannel->LastKeySwitch;
129 q.prev_sw_key = pChannel->LastKey;
130 q.trig = TRIGGER_RELEASE;
131
132 // now launch the required amount of voices
133 int i = 0;
134 while (::sfz::Region* region = q.next()) {
135 itNoteOffEvent->Param.Note.pRegion = region;
136 LaunchVoice(pChannel, itNoteOffEvent, i, true, false, false); //FIXME: for the moment we don't perform voice stealing for release triggered samples
137 i++;
138 }
139 }
140
141 Pool<Voice>::Iterator Engine::LaunchVoice (
142 LinuxSampler::EngineChannel* pEngineChannel,
143 Pool<Event>::Iterator& itNoteOnEvent,
144 int iLayer,
145 bool ReleaseTriggerVoice,
146 bool VoiceStealing,
147 bool HandleKeyGroupConflicts
148 ) {
149 EngineChannel* pChannel = static_cast<EngineChannel*>(pEngineChannel);
150 int key = itNoteOnEvent->Param.Note.Key;
151 EngineChannel::MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
152 Voice::type_t VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal;
153
154 Pool<Voice>::Iterator itNewVoice;
155 ::sfz::Region* pRgn = static_cast< ::sfz::Region*>(itNoteOnEvent->Param.Note.pRegion);
156
157 // no need to process if sample is silent
158 if (!pRgn->GetSample() || !pRgn->GetSample()->GetTotalFrameCount()) return Pool<Voice>::Iterator();
159
160 // only mark the first voice of a layered voice (group) to be in a
161 // key group, so the layered voices won't kill each other
162 int iKeyGroup = (iLayer == 0 && !ReleaseTriggerVoice) ? pRgn->group : 0;
163 if (HandleKeyGroupConflicts) pChannel->HandleKeyGroupConflicts(iKeyGroup, itNoteOnEvent, pRgn->off_mode == ::sfz::OFF_NORMAL);
164
165 // allocate a new voice for the key
166 itNewVoice = pKey->pActiveVoices->allocAppend();
167 int res = InitNewVoice (
168 pChannel, pRgn, itNoteOnEvent, VoiceType, iLayer,
169 iKeyGroup, ReleaseTriggerVoice, VoiceStealing, itNewVoice
170 );
171 if (!res) return itNewVoice;
172
173 // return if this is a release triggered voice and there is no
174 // releasetrigger dimension (could happen if an instrument
175 // change has occured between note on and off)
176 //if (ReleaseTriggerVoice && VoiceType != Voice::type_release_trigger) return Pool<Voice>::Iterator();
177
178 return Pool<Voice>::Iterator(); // no free voice or error
179 }
180
181 bool Engine::DiskStreamSupported() {
182 return true;
183 }
184
185 String Engine::Description() {
186 return "SFZ Format Engine";
187 }
188
189 String Engine::Version() {
190 String s = "$Revision: 1.8 $";
191 return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
192 }
193
194 }} // namespace LinuxSampler::sfz

  ViewVC Help
Powered by ViewVC