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) : 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 |
for (uint i = 0; i < MAX_AUDIO_VOICES; i++) { |
32 |
pVoices[i] = new Voice(pDiskThread); |
33 |
} |
34 |
for (uint i = 0; i < 128; i++) { |
35 |
ActiveVoices[i] = NULL; |
36 |
} |
37 |
|
38 |
pAudioSumBuffer = new float[pAudioIO->FragmentSize * pAudioIO->Channels]; |
39 |
|
40 |
// set all voice outputs to the AudioSumBuffer |
41 |
for (int i = 0; i < MAX_AUDIO_VOICES; i++) { |
42 |
pVoices[i]->SetOutput(pAudioSumBuffer, pAudioIO->FragmentSize * 2); //FIXME: assuming stereo |
43 |
} |
44 |
|
45 |
// cache initial samples points (for actually needed samples) |
46 |
dmsg(("Caching initial samples...")); |
47 |
gig::Region* pRgn = this->pInstrument->GetFirstRegion(); |
48 |
while (pRgn) { |
49 |
if (!pRgn->GetSample()->GetCache().Size) { |
50 |
CacheInitialSamples(pRgn->GetSample()); |
51 |
} |
52 |
for (uint i = 0; i < pRgn->DimensionRegions; i++) { |
53 |
CacheInitialSamples(pRgn->pDimensionRegions[i]->pSample); |
54 |
} |
55 |
|
56 |
pRgn = this->pInstrument->GetNextRegion(); |
57 |
} |
58 |
dmsg(("OK\n")); |
59 |
} |
60 |
|
61 |
AudioThread::~AudioThread() { |
62 |
if (pCommandQueue) delete pCommandQueue; |
63 |
if (pVoices) { |
64 |
for (uint i = 0; i < MAX_AUDIO_VOICES; i++) { |
65 |
if (pVoices[i]) delete pVoices[i]; |
66 |
} |
67 |
} |
68 |
delete[] pVoices; |
69 |
} |
70 |
|
71 |
int AudioThread::Main() { |
72 |
dmsg(("Audio thread running\n")); |
73 |
|
74 |
while (true) { |
75 |
|
76 |
// read and process commands from the queue |
77 |
while (true) { |
78 |
command_t command; |
79 |
if (pCommandQueue->read(&command, 1) == 0) break; |
80 |
|
81 |
switch (command.type) { |
82 |
case command_type_note_on: |
83 |
dmsg(("Audio Thread: Note on received\n")); |
84 |
ActivateVoice(command.pitch, command.velocity); |
85 |
break; |
86 |
case command_type_note_off: |
87 |
dmsg(("Audio Thread: Note off received\n")); |
88 |
ReleaseVoice(command.pitch, command.velocity); |
89 |
break; |
90 |
} |
91 |
} |
92 |
|
93 |
|
94 |
// zero out the sum buffer |
95 |
for (uint u = 0; u < pAudioIO->FragmentSize * pAudioIO->Channels; u++) { |
96 |
pAudioSumBuffer[u] = 0.0; |
97 |
} |
98 |
|
99 |
|
100 |
// render audio from all active voices |
101 |
for (uint i = 0; i < MAX_AUDIO_VOICES; i++) { |
102 |
if (pVoices[i]->IsActive()) { |
103 |
pVoices[i]->RenderAudio(); |
104 |
} |
105 |
} |
106 |
|
107 |
|
108 |
// check clipping in the audio sum, convert to sample_type |
109 |
// (from 32bit to 16bit sample) and copy to output buffer |
110 |
float sample_point; |
111 |
for (uint u = 0; u < pAudioIO->FragmentSize * pAudioIO->Channels; u++) { |
112 |
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) |
113 |
if (sample_point < -32768.0) sample_point = -32768.0; |
114 |
if (sample_point > 32767.0) sample_point = 32767.0; |
115 |
this->pAudioIO->pOutputBuffer[u] = (sample_t) sample_point; |
116 |
} |
117 |
|
118 |
|
119 |
// call audio driver to output sound |
120 |
int res = this->pAudioIO->Output(); |
121 |
if (res < 0) exit(EXIT_FAILURE); |
122 |
} |
123 |
} |
124 |
|
125 |
/// Will be called by the MIDIIn Thread to let the audio thread trigger a new voice. |
126 |
void AudioThread::ProcessNoteOn(uint8_t Pitch, uint8_t Velocity) { |
127 |
command_t cmd; |
128 |
cmd.type = command_type_note_on; |
129 |
cmd.pitch = Pitch; |
130 |
cmd.velocity = Velocity; |
131 |
this->pCommandQueue->write(&cmd, 1); |
132 |
} |
133 |
|
134 |
/// Will be called by the MIDIIn Thread to signal the audio thread to release a voice. |
135 |
void AudioThread::ProcessNoteOff(uint8_t Pitch, uint8_t Velocity) { |
136 |
command_t cmd; |
137 |
cmd.type = command_type_note_off; |
138 |
cmd.pitch = Pitch; |
139 |
cmd.velocity = Velocity; |
140 |
this->pCommandQueue->write(&cmd, 1); |
141 |
} |
142 |
|
143 |
void AudioThread::ActivateVoice(uint8_t MIDIKey, uint8_t Velocity) { |
144 |
for (int i = 0; i < MAX_AUDIO_VOICES; i++) { |
145 |
if (pVoices[i]->IsActive()) continue; |
146 |
pVoices[i]->Trigger(MIDIKey, Velocity, this->pInstrument); |
147 |
ActiveVoices[MIDIKey] = pVoices[i]; |
148 |
return; |
149 |
} |
150 |
std::cerr << "No free voice!" << std::endl << std::flush; |
151 |
} |
152 |
|
153 |
void AudioThread::ReleaseVoice(uint8_t MIDIKey, uint8_t Velocity) { |
154 |
Voice* pVoice = ActiveVoices[MIDIKey]; |
155 |
if (pVoice) { |
156 |
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 |
157 |
ActiveVoices[MIDIKey] = NULL; |
158 |
} |
159 |
else std::cerr << "Couldn't find active voice for note off command!" << std::endl << std::flush; |
160 |
} |
161 |
|
162 |
void AudioThread::CacheInitialSamples(gig::Sample* pSample) { |
163 |
if (!pSample || pSample->GetCache().Size) return; |
164 |
if (pSample->SamplesTotal <= NUM_RAM_PRELOAD_SAMPLES) { |
165 |
// Sample is too short for disk streaming, so we load the whole |
166 |
// sample into RAM and place 'pAudioIO->FragmentSize << MAX_PITCH' |
167 |
// number of '0' samples (silence samples) behind the official buffer |
168 |
// border, to allow the interpolator do it's work even at the end of |
169 |
// the sample. |
170 |
gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(pAudioIO->FragmentSize << MAX_PITCH); |
171 |
dmsg(("Cached %d Bytes, %d silence bytes.\n", buf.Size, buf.NullExtensionSize)); |
172 |
} |
173 |
else { // we only cache NUM_RAM_PRELOAD_SAMPLES and stream the other sample points from disk |
174 |
pSample->LoadSampleData(NUM_RAM_PRELOAD_SAMPLES); |
175 |
} |
176 |
|
177 |
if (!pSample->GetCache().Size) std::cerr << "Unable to cache sample - maybe memory full!" << std::endl << std::flush; |
178 |
} |