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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 33 - (hide 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 schoenebeck 9 /***************************************************************************
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 schoenebeck 32 DiskThread* Voice::pDiskThread = NULL;
28     AudioThread* Voice::pEngine = NULL;
29 schoenebeck 9
30 schoenebeck 32 Voice::Voice() {
31     Active = false;
32 schoenebeck 9 }
33    
34     Voice::~Voice() {
35     }
36    
37 schoenebeck 18 /**
38     * Initializes and triggers the voice, a disk stream will be launched if
39     * needed.
40     *
41 schoenebeck 33 * @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 schoenebeck 18 */
46 schoenebeck 33 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 schoenebeck 9
56     if (!pRegion) {
57     std::cerr << "Audio Thread: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;
58 schoenebeck 18 Kill();
59     return -1;
60 schoenebeck 9 }
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 schoenebeck 33 DimValues[i] = pNoteOnEvent->Velocity;
68 schoenebeck 9 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 schoenebeck 26 if (DiskVoice) { // voice to be streamed from disk
83 schoenebeck 32 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 schoenebeck 26
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 schoenebeck 18 dmsg(1,("Disk stream order failed!\n"));
94     Kill();
95     return -1;
96     }
97 schoenebeck 31 dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s)\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
98 schoenebeck 9 }
99 schoenebeck 26 else { // RAM only voice
100 schoenebeck 9 MaxRAMPos = cachedsamples;
101 schoenebeck 26 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 schoenebeck 9 }
108    
109    
110 schoenebeck 32 // 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 schoenebeck 30
114 schoenebeck 33 Volume = pDimRgn->GetVelocityAttenuation(pNoteOnEvent->Velocity);
115 schoenebeck 30
116 schoenebeck 33 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 schoenebeck 30
127 schoenebeck 9 // ************************************************
128     // TODO: ARTICULATION DATA HANDLING IS MISSING HERE
129     // ************************************************
130 schoenebeck 18
131     return 0; // success
132 schoenebeck 9 }
133    
134 schoenebeck 26 /**
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 schoenebeck 32 *
143     * @param Samples - number of samples to be rendered in this audio fragment cycle
144 schoenebeck 26 */
145 schoenebeck 31 void Voice::Render(uint Samples) {
146 schoenebeck 9
147 schoenebeck 32 // 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 schoenebeck 30 // Let all modulators throw their parameter changes for the current audio fragment
157 schoenebeck 33 EG1.Process(Samples, pEngine->pMIDIKeyInfo[MIDIKey].pEvents, pTriggerEvent, this->Pos, this->Pitch);
158 schoenebeck 30
159    
160 schoenebeck 9 switch (this->PlaybackState) {
161    
162     case playback_state_ram: {
163 schoenebeck 32 if (RAMLoop) InterpolateAndLoop(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
164     else Interpolate(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
165 schoenebeck 9 if (DiskVoice) {
166     // check if we reached the allowed limit of the sample RAM cache
167     if (Pos > MaxRAMPos) {
168 schoenebeck 12 dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));
169 schoenebeck 9 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 schoenebeck 18 Kill();
185 schoenebeck 9 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 schoenebeck 31 if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels) {
193     DiskStreamRef.pStream->WriteSilence((MaxSamplesPerCycle << MAX_PITCH) / pSample->Channels);
194 schoenebeck 9 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 schoenebeck 32 Interpolate(Samples, ptr, Delay);
199 schoenebeck 9 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 schoenebeck 13 Kill(); // free voice
206 schoenebeck 9 break;
207     }
208 schoenebeck 30
209 schoenebeck 32
210     // Reset delay
211     Delay = 0;
212    
213 schoenebeck 33 pTriggerEvent = NULL;
214 schoenebeck 32
215 schoenebeck 30 // If release stage finished, let the voice be killed
216     if (EG1.GetStage() == EG_VCA::stage_end) this->PlaybackState = playback_state_end;
217 schoenebeck 9 }
218    
219 schoenebeck 26 /**
220 schoenebeck 32 * 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 schoenebeck 26 * Interpolates the input audio data (no loop).
255     *
256 schoenebeck 32 * @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 schoenebeck 26 */
261 schoenebeck 32 void Voice::Interpolate(uint Samples, sample_t* pSrc, uint Skip) {
262     int i = Skip;
263 schoenebeck 9
264     // FIXME: assuming either mono or stereo
265     if (this->pSample->Channels == 2) { // Stereo Sample
266 schoenebeck 31 while (i < Samples) {
267 schoenebeck 32 InterpolateOneStep_Stereo(pSrc, i,
268     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
269     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
270 schoenebeck 9 }
271     }
272     else { // Mono Sample
273 schoenebeck 31 while (i < Samples) {
274 schoenebeck 32 InterpolateOneStep_Mono(pSrc, i,
275     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
276     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
277 schoenebeck 26 }
278     }
279     }
280 schoenebeck 18
281 schoenebeck 26 /**
282     * Interpolates the input audio data, this method honors looping.
283     *
284 schoenebeck 32 * @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 schoenebeck 26 */
289 schoenebeck 32 void Voice::InterpolateAndLoop(uint Samples, sample_t* pSrc, uint Skip) {
290     int i = Skip;
291 schoenebeck 9
292 schoenebeck 26 // FIXME: assuming either mono or stereo
293     if (pSample->Channels == 2) { // Stereo Sample
294     if (pSample->LoopPlayCount) {
295     // render loop (loop count limited)
296 schoenebeck 31 while (i < Samples && LoopCyclesLeft) {
297 schoenebeck 32 InterpolateOneStep_Stereo(pSrc, i,
298     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
299     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
300 schoenebeck 26 if (Pos > pSample->LoopEnd) {
301     Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
302     LoopCyclesLeft--;
303     }
304     }
305     // render on without loop
306 schoenebeck 31 while (i < Samples) {
307 schoenebeck 32 InterpolateOneStep_Stereo(pSrc, i,
308     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
309     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
310 schoenebeck 26 }
311 schoenebeck 9 }
312 schoenebeck 26 else { // render loop (endless loop)
313 schoenebeck 31 while (i < Samples) {
314 schoenebeck 32 InterpolateOneStep_Stereo(pSrc, i,
315     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
316     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
317 schoenebeck 26 if (Pos > pSample->LoopEnd) {
318     Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
319     }
320     }
321     }
322 schoenebeck 9 }
323 schoenebeck 26 else { // Mono Sample
324     if (pSample->LoopPlayCount) {
325     // render loop (loop count limited)
326 schoenebeck 31 while (i < Samples && LoopCyclesLeft) {
327 schoenebeck 32 InterpolateOneStep_Mono(pSrc, i,
328     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
329     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
330 schoenebeck 26 if (Pos > pSample->LoopEnd) {
331     Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
332     LoopCyclesLeft--;
333     }
334     }
335     // render on without loop
336 schoenebeck 31 while (i < Samples) {
337 schoenebeck 32 InterpolateOneStep_Mono(pSrc, i,
338     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
339     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
340 schoenebeck 26 }
341     }
342     else { // render loop (endless loop)
343 schoenebeck 31 while (i < Samples) {
344 schoenebeck 32 InterpolateOneStep_Mono(pSrc, i,
345     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i],
346     ModulationSystem::pDestinationParameter[ModulationSystem::destination_vco][i]);
347 schoenebeck 26 if (Pos > pSample->LoopEnd) {
348     Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
349     }
350     }
351     }
352     }
353 schoenebeck 9 }
354    
355 schoenebeck 26 /**
356     * Immediately kill the voice.
357     */
358 schoenebeck 9 void Voice::Kill() {
359     if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
360     pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
361     }
362 schoenebeck 18 DiskStreamRef.pStream = NULL;
363     DiskStreamRef.hStream = 0;
364     DiskStreamRef.State = Stream::state_unused;
365     DiskStreamRef.OrderID = 0;
366 schoenebeck 9 Active = false;
367     }

  ViewVC Help
Powered by ViewVC