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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15 - (hide annotations) (download)
Sun Nov 23 21:16:49 2003 UTC (20 years, 5 months ago) by schoenebeck
File size: 14866 byte(s)
* rewrote sustain pedal handling: instead of just queuing the note-offs I
  added a sustain pointer for each midi key which starts to point to the
  first active voice on the respective key and increments to the next voice
  on the key when a note-off arrived, the release velocity value will
  immediately be stored in the respective voice object (this also fixes the
  segmentation fault issue when the sustain pool was full)

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

  ViewVC Help
Powered by ViewVC