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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 30 - (show annotations) (download)
Sun Jan 11 16:43:54 2004 UTC (20 years, 3 months ago) by schoenebeck
File size: 12463 byte(s)
* implemented amplitude envelope generator
* src/voice.cpp: some .gig instruments still sounded detuned, I hope
  finally to have this fixed now

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
29 Voice::Voice(DiskThread* pDiskThread) {
30 Active = false;
31 Voice::pDiskThread = pDiskThread;
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 * @returns 0 on success, a value < 0 if something failed
42 */
43 int Voice::Trigger(int MIDIKey, uint8_t Velocity, gig::Instrument* Instrument) {
44 Active = true;
45 this->MIDIKey = MIDIKey;
46 pRegion = Instrument->GetRegion(MIDIKey);
47 PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed
48 Pos = 0;
49 ReleaseVelocity = 127; // default release velocity value
50
51 if (!pRegion) {
52 std::cerr << "Audio Thread: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;
53 Kill();
54 return -1;
55 }
56
57 //TODO: current MIDI controller values are not taken into account yet
58 gig::DimensionRegion* pDimRgn = NULL;
59 for (int i = pRegion->Dimensions - 1; i >= 0; i--) { // Check if instrument has a velocity split
60 if (pRegion->pDimensionDefinitions[i].dimension == gig::dimension_velocity) {
61 uint DimValues[5] = {0,0,0,0,0};
62 DimValues[i] = Velocity;
63 pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);
64 break;
65 }
66 }
67 if (!pDimRgn) { // if there was no velocity split
68 pDimRgn = pRegion->GetDimensionRegionByValue(0,0,0,0,0);
69 }
70
71 pSample = pDimRgn->pSample; // sample won't change until the voice is finished
72
73 // Check if the sample needs disk streaming or is too short for that
74 long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
75 DiskVoice = cachedsamples < pSample->SamplesTotal;
76
77 if (DiskVoice) { // voice to be streamed from disk
78 MaxRAMPos = cachedsamples - (OutputBufferSize << MAX_PITCH) / pSample->Channels;
79
80 // check if there's a loop defined which completely fits into the cached (RAM) part of the sample
81 if (pSample->Loops && pSample->LoopEnd <= MaxRAMPos) {
82 RAMLoop = true;
83 LoopCyclesLeft = pSample->LoopPlayCount;
84 }
85 else RAMLoop = false;
86
87 if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos, !RAMLoop) < 0) {
88 dmsg(1,("Disk stream order failed!\n"));
89 Kill();
90 return -1;
91 }
92 dmsg(4,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d, RAMLooping: %s\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos, (RAMLoop) ? "yes" : "no"));
93 }
94 else { // RAM only voice
95 MaxRAMPos = cachedsamples;
96 if (pSample->Loops) {
97 RAMLoop = true;
98 LoopCyclesLeft = pSample->LoopPlayCount;
99 }
100 else RAMLoop = false;
101 dmsg(4,("RAM only voice launched (Looping: %s)\n", (RAMLoop) ? "yes" : "no"));
102 }
103
104
105 // Pitch according to keyboard position (if 'PitchTrack' is set)
106 CurrentPitch = (pDimRgn->PitchTrack) ? pow(2, ((double) (MIDIKey - (int) pDimRgn->UnityNote) + (double) pDimRgn->FineTune / 100.0) / 12.0)
107 : pow(2, ((double) pDimRgn->FineTune / 100.0) / 12.0);
108
109 Volume = pDimRgn->GetVelocityAttenuation(Velocity);
110
111 EG1.Trigger(pDimRgn->EG1PreAttack, pDimRgn->EG1Attack, pDimRgn->EG1Release);
112
113 // ************************************************
114 // TODO: ARTICULATION DATA HANDLING IS MISSING HERE
115 // ************************************************
116
117 return 0; // success
118 }
119
120 /**
121 * Renders the audio data for this voice for the current audio fragment.
122 * The sample input data can either come from RAM (cached sample or sample
123 * part) or directly from disk. The output signal will be rendered by
124 * resampling / interpolation. If this voice is a disk streaming voice and
125 * the voice completely played back the cached RAM part of the sample, it
126 * will automatically switch to disk playback for the next RenderAudio()
127 * call.
128 */
129 void Voice::RenderAudio() {
130
131 // Let all modulators throw their parameter changes for the current audio fragment
132 ModulationSystem::ResetDestinationParameter(ModulationSystem::destination_vca, this->Volume);
133 EG1.ProcessFragment();
134
135
136 switch (this->PlaybackState) {
137
138 case playback_state_ram: {
139 if (RAMLoop) InterpolateAndLoop((sample_t*) pSample->GetCache().pStart);
140 else Interpolate((sample_t*) pSample->GetCache().pStart);
141 if (DiskVoice) {
142 // check if we reached the allowed limit of the sample RAM cache
143 if (Pos > MaxRAMPos) {
144 dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));
145 this->PlaybackState = playback_state_disk;
146 }
147 }
148 else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) {
149 this->PlaybackState = playback_state_end;
150 }
151 }
152 break;
153
154 case playback_state_disk: {
155 if (!DiskStreamRef.pStream) {
156 // check if the disk thread created our ordered disk stream in the meantime
157 DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
158 if (!DiskStreamRef.pStream) {
159 std::cout << stderr << "Disk stream not available in time!" << std::endl << std::flush;
160 Kill();
161 return;
162 }
163 DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (double_to_int(Pos) - MaxRAMPos));
164 Pos -= double_to_int(Pos);
165 }
166
167 // add silence sample at the end if we reached the end of the stream (for the interpolator)
168 if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (OutputBufferSize << MAX_PITCH) / pSample->Channels) {
169 DiskStreamRef.pStream->WriteSilence((OutputBufferSize << MAX_PITCH) / pSample->Channels);
170 this->PlaybackState = playback_state_end;
171 }
172
173 sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from
174 Interpolate(ptr);
175 DiskStreamRef.pStream->IncrementReadPos(double_to_int(Pos) * pSample->Channels);
176 Pos -= double_to_int(Pos);
177 }
178 break;
179
180 case playback_state_end:
181 Kill(); // free voice
182 break;
183 }
184
185 // If release stage finished, let the voice be killed
186 if (EG1.GetStage() == EG_VCA::stage_end) this->PlaybackState = playback_state_end;
187 }
188
189 /**
190 * Interpolates the input audio data (no loop).
191 *
192 * @param pSrc - pointer to input sample data
193 */
194 void Voice::Interpolate(sample_t* pSrc) {
195 int i = 0;
196 float e = 1.0;
197
198 // FIXME: assuming either mono or stereo
199 if (this->pSample->Channels == 2) { // Stereo Sample
200 while (i < this->OutputBufferSize) {
201 InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
202 }
203 }
204 else { // Mono Sample
205 while (i < this->OutputBufferSize) {
206 InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
207 }
208 }
209 }
210
211 /**
212 * Interpolates the input audio data, this method honors looping.
213 *
214 * @param pSrc - pointer to input sample data
215 */
216 void Voice::InterpolateAndLoop(sample_t* pSrc) {
217 int i = 0;
218
219 // FIXME: assuming either mono or stereo
220 if (pSample->Channels == 2) { // Stereo Sample
221 if (pSample->LoopPlayCount) {
222 // render loop (loop count limited)
223 while (i < OutputBufferSize && LoopCyclesLeft) {
224 InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
225 if (Pos > pSample->LoopEnd) {
226 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
227 LoopCyclesLeft--;
228 }
229 }
230 // render on without loop
231 while (i < OutputBufferSize) {
232 InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
233 }
234 }
235 else { // render loop (endless loop)
236 while (i < OutputBufferSize) {
237 InterpolateOneStep_Stereo(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
238 if (Pos > pSample->LoopEnd) {
239 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);
240 }
241 }
242 }
243 }
244 else { // Mono Sample
245 if (pSample->LoopPlayCount) {
246 // render loop (loop count limited)
247 while (i < OutputBufferSize && LoopCyclesLeft) {
248 InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
249 if (Pos > pSample->LoopEnd) {
250 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
251 LoopCyclesLeft--;
252 }
253 }
254 // render on without loop
255 while (i < OutputBufferSize) {
256 InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
257 }
258 }
259 else { // render loop (endless loop)
260 while (i < OutputBufferSize) {
261 InterpolateOneStep_Mono(pSrc, i, ModulationSystem::pDestinationParameter[ModulationSystem::destination_vca][i>>1]);
262 if (Pos > pSample->LoopEnd) {
263 Pos = pSample->LoopStart + fmod(Pos - pSample->LoopEnd, pSample->LoopSize);;
264 }
265 }
266 }
267 }
268 }
269
270 /**
271 * Immediately kill the voice.
272 */
273 void Voice::Kill() {
274 if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
275 pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
276 }
277 DiskStreamRef.pStream = NULL;
278 DiskStreamRef.hStream = 0;
279 DiskStreamRef.State = Stream::state_unused;
280 DiskStreamRef.OrderID = 0;
281 Active = false;
282 }
283
284 /**
285 * Release the voice in an appropriate time range, the voice will go through
286 * it's release stage before it will be killed.
287 */
288 void Voice::Release() {
289 EG1.Release();
290 }

  ViewVC Help
Powered by ViewVC