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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Sun Jan 18 20:31:31 2004 UTC (20 years, 3 months ago) by schoenebeck
File size: 15534 byte(s)
* Added JACK support: Audio rendering process is now callback based and
  independant of used audio output system. Interfaces to other audio output
  systems can be added by creating a class derived from abstract base class
  'AudioIO' and embedding the new class into linuxsampler.cpp.
* src/audiothread.cpp: applied patch from Vladimir Senkov which fixes
  hanging notes in conjunction with the sustain pedal

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 pCommandQueue = new RingBuffer<command_t>(1024);
30 pVoices = new Voice*[MAX_AUDIO_VOICES];
31 // allocate the ActiveVoicePool (for each midi key there is a variable size linked list
32 // of pointers to Voice objects)
33 ActiveVoicePool = new RTELMemoryPool<Voice*>(MAX_AUDIO_VOICES);
34 for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {
35 pVoices[i] = new Voice(pDiskThread);
36 }
37 for (uint i = 0; i < 128; i++) {
38 pMIDIKeyInfo[i].pActiveVoices = new RTEList<Voice*>;
39 pMIDIKeyInfo[i].hSustainPtr = NULL;
40 pMIDIKeyInfo[i].Sustained = false;
41 pMIDIKeyInfo[i].KeyPressed = false;
42 pMIDIKeyInfo[i].pSustainPoolNode = NULL;
43 }
44 SustainedKeyPool = new RTELMemoryPool<uint>(128);
45
46 // FIXME: assuming stereo output
47 pAudioSumBuffer[0] = new float[pAudioIO->MaxSamplesPerCycle() * pAudioIO->Channels()];
48 pAudioSumBuffer[1] = &pAudioSumBuffer[0][pAudioIO->MaxSamplesPerCycle()];
49
50 // set all voice outputs to the AudioSumBuffer
51 for (int i = 0; i < MAX_AUDIO_VOICES; i++) { //FIXME: assuming stereo
52 pVoices[i]->SetOutputLeft(pAudioSumBuffer[0], pAudioIO->MaxSamplesPerCycle());
53 pVoices[i]->SetOutputRight(pAudioSumBuffer[1], pAudioIO->MaxSamplesPerCycle());
54 }
55
56 // cache initial samples points (for actually needed samples)
57 dmsg(1,("Caching initial samples..."));
58 gig::Region* pRgn = this->pInstrument->GetFirstRegion();
59 while (pRgn) {
60 if (!pRgn->GetSample()->GetCache().Size) {
61 dmsg(2,("C"));
62 CacheInitialSamples(pRgn->GetSample());
63 }
64 for (uint i = 0; i < pRgn->DimensionRegions; i++) {
65 CacheInitialSamples(pRgn->pDimensionRegions[i]->pSample);
66 }
67
68 pRgn = this->pInstrument->GetNextRegion();
69 }
70
71 // initialize modulation system
72 ModulationSystem::Initialize(pAudioIO->SampleRate(), pAudioIO->MaxSamplesPerCycle());
73
74 // sustain pedal value
75 PrevHoldCCValue = 0;
76 SustainPedal = 0;
77
78 dmsg(1,("OK\n"));
79 }
80
81 AudioThread::~AudioThread() {
82 ModulationSystem::Close();
83 if (pCommandQueue) delete pCommandQueue;
84 if (pVoices) {
85 for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {
86 if (pVoices[i]) delete pVoices[i];
87 }
88 }
89 delete[] pVoices;
90 delete[] pAudioSumBuffer[0]; // this also frees the right channel buffer
91 }
92
93 int AudioThread::RenderAudio(uint Samples) {
94
95 // read and process commands from the queue
96 while (true) {
97 command_t command;
98 if (!pCommandQueue->pop(&command)) break;
99
100 switch (command.type) {
101 case command_type_note_on:
102 dmsg(5,("Audio Thread: Note on received\n"));
103 ProcessNoteOn(command.pitch, command.velocity);
104 break;
105 case command_type_note_off:
106 dmsg(5,("Audio Thread: Note off received\n"));
107 ProcessNoteOff(command.pitch, command.velocity);
108 break;
109 case command_type_continuous_controller:
110 dmsg(5,("Audio Thread: MIDI CC received\n"));
111 ProcessControlChange(command.channel, command.number, command.value);
112 break;
113 }
114 }
115
116
117 // zero out the output sum buffer (left and right channel)
118 memset(pAudioSumBuffer[0], 0, Samples * pAudioIO->Channels() * sizeof(float));
119
120
121 // render audio from all active voices
122 int active_voices = 0;
123 for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {
124 if (pVoices[i]->IsActive()) {
125 pVoices[i]->Render(Samples);
126 if (pVoices[i]->IsActive()) active_voices++; // still active
127 else { // voice reached end, is now inactive
128 KillVoice(pVoices[i]); // remove voice from the list of active voices
129 }
130 }
131 }
132 // write that to the disk thread class so that it can print it
133 // on the console for debugging purposes
134 ActiveVoiceCount = active_voices;
135 if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;
136
137
138 return 0;
139 }
140
141 /// Will be called by the MIDIIn Thread to let the audio thread trigger a new voice.
142 void AudioThread::SendNoteOn(uint8_t Pitch, uint8_t Velocity) {
143 command_t cmd;
144 cmd.type = command_type_note_on;
145 cmd.pitch = Pitch;
146 cmd.velocity = Velocity;
147 if (this->pCommandQueue->write_space() > 0) this->pCommandQueue->push(&cmd);
148 else dmsg(1,("AudioThread: Command queue full!"));
149 }
150
151 /// Will be called by the MIDIIn Thread to signal the audio thread to release voice(s).
152 void AudioThread::SendNoteOff(uint8_t Pitch, uint8_t Velocity) {
153 command_t cmd;
154 cmd.type = command_type_note_off;
155 cmd.pitch = Pitch;
156 cmd.velocity = Velocity;
157 if (this->pCommandQueue->write_space() > 0) this->pCommandQueue->push(&cmd);
158 else dmsg(1,("AudioThread: Command queue full!"));
159 }
160
161 // Will be called by the MIDIIn Thread to signal the audio thread that a continuous controller value has changed.
162 void AudioThread::SendControlChange(uint8_t Channel, uint8_t Number, uint8_t Value) {
163 command_t cmd;
164 cmd.type = command_type_continuous_controller;
165 cmd.channel = Channel;
166 cmd.number = Number;
167 cmd.value = Value;
168 if (this->pCommandQueue->write_space() > 0) this->pCommandQueue->push(&cmd);
169 else dmsg(1,("AudioThread: Command queue full!"));
170 }
171
172 /**
173 * Assigns and triggers a new voice for the respective MIDI key.
174 */
175 void AudioThread::ProcessNoteOn(uint8_t MIDIKey, uint8_t Velocity) {
176 pMIDIKeyInfo[MIDIKey].KeyPressed = true; // the MIDI key was currently pressed down
177 for (int i = 0; i < MAX_AUDIO_VOICES; i++) {
178 if (pVoices[i]->IsActive()) continue; // search for a free voice
179
180 // launch the new voice
181 if (pVoices[i]->Trigger(MIDIKey, Velocity, this->pInstrument) < 0) {
182 return; // failed to trigger the new voice
183 }
184
185 // add (append) a new voice to the corresponding MIDIKey active voices list
186 Voice** new_voice_ptr = ActiveVoicePool->alloc_append(pMIDIKeyInfo[MIDIKey].pActiveVoices);
187 *new_voice_ptr = pVoices[i];
188 pVoices[i]->pSelfPtr = new_voice_ptr; // FIXME: hack to allow fast deallocation
189
190 // update key info
191 if (!pMIDIKeyInfo[MIDIKey].hSustainPtr) {
192 dmsg(4,("ActivateVoice(uint,uint): hSustainPtr == null, setting release pointer to the last voice on the key...\n"));
193 pMIDIKeyInfo[MIDIKey].pActiveVoices->last();
194 pMIDIKeyInfo[MIDIKey].hSustainPtr = pMIDIKeyInfo[MIDIKey].pActiveVoices->current();
195 }
196 return;
197 }
198 std::cerr << "No free voice!" << std::endl << std::flush;
199 }
200
201 /**
202 * Releases the voices on the given key if sustain pedal is not pressed.
203 * If sustain is pressed, the release of the note will be postponed until
204 * sustain pedal will be released or voice turned inactive by itself (e.g.
205 * due to completion of sample playback).
206 */
207 void AudioThread::ProcessNoteOff(uint8_t MIDIKey, uint8_t Velocity) {
208 pMIDIKeyInfo[MIDIKey].KeyPressed = false; // the MIDI key was currently released
209 midi_key_info_t* pmidikey = &pMIDIKeyInfo[MIDIKey];
210 if (SustainPedal) { // if sustain pedal is pressed postpone the Note-Off
211 if (pmidikey->hSustainPtr) {
212 // stick the note-off information to the respective voice
213 Voice** pVoiceToRelease = pmidikey->pActiveVoices->set_current(pmidikey->hSustainPtr);
214 if (pVoiceToRelease) {
215 (*pVoiceToRelease)->ReleaseVelocity = Velocity;
216 // now increment the sustain pointer
217 pmidikey->pActiveVoices->next();
218 pmidikey->hSustainPtr = pmidikey->pActiveVoices->current();
219 // if the key was not sustained yet, add it's MIDI key number to the sustained key pool
220 if (!pmidikey->Sustained) {
221 uint* sustainedmidikey = SustainedKeyPool->alloc();
222 *sustainedmidikey = MIDIKey;
223 pmidikey->pSustainPoolNode = sustainedmidikey;
224 pmidikey->Sustained = true;
225 }
226 }
227 else dmsg(3,("Ignoring NOTE OFF --> pVoiceToRelease == null!\n"));
228 }
229 else dmsg(3,("Ignoring NOTE OFF, seems like more Note-Offs than Note-Ons or no free voices available?\n"));
230 }
231 else {
232 // release all active voices on the midi key
233 Voice** pVoicePtr = pmidikey->pActiveVoices->first();
234 while (pVoicePtr) {
235 Voice** pVoicePtrNext = pMIDIKeyInfo[MIDIKey].pActiveVoices->next();
236 (*pVoicePtr)->Release();
237 pVoicePtr = pVoicePtrNext;
238 }
239 }
240 }
241
242 /**
243 * Immediately kills the voice given with pVoice (no matter if sustain is
244 * pressed or not) and removes it from the MIDI key's list of active voice.
245 * This method will e.g. be called if a voice went inactive by itself. If
246 * sustain pedal is pressed the method takes care to free those sustain
247 * informations of the voice.
248 */
249 void AudioThread::KillVoice(Voice* pVoice) {
250 if (pVoice) {
251 if (pVoice->IsActive()) pVoice->Kill();
252
253 if (pMIDIKeyInfo[pVoice->MIDIKey].Sustained) {
254 // check if the sustain pointer has to be moved, now that we kill the voice
255 RTEList<Voice*>::NodeHandle hSustainPtr = pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr;
256 if (hSustainPtr) {
257 Voice** pVoicePtr = pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->set_current(hSustainPtr);
258 if (pVoicePtr) {
259 if (*pVoicePtr == pVoice) { // move sustain pointer to the next sustained voice
260 dmsg(3,("Correcting sustain pointer\n"));
261 pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->next();
262 pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr = pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->current();
263 }
264 else dmsg(4,("ReleaseVoice(Voice*): *hSustain != pVoice\n"));
265 }
266 else dmsg(3,("ReleaseVoice(Voice*): pVoicePtr == null\n"));
267 }
268 else dmsg(3,("ReleaseVoice(Voice*): hSustainPtr == null\n"));
269 }
270
271 // remove the voice from the list associated with this MIDI key
272 ActiveVoicePool->free(pVoice->pSelfPtr);
273
274 // check if there are no voices left on the MIDI key and update the key info if so
275 if (pMIDIKeyInfo[pVoice->MIDIKey].pActiveVoices->is_empty()) {
276 pMIDIKeyInfo[pVoice->MIDIKey].hSustainPtr = NULL;
277 if (pMIDIKeyInfo[pVoice->MIDIKey].Sustained) {
278 SustainedKeyPool->free(pMIDIKeyInfo[pVoice->MIDIKey].pSustainPoolNode);
279 pMIDIKeyInfo[pVoice->MIDIKey].pSustainPoolNode = NULL;
280 pMIDIKeyInfo[pVoice->MIDIKey].Sustained = false;
281 }
282 dmsg(3,("Key has no more voices now\n"));
283 }
284 }
285 else std::cerr << "Couldn't release voice! (pVoice == NULL)\n" << std::flush;
286 }
287
288 void AudioThread::ProcessControlChange(uint8_t Channel, uint8_t Number, uint8_t Value) {
289 dmsg(4,("AudioThread::ContinuousController c=%d n=%d v=%d\n", Channel, Number, Value));
290 if (Number == 64) {
291 if (Value >= 64 && PrevHoldCCValue < 64) {
292 dmsg(4,("PEDAL DOWN\n"));
293 SustainPedal = true;
294 }
295 if (Value < 64 && PrevHoldCCValue >= 64) {
296 dmsg(4,("PEDAL UP\n"));
297 SustainPedal = false;
298 // iterate through all keys that are currently sustained
299 for (uint* key = SustainedKeyPool->first(); key; key = SustainedKeyPool->next()) {
300 if (!pMIDIKeyInfo[*key].KeyPressed) { // release the voices on the key, if the key is not pressed anymore
301 // release all active voices on the midi key
302 Voice** pVoicePtr = pMIDIKeyInfo[*key].pActiveVoices->first();
303 while (pVoicePtr) {
304 Voice** pVoicePtrNext = pMIDIKeyInfo[*key].pActiveVoices->next();
305 dmsg(3,("Sustain CC: releasing voice on midi key %d\n", *key));
306 (*pVoicePtr)->Release();
307 pVoicePtr = pVoicePtrNext;
308 }
309 SustainedKeyPool->free(pMIDIKeyInfo[*key].pSustainPoolNode);
310 pMIDIKeyInfo[*key].pSustainPoolNode = NULL;
311 pMIDIKeyInfo[*key].Sustained = false;
312 pMIDIKeyInfo[*key].hSustainPtr = NULL;
313 }
314 }
315 //SustainedKeyPool->empty();
316 }
317 PrevHoldCCValue = Value;
318 }
319 }
320
321 void AudioThread::CacheInitialSamples(gig::Sample* pSample) {
322 if (!pSample || pSample->GetCache().Size) return;
323 if (pSample->SamplesTotal <= NUM_RAM_PRELOAD_SAMPLES) {
324 // Sample is too short for disk streaming, so we load the whole
325 // sample into RAM and place 'pAudioIO->FragmentSize << MAX_PITCH'
326 // number of '0' samples (silence samples) behind the official buffer
327 // border, to allow the interpolator do it's work even at the end of
328 // the sample.
329 gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension((pAudioIO->MaxSamplesPerCycle() << MAX_PITCH) + 3);
330 dmsg(4,("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize));
331 }
332 else { // we only cache NUM_RAM_PRELOAD_SAMPLES and stream the other sample points from disk
333 pSample->LoadSampleData(NUM_RAM_PRELOAD_SAMPLES);
334 }
335
336 if (!pSample->GetCache().Size) std::cerr << "Unable to cache sample - maybe memory full!" << std::endl << std::flush;
337 }

  ViewVC Help
Powered by ViewVC