/[svn]/linuxsampler/trunk/src/audiothread.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/audiothread.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (show annotations) (download)
Tue Feb 3 13:21:19 2004 UTC (20 years, 2 months ago) by schoenebeck
File size: 19334 byte(s)
* introduced time stamped events
* implemented jitter correction
* added pitchbend wheel support
* src/audiothread.cpp: using voice pool instead of a voice array, makes
  voice allocation more efficient and code more readable
* src/rtelmemorypool: redesigned, added some new methods and pool is now
  derived from list

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003 by Benno Senoner and Christian Schoenebeck *
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the Free Software *
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
20 * MA 02111-1307 USA *
21 ***************************************************************************/
22
23 #include "audiothread.h"
24
25 AudioThread::AudioThread(AudioIO* pAudioIO, DiskThread* pDiskThread, gig::Instrument* pInstrument) {
26 this->pAudioIO = pAudioIO;
27 this->pDiskThread = pDiskThread;
28 this->pInstrument = pInstrument;
29 this->Pitch = 0;
30 Voice::pDiskThread = pDiskThread;
31 Voice::pEngine = this;
32 pEventQueue = new RingBuffer<ModulationSystem::Event>(MAX_EVENTS_PER_FRAGMENT);
33 pEventPool = new RTELMemoryPool<ModulationSystem::Event>(MAX_EVENTS_PER_FRAGMENT);
34 pVoicePool = new RTELMemoryPool<Voice>(MAX_AUDIO_VOICES);
35 pSustainedKeyPool = new RTELMemoryPool<uint>(128);
36 pEvents = new RTEList<ModulationSystem::Event>(pEventPool);
37 for (uint i = 0; i < ModulationSystem::destination_count; i++) {
38 pCCEvents[i] = new RTEList<ModulationSystem::Event>(pEventPool);
39 }
40 for (uint i = 0; i < 128; i++) {
41 pMIDIKeyInfo[i].pActiveVoices = new RTEList<Voice>(pVoicePool);
42 pMIDIKeyInfo[i].pSustainPtr = NULL;
43 pMIDIKeyInfo[i].Sustained = false;
44 pMIDIKeyInfo[i].KeyPressed = false;
45 pMIDIKeyInfo[i].pSustainPoolNode = NULL;
46 }
47
48 // FIXME: assuming stereo output
49 pAudioSumBuffer[0] = new float[pAudioIO->MaxSamplesPerCycle() * pAudioIO->Channels()];
50 pAudioSumBuffer[1] = &pAudioSumBuffer[0][pAudioIO->MaxSamplesPerCycle()];
51
52 // set all voice outputs to the AudioSumBuffer
53 for (Voice* pVoice = pVoicePool->alloc(); pVoice; pVoice = pVoicePool->alloc()) { //FIXME: assuming stereo
54 pVoice->SetOutputLeft(pAudioSumBuffer[0], pAudioIO->MaxSamplesPerCycle());
55 pVoice->SetOutputRight(pAudioSumBuffer[1], pAudioIO->MaxSamplesPerCycle());
56 }
57 pVoicePool->clear();
58
59 // cache initial samples points (for actually needed samples)
60 dmsg(1,("Caching initial samples..."));
61 gig::Region* pRgn = this->pInstrument->GetFirstRegion();
62 while (pRgn) {
63 if (!pRgn->GetSample()->GetCache().Size) {
64 dmsg(2,("C"));
65 CacheInitialSamples(pRgn->GetSample());
66 }
67 for (uint i = 0; i < pRgn->DimensionRegions; i++) {
68 CacheInitialSamples(pRgn->pDimensionRegions[i]->pSample);
69 }
70
71 pRgn = this->pInstrument->GetNextRegion();
72 }
73
74 // initialize modulation system
75 ModulationSystem::Initialize(pAudioIO->SampleRate(), pAudioIO->MaxSamplesPerCycle());
76
77 // sustain pedal value
78 PrevHoldCCValue = 0;
79 SustainPedal = 0;
80
81 dmsg(1,("OK\n"));
82 }
83
84 AudioThread::~AudioThread() {
85 ModulationSystem::Close();
86 for (uint i = 0; i < 128; i++) {
87 if (pMIDIKeyInfo[i].pActiveVoices) delete pMIDIKeyInfo[i].pActiveVoices;
88 }
89 for (uint i = 0; i < ModulationSystem::destination_count; i++) {
90 if (pCCEvents[i]) delete pCCEvents[i];
91 }
92 delete[] pCCEvents;
93 if (pEvents) delete pEvents;
94 if (pEventQueue) delete pEventQueue;
95 if (pEventPool) delete pEventPool;
96 if (pVoicePool) delete pVoicePool;
97 if (pSustainedKeyPool) delete pSustainedKeyPool;
98 delete[] pAudioSumBuffer[0]; // this also frees the right channel buffer
99 }
100
101 /**
102 * Let this engine proceed to render the given amount of sample points. The
103 * calculated audio data of all voices of this engine will be placed into
104 * the engine's audio sum buffer which has to be copied and eventually be
105 * converted to the appropriate value range by the audio output class (e.g.
106 * AlsaIO or JackIO) right after.
107 *
108 * @param Samples - number of sample points to be rendered
109 * @returns 0 on success
110 */
111 int AudioThread::RenderAudio(uint Samples) {
112
113 // empty the event lists for the new fragment
114 pEvents->clear();
115 for (uint i = 0; i < ModulationSystem::destination_count; i++) {
116 pCCEvents[i]->clear();
117 }
118
119 // read and copy events from input queue
120 ModulationSystem::Event Event;
121 while (true) {
122 if (!pEventQueue->pop(&Event)) break;
123 pEvents->alloc_assign(Event);
124 }
125
126
127 // update time of start and end of this audio fragment (as events' time stamps relate to this)
128 ModulationSystem::UpdateFragmentTime();
129
130
131 // process events
132 ModulationSystem::Event* pNextEvent = pEvents->first();
133 while (pNextEvent) {
134 ModulationSystem::Event* pEvent = pNextEvent;
135 pEvents->set_current(pEvent);
136 pNextEvent = pEvents->next();
137 switch (pEvent->Type) {
138 case ModulationSystem::event_type_note_on:
139 dmsg(5,("Audio Thread: Note on received\n"));
140 ProcessNoteOn(pEvent);
141 break;
142 case ModulationSystem::event_type_note_off:
143 dmsg(5,("Audio Thread: Note off received\n"));
144 ProcessNoteOff(pEvent);
145 break;
146 case ModulationSystem::event_type_control_change:
147 dmsg(5,("Audio Thread: MIDI CC received\n"));
148 ProcessControlChange(pEvent);
149 break;
150 case ModulationSystem::event_type_pitchbend:
151 dmsg(5,("Audio Thread: Pitchbend received\n"));
152 ProcessPitchbend(pEvent);
153 break;
154 }
155 }
156
157
158 // zero out the output sum buffer (left and right channel)
159 memset(pAudioSumBuffer[0], 0, Samples * pAudioIO->Channels() * sizeof(float));
160
161
162 // render audio from all active voices
163 int active_voices = 0;
164 for (uint i = 0; i < 128; i++) {
165 midi_key_info_t* pKey = &pMIDIKeyInfo[i];
166 Voice* pVoiceNext = pKey->pActiveVoices->first();
167 while (pVoiceNext) {
168 // already get next voice on key
169 Voice* pVoice = pVoiceNext;
170 pKey->pActiveVoices->set_current(pVoice);
171 pVoiceNext = pKey->pActiveVoices->next();
172
173 // now render current voice
174 pVoice->Render(Samples);
175 if (pVoice->IsActive()) active_voices++; // still active
176 else { // voice reached end, is now inactive
177 KillVoice(pVoice); // remove voice from the list of active voices
178 }
179 }
180 }
181
182 // write that to the disk thread class so that it can print it
183 // on the console for debugging purposes
184 ActiveVoiceCount = active_voices;
185 if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;
186
187
188 return 0;
189 }
190
191 /**
192 * Will be called by the MIDIIn Thread to let the audio thread trigger a new
193 * voice for the given key.
194 *
195 * @param Key - MIDI key number of the triggered key
196 * @param Velocity - MIDI velocity value of the triggered key
197 */
198 void AudioThread::SendNoteOn(uint8_t Key, uint8_t Velocity) {
199 ModulationSystem::Event Event;
200 Event.Type = ModulationSystem::event_type_note_on;
201 Event.Key = Key;
202 Event.Velocity = Velocity;
203 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&Event);
204 else dmsg(1,("AudioThread: Input event queue full!"));
205 }
206
207 /**
208 * Will be called by the MIDIIn Thread to signal the audio thread to release
209 * voice(s) on the given key.
210 *
211 * @param Key - MIDI key number of the released key
212 * @param Velocity - MIDI release velocity value of the released key
213 */
214 void AudioThread::SendNoteOff(uint8_t Key, uint8_t Velocity) {
215 ModulationSystem::Event Event;
216 Event.Type = ModulationSystem::event_type_note_off;
217 Event.Key = Key;
218 Event.Velocity = Velocity;
219 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&Event);
220 else dmsg(1,("AudioThread: Input event queue full!"));
221 }
222
223 /**
224 * Will be called by the MIDIIn Thread to signal the audio thread to change
225 * the pitch value for all voices.
226 *
227 * @param Pitch - MIDI pitch value (-8192 ... +8191)
228 */
229 void AudioThread::SendPitchbend(int Pitch) {
230 ModulationSystem::Event Event;
231 Event.Type = ModulationSystem::event_type_pitchbend;
232 Event.Pitch = Pitch;
233 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&Event);
234 else dmsg(1,("AudioThread: Input event queue full!"));
235 }
236
237 /**
238 * Will be called by the MIDIIn Thread to signal the audio thread that a
239 * continuous controller value has changed.
240 *
241 * @param Controller - MIDI controller number of the occured control change
242 * @param Value - value of the control change
243 */
244 void AudioThread::SendControlChange(uint8_t Controller, uint8_t Value) {
245 ModulationSystem::Event Event;
246 Event.Type = ModulationSystem::event_type_control_change;
247 Event.Controller = Controller;
248 Event.Value = Value;
249 if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&Event);
250 else dmsg(1,("AudioThread: Input event queue full!"));
251 }
252
253 /**
254 * Assigns and triggers a new voice for the respective MIDI key.
255 *
256 * @param pNoteOnEvent - key, velocity and time stamp of the event
257 */
258 void AudioThread::ProcessNoteOn(ModulationSystem::Event* pNoteOnEvent) {
259 midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOnEvent->Key];
260
261 pKey->KeyPressed = true; // the MIDI key was now pressed down
262 Voice* pNewVoice = pKey->pActiveVoices->alloc(); // allocate a new voice for the key
263 if (pNewVoice) {
264 // launch the new voice
265 if (pNewVoice->Trigger(pNoteOnEvent->Key, pNoteOnEvent->Velocity, this->Pitch, this->pInstrument, pNoteOnEvent->FragmentPos()) < 0) {
266 return; // failed to trigger the new voice
267 }
268
269 // update key info
270 if (!pKey->pSustainPtr) {
271 dmsg(4,("ProcessNoteOn(): pSustainPtr == null, setting release pointer to the last voice on the key...\n"));
272 pKey->pSustainPtr = pKey->pActiveVoices->last();
273 }
274 }
275 else std::cerr << "No free voice!" << std::endl << std::flush;
276 }
277
278 /**
279 * Releases the voices on the given key if sustain pedal is not pressed.
280 * If sustain is pressed, the release of the note will be postponed until
281 * sustain pedal will be released or voice turned inactive by itself (e.g.
282 * due to completion of sample playback).
283 *
284 * @param pNoteOffEvent - key, velocity and time stamp of the event
285 */
286 void AudioThread::ProcessNoteOff(ModulationSystem::Event* pNoteOffEvent) {
287 midi_key_info_t* pKey = &pMIDIKeyInfo[pNoteOffEvent->Key];
288
289 pKey->KeyPressed = false; // the MIDI key was now released
290 if (SustainPedal) { // if sustain pedal is pressed postpone the Note-Off
291 if (pKey->pSustainPtr) {
292 // stick the note-off information to the respective voice
293 Voice* pVoiceToRelease = pKey->pSustainPtr;
294 pVoiceToRelease->ReleaseVelocity = pNoteOffEvent->Velocity;
295
296 // now increment the sustain pointer
297 pKey->pActiveVoices->set_current(pVoiceToRelease);
298 pKey->pSustainPtr = pKey->pActiveVoices->next();
299
300 // if the key was not marked as sustained yet, add it's MIDI key number to the sustained key pool
301 if (!pKey->Sustained) {
302 uint* puiSustainedKey = pSustainedKeyPool->alloc();
303 *puiSustainedKey = pNoteOffEvent->Key;
304 pKey->pSustainPoolNode = puiSustainedKey;
305 pKey->Sustained = true;
306 }
307 }
308 else dmsg(3,("Ignoring NOTE OFF, seems like more Note-Offs than Note-Ons or no free voices available?\n"));
309 }
310 else {
311 // release all active voices on the midi key
312 Voice* pVoiceNext = pKey->pActiveVoices->first();
313 while (pVoiceNext) {
314 Voice* pVoiceToRelease = pVoiceNext;
315 pKey->pActiveVoices->set_current(pVoiceToRelease);
316 pVoiceNext = pKey->pActiveVoices->next();
317 pVoiceToRelease->Release(pNoteOffEvent->FragmentPos());
318 }
319 }
320 }
321
322 /**
323 * Moves pitchbend event from the general (input) event list to the pitch
324 * event list and converts absolute pitch value to delta pitch value.
325 *
326 * @param pPitchbendEvent - absolute pitch value and time stamp of the event
327 */
328 void AudioThread::ProcessPitchbend(ModulationSystem::Event* pPitchbendEvent) {
329 int currentPitch = pPitchbendEvent->Pitch;
330 pPitchbendEvent->Pitch -= this->Pitch; // convert to delta
331 this->Pitch = currentPitch; // store current absolute pitch value
332 pEvents->move(pPitchbendEvent, pCCEvents[ModulationSystem::destination_vco]);
333 }
334
335 /**
336 * Immediately kills the voice given with pVoice (no matter if sustain is
337 * pressed or not) and removes it from the MIDI key's list of active voice.
338 * This method will e.g. be called if a voice went inactive by itself. If
339 * sustain pedal is pressed the method takes care to free those sustain
340 * informations of the voice.
341 *
342 * @param pVoice - points to the voice to be killed
343 */
344 void AudioThread::KillVoice(Voice* pVoice) {
345 if (pVoice) {
346 if (pVoice->IsActive()) pVoice->Kill();
347
348 midi_key_info_t* pKey = &pMIDIKeyInfo[pVoice->MIDIKey];
349
350 if (pKey->Sustained) {
351 // check if the sustain pointer has to be moved, now that we kill the voice
352 if (pKey->pSustainPtr) {
353 if (pKey->pSustainPtr == pVoice) {
354 // move sustain pointer to the next sustained voice
355 dmsg(3,("Correcting sustain pointer\n"));
356 pKey->pActiveVoices->set_current(pVoice);
357 pKey->pSustainPtr = pKey->pActiveVoices->next();
358 }
359 else dmsg(4,("KillVoice(Voice*): pSustainPtr != pVoice\n"));
360 }
361 else dmsg(3,("KillVoice(Voice*): pSustainPtr == null\n"));
362 }
363
364 // free the voice object
365 pVoicePool->free(pVoice);
366
367 // check if there are no voices left on the MIDI key and update the key info if so
368 if (pKey->pActiveVoices->is_empty()) {
369 pKey->pSustainPtr = NULL;
370 if (pKey->Sustained) {
371 pSustainedKeyPool->free(pKey->pSustainPoolNode);
372 pKey->pSustainPoolNode = NULL;
373 pKey->Sustained = false;
374 }
375 dmsg(3,("Key has no more voices now\n"));
376 }
377 }
378 else std::cerr << "Couldn't release voice! (pVoice == NULL)\n" << std::flush;
379 }
380
381 /**
382 * Reacts on supported control change commands (e.g. pitch bend wheel,
383 * modulation wheel, aftertouch).
384 *
385 * @param pControlChangeEvent - controller, value and time stamp of the event
386 */
387 void AudioThread::ProcessControlChange(ModulationSystem::Event* pControlChangeEvent) {
388 dmsg(4,("AudioThread::ContinuousController cc=%d v=%d\n", pControlChangeEvent->Controller, pControlChangeEvent->Value));
389
390 switch (pControlChangeEvent->Controller) {
391 case 64: {
392 if (pControlChangeEvent->Value >= 64 && PrevHoldCCValue < 64) {
393 dmsg(4,("PEDAL DOWN\n"));
394 SustainPedal = true;
395 }
396 if (pControlChangeEvent->Value < 64 && PrevHoldCCValue >= 64) {
397 dmsg(4,("PEDAL UP\n"));
398 SustainPedal = false;
399 // iterate through all keys that are currently sustained
400 for (uint* key = pSustainedKeyPool->first(); key; key = pSustainedKeyPool->next()) {
401 if (!pMIDIKeyInfo[*key].KeyPressed) { // release the voices on the key, if the key is not pressed anymore
402 // release all active voices on the midi key
403 Voice* pNextVoice = pMIDIKeyInfo[*key].pActiveVoices->first();
404 while (pNextVoice) {
405 Voice* pVoiceToRelease = pNextVoice;
406 pMIDIKeyInfo[*key].pActiveVoices->set_current(pVoiceToRelease);
407 pNextVoice = pMIDIKeyInfo[*key].pActiveVoices->next();
408 dmsg(3,("Sustain CC: releasing voice on midi key %d\n", *key));
409 pVoiceToRelease->Release(pControlChangeEvent->FragmentPos());
410 }
411 pSustainedKeyPool->free(pMIDIKeyInfo[*key].pSustainPoolNode);
412 pMIDIKeyInfo[*key].pSustainPoolNode = NULL;
413 pMIDIKeyInfo[*key].Sustained = false;
414 pMIDIKeyInfo[*key].pSustainPtr = NULL;
415 }
416 }
417 //SustainedKeyPool->empty();
418 }
419 PrevHoldCCValue = pControlChangeEvent->Value;
420 break;
421 }
422 }
423 }
424
425 /**
426 * Caches a certain size at the beginning of the given sample in RAM. If the
427 * sample is very short, the whole sample will be loaded into RAM and thus
428 * no disk streaming is needed for this sample. Caching an initial part of
429 * samples is needed to compensate disk reading latency.
430 *
431 * @param pSample - points to the sample to be cached
432 */
433 void AudioThread::CacheInitialSamples(gig::Sample* pSample) {
434 if (!pSample || pSample->GetCache().Size) return;
435 if (pSample->SamplesTotal <= NUM_RAM_PRELOAD_SAMPLES) {
436 // Sample is too short for disk streaming, so we load the whole
437 // sample into RAM and place 'pAudioIO->FragmentSize << MAX_PITCH'
438 // number of '0' samples (silence samples) behind the official buffer
439 // border, to allow the interpolator do it's work even at the end of
440 // the sample.
441 gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension((pAudioIO->MaxSamplesPerCycle() << MAX_PITCH) + 3);
442 dmsg(4,("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize));
443 }
444 else { // we only cache NUM_RAM_PRELOAD_SAMPLES and stream the other sample points from disk
445 pSample->LoadSampleData(NUM_RAM_PRELOAD_SAMPLES);
446 }
447
448 if (!pSample->GetCache().Size) std::cerr << "Unable to cache sample - maybe memory full!" << std::endl << std::flush;
449 }

  ViewVC Help
Powered by ViewVC