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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 18 - (hide annotations) (download)
Sun Dec 7 05:03:43 2003 UTC (20 years, 4 months ago) by schoenebeck
File size: 10332 byte(s)
* src/audioio.cpp: added support for Alsa 1.0.0
* src/audiothread.cpp: fixed several bugs in sustain pedal handling
* src/diskthread.cpp: fixed several bugs which occured under extreme
  conditions (endless loop in audiothread, freezing the whole application,
  outage of available disk streams)
* src/voice.cpp: fixed cubic interpolation (disabled by default; you can
  enable it by setting USE_LINEAR_INTERPOLATION to 0 in src/voice.h)
* src/configure.in: added check for Alsa version

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     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 schoenebeck 18 /**
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 schoenebeck 15 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 schoenebeck 9
51     if (!pRegion) {
52     std::cerr << "Audio Thread: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;
53 schoenebeck 18 Kill();
54     return -1;
55 schoenebeck 9 }
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) {
78     MaxRAMPos = cachedsamples - (OutputBufferSize << MAX_PITCH) / pSample->Channels;
79 schoenebeck 18 if (pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos) < 0) {
80     dmsg(1,("Disk stream order failed!\n"));
81     Kill();
82     return -1;
83     }
84 schoenebeck 12 dmsg(5,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos));
85 schoenebeck 9 }
86     else {
87     MaxRAMPos = cachedsamples;
88 schoenebeck 12 dmsg(5,("RAM only voice launched\n"));
89 schoenebeck 9 }
90    
91     CurrentPitch = pow(2, (double) (MIDIKey - (int) pSample->MIDIUnityNote) / (double) 12);
92 schoenebeck 17 Volume = pDimRgn->GetVelocityAttenuation(Velocity);
93 schoenebeck 9
94     // ************************************************
95     // TODO: ARTICULATION DATA HANDLING IS MISSING HERE
96     // ************************************************
97 schoenebeck 18
98     return 0; // success
99 schoenebeck 9 }
100    
101     void Voice::RenderAudio() {
102    
103     switch (this->PlaybackState) {
104    
105     case playback_state_ram: {
106     Interpolate((sample_t*) pSample->GetCache().pStart);
107     if (DiskVoice) {
108     // check if we reached the allowed limit of the sample RAM cache
109     if (Pos > MaxRAMPos) {
110 schoenebeck 12 dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));
111 schoenebeck 9 this->PlaybackState = playback_state_disk;
112     }
113     }
114     else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) {
115     this->PlaybackState = playback_state_end;
116     }
117     }
118     break;
119    
120     case playback_state_disk: {
121     if (!DiskStreamRef.pStream) {
122     // check if the disk thread created our ordered disk stream in the meantime
123     DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
124     if (!DiskStreamRef.pStream) {
125     std::cout << stderr << "Disk stream not available in time!" << std::endl << std::flush;
126 schoenebeck 18 Kill();
127 schoenebeck 9 return;
128     }
129     DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (double_to_int(Pos) - MaxRAMPos));
130     Pos -= double_to_int(Pos);
131     }
132    
133     // add silence sample at the end if we reached the end of the stream (for the interpolator)
134     if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (OutputBufferSize << MAX_PITCH) / pSample->Channels) {
135     DiskStreamRef.pStream->WriteSilence((OutputBufferSize << MAX_PITCH) / pSample->Channels);
136     this->PlaybackState = playback_state_end;
137     }
138    
139     sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from
140     Interpolate(ptr);
141     DiskStreamRef.pStream->IncrementReadPos(double_to_int(Pos) * pSample->Channels);
142     Pos -= double_to_int(Pos);
143     }
144     break;
145    
146     case playback_state_end:
147 schoenebeck 13 Kill(); // free voice
148 schoenebeck 9 break;
149     }
150     }
151    
152     void Voice::Interpolate(sample_t* pSrc) {
153 schoenebeck 17 float effective_volume = this->Volume;
154 schoenebeck 9 int i = 0;
155    
156     // ************************************************
157     // TODO: ARTICULATION DATA HANDLING IS MISSING HERE
158     // ************************************************
159    
160     // FIXME: assuming either mono or stereo
161     if (this->pSample->Channels == 2) { // Stereo Sample
162     while (i < this->OutputBufferSize) {
163 schoenebeck 18 int pos_int = double_to_int(this->Pos); // integer position
164     float pos_fract = this->Pos - pos_int; // fractional part of position
165     pos_int <<= 1;
166    
167     #if USE_LINEAR_INTERPOLATION
168 schoenebeck 9 // left channel
169     this->pOutput[i++] += effective_volume * (pSrc[pos_int] + pos_fract * (pSrc[pos_int+2] - pSrc[pos_int]));
170     // right channel
171     this->pOutput[i++] += effective_volume * (pSrc[pos_int+1] + pos_fract * (pSrc[pos_int+3] - pSrc[pos_int+1]));
172     #else // polynomial interpolation
173 schoenebeck 18 // calculate left channel
174     float xm1 = pSrc[pos_int];
175     float x0 = pSrc[pos_int+2];
176     float x1 = pSrc[pos_int+4];
177     float x2 = pSrc[pos_int+6];
178     float a = (3 * (x0 - x1) - xm1 + x2) / 2;
179     float b = 2 * x1 + xm1 - (5 * x0 + x2) / 2;
180     float c = (x1 - xm1) / 2;
181     this->pOutput[i++] += effective_volume * ((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0);
182    
183     //calculate right channel
184     xm1 = pSrc[pos_int+1];
185     x0 = pSrc[pos_int+3];
186     x1 = pSrc[pos_int+5];
187     x2 = pSrc[pos_int+7];
188     a = (3 * (x0 - x1) - xm1 + x2) / 2;
189 schoenebeck 9 b = 2 * x1 + xm1 - (5 * x0 + x2) / 2;
190     c = (x1 - xm1) / 2;
191 schoenebeck 18 this->pOutput[i++] += effective_volume * ((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0);
192 schoenebeck 9 #endif // USE_LINEAR_INTERPOLATION
193    
194     this->Pos += this->CurrentPitch;
195     }
196     }
197     else { // Mono Sample
198     while (i < this->OutputBufferSize) {
199 schoenebeck 18 int pos_int = double_to_int(this->Pos); // integer position
200     float pos_fract = this->Pos - pos_int; // fractional part of position
201    
202     #if USE_LINEAR_INTERPOLATION
203 schoenebeck 9 float sample_point = effective_volume * (pSrc[pos_int] + pos_fract * (pSrc[pos_int+1] - pSrc[pos_int]));
204     #else // polynomial interpolation
205 schoenebeck 18 float xm1 = pSrc[pos_int];
206     float x0 = pSrc[pos_int+1];
207     float x1 = pSrc[pos_int+2];
208     float x2 = pSrc[pos_int+3];
209     float a = (3 * (x0 - x1) - xm1 + x2) / 2;
210     float b = 2 * x1 + xm1 - (5 * x0 + x2) / 2;
211     float c = (x1 - xm1) / 2;
212     float sample_point = effective_volume * ((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0);
213     #endif // USE_LINEAR_INTERPOLATION
214 schoenebeck 9
215 schoenebeck 18 this->pOutput[i++] += sample_point;
216     this->pOutput[i++] += sample_point;
217    
218 schoenebeck 9 this->Pos += this->CurrentPitch;
219     }
220     }
221     }
222    
223     void Voice::Kill() {
224     if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
225     pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
226     }
227 schoenebeck 18 DiskStreamRef.pStream = NULL;
228     DiskStreamRef.hStream = 0;
229     DiskStreamRef.State = Stream::state_unused;
230     DiskStreamRef.OrderID = 0;
231 schoenebeck 9 Active = false;
232     }

  ViewVC Help
Powered by ViewVC