/[svn]/linuxsampler/trunk/src/engines/common/VoiceBase.h
ViewVC logotype

Annotation of /linuxsampler/trunk/src/engines/common/VoiceBase.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3725 - (hide annotations) (download) (as text)
Thu Jan 23 18:45:00 2020 UTC (4 years, 2 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 14226 byte(s)
* Fixed playing noise at the end of a disk stream under certain
  conditions.

* Bumped version (2.1.1.svn42).

1 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 3725 * Copyright (C) 2005-2020 Christian Schoenebeck *
7     * Copyright (C) 2009-2011 Grigor Iliev *
8 iliev 2012 * *
9     * This program is free software; you can redistribute it and/or modify *
10     * it under the terms of the GNU General Public License as published by *
11     * the Free Software Foundation; either version 2 of the License, or *
12     * (at your option) any later version. *
13     * *
14     * This program is distributed in the hope that it will be useful, *
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17     * GNU General Public License for more details. *
18     * *
19     * You should have received a copy of the GNU General Public License *
20     * along with this program; if not, write to the Free Software *
21     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
22     * MA 02111-1307 USA *
23     ***************************************************************************/
24    
25     #ifndef __LS_VOICEBASE_H__
26     #define __LS_VOICEBASE_H__
27    
28 iliev 2015 #include "AbstractVoice.h"
29 schoenebeck 3725 #include <limits.h> // for INT_MIN
30 iliev 2012
31 schoenebeck 3725 /*
32     * Used as private, special constant value for @c VoiceBase member variable
33     * @c RealSampleWordsLeftToRead. This special constant value denotes that no
34     * silence samples have been added to the end of the stream yet.
35     */
36     #define NO_SILENCE_STREAM_SAMPLES_YET INT_MIN
37    
38 iliev 2012 namespace LinuxSampler {
39    
40 iliev 2015 template <class EC /* Engine Channel */, class R /* Region */, class S /* Sample */, class D /* DiskThread */>
41     class VoiceBase : public AbstractVoice {
42 iliev 2012 public:
43 iliev 2015 D* pDiskThread; ///< Pointer to the disk thread, to be able to order a disk stream and later to delete the stream again
44     int RealSampleWordsLeftToRead; ///< Number of samples left to read, not including the silence added for the interpolator
45 iliev 2012
46 iliev 2217 VoiceBase(SignalUnitRack* pRack = NULL): AbstractVoice(pRack) {
47 iliev 2015 pRegion = NULL;
48     pDiskThread = NULL;
49     }
50     virtual ~VoiceBase() { }
51    
52 iliev 2012 virtual R* GetRegion() { return pRegion; }
53    
54 iliev 2015 virtual unsigned long GetSampleCacheSize() {
55     return pSample->GetCache().Size;
56     }
57    
58     /**
59     * Initializes and triggers the voice, a disk stream will be launched if
60     * needed.
61     *
62     * @param pEngineChannel - engine channel on which this voice was ordered
63     * @param itNoteOnEvent - event that caused triggering of this voice
64     * @param PitchBend - MIDI detune factor (-8192 ... +8191)
65     * @param pRegion - points to the region which provides sample wave(s) and articulation data
66     * @param VoiceType - type of this voice
67     * @param iKeyGroup - a value > 0 defines a key group in which this voice is member of
68     * @returns 0 on success, a value < 0 if the voice wasn't triggered
69     * (either due to an error or e.g. because no region is
70     * defined for the given key)
71     */
72     virtual int Trigger (
73     AbstractEngineChannel* pEngineChannel,
74     Pool<Event>::Iterator& itNoteOnEvent,
75     int PitchBend,
76     R* pRegion,
77     type_t VoiceType,
78     int iKeyGroup
79     ) {
80     this->pRegion = pRegion;
81     this->pSample = pRegion->pSample; // sample won't change until the voice is finished
82    
83     return AbstractVoice::Trigger (
84     pEngineChannel, itNoteOnEvent, PitchBend, VoiceType, iKeyGroup
85     );
86     }
87    
88     virtual int OrderNewStream() {
89     int res = pDiskThread->OrderNewStream (
90 iliev 2216 &DiskStreamRef, pRegion, MaxRAMPos + GetRAMCacheOffset(), !RAMLoop
91 iliev 2015 );
92    
93     if (res < 0) {
94     dmsg(1,("Disk stream order failed!\n"));
95     KillImmediately();
96     return -1;
97     }
98    
99     return 0;
100     }
101 iliev 2216
102     /** The offset of the RAM cache from the sample start (in sample units). */
103     virtual int GetRAMCacheOffset() { return 0; }
104 iliev 2015
105     /**
106     * Renders the audio data for this voice for the current audio fragment.
107     * The sample input data can either come from RAM (cached sample or sample
108     * part) or directly from disk. The output signal will be rendered by
109     * resampling / interpolation. If this voice is a disk streaming voice and
110     * the voice completely played back the cached RAM part of the sample, it
111     * will automatically switch to disk playback for the next RenderAudio()
112     * call.
113     *
114     * @param Samples - number of samples to be rendered in this audio fragment cycle
115     */
116     void Render(uint Samples) {
117     // select default values for synthesis mode bits
118     SYNTHESIS_MODE_SET_LOOP(SynthesisMode, false);
119    
120     switch (this->PlaybackState) {
121    
122     case Voice::playback_state_init:
123     this->PlaybackState = Voice::playback_state_ram; // we always start playback from RAM cache and switch then to disk if needed
124     // no break - continue with playback_state_ram
125    
126     case Voice::playback_state_ram: {
127     if (RAMLoop) SYNTHESIS_MODE_SET_LOOP(SynthesisMode, true); // enable looping
128    
129     // render current fragment
130     Synthesize(Samples, (sample_t*) pSample->GetCache().pStart, Delay);
131    
132     if (DiskVoice) {
133     // check if we reached the allowed limit of the sample RAM cache
134     if (finalSynthesisParameters.dPos > MaxRAMPos) {
135 iliev 2027 dmsg(5,("VoiceBase: switching to disk playback (Pos=%f)\n", finalSynthesisParameters.dPos));
136 iliev 2015 this->PlaybackState = Voice::playback_state_disk;
137     }
138     } else if (finalSynthesisParameters.dPos >= pSample->GetCache().Size / SmplInfo.FrameSize) {
139     this->PlaybackState = Voice::playback_state_end;
140     }
141     }
142     break;
143    
144     case Voice::playback_state_disk: {
145     if (!DiskStreamRef.pStream) {
146     // check if the disk thread created our ordered disk stream in the meantime
147     DiskStreamRef.pStream = pDiskThread->AskForCreatedStream(DiskStreamRef.OrderID);
148     if (!DiskStreamRef.pStream) {
149 schoenebeck 2375 std::cerr << "Disk stream not available in time!\n" << std::flush;
150 iliev 2015 KillImmediately();
151     return;
152     }
153 schoenebeck 3054 DiskStreamRef.pStream->IncrementReadPos(uint(
154     SmplInfo.ChannelCount * (int(finalSynthesisParameters.dPos) - MaxRAMPos)
155     ));
156 iliev 2015 finalSynthesisParameters.dPos -= int(finalSynthesisParameters.dPos);
157 schoenebeck 3725 RealSampleWordsLeftToRead = NO_SILENCE_STREAM_SAMPLES_YET;
158 iliev 2015 }
159    
160     const int sampleWordsLeftToRead = DiskStreamRef.pStream->GetReadSpace();
161    
162     // add silence sample at the end if we reached the end of the stream (for the interpolator)
163     if (DiskStreamRef.State == Stream::state_end) {
164 schoenebeck 3725 if (RealSampleWordsLeftToRead == NO_SILENCE_STREAM_SAMPLES_YET) {
165     // remember how many sample words there are before any silence has been added
166     RealSampleWordsLeftToRead = sampleWordsLeftToRead;
167     }
168 iliev 2015 const int maxSampleWordsPerCycle = (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH) * SmplInfo.ChannelCount + 6; // +6 for the interpolator algorithm
169 schoenebeck 3725 if (sampleWordsLeftToRead < maxSampleWordsPerCycle) {
170 iliev 2015 DiskStreamRef.pStream->WriteSilence(maxSampleWordsPerCycle - sampleWordsLeftToRead);
171     }
172     }
173    
174     sample_t* ptr = (sample_t*)DiskStreamRef.pStream->GetReadPtr(); // get the current read_ptr within the ringbuffer where we read the samples from
175    
176     // render current audio fragment
177     Synthesize(Samples, ptr, Delay);
178    
179     const int iPos = (int) finalSynthesisParameters.dPos;
180     const int readSampleWords = iPos * SmplInfo.ChannelCount; // amount of sample words actually been read
181     DiskStreamRef.pStream->IncrementReadPos(readSampleWords);
182     finalSynthesisParameters.dPos -= iPos; // just keep fractional part of playback position
183    
184     // change state of voice to 'end' if we really reached the end of the sample data
185     if (RealSampleWordsLeftToRead >= 0) {
186     RealSampleWordsLeftToRead -= readSampleWords;
187 schoenebeck 3725 if (RealSampleWordsLeftToRead <= 0) {
188     this->PlaybackState = Voice::playback_state_end;
189     RealSampleWordsLeftToRead = 0;
190     }
191 iliev 2015 }
192     }
193     break;
194    
195     case Voice::playback_state_end:
196 iliev 2027 std::cerr << "VoiceBase::Render(): entered with playback_state_end, this is a bug!\n" << std::flush;
197 iliev 2015 break;
198     }
199    
200     // Reset delay
201     Delay = 0;
202    
203     itTriggerEvent = Pool<Event>::Iterator();
204    
205     // If sample stream or release stage finished, kill the voice
206 iliev 2205 if (PlaybackState == Voice::playback_state_end || EG1Finished()) {
207 persson 2055 KillImmediately();
208     }
209 iliev 2015 }
210    
211     /**
212     * Immediately kill the voice. This method should not be used to kill
213     * a normal, active voice, because it doesn't take care of things like
214     * fading down the volume level to avoid clicks and regular processing
215     * until the kill event actually occured!
216     *
217     * If it's necessary to know when the voice's disk stream was actually
218     * deleted, then one can set the optional @a bRequestNotification
219     * parameter and this method will then return the handle of the disk
220     * stream (unique identifier) and one can use this handle to poll the
221     * disk thread if this stream has been deleted. In any case this method
222     * will return immediately and will not block until the stream actually
223     * was deleted.
224     *
225     * @param bRequestNotification - (optional) whether the disk thread shall
226     * provide a notification once it deleted
227     * the respective disk stream
228     * (default=false)
229     * @returns handle to the voice's disk stream or @c Stream::INVALID_HANDLE
230     * if the voice did not use a disk stream at all
231     * @see Kill()
232     */
233     Stream::Handle KillImmediately(bool bRequestNotification = false) {
234     Stream::Handle hStream = Stream::INVALID_HANDLE;
235     if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
236     pDiskThread->OrderDeletionOfStream(&DiskStreamRef, bRequestNotification);
237     hStream = DiskStreamRef.hStream;
238     }
239     Reset();
240     return hStream;
241     }
242    
243 iliev 2012 protected:
244 iliev 2015 S* pSample; ///< Pointer to the sample to be played back
245     R* pRegion; ///< Pointer to the articulation information of current region of this voice
246    
247 schoenebeck 2121 virtual MidiKeyBase* GetMidiKeyInfo(int MIDIKey) {
248     EC* pChannel = static_cast<EC*>(pEngineChannel);
249     return &pChannel->pMIDIKeyInfo[MIDIKey];
250     }
251    
252 iliev 2015 virtual unsigned long GetNoteOnTime(int MIDIKey) {
253     EC* pChannel = static_cast<EC*>(pEngineChannel);
254     return pChannel->pMIDIKeyInfo[MIDIKey].NoteOnTime;
255     }
256    
257     void GetFirstEventOnKey(uint8_t MIDIKey, RTList<Event>::Iterator& itEvent) {
258     EC* pChannel = static_cast<EC*>(pEngineChannel);
259     itEvent = pChannel->pMIDIKeyInfo[MIDIKey].pEvents->first();
260     }
261 iliev 2012 };
262     } // namespace LinuxSampler
263    
264     #endif /* __LS_VOICEBASE_H__ */
265    

  ViewVC Help
Powered by ViewVC