/[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 2121 - (show annotations) (download) (as text)
Tue Sep 14 17:09:08 2010 UTC (13 years, 7 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 13461 byte(s)
* implemented Roland GS NRPN 1ArrH which allows to set volume per note
* implemented Roland GS NRPN 1CrrH which allows to set pan per note
* implemented Roland GS NRPN 1DrrH which allows to set reverb send per
  note (in this implementation of the sampler its simply hard routed to
  the 1st effect send of the sampler channel, no matter what the actual
  effect type is)
* implemented Roland GS NRPN 1ErrH which allows to set chorus send per
  note (in this implementation of the sampler its simply hard routed to
  the 2nd effect send of the sampler channel, no matter what the actual
  effect type is)
* bumped version to 1.0.0cvs4

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 ||
189 pEG1->getSegmentType() == EG::segment_end) {
190 KillImmediately();
191 }
192 }
193
194 /**
195 * Immediately kill the voice. This method should not be used to kill
196 * a normal, active voice, because it doesn't take care of things like
197 * fading down the volume level to avoid clicks and regular processing
198 * until the kill event actually occured!
199 *
200 * If it's necessary to know when the voice's disk stream was actually
201 * deleted, then one can set the optional @a bRequestNotification
202 * parameter and this method will then return the handle of the disk
203 * stream (unique identifier) and one can use this handle to poll the
204 * disk thread if this stream has been deleted. In any case this method
205 * will return immediately and will not block until the stream actually
206 * was deleted.
207 *
208 * @param bRequestNotification - (optional) whether the disk thread shall
209 * provide a notification once it deleted
210 * the respective disk stream
211 * (default=false)
212 * @returns handle to the voice's disk stream or @c Stream::INVALID_HANDLE
213 * if the voice did not use a disk stream at all
214 * @see Kill()
215 */
216 Stream::Handle KillImmediately(bool bRequestNotification = false) {
217 Stream::Handle hStream = Stream::INVALID_HANDLE;
218 if (DiskVoice && DiskStreamRef.State != Stream::state_unused) {
219 pDiskThread->OrderDeletionOfStream(&DiskStreamRef, bRequestNotification);
220 hStream = DiskStreamRef.hStream;
221 }
222 Reset();
223 return hStream;
224 }
225
226 protected:
227 S* pSample; ///< Pointer to the sample to be played back
228 R* pRegion; ///< Pointer to the articulation information of current region of this voice
229
230 virtual MidiKeyBase* GetMidiKeyInfo(int MIDIKey) {
231 EC* pChannel = static_cast<EC*>(pEngineChannel);
232 return &pChannel->pMIDIKeyInfo[MIDIKey];
233 }
234
235 virtual unsigned long GetNoteOnTime(int MIDIKey) {
236 EC* pChannel = static_cast<EC*>(pEngineChannel);
237 return pChannel->pMIDIKeyInfo[MIDIKey].NoteOnTime;
238 }
239
240 void GetFirstEventOnKey(uint8_t MIDIKey, RTList<Event>::Iterator& itEvent) {
241 EC* pChannel = static_cast<EC*>(pEngineChannel);
242 itEvent = pChannel->pMIDIKeyInfo[MIDIKey].pEvents->first();
243 }
244 };
245 } // namespace LinuxSampler
246
247 #endif /* __LS_VOICEBASE_H__ */
248

  ViewVC Help
Powered by ViewVC