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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations) (download)
Tue Nov 11 23:30:47 2003 UTC (20 years, 5 months ago) by senoner
File size: 10511 byte(s)
* src/audiothread.cpp, src/audiothread.h: added Sustain Pedal support
  implemented by postponing note-offs and leting multiple voices play
  on the same MIDI key.
* added the RTELMemoryPool Class which is a fast RT-safe memory allocator
  and list manger
* src/linuxsampler.cpp: added a voice and stream counter debug message

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     // of pointers to Voice classes)
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 senoner 10 pActiveVoices[i] = new RTEList<Voice *>;
39 schoenebeck 9 }
40    
41 senoner 10 SustainedKeyPool=new RTELMemoryPool<sustained_key_t>(200);
42    
43    
44    
45 schoenebeck 9 pAudioSumBuffer = new float[pAudioIO->FragmentSize * pAudioIO->Channels];
46    
47     // set all voice outputs to the AudioSumBuffer
48     for (int i = 0; i < MAX_AUDIO_VOICES; i++) {
49     pVoices[i]->SetOutput(pAudioSumBuffer, pAudioIO->FragmentSize * 2); //FIXME: assuming stereo
50     }
51    
52     // cache initial samples points (for actually needed samples)
53     dmsg(("Caching initial samples..."));
54     gig::Region* pRgn = this->pInstrument->GetFirstRegion();
55     while (pRgn) {
56     if (!pRgn->GetSample()->GetCache().Size) {
57 senoner 10 //printf("C");
58 schoenebeck 9 CacheInitialSamples(pRgn->GetSample());
59     }
60     for (uint i = 0; i < pRgn->DimensionRegions; i++) {
61     CacheInitialSamples(pRgn->pDimensionRegions[i]->pSample);
62     }
63    
64     pRgn = this->pInstrument->GetNextRegion();
65     }
66 senoner 10
67     // sustain pedal value
68     PrevHoldCCValue=0;
69     SustainPedal=0;
70    
71 schoenebeck 9 dmsg(("OK\n"));
72     }
73    
74     AudioThread::~AudioThread() {
75     if (pCommandQueue) delete pCommandQueue;
76     if (pVoices) {
77     for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {
78     if (pVoices[i]) delete pVoices[i];
79     }
80     }
81     delete[] pVoices;
82     }
83    
84     int AudioThread::Main() {
85     dmsg(("Audio thread running\n"));
86 senoner 10 //int fifofd=open("/tmp/fifo1",O_WRONLY);
87 schoenebeck 9
88     while (true) {
89    
90     // read and process commands from the queue
91     while (true) {
92     command_t command;
93     if (pCommandQueue->read(&command, 1) == 0) break;
94    
95     switch (command.type) {
96     case command_type_note_on:
97     dmsg(("Audio Thread: Note on received\n"));
98     ActivateVoice(command.pitch, command.velocity);
99     break;
100     case command_type_note_off:
101     dmsg(("Audio Thread: Note off received\n"));
102     ReleaseVoice(command.pitch, command.velocity);
103     break;
104 senoner 10 case command_type_continuous_controller:
105     dmsg(("Audio Thread: MIDI CC received\n"));
106     ContinuousController(command.channel, command.number, command.value);
107     break;
108 schoenebeck 9 }
109     }
110    
111    
112     // zero out the sum buffer
113     for (uint u = 0; u < pAudioIO->FragmentSize * pAudioIO->Channels; u++) {
114     pAudioSumBuffer[u] = 0.0;
115     }
116    
117    
118     // render audio from all active voices
119 senoner 10 int act_voices=0;
120 schoenebeck 9 for (uint i = 0; i < MAX_AUDIO_VOICES; i++) {
121     if (pVoices[i]->IsActive()) {
122     pVoices[i]->RenderAudio();
123 senoner 10 act_voices++;
124 schoenebeck 9 }
125     }
126 senoner 10 // write that to the disk thread class so that it can print it
127     // on the console for debugging purposes
128     ActiveVoiceCount=act_voices;
129 schoenebeck 9
130    
131     // check clipping in the audio sum, convert to sample_type
132     // (from 32bit to 16bit sample) and copy to output buffer
133     float sample_point;
134     for (uint u = 0; u < pAudioIO->FragmentSize * pAudioIO->Channels; u++) {
135     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)
136     if (sample_point < -32768.0) sample_point = -32768.0;
137     if (sample_point > 32767.0) sample_point = 32767.0;
138     this->pAudioIO->pOutputBuffer[u] = (sample_t) sample_point;
139     }
140    
141    
142     // call audio driver to output sound
143     int res = this->pAudioIO->Output();
144     if (res < 0) exit(EXIT_FAILURE);
145 senoner 10
146     // FIXME remove because we use it only to write to a fifo to save the audio
147     //write(fifofd, pAudioIO->pOutputBuffer, pAudioIO->FragmentSize * pAudioIO->Channels * sizeof(short));
148    
149 schoenebeck 9 }
150     }
151    
152     /// Will be called by the MIDIIn Thread to let the audio thread trigger a new voice.
153     void AudioThread::ProcessNoteOn(uint8_t Pitch, uint8_t Velocity) {
154     command_t cmd;
155     cmd.type = command_type_note_on;
156     cmd.pitch = Pitch;
157     cmd.velocity = Velocity;
158     this->pCommandQueue->write(&cmd, 1);
159     }
160    
161     /// Will be called by the MIDIIn Thread to signal the audio thread to release a voice.
162     void AudioThread::ProcessNoteOff(uint8_t Pitch, uint8_t Velocity) {
163     command_t cmd;
164     cmd.type = command_type_note_off;
165     cmd.pitch = Pitch;
166     cmd.velocity = Velocity;
167     this->pCommandQueue->write(&cmd, 1);
168     }
169    
170 senoner 10 // Will be called by the MIDIIn Thead to send MIDI continuos controller events
171     void AudioThread::ProcessContinuousController(uint8_t Channel, uint8_t Number, uint8_t Value) {
172     command_t cmd;
173     cmd.type = command_type_continuous_controller;
174     cmd.channel = Channel;
175     cmd.number = Number;
176     cmd.value = Value;
177     this->pCommandQueue->write(&cmd, 1);
178     }
179    
180    
181 schoenebeck 9 void AudioThread::ActivateVoice(uint8_t MIDIKey, uint8_t Velocity) {
182     for (int i = 0; i < MAX_AUDIO_VOICES; i++) {
183     if (pVoices[i]->IsActive()) continue;
184     pVoices[i]->Trigger(MIDIKey, Velocity, this->pInstrument);
185 senoner 10 // add (append) a new voice to the corresponding MIDIKey active voices list
186     Voice **new_voice_ptr=ActiveVoicePool->alloc_append(pActiveVoices[MIDIKey]);
187     *new_voice_ptr=pVoices[i];
188 schoenebeck 9 return;
189     }
190     std::cerr << "No free voice!" << std::endl << std::flush;
191     }
192    
193     void AudioThread::ReleaseVoice(uint8_t MIDIKey, uint8_t Velocity) {
194 senoner 10
195    
196     // get the first voice in the list of active voices on the MIDI Key
197     Voice** pVoicePtr = pActiveVoices[MIDIKey]->first();
198     Voice *pVoice=*pVoicePtr;
199    
200 schoenebeck 9 if (pVoice) {
201 senoner 10
202     // if sustain pedal is pressed postpone the Note-Off
203     if(SustainPedal) {
204     // alloc an element in the SustainedKeyPool and add the current midikey to it
205     sustained_key_t *key=SustainedKeyPool->alloc();
206     if(key == NULL) { /* FIXME */ printf("ERROR: SustainedKeyPool FULL ! exiting\n"); exit(0); }
207     key->midikey=MIDIKey;
208     key->velocity=Velocity;
209     return;
210     }
211    
212 schoenebeck 9 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
213 senoner 10
214     // remove the voice from the list associated to this MIDI key
215     ActiveVoicePool->free(pVoicePtr);
216 schoenebeck 9 }
217     else std::cerr << "Couldn't find active voice for note off command!" << std::endl << std::flush;
218     }
219    
220 senoner 10 void AudioThread::ContinuousController(uint8_t Channel, uint8_t Number, uint8_t Value) {
221     //printf("AudioThread::ContinuousController c=%d n=%d v=%d\n",Channel, Number, Value);
222     if(Number == 64) {
223     if(Value >=64 && PrevHoldCCValue < 64) {
224     //printf("PEDAL DOWN\n");
225     SustainPedal=1;
226     }
227     if(Value < 64 && PrevHoldCCValue >=64) {
228     //printf("PEDAL UP\n");
229     SustainPedal=0;
230     sustained_key_t *key;
231     for(key = SustainedKeyPool->first(); key ; key=SustainedKeyPool->next() ) {
232     ReleaseVoice(key->midikey, key->velocity);
233     }
234     // empty the SustainedKeyPool (free all the elements)
235     SustainedKeyPool->empty();
236    
237    
238     }
239     PrevHoldCCValue=Value;
240     }
241    
242     }
243    
244    
245 schoenebeck 9 void AudioThread::CacheInitialSamples(gig::Sample* pSample) {
246     if (!pSample || pSample->GetCache().Size) return;
247     if (pSample->SamplesTotal <= NUM_RAM_PRELOAD_SAMPLES) {
248     // Sample is too short for disk streaming, so we load the whole
249     // sample into RAM and place 'pAudioIO->FragmentSize << MAX_PITCH'
250     // number of '0' samples (silence samples) behind the official buffer
251     // border, to allow the interpolator do it's work even at the end of
252     // the sample.
253     gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(pAudioIO->FragmentSize << MAX_PITCH);
254     dmsg(("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize));
255     }
256     else { // we only cache NUM_RAM_PRELOAD_SAMPLES and stream the other sample points from disk
257     pSample->LoadSampleData(NUM_RAM_PRELOAD_SAMPLES);
258     }
259    
260     if (!pSample->GetCache().Size) std::cerr << "Unable to cache sample - maybe memory full!" << std::endl << std::flush;
261     }

  ViewVC Help
Powered by ViewVC