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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (hide annotations) (download)
Sun Nov 16 19:01:50 2003 UTC (20 years, 5 months ago) by schoenebeck
File size: 9552 byte(s)
* src/gig.cpp: fixed bug in decompression algorithm which caused it not to
  detect the end of a stream and let the disk streams reload forever also
  resulting in strange sounds at the end of disk voices (concerned only
  playback of compressed gig files)
* src/audiothread.cpp: deallocation of voices when they reached the end of
  playback (thus e.g. when sustain pedal is pressed and a disk stream
  reached it's end)
* various endian corrections needed for non intel systems
* introduced debug level, you can set the debug level and thus the
  verbosity of LinuxSampler in src/global.h

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     void Voice::Trigger(int MIDIKey, uint8_t Velocity, gig::Instrument* Instrument) {
38     Active = true;
39 schoenebeck 12 this->MIDIKey = MIDIKey;
40 schoenebeck 9 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 schoenebeck 12 dmsg(5,("Disk voice launched (cached samples: %d, total Samples: %d, MaxRAMPos: %d\n", cachedsamples, pSample->SamplesTotal, MaxRAMPos));
74 schoenebeck 9 }
75     else {
76     MaxRAMPos = cachedsamples;
77 schoenebeck 12 dmsg(5,("RAM only voice launched\n"));
78 schoenebeck 9 }
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 schoenebeck 12 dmsg(5,("Voice: switching to disk playback (Pos=%f)\n", Pos));
97 schoenebeck 9 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     this->Active = false; // 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