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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2205 - (show annotations) (download) (as text)
Mon Jul 11 17:52:01 2011 UTC (12 years, 9 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 13413 byte(s)
* Introduced Signal Units and Signal Unit Racks, which hopefully will meet
  the demands of the new engines for flexible signal processing.
* sf2: Initial implementation of vibrato LFO, fixes in modulation EG and
  and volume EG (work in progress)

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

  ViewVC Help
Powered by ViewVC