1 /***************************************************************************
2  *                                                                         *
3  *   LinuxSampler - modular, streaming capable sampler                     *
4  *                                                                         *
5  *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6  *   Copyright (C) 2005-2020 Christian Schoenebeck                         *
7  *   Copyright (C) 2009-2011 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 #include <limits.h> // for INT_MIN
30 
31 /*
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 namespace LinuxSampler {
39 
40     template <class EC /* Engine Channel */, class R /* Region */, class S /* Sample */, class D /* DiskThread */>
41     class VoiceBase : public AbstractVoice {
42         public:
43             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 
AbstractVoice(pRack)46             VoiceBase(SignalUnitRack* pRack = NULL): AbstractVoice(pRack) {
47                 pRegion      = NULL;
48                 pDiskThread  = NULL;
49             }
~VoiceBase()50             virtual ~VoiceBase() { }
51 
GetRegion()52             virtual R* GetRegion() { return pRegion; }
53 
GetSampleCacheSize()54             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              */
Trigger(AbstractEngineChannel * pEngineChannel,Pool<Event>::Iterator & itNoteOnEvent,int PitchBend,R * pRegion,type_t VoiceType,int iKeyGroup)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 
OrderNewStream()88             virtual int OrderNewStream() {
89                 int res = pDiskThread->OrderNewStream (
90                     &DiskStreamRef, pRegion, MaxRAMPos + GetRAMCacheOffset(), !RAMLoop
91                 );
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 
102             /** The offset of the RAM cache from the sample start (in sample units). */
GetRAMCacheOffset()103             virtual int GetRAMCacheOffset() { return 0; }
104 
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              */
Render(uint Samples)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                                     dmsg(5,("VoiceBase: switching to disk playback (Pos=%f)\n", finalSynthesisParameters.dPos));
136                                     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                                     std::cerr << "Disk stream not available in time!\n" << std::flush;
150                                     KillImmediately();
151                                     return;
152                                 }
153                                 DiskStreamRef.pStream->IncrementReadPos(uint(
154                                     SmplInfo.ChannelCount * (int(finalSynthesisParameters.dPos) - MaxRAMPos)
155                                 ));
156                                 finalSynthesisParameters.dPos -= int(finalSynthesisParameters.dPos);
157                                 RealSampleWordsLeftToRead = NO_SILENCE_STREAM_SAMPLES_YET;
158                             }
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                                 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                                 const int maxSampleWordsPerCycle = (GetEngine()->MaxSamplesPerCycle << CONFIG_MAX_PITCH) * SmplInfo.ChannelCount + 6; // +6 for the interpolator algorithm
169                                 if (sampleWordsLeftToRead < maxSampleWordsPerCycle) {
170                                     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                                 if (RealSampleWordsLeftToRead <= 0) {
188                                     this->PlaybackState = Voice::playback_state_end;
189                                     RealSampleWordsLeftToRead = 0;
190                                 }
191                             }
192                         }
193                         break;
194 
195                     case Voice::playback_state_end:
196                         std::cerr << "VoiceBase::Render(): entered with playback_state_end, this is a bug!\n" << std::flush;
197                         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                 if (PlaybackState == Voice::playback_state_end || EG1Finished()) {
207                     KillImmediately();
208                 }
209             }
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         protected:
244             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 
GetMidiKeyInfo(int MIDIKey)247             virtual MidiKeyBase* GetMidiKeyInfo(int MIDIKey) {
248                 EC* pChannel = static_cast<EC*>(pEngineChannel);
249                 return &pChannel->pMIDIKeyInfo[MIDIKey];
250             }
251 
GetNoteOnTime(int MIDIKey)252             virtual unsigned long GetNoteOnTime(int MIDIKey) {
253                 EC* pChannel = static_cast<EC*>(pEngineChannel);
254                 return pChannel->pMIDIKeyInfo[MIDIKey].NoteOnTime;
255             }
256 
GetFirstEventOnKey(uint8_t MIDIKey,RTList<Event>::Iterator & itEvent)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     };
262 } // namespace LinuxSampler
263 
264 #endif	/* __LS_VOICEBASE_H__ */
265 
266