/[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 3054 - (hide annotations) (download) (as text)
Thu Dec 15 12:47:45 2016 UTC (7 years, 4 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 13776 byte(s)
* Fixed numerous compiler warnings.
* Bumped version (2.0.0.svn32).

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

  ViewVC Help
Powered by ViewVC