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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 13 - (show annotations) (download)
Fri Nov 21 15:07:23 2003 UTC (20 years, 4 months ago) by schoenebeck
File size: 9538 byte(s)
* src/voice.cpp: fixed bug which caused a voice not free it's disk stream
  when the whole sample was already played back and the voice was going to
  free itself resulting in outage of unused disk streams after a while
* src/audioio.cpp: implemented automatic fallback to ALSA plughw when the
  sound card doesn't support one of the hardware parameters
* src/linuxsampler.cpp: solved segmentation fault issue when receiving a
  SIGINT which was caused due to the fact that all threads entered the
  signal handler (there still seems to occur a segfault on some certain
  circumstances though)
* added print out of all-time maximum usage of voices and streams and the
  current number of unused streams
* src/thread.cpp: the StopThread() method will now block until the
  associated thread actually stopped it's execution

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 void Voice::Trigger(int MIDIKey, uint8_t Velocity, gig::Instrument* Instrument) {
38 Active = true;
39 this->MIDIKey = MIDIKey;
40 pRegion = Instrument->GetRegion(MIDIKey);
41 PlaybackState = playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed
42 Pos = 0;
43
44 if (!pRegion) {
45 std::cerr << "Audio Thread: No Region defined for MIDI key " << MIDIKey << std::endl << std::flush;
46 Active = false;
47 return;
48 }
49
50 //TODO: current MIDI controller values are not taken into account yet
51 gig::DimensionRegion* pDimRgn = NULL;
52 for (int i = pRegion->Dimensions - 1; i >= 0; i--) { // Check if instrument has a velocity split
53 if (pRegion->pDimensionDefinitions[i].dimension == gig::dimension_velocity) {
54 uint DimValues[5] = {0,0,0,0,0};
55 DimValues[i] = Velocity;
56 pDimRgn = pRegion->GetDimensionRegionByValue(DimValues[4],DimValues[3],DimValues[2],DimValues[1],DimValues[0]);
57 break;
58 }
59 }
60 if (!pDimRgn) { // if there was no velocity split
61 pDimRgn = pRegion->GetDimensionRegionByValue(0,0,0,0,0);
62 }
63
64 pSample = pDimRgn->pSample; // sample won't change until the voice is finished
65
66 // Check if the sample needs disk streaming or is too short for that
67 long cachedsamples = pSample->GetCache().Size / pSample->FrameSize;
68 DiskVoice = cachedsamples < pSample->SamplesTotal;
69
70 if (DiskVoice) {
71 MaxRAMPos = cachedsamples - (OutputBufferSize << MAX_PITCH) / pSample->Channels;
72 pDiskThread->OrderNewStream(&DiskStreamRef, pSample, MaxRAMPos);
73 dmsg(5,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos));
74 }
75 else {
76 MaxRAMPos = cachedsamples;
77 dmsg(5,("RAM only voice launched\n"));
78 }
79
80 CurrentPitch = pow(2, (double) (MIDIKey - (int) pSample->MIDIUnityNote) / (double) 12);
81
82 // ************************************************
83 // TODO: ARTICULATION DATA HANDLING IS MISSING HERE
84 // ************************************************
85 }
86
87 void Voice::RenderAudio() {
88
89 switch (this->PlaybackState) {
90
91 case playback_state_ram: {
92 Interpolate((sample_t*) pSample->GetCache().pStart);
93 if (DiskVoice) {
94 // check if we reached the allowed limit of the sample RAM cache
95 if (Pos > MaxRAMPos) {
96 dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));
97 this->PlaybackState = playback_state_disk;
98 }
99 }
100 else if (Pos >= pSample->GetCache().Size / pSample->FrameSize) {
101 this->PlaybackState = playback_state_end;
102 }
103 }
104 break;
105
106 case playback_state_disk: {
107 if (!DiskStreamRef.pStream) {
108 // check if the disk thread created our ordered disk stream in the meantime
109 DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
110 if (!DiskStreamRef.pStream) {
111 std::cout << stderr << "Disk stream not available in time!" << std::endl << std::flush;
112 pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
113 this->Active = false;
114 return;
115 }
116 DiskStreamRef.pStream->IncrementReadPos(pSample->Channels * (double_to_int(Pos) - MaxRAMPos));
117 Pos -= double_to_int(Pos);
118 }
119
120 // add silence sample at the end if we reached the end of the stream (for the interpolator)
121 if (DiskStreamRef.State == Stream::state_end && DiskStreamRef.pStream->GetReadSpace() < (OutputBufferSize << MAX_PITCH) / pSample->Channels) {
122 DiskStreamRef.pStream->WriteSilence((OutputBufferSize << MAX_PITCH) / pSample->Channels);
123 this->PlaybackState = playback_state_end;
124 }
125
126 sample_t* ptr = DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from
127 Interpolate(ptr);
128 DiskStreamRef.pStream->IncrementReadPos(double_to_int(Pos) * pSample->Channels);
129 Pos -= double_to_int(Pos);
130 }
131 break;
132
133 case playback_state_end:
134 Kill(); // free voice
135 break;
136 }
137 }
138
139 void Voice::Interpolate(sample_t* pSrc) {
140 float effective_volume = 1; // TODO: use the art. data instead
141 int i = 0;
142
143 // ************************************************
144 // TODO: ARTICULATION DATA HANDLING IS MISSING HERE
145 // ************************************************
146
147 // FIXME: assuming either mono or stereo
148 if (this->pSample->Channels == 2) { // Stereo Sample
149 while (i < this->OutputBufferSize) {
150 #ifdef USE_LINEAR_INTERPOLATION
151 int pos_int = double_to_int(this->Pos); // integer position
152 float pos_fract = this->Pos - pos_int; // fractional part of position
153 pos_int <<= 1;
154 // left channel
155 this->pOutput[i++] += effective_volume * (pSrc[pos_int] + pos_fract * (pSrc[pos_int+2] - pSrc[pos_int]));
156 // right channel
157 this->pOutput[i++] += effective_volume * (pSrc[pos_int+1] + pos_fract * (pSrc[pos_int+3] - pSrc[pos_int+1]));
158 #else // polynomial interpolation
159 //FIXME: !!!THIS WON'T WORK!!! needs to be adjusted for stereo, use linear interpolation meanwhile
160 xm1 = pSrc[pos_int];
161 x0 = pSrc[pos_int+1];
162 x1 = pSrc[pos_int+2];
163 x2 = pSrc[pos_int+3];
164 a = (3 * (x0-x1) - xm1 + x2) / 2;
165 b = 2 * x1 + xm1 - (5 * x0 + x2) / 2;
166 c = (x1 - xm1) / 2;
167 this->pOutput[u] += effective_volume*((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0);
168 #endif // USE_LINEAR_INTERPOLATION
169
170 this->Pos += this->CurrentPitch;
171 }
172 }
173 else { // Mono Sample
174 while (i < this->OutputBufferSize) {
175 #ifdef USE_LINEAR_INTERPOLATION
176 int pos_int = double_to_int(this->Pos); // integer position
177 float pos_fract = this->Pos - pos_int; // fractional part of position
178 float sample_point = effective_volume * (pSrc[pos_int] + pos_fract * (pSrc[pos_int+1] - pSrc[pos_int]));
179 this->pOutput[i] += sample_point;
180 this->pOutput[i+1] += sample_point;
181 i += 2;
182 #else // polynomial interpolation
183 //FIXME: !!!THIS WON'T WORK!!! needs to be adjusted for stereo, use linear interpolation meanwhile
184 xm1 = pSrc[pos_int];
185 x0 = pSrc[pos_int+1];
186 x1 = pSrc[pos_int+2];
187 x2 = pSrc[pos_int+3];
188 a = (3 * (x0-x1) - xm1 + x2) / 2;
189 b = 2 * x1 + xm1 - (5 * x0 + x2) / 2;
190 c = (x1 - xm1) / 2;
191 this->pOutput[u] += effective_volume*((((a * pos_fract) + b) * pos_fract + c) * pos_fract + x0);
192 #endif
193
194 this->Pos += this->CurrentPitch;
195 }
196 }
197 }
198
199 void Voice::Kill() {
200 if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
201 pDiskThread->OrderDeletionOfStream(&DiskStreamRef);
202 }
203 Active = false;
204 }

  ViewVC Help
Powered by ViewVC