22 |
|
|
23 |
#include "audiothread.h" |
#include "audiothread.h" |
24 |
|
|
25 |
AudioThread::AudioThread(AudioIO* pAudioIO, DiskThread* pDiskThread, gig::Instrument* pInstrument) : Thread(true, 1, 0) { |
AudioThread::AudioThread(AudioIO* pAudioIO, DiskThread* pDiskThread, gig::Instrument* pInstrument) { |
26 |
this->pAudioIO = pAudioIO; |
this->pAudioIO = pAudioIO; |
27 |
this->pDiskThread = pDiskThread; |
this->pDiskThread = pDiskThread; |
28 |
this->pInstrument = pInstrument; |
this->pInstrument = pInstrument; |
43 |
} |
} |
44 |
SustainedKeyPool = new RTELMemoryPool<uint>(128); |
SustainedKeyPool = new RTELMemoryPool<uint>(128); |
45 |
|
|
46 |
pAudioSumBuffer = new float[pAudioIO->FragmentSize * pAudioIO->Channels]; |
// 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 |
// set all voice outputs to the AudioSumBuffer |
51 |
for (int i = 0; i < MAX_AUDIO_VOICES; i++) { |
for (int i = 0; i < MAX_AUDIO_VOICES; i++) { //FIXME: assuming stereo |
52 |
pVoices[i]->SetOutput(pAudioSumBuffer, pAudioIO->FragmentSize * 2); //FIXME: assuming stereo |
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) |
// cache initial samples points (for actually needed samples) |
69 |
} |
} |
70 |
|
|
71 |
// initialize modulation system |
// initialize modulation system |
72 |
ModulationSystem::Initialize(pAudioIO->Samplerate, pAudioIO->FragmentSize); |
ModulationSystem::Initialize(pAudioIO->SampleRate(), pAudioIO->MaxSamplesPerCycle()); |
73 |
|
|
74 |
// sustain pedal value |
// sustain pedal value |
75 |
PrevHoldCCValue = 0; |
PrevHoldCCValue = 0; |
87 |
} |
} |
88 |
} |
} |
89 |
delete[] pVoices; |
delete[] pVoices; |
90 |
|
delete[] pAudioSumBuffer[0]; // this also frees the right channel buffer |
91 |
} |
} |
92 |
|
|
93 |
int AudioThread::Main() { |
int AudioThread::RenderAudio(uint Samples) { |
|
dmsg(2,("Audio thread running\n")); |
|
94 |
|
|
95 |
|
// read and process commands from the queue |
96 |
while (true) { |
while (true) { |
97 |
|
command_t command; |
98 |
|
if (!pCommandQueue->pop(&command)) break; |
99 |
|
|
100 |
// read and process commands from the queue |
switch (command.type) { |
101 |
while (true) { |
case command_type_note_on: |
102 |
command_t command; |
dmsg(5,("Audio Thread: Note on received\n")); |
103 |
if (!pCommandQueue->pop(&command)) break; |
ProcessNoteOn(command.pitch, command.velocity); |
104 |
|
break; |
105 |
switch (command.type) { |
case command_type_note_off: |
106 |
case command_type_note_on: |
dmsg(5,("Audio Thread: Note off received\n")); |
107 |
dmsg(5,("Audio Thread: Note on received\n")); |
ProcessNoteOff(command.pitch, command.velocity); |
108 |
ProcessNoteOn(command.pitch, command.velocity); |
break; |
109 |
break; |
case command_type_continuous_controller: |
110 |
case command_type_note_off: |
dmsg(5,("Audio Thread: MIDI CC received\n")); |
111 |
dmsg(5,("Audio Thread: Note off received\n")); |
ProcessControlChange(command.channel, command.number, command.value); |
112 |
ProcessNoteOff(command.pitch, command.velocity); |
break; |
|
break; |
|
|
case command_type_continuous_controller: |
|
|
dmsg(5,("Audio Thread: MIDI CC received\n")); |
|
|
ProcessControlChange(command.channel, command.number, command.value); |
|
|
break; |
|
|
} |
|
113 |
} |
} |
114 |
|
} |
115 |
|
|
116 |
|
|
117 |
// zero out the output sum buffer |
// zero out the output sum buffer (left and right channel) |
118 |
memset(pAudioSumBuffer, 0, pAudioIO->FragmentSize * pAudioIO->Channels * sizeof(float)); |
memset(pAudioSumBuffer[0], 0, Samples * pAudioIO->Channels() * sizeof(float)); |
119 |
|
|
120 |
|
|
121 |
// render audio from all active voices |
// render audio from all active voices |
122 |
int active_voices = 0; |
int active_voices = 0; |
123 |
for (uint i = 0; i < MAX_AUDIO_VOICES; i++) { |
for (uint i = 0; i < MAX_AUDIO_VOICES; i++) { |
124 |
if (pVoices[i]->IsActive()) { |
if (pVoices[i]->IsActive()) { |
125 |
pVoices[i]->RenderAudio(); |
pVoices[i]->Render(Samples); |
126 |
if (pVoices[i]->IsActive()) active_voices++; // still active |
if (pVoices[i]->IsActive()) active_voices++; // still active |
127 |
else { // voice reached end, is now inactive |
else { // voice reached end, is now inactive |
128 |
KillVoice(pVoices[i]); // remove voice from the list of active voices |
KillVoice(pVoices[i]); // remove voice from the list of active voices |
|
} |
|
129 |
} |
} |
130 |
} |
} |
131 |
// write that to the disk thread class so that it can print it |
} |
132 |
// on the console for debugging purposes |
// write that to the disk thread class so that it can print it |
133 |
ActiveVoiceCount = active_voices; |
// on the console for debugging purposes |
134 |
if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount; |
ActiveVoiceCount = active_voices; |
135 |
|
if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount; |
|
|
|
|
// check clipping in the audio sum, convert to sample_type |
|
|
// (from 32bit to 16bit sample) and copy to output buffer |
|
|
float sample_point; |
|
|
for (uint u = 0; u < pAudioIO->FragmentSize * pAudioIO->Channels; u++) { |
|
|
sample_point = this->pAudioSumBuffer[u] * this->Volume; |
|
|
if (sample_point < -32768.0) sample_point = -32768.0; |
|
|
if (sample_point > 32767.0) sample_point = 32767.0; |
|
|
this->pAudioIO->pOutputBuffer[u] = (sample_t) sample_point; |
|
|
} |
|
136 |
|
|
137 |
|
|
138 |
// call audio driver to output sound |
return 0; |
|
int res = this->pAudioIO->Output(); |
|
|
if (res < 0) exit(EXIT_FAILURE); |
|
|
} |
|
139 |
} |
} |
140 |
|
|
141 |
/// Will be called by the MIDIIn Thread to let the audio thread trigger a new voice. |
/// Will be called by the MIDIIn Thread to let the audio thread trigger a new voice. |
306 |
(*pVoicePtr)->Release(); |
(*pVoicePtr)->Release(); |
307 |
pVoicePtr = pVoicePtrNext; |
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 |
} |
} |
|
SustainedKeyPool->free(pMIDIKeyInfo[*key].pSustainPoolNode); |
|
|
pMIDIKeyInfo[*key].pSustainPoolNode = NULL; |
|
|
pMIDIKeyInfo[*key].Sustained = false; |
|
|
pMIDIKeyInfo[*key].hSustainPtr = NULL; |
|
314 |
} |
} |
315 |
//SustainedKeyPool->empty(); |
//SustainedKeyPool->empty(); |
316 |
} |
} |
326 |
// number of '0' samples (silence samples) behind the official buffer |
// 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 |
// border, to allow the interpolator do it's work even at the end of |
328 |
// the sample. |
// the sample. |
329 |
gig::buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension((pAudioIO->FragmentSize << MAX_PITCH) + 3); |
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)); |
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 |
else { // we only cache NUM_RAM_PRELOAD_SAMPLES and stream the other sample points from disk |