/[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 2121 - (hide 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 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     * Copyright (C) 2009-2010 Christian Schoenebeck and 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 iliev 2012
30     namespace LinuxSampler {
31    
32 iliev 2015 template <class EC /* Engine Channel */, class R /* Region */, class S /* Sample */, class D /* DiskThread */>
33     class VoiceBase : public AbstractVoice {
34 iliev 2012 public:
35 iliev 2015 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 iliev 2012
38 iliev 2015 VoiceBase() {
39     pRegion = NULL;
40     pDiskThread = NULL;
41     }
42     virtual ~VoiceBase() { }
43    
44 iliev 2012 virtual R* GetRegion() { return pRegion; }
45    
46 iliev 2015 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 iliev 2027 dmsg(5,("VoiceBase: switching to disk playback (Pos=%f)\n", finalSynthesisParameters.dPos));
125 iliev 2015 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 iliev 2027 std::cerr << "VoiceBase::Render(): entered with playback_state_end, this is a bug!\n" << std::flush;
179 iliev 2015 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 persson 2055 if (PlaybackState == Voice::playback_state_end ||
189     pEG1->getSegmentType() == EG::segment_end) {
190     KillImmediately();
191     }
192 iliev 2015 }
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 iliev 2012 protected:
227 iliev 2015 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 schoenebeck 2121 virtual MidiKeyBase* GetMidiKeyInfo(int MIDIKey) {
231     EC* pChannel = static_cast<EC*>(pEngineChannel);
232     return &pChannel->pMIDIKeyInfo[MIDIKey];
233     }
234    
235 iliev 2015 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 iliev 2012 };
245     } // namespace LinuxSampler
246    
247     #endif /* __LS_VOICEBASE_H__ */
248    

  ViewVC Help
Powered by ViewVC