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