22 |
|
|
23 |
#include "audiothread.h" |
#include "audiothread.h" |
24 |
|
|
25 |
AudioThread::AudioThread(AudioIO* pAudioIO, DiskThread* pDiskThread, gig::Instrument* pInstrument) { |
AudioThread::AudioThread(AudioIO* pAudioIO) { |
26 |
this->pAudioIO = pAudioIO; |
this->pAudioIO = pAudioIO; |
27 |
this->pDiskThread = pDiskThread; |
this->pDiskThread = new DiskThread(((pAudioIO->MaxSamplesPerCycle() << MAX_PITCH) << 1) + 6); //FIXME: assuming stereo |
28 |
this->pInstrument = pInstrument; |
this->pInstrument = NULL; |
29 |
this->Pitch = 0; |
this->Pitch = 0; |
30 |
Voice::pDiskThread = pDiskThread; |
Voice::pDiskThread = this->pDiskThread; |
31 |
Voice::pEngine = this; |
Voice::pEngine = this; |
32 |
pEventQueue = new RingBuffer<ModulationSystem::Event>(MAX_EVENTS_PER_FRAGMENT); |
pEventQueue = new RingBuffer<ModulationSystem::Event>(MAX_EVENTS_PER_FRAGMENT); |
33 |
pEventPool = new RTELMemoryPool<ModulationSystem::Event>(MAX_EVENTS_PER_FRAGMENT); |
pEventPool = new RTELMemoryPool<ModulationSystem::Event>(MAX_EVENTS_PER_FRAGMENT); |
38 |
pCCEvents[i] = new RTEList<ModulationSystem::Event>(pEventPool); |
pCCEvents[i] = new RTEList<ModulationSystem::Event>(pEventPool); |
39 |
} |
} |
40 |
for (uint i = 0; i < 128; i++) { |
for (uint i = 0; i < 128; i++) { |
41 |
pMIDIKeyInfo[i].pActiveVoices = new RTEList<Voice>(pVoicePool); |
pMIDIKeyInfo[i].pActiveVoices = new RTEList<Voice>(pVoicePool); |
42 |
pMIDIKeyInfo[i].KeyPressed = false; |
pMIDIKeyInfo[i].KeyPressed = false; |
43 |
pMIDIKeyInfo[i].Active = false; |
pMIDIKeyInfo[i].Active = false; |
44 |
pMIDIKeyInfo[i].pSelf = NULL; |
pMIDIKeyInfo[i].pSelf = NULL; |
45 |
pMIDIKeyInfo[i].pEvents = new RTEList<ModulationSystem::Event>(pEventPool); |
pMIDIKeyInfo[i].pEvents = new RTEList<ModulationSystem::Event>(pEventPool); |
46 |
} |
} |
47 |
|
|
48 |
// FIXME: assuming stereo output |
// FIXME: assuming stereo output |
56 |
} |
} |
57 |
pVoicePool->clear(); |
pVoicePool->clear(); |
58 |
|
|
59 |
// cache initial samples points (for actually needed samples) |
pRIFF = NULL; |
60 |
dmsg(1,("Caching initial samples...")); |
pGig = NULL; |
61 |
gig::Region* pRgn = this->pInstrument->GetFirstRegion(); |
pInstrument = NULL; |
|
while (pRgn) { |
|
|
if (!pRgn->GetSample()->GetCache().Size) { |
|
|
dmsg(2,("C")); |
|
|
CacheInitialSamples(pRgn->GetSample()); |
|
|
} |
|
|
for (uint i = 0; i < pRgn->DimensionRegions; i++) { |
|
|
CacheInitialSamples(pRgn->pDimensionRegions[i]->pSample); |
|
|
} |
|
|
|
|
|
pRgn = this->pInstrument->GetNextRegion(); |
|
|
} |
|
62 |
|
|
63 |
// initialize modulation system |
// initialize modulation system |
64 |
ModulationSystem::Initialize(pAudioIO->SampleRate(), pAudioIO->MaxSamplesPerCycle()); |
ModulationSystem::Initialize(pAudioIO->SampleRate(), pAudioIO->MaxSamplesPerCycle()); |
67 |
PrevHoldCCValue = 0; |
PrevHoldCCValue = 0; |
68 |
SustainPedal = 0; |
SustainPedal = 0; |
69 |
|
|
70 |
|
SuspensionRequested = false; |
71 |
|
pthread_mutex_init(&__render_state_mutex, NULL); |
72 |
|
pthread_cond_init(&__render_exit_condition, NULL); |
73 |
|
|
74 |
|
dmsg(1,("Starting disk thread...")); |
75 |
|
pDiskThread->StartThread(); |
76 |
dmsg(1,("OK\n")); |
dmsg(1,("OK\n")); |
77 |
} |
} |
78 |
|
|
79 |
AudioThread::~AudioThread() { |
AudioThread::~AudioThread() { |
80 |
|
if (pDiskThread) { |
81 |
|
pDiskThread->StopThread(); |
82 |
|
delete pDiskThread; |
83 |
|
} |
84 |
|
if (pGig) delete pGig; |
85 |
|
if (pRIFF) delete pRIFF; |
86 |
ModulationSystem::Close(); |
ModulationSystem::Close(); |
87 |
for (uint i = 0; i < 128; i++) { |
for (uint i = 0; i < 128; i++) { |
88 |
if (pMIDIKeyInfo[i].pActiveVoices) delete pMIDIKeyInfo[i].pActiveVoices; |
if (pMIDIKeyInfo[i].pActiveVoices) delete pMIDIKeyInfo[i].pActiveVoices; |
98 |
if (pVoicePool) delete pVoicePool; |
if (pVoicePool) delete pVoicePool; |
99 |
if (pActiveKeys) delete pActiveKeys; |
if (pActiveKeys) delete pActiveKeys; |
100 |
delete[] pAudioSumBuffer[0]; // this also frees the right channel buffer |
delete[] pAudioSumBuffer[0]; // this also frees the right channel buffer |
101 |
|
pthread_cond_destroy(&__render_exit_condition); |
102 |
|
pthread_mutex_destroy(&__render_state_mutex); |
103 |
} |
} |
104 |
|
|
105 |
/** |
/** |
114 |
*/ |
*/ |
115 |
int AudioThread::RenderAudio(uint Samples) { |
int AudioThread::RenderAudio(uint Samples) { |
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 |
|
// check if rendering process was requested to be interrupted (e.g. to load another instrument) |
122 |
|
if (SuspensionRequested) { |
123 |
|
pthread_cond_broadcast(&__render_exit_condition); // wake up anybody waiting for us |
124 |
|
return 0; |
125 |
|
} |
126 |
|
|
127 |
|
|
128 |
// empty the event lists for the new fragment |
// empty the event lists for the new fragment |
129 |
pEvents->clear(); |
pEvents->clear(); |
130 |
for (uint i = 0; i < ModulationSystem::destination_count; i++) { |
for (uint i = 0; i < ModulationSystem::destination_count; i++) { |
170 |
} |
} |
171 |
|
|
172 |
|
|
|
// zero out the output sum buffer (left and right channel) |
|
|
memset(pAudioSumBuffer[0], 0, Samples * pAudioIO->Channels() * sizeof(float)); |
|
|
|
|
|
|
|
173 |
// render audio from all active voices |
// render audio from all active voices |
174 |
int active_voices = 0; |
int active_voices = 0; |
175 |
uint* piKey = pActiveKeys->first(); |
uint* piKey = pActiveKeys->first(); |
445 |
|
|
446 |
if (!pSample->GetCache().Size) std::cerr << "Unable to cache sample - maybe memory full!" << std::endl << std::flush; |
if (!pSample->GetCache().Size) std::cerr << "Unable to cache sample - maybe memory full!" << std::endl << std::flush; |
447 |
} |
} |
448 |
|
|
449 |
|
/** |
450 |
|
* Load an instrument from a .gig file. |
451 |
|
* |
452 |
|
* @param FileName - file name of the Gigasampler instrument file |
453 |
|
* @param Instrument - index of the instrument in the .gig file |
454 |
|
* @returns detailed description of the result of the method call |
455 |
|
*/ |
456 |
|
result_t AudioThread::LoadInstrument(const char* FileName, uint Instrument) { |
457 |
|
result_t result; |
458 |
|
|
459 |
|
if (pInstrument) { // if already running |
460 |
|
// signal audio thread not to enter render part anymore |
461 |
|
SuspensionRequested = true; |
462 |
|
// sleep until wakened by audio thread |
463 |
|
pthread_mutex_lock(&__render_state_mutex); |
464 |
|
pthread_cond_wait(&__render_exit_condition, &__render_state_mutex); |
465 |
|
pthread_mutex_unlock(&__render_state_mutex); |
466 |
|
|
467 |
|
dmsg(1,("Freeing old instrument from memory...")); |
468 |
|
delete pGig; |
469 |
|
delete pRIFF; |
470 |
|
pInstrument = NULL; |
471 |
|
dmsg(1,("OK\n")); |
472 |
|
} |
473 |
|
|
474 |
|
// loading gig file |
475 |
|
try { |
476 |
|
dmsg(1,("Loading gig file...")); |
477 |
|
pRIFF = new RIFF::File(FileName); |
478 |
|
pGig = new gig::File(pRIFF); |
479 |
|
pInstrument = pGig->GetInstrument(Instrument); |
480 |
|
if (!pInstrument) { |
481 |
|
std::stringstream msg; |
482 |
|
msg << "There's no instrument with index " << Instrument << "."; |
483 |
|
std::cerr << msg << std::endl; |
484 |
|
result.type = result_type_error; |
485 |
|
result.code = LSCP_ERR_UNKNOWN; |
486 |
|
result.message = msg.str(); |
487 |
|
return result; |
488 |
|
} |
489 |
|
pGig->GetFirstSample(); // just to complete instrument loading before we enter the realtime part |
490 |
|
dmsg(1,("OK\n")); |
491 |
|
} |
492 |
|
catch (RIFF::Exception e) { |
493 |
|
e.PrintMessage(); |
494 |
|
result.type = result_type_error; |
495 |
|
result.code = LSCP_ERR_UNKNOWN; |
496 |
|
result.message = e.Message; |
497 |
|
return result; |
498 |
|
} |
499 |
|
catch (...) { |
500 |
|
dmsg(1,("Unknown exception while trying to parse gig file.\n")); |
501 |
|
result.type = result_type_error; |
502 |
|
result.code = LSCP_ERR_UNKNOWN; |
503 |
|
result.message = "Unknown exception while trying to parse gig file."; |
504 |
|
return result; |
505 |
|
} |
506 |
|
|
507 |
|
// cache initial samples points (for actually needed samples) |
508 |
|
dmsg(1,("Caching initial samples...")); |
509 |
|
gig::Region* pRgn = this->pInstrument->GetFirstRegion(); |
510 |
|
while (pRgn) { |
511 |
|
if (!pRgn->GetSample()->GetCache().Size) { |
512 |
|
dmsg(2,("C")); |
513 |
|
CacheInitialSamples(pRgn->GetSample()); |
514 |
|
} |
515 |
|
for (uint i = 0; i < pRgn->DimensionRegions; i++) { |
516 |
|
CacheInitialSamples(pRgn->pDimensionRegions[i]->pSample); |
517 |
|
} |
518 |
|
|
519 |
|
pRgn = this->pInstrument->GetNextRegion(); |
520 |
|
} |
521 |
|
dmsg(1,("OK\n")); |
522 |
|
|
523 |
|
ResetInternal(); // reset engine |
524 |
|
|
525 |
|
// signal audio thread to continue with rendering |
526 |
|
SuspensionRequested = false; |
527 |
|
|
528 |
|
// success |
529 |
|
result.type = result_type_success; |
530 |
|
return result; |
531 |
|
} |
532 |
|
|
533 |
|
/** |
534 |
|
* Reset all voices and disk thread and clear input event queue and all |
535 |
|
* control and status variables. |
536 |
|
*/ |
537 |
|
void AudioThread::Reset() { |
538 |
|
if (pInstrument) { // if already running |
539 |
|
// signal audio thread not to enter render part anymore |
540 |
|
SuspensionRequested = true; |
541 |
|
// sleep until wakened by audio thread |
542 |
|
pthread_mutex_lock(&__render_state_mutex); |
543 |
|
pthread_cond_wait(&__render_exit_condition, &__render_state_mutex); |
544 |
|
pthread_mutex_unlock(&__render_state_mutex); |
545 |
|
} |
546 |
|
|
547 |
|
ResetInternal(); |
548 |
|
|
549 |
|
// signal audio thread to continue with rendering |
550 |
|
SuspensionRequested = false; |
551 |
|
} |
552 |
|
|
553 |
|
/** |
554 |
|
* Reset all voices and disk thread and clear input event queue and all |
555 |
|
* control and status variables. This method is not thread safe! |
556 |
|
*/ |
557 |
|
void AudioThread::ResetInternal() { |
558 |
|
this->Pitch = 0; |
559 |
|
PrevHoldCCValue = 0; // sustain pedal value |
560 |
|
SustainPedal = 0; |
561 |
|
ActiveVoiceCount = 0; |
562 |
|
ActiveVoiceCountMax = 0; |
563 |
|
|
564 |
|
// reset key info |
565 |
|
for (uint i = 0; i < 128; i++) { |
566 |
|
pMIDIKeyInfo[i].pActiveVoices->clear(); |
567 |
|
pMIDIKeyInfo[i].pEvents->clear(); |
568 |
|
pMIDIKeyInfo[i].KeyPressed = false; |
569 |
|
pMIDIKeyInfo[i].Active = false; |
570 |
|
pMIDIKeyInfo[i].pSelf = NULL; |
571 |
|
} |
572 |
|
|
573 |
|
// reset all voices |
574 |
|
for (Voice* pVoice = pVoicePool->first(); pVoice; pVoice = pVoicePool->next()) { |
575 |
|
pVoice->Reset(); |
576 |
|
} |
577 |
|
|
578 |
|
// free all active keys |
579 |
|
pActiveKeys->clear(); |
580 |
|
|
581 |
|
// reset disk thread |
582 |
|
pDiskThread->Reset(); |
583 |
|
|
584 |
|
// delete all input events |
585 |
|
pEventQueue->init(); |
586 |
|
} |