/[svn]/linuxsampler/trunk/src/voice.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/voice.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 33 - (show annotations) (download)
Mon Feb 16 19:30:42 2004 UTC (20 years, 2 months ago) by schoenebeck
File size: 16675 byte(s)
* implemented bidirectional voice state transition, means voice state can
  switch arbitrary times between 'Sustained'<-->'Released' within it's life
  time, thus the release process of a voice can be cancelled
* src/eg_vca.cpp: extended envelope generator by additional states
  ('Attack_Hold', 'Decay_1' and 'Decay_2')
* applied patch from Vladimir Senkov which adds new command line parameters
  ('--jackout', '--alsaout' and '--samplerate')
* configure.in: fixed compiler warning

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003 by Benno Senoner and Christian Schoenebeck *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
20 * MA 02111-1307 USA *
21 ***************************************************************************/
22
23 #include "voice.h"
24
25 // FIXME: no support for layers (nor crossfades) yet
26
27 DiskThread* Voice::pDiskThread = NULL;
28 AudioThread* Voice::pEngine = NULL;
29
30 Voice::Voice() {
31 Active = false;
32 }
33
34 Voice::~Voice() {
35 }
36
37 /**
38 * Initializes and triggers the voice, a disk stream will be launched if
39 * needed.
40 *
41 * @param pNoteOnEvent - event that caused triggering of this voice
42 * @param Pitch - MIDI detune factor (-8192 ... +8191)
43 * @param pInstrument - points to the loaded instrument which provides sample wave(s) and articulation data
44 * @returns 0 on success, a value < 0 if something failed
45 */
46 int Voice::Trigger(ModulationSystem::Event* pNoteOnEvent, int Pitch, gig::Instrument* pInstrument) {
47 Active = true;
48 MIDIKey = pNoteOnEvent->Key;
49 pRegion = pInstrument->GetRegion(MIDIKey);
50 PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed
51 Pos = 0;
52 ReleaseVelocity = 127; // default release velocity value
53 Delay = pNoteOnEvent->FragmentPos();
54 pTriggerEvent = pNoteOnEvent;
55
56 if (!pRegion) {
57 std::cerr << "Audio Thread: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;
58 Kill();
59 return -1;
60 }
61
62 //TODO: current MIDI controller values are not taken into account yet
63 gig::DimensionRegion* pDimRgn = NULL;
64 for (int i = pRegion->Dimensions - 1; i >= 0; i--) { // Check if instrument has a velocity split
65 if (pRegion->pDimensionDefinitions[i].dimension == gig::dimension_velocity) {
66 uint DimValues[5] = {0,0,0,0,0};
67 DimValues[i] = pNoteOnEvent->Velocity;
68 pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);
69 break;
70 }
71 }
72 if (!pDimRgn) { // if there was no velocity split
73 pDimRgn = pRegion->GetDimensionRegionByValue(0,0,0,0,0);
74 }
75
76 pSample = pDimRgn->pSample; // sample won't change until the voice is finished
77
78 // Check if the sample needs disk streaming or is too short for that
79 long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
80 DiskVoice = cachedsamples < pSample->SamplesTotal;
81
82 if (DiskVoice) { // voice to be streamed from disk
83 MaxRAMPos = cachedsamples - (MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels; //TODO: this calculation is too pessimistic and may better be moved to Render() method, so it calculates MaxRAMPos dependent to the current demand of sample points to be rendered (e.g. in case of JACK)
84
85 // check if there's a loop defined which completely fits into the cached (RAM) part of the sample
86 if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
87 RAMLoop = true;
88 LoopCyclesLeft = pSample->LoopPlayCount;
89 }
90 else RAMLoop = false;
91
92 if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {
93 dmsg(1,("Disk stream order failed!\n"));
94 Kill();
95 return -1;
96 }
97 dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
98 }
99 else { // RAM only voice
100 MaxRAMPos = cachedsamples;
101 if (pSample->Loops) {
102 RAMLoop = true;
103 LoopCyclesLeft = pSample->LoopPlayCount;
104 }
105 else RAMLoop = false;
106 dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));
107 }
108
109
110 // Pitch according to keyboard position (if 'PitchTrack' is set) and given detune factor
111 this->Pitch = ((double) Pitch / 8192.0) / 12.0 + (pDimRgn->PitchTrack) ? pow(2, ((double) (MIDIKey - (int) pDimRgn->UnityNote) + (double) pDimRgn->FineTune / 100.0) / 12.0)
112 : pow(2, ((double) pDimRgn->FineTune / 100.0) / 12.0);
113
114 Volume = pDimRgn->GetVelocityAttenuation(pNoteOnEvent->Velocity);
115
116 EG1.Trigger(pDimRgn->EG1PreAttack,
117 pDimRgn->EG1Attack,
118 pDimRgn->EG1Hold,
119 pSample->LoopStart,
120 pDimRgn->EG1Decay1,
121 pDimRgn->EG1Decay2,
122 pDimRgn->EG1InfiniteSustain,
123 pDimRgn->EG1Sustain,
124 pDimRgn->EG1Release,
125 Delay);
126
127 // ************************************************
128 // TODO: ARTICULATION DATA HANDLING IS MISSING HERE
129 // ************************************************
130
131 return 0; // success
132 }
133
134 /**
135 * Renders the audio data for this voice for the current audio fragment.
136 * The sample input data can either come from RAM (cached sample or sample
137 * part) or directly from disk. The output signal will be rendered by
138 * resampling / interpolation. If this voice is a disk streaming voice and
139 * the voice completely played back the cached RAM part of the sample, it
140 * will automatically switch to disk playback for the next RenderAudio()
141 * call.
142 *
143 * @param Samples - number of samples to be rendered in this audio fragment cycle
144 */
145 void Voice::Render(uint Samples) {
146
147 // Reset the synthesis parameter matrix
148 ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vca, this->Volume);
149 ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vco, this->Pitch);
150
151
152 // Apply events to the synthesis parameter matrix
153 ProcessEvents(Samples);
154
155
156 // Let all modulators throw their parameter changes for the current audio fragment
157 EG1.Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->Pitch);
158
159
160 switch (this->PlaybackState) {
161
162 case playback_state_ram: {
163 if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
164 else Interpolate(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
165 if (DiskVoice) {
166 // check if we reached the allowed limit of the sample RAM cache
167 if (Pos > MaxRAMPos) {
168 dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));
169 this->PlaybackState = playback_state_disk;
170 }
171 }
172 else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) {
173 this->PlaybackState = playback_state_end;
174 }
175 }
176 break;
177
178 case playback_state_disk: {
179 if (!DiskStreamRef.pStream) {
180 // check if the disk thread created our ordered disk stream in the meantime
181 DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
182 if (!DiskStreamRef.pStream) {
183 std::cout << stderr << "Disk stream not available in time!" << std::endl << std::flush;
184 Kill();
185 return;
186 }
187 DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (double_to_int(Pos) - MaxRAMPos));
188 Pos -= double_to_int(Pos);
189 }
190
191 // add silence sample at the end if we reached the end of the stream (for the interpolator)
192 if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) {
193 DiskStreamRef.pStream->WriteSilence((MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);
194 this->PlaybackState = playback_state_end;
195 }
196
197 sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from
198 Interpolate(Samples, ptr, Delay);
199 DiskStreamRef.pStream->IncrementReadPos(double_to_int(Pos) * pSample->Channels);
200 Pos -= double_to_int(Pos);
201 }
202 break;
203
204 case playback_state_end:
205 Kill(); // free voice
206 break;
207 }
208
209
210 // Reset delay
211 Delay = 0;
212
213 pTriggerEvent = NULL;
214
215 // If release stage finished, let the voice be killed
216 if (EG1.GetStage() == EG_VCA::stage_end) this->PlaybackState = playback_state_end;
217 }
218
219 /**
220 * Process the control change event lists of the engine for the current
221 * audio fragment. Event values will be applied to the synthesis parameter
222 * matrix.
223 *
224 * @param Samples - number of samples to be rendered in this audio fragment cycle
225 */
226 void Voice::ProcessEvents(uint Samples) {
227 // process pitch events
228 RTEList<ModulationSystem::Event>* pEventList = pEngine->pCCEvents[ModulationSystem::destination_vco];
229 ModulationSystem::Event* pEvent = pEventList->first();;
230 while (pEvent) {
231 ModulationSystem::Event* pNextEvent = pEventList->next();
232
233 // calculate the influence length of this event (in sample points)
234 uint duration = (pNextEvent) ? pNextEvent->FragmentPos() - pEvent->FragmentPos()
235 : Samples - pEvent->FragmentPos();
236
237 // calculate actual pitch value
238 switch (pEvent->Type) {
239 case ModulationSystem::event_type_pitchbend:
240 this->Pitch += ((double) pEvent->Pitch / 8192.0) / 12.0; // +- one semitone
241 break;
242 }
243
244 // apply pitch value to the pitch parameter sequence
245 for (uint i = pEvent->FragmentPos(); i < duration; i++) {
246 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i] = this->Pitch;
247 }
248
249 pEvent = pNextEvent;
250 }
251 }
252
253 /**
254 * Interpolates the input audio data (no loop).
255 *
256 * @param Samples - number of sample points to be rendered in this audio
257 * fragment cycle
258 * @param pSrc - pointer to input sample data
259 * @param Skip - number of sample points to skip in output buffer
260 */
261 void Voice::Interpolate(uint Samples, sample_t* pSrc, uint Skip) {
262 int i = Skip;
263
264 // FIXME: assuming either mono or stereo
265 if (this->pSample->Channels == 2) { // Stereo Sample
266 while (i < Samples) {
267 InterpolateOneStep_Stereo(pSrc, i,
268 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
269 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
270 }
271 }
272 else { // Mono Sample
273 while (i < Samples) {
274 InterpolateOneStep_Mono(pSrc, i,
275 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
276 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
277 }
278 }
279 }
280
281 /**
282 * Interpolates the input audio data, this method honors looping.
283 *
284 * @param Samples - number of sample points to be rendered in this audio
285 * fragment cycle
286 * @param pSrc - pointer to input sample data
287 * @param Skip - number of sample points to skip in output buffer
288 */
289 void Voice::InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip) {
290 int i = Skip;
291
292 // FIXME: assuming either mono or stereo
293 if (pSample->Channels == 2) { // Stereo Sample
294 if (pSample->LoopPlayCount) {
295 // render loop (loop count limited)
296 while (i < Samples && LoopCyclesLeft) {
297 InterpolateOneStep_Stereo(pSrc, i,
298 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
299 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
300 if (Pos > pSample->LoopEnd) {
301 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
302 LoopCyclesLeft--;
303 }
304 }
305 // render on without loop
306 while (i < Samples) {
307 InterpolateOneStep_Stereo(pSrc, i,
308 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
309 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
310 }
311 }
312 else { // render loop (endless loop)
313 while (i < Samples) {
314 InterpolateOneStep_Stereo(pSrc, i,
315 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
316 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
317 if (Pos > pSample->LoopEnd) {
318 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
319 }
320 }
321 }
322 }
323 else { // Mono Sample
324 if (pSample->LoopPlayCount) {
325 // render loop (loop count limited)
326 while (i < Samples && LoopCyclesLeft) {
327 InterpolateOneStep_Mono(pSrc, i,
328 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
329 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
330 if (Pos > pSample->LoopEnd) {
331 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
332 LoopCyclesLeft--;
333 }
334 }
335 // render on without loop
336 while (i < Samples) {
337 InterpolateOneStep_Mono(pSrc, i,
338 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
339 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
340 }
341 }
342 else { // render loop (endless loop)
343 while (i < Samples) {
344 InterpolateOneStep_Mono(pSrc, i,
345 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
346 ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
347 if (Pos > pSample->LoopEnd) {
348 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
349 }
350 }
351 }
352 }
353 }
354
355 /**
356 * Immediately kill the voice.
357 */
358 void Voice::Kill() {
359 if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
360 pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
361 }
362 DiskStreamRef.pStream = NULL;
363 DiskStreamRef.hStream = 0;
364 DiskStreamRef.State = Stream::state_unused;
365 DiskStreamRef.OrderID = 0;
366 Active = false;
367 }

  ViewVC Help
Powered by ViewVC