116 |
* Destructor |
* Destructor |
117 |
*/ |
*/ |
118 |
Engine::~Engine() { |
Engine::~Engine() { |
119 |
|
MidiInputPort::RemoveSysexListener(this); |
120 |
if (pDiskThread) { |
if (pDiskThread) { |
121 |
dmsg(1,("Stopping disk thread...")); |
dmsg(1,("Stopping disk thread...")); |
122 |
pDiskThread->StopThread(); |
pDiskThread->StopThread(); |
166 |
|
|
167 |
/** |
/** |
168 |
* Reset all voices and disk thread and clear input event queue and all |
* Reset all voices and disk thread and clear input event queue and all |
169 |
* control and status variables. This method is not thread safe! |
* control and status variables. This method is protected by a mutex. |
170 |
*/ |
*/ |
171 |
void Engine::ResetInternal() { |
void Engine::ResetInternal() { |
172 |
|
ResetInternalMutex.Lock(); |
173 |
|
|
174 |
|
// make sure that the engine does not get any sysex messages |
175 |
|
// while it's reseting |
176 |
|
bool sysexDisabled = MidiInputPort::RemoveSysexListener(this); |
177 |
ActiveVoiceCount = 0; |
ActiveVoiceCount = 0; |
178 |
ActiveVoiceCountMax = 0; |
ActiveVoiceCountMax = 0; |
179 |
|
|
197 |
// delete all input events |
// delete all input events |
198 |
pEventQueue->init(); |
pEventQueue->init(); |
199 |
pSysexBuffer->init(); |
pSysexBuffer->init(); |
200 |
|
if (sysexDisabled) MidiInputPort::AddSysexListener(this); |
201 |
|
ResetInternalMutex.Unlock(); |
202 |
} |
} |
203 |
|
|
204 |
/** |
/** |
228 |
} |
} |
229 |
catch (AudioOutputException e) { |
catch (AudioOutputException e) { |
230 |
String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message(); |
String msg = "Audio output device unable to provide 2 audio channels, cause: " + e.Message(); |
231 |
throw LinuxSamplerException(msg); |
throw Exception(msg); |
232 |
} |
} |
233 |
|
|
234 |
this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle(); |
this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle(); |
329 |
} |
} |
330 |
|
|
331 |
/** |
/** |
332 |
* Let this engine proceed to render the given amount of sample points. The |
* Let this engine proceed to render the given amount of sample points. |
333 |
* calculated audio data of all voices of this engine will be placed into |
* The engine will iterate through all engine channels and render audio |
334 |
* the engine's audio sum buffer which has to be copied and eventually be |
* for each engine channel independently. The calculated audio data of |
335 |
* converted to the appropriate value range by the audio output class (e.g. |
* all voices of each engine channel will be placed into the audio sum |
336 |
* AlsaIO or JackIO) right after. |
* buffers of the respective audio output device, connected to the |
337 |
|
* respective engine channel. |
338 |
* |
* |
339 |
* @param Samples - number of sample points to be rendered |
* @param Samples - number of sample points to be rendered |
340 |
* @returns 0 on success |
* @returns 0 on success |
643 |
{ |
{ |
644 |
const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument; |
const ::gig::Instrument* pInstrument = pEngineChannel->pInstrument; |
645 |
if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high) |
if (key >= pInstrument->DimensionKeyRange.low && key <= pInstrument->DimensionKeyRange.high) |
646 |
pEngineChannel->CurrentKeyDimension = ((key - pInstrument->DimensionKeyRange.low) * 128) / |
pEngineChannel->CurrentKeyDimension = float(key - pInstrument->DimensionKeyRange.low) / |
647 |
(pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1); |
(pInstrument->DimensionKeyRange.high - pInstrument->DimensionKeyRange.low + 1); |
648 |
} |
} |
649 |
|
|
871 |
DimValues[i] = itNoteOnEvent->Param.Note.Velocity; |
DimValues[i] = itNoteOnEvent->Param.Note.Velocity; |
872 |
break; |
break; |
873 |
case ::gig::dimension_channelaftertouch: |
case ::gig::dimension_channelaftertouch: |
874 |
DimValues[i] = 0; //TODO: we currently ignore this dimension |
DimValues[i] = pEngineChannel->ControllerTable[128]; |
875 |
break; |
break; |
876 |
case ::gig::dimension_releasetrigger: |
case ::gig::dimension_releasetrigger: |
877 |
VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal; |
VoiceType = (ReleaseTriggerVoice) ? Voice::type_release_trigger : (!iLayer) ? Voice::type_release_trigger_required : Voice::type_normal; |
878 |
DimValues[i] = (uint) ReleaseTriggerVoice; |
DimValues[i] = (uint) ReleaseTriggerVoice; |
879 |
break; |
break; |
880 |
case ::gig::dimension_keyboard: |
case ::gig::dimension_keyboard: |
881 |
DimValues[i] = (uint) pEngineChannel->CurrentKeyDimension; |
DimValues[i] = (uint) (pEngineChannel->CurrentKeyDimension * pRegion->pDimensionDefinitions[i].zones); |
882 |
break; |
break; |
883 |
case ::gig::dimension_roundrobin: |
case ::gig::dimension_roundrobin: |
884 |
DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on |
DimValues[i] = (uint) pEngineChannel->pMIDIKeyInfo[MIDIKey].RoundRobinIndex; // incremented for each note on |
1243 |
} |
} |
1244 |
case 7: { // volume |
case 7: { // volume |
1245 |
//TODO: not sample accurate yet |
//TODO: not sample accurate yet |
1246 |
pEngineChannel->GlobalVolume = (float) itControlChangeEvent->Param.CC.Value / 127.0f * CONFIG_GLOBAL_ATTENUATION; |
pEngineChannel->GlobalVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value] * CONFIG_GLOBAL_ATTENUATION; |
1247 |
pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag |
pEngineChannel->bStatusChanged = true; // engine channel status has changed, so set notify flag |
1248 |
break; |
break; |
1249 |
} |
} |
1250 |
case 10: { // panpot |
case 10: { // panpot |
1251 |
//TODO: not sample accurate yet |
//TODO: not sample accurate yet |
1252 |
const int pan = (int) itControlChangeEvent->Param.CC.Value - 64; |
pEngineChannel->GlobalPanLeft = PanCurve[128 - itControlChangeEvent->Param.CC.Value]; |
1253 |
pEngineChannel->GlobalPanLeft = 1.0f - float(RTMath::Max(pan, 0)) / 63.0f; |
pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value]; |
|
pEngineChannel->GlobalPanRight = 1.0f - float(RTMath::Min(pan, 0)) / -64.0f; |
|
1254 |
break; |
break; |
1255 |
} |
} |
1256 |
case 64: { // sustain |
case 64: { // sustain |
1358 |
break; |
break; |
1359 |
} |
} |
1360 |
case 123: { // all notes off |
case 123: { // all notes off |
1361 |
|
#if CONFIG_PROCESS_ALL_NOTES_OFF |
1362 |
ReleaseAllVoices(pEngineChannel, itControlChangeEvent); |
ReleaseAllVoices(pEngineChannel, itControlChangeEvent); |
1363 |
|
#endif // CONFIG_PROCESS_ALL_NOTES_OFF |
1364 |
break; |
break; |
1365 |
} |
} |
1366 |
case 126: { // mono mode on |
case 126: { // mono mode on |
1568 |
} |
} |
1569 |
|
|
1570 |
String Engine::Version() { |
String Engine::Version() { |
1571 |
String s = "$Revision: 1.57 $"; |
String s = "$Revision: 1.65 $"; |
1572 |
return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword |
return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword |
1573 |
} |
} |
1574 |
|
|
1575 |
|
// static constant initializers |
1576 |
|
const float* Engine::VolumeCurve(InitVolumeCurve()); |
1577 |
|
const float* Engine::PanCurve(InitPanCurve()); |
1578 |
|
const float* Engine::CrossfadeCurve(InitCrossfadeCurve()); |
1579 |
|
|
1580 |
|
float* Engine::InitVolumeCurve() { |
1581 |
|
// line-segment approximation |
1582 |
|
const float segments[] = { |
1583 |
|
0, 0, 2, 0.0046, 16, 0.016, 31, 0.051, 45, 0.115, 54.5, 0.2, |
1584 |
|
64.5, 0.39, 74, 0.74, 92, 1.03, 114, 1.94, 119.2, 2.2, 127, 2.2 |
1585 |
|
}; |
1586 |
|
return InitCurve(segments); |
1587 |
|
} |
1588 |
|
|
1589 |
|
float* Engine::InitPanCurve() { |
1590 |
|
// line-segment approximation |
1591 |
|
const float segments[] = { |
1592 |
|
0, 0, 1, 0, |
1593 |
|
2, 0.05, 31.5, 0.7, 51, 0.851, 74.5, 1.12, |
1594 |
|
127, 1.41, 128, 1.41 |
1595 |
|
}; |
1596 |
|
return InitCurve(segments, 129); |
1597 |
|
} |
1598 |
|
|
1599 |
|
float* Engine::InitCrossfadeCurve() { |
1600 |
|
// line-segment approximation |
1601 |
|
const float segments[] = { |
1602 |
|
0, 0, 1, 0.03, 10, 0.1, 51, 0.58, 127, 1 |
1603 |
|
}; |
1604 |
|
return InitCurve(segments); |
1605 |
|
} |
1606 |
|
|
1607 |
|
float* Engine::InitCurve(const float* segments, int size) { |
1608 |
|
float* y = new float[size]; |
1609 |
|
for (int x = 0 ; x < size ; x++) { |
1610 |
|
if (x > segments[2]) segments += 2; |
1611 |
|
y[x] = segments[1] + (x - segments[0]) * |
1612 |
|
(segments[3] - segments[1]) / (segments[2] - segments[0]); |
1613 |
|
} |
1614 |
|
return y; |
1615 |
|
} |
1616 |
|
|
1617 |
}} // namespace LinuxSampler::gig |
}} // namespace LinuxSampler::gig |