3 |
* LinuxSampler - modular, streaming capable sampler * |
* LinuxSampler - modular, streaming capable sampler * |
4 |
* * |
* * |
5 |
* Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck * |
* Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck * |
6 |
* Copyright (C) 2005-2008 Christian Schoenebeck * |
* Copyright (C) 2005-2009 Christian Schoenebeck * |
7 |
* * |
* * |
8 |
* This program is free software; you can redistribute it and/or modify * |
* This program is free software; you can redistribute it and/or modify * |
9 |
* it under the terms of the GNU General Public License as published by * |
* it under the terms of the GNU General Public License as published by * |
107 |
pSysexBuffer = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0); |
pSysexBuffer = new RingBuffer<uint8_t,false>(CONFIG_SYSEX_BUFFER_SIZE, 0); |
108 |
pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0); |
pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0); |
109 |
pEventPool = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT); |
pEventPool = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT); |
110 |
pVoicePool = new Pool<Voice>(CONFIG_MAX_VOICES); |
pVoicePool = new Pool<Voice>(GLOBAL_MAX_VOICES); |
111 |
pDimRegionPool[0] = new Pool< ::gig::DimensionRegion*>(CONFIG_MAX_VOICES); |
pDimRegionPool[0] = new Pool< ::gig::DimensionRegion*>(GLOBAL_MAX_VOICES); |
112 |
pDimRegionPool[1] = new Pool< ::gig::DimensionRegion*>(CONFIG_MAX_VOICES); |
pDimRegionPool[1] = new Pool< ::gig::DimensionRegion*>(GLOBAL_MAX_VOICES); |
113 |
pVoiceStealingQueue = new RTList<Event>(pEventPool); |
pVoiceStealingQueue = new RTList<Event>(pEventPool); |
114 |
pGlobalEvents = new RTList<Event>(pEventPool); |
pGlobalEvents = new RTList<Event>(pEventPool); |
115 |
|
iMaxDiskStreams = GLOBAL_MAX_STREAMS; |
116 |
|
FrameTime = 0; |
117 |
|
|
118 |
for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) { |
for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) { |
119 |
iterVoice->SetEngine(this); |
iterVoice->SetEngine(this); |
154 |
|
|
155 |
void Engine::Enable() { |
void Engine::Enable() { |
156 |
dmsg(3,("gig::Engine: enabling\n")); |
dmsg(3,("gig::Engine: enabling\n")); |
157 |
EngineDisabled.PushAndUnlock(false, 2); // set condition object 'EngineDisabled' to false (wait max. 2s) |
EngineDisabled.PushAndUnlock(false, 2, 0, true); // set condition object 'EngineDisabled' to false (wait max. 2s) |
158 |
dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe())); |
dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe())); |
159 |
} |
} |
160 |
|
|
213 |
if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream |
if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream |
214 |
iPendingStreamDeletions++; |
iPendingStreamDeletions++; |
215 |
} |
} |
216 |
|
// free the voice to the voice pool and update key info |
217 |
|
FreeVoice(pEngineChannel, itVoice); |
218 |
} |
} |
219 |
} |
} |
220 |
} |
} |
346 |
* @param pAudioOut - audio output device to connect to |
* @param pAudioOut - audio output device to connect to |
347 |
*/ |
*/ |
348 |
void Engine::Connect(AudioOutputDevice* pAudioOut) { |
void Engine::Connect(AudioOutputDevice* pAudioOut) { |
349 |
|
// caution: don't ignore if connecting to the same device here, |
350 |
|
// because otherwise SetMaxDiskStreams() implementation won't work anymore! |
351 |
|
|
352 |
pAudioOutputDevice = pAudioOut; |
pAudioOutputDevice = pAudioOut; |
353 |
|
|
354 |
ResetInternal(); |
ResetInternal(); |
387 |
delete this->pDiskThread; |
delete this->pDiskThread; |
388 |
dmsg(1,("OK\n")); |
dmsg(1,("OK\n")); |
389 |
} |
} |
390 |
this->pDiskThread = new DiskThread(((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo |
this->pDiskThread = |
391 |
&instruments); |
new DiskThread( |
392 |
|
iMaxDiskStreams, |
393 |
|
((pAudioOut->MaxSamplesPerCycle() << CONFIG_MAX_PITCH) << 1) + 6, //FIXME: assuming stereo |
394 |
|
&instruments |
395 |
|
); |
396 |
|
|
397 |
if (!pDiskThread) { |
if (!pDiskThread) { |
398 |
dmsg(0,("gig::Engine new diskthread = NULL\n")); |
dmsg(0,("gig::Engine new diskthread = NULL\n")); |
399 |
exit(EXIT_FAILURE); |
exit(EXIT_FAILURE); |
419 |
exit(EXIT_FAILURE); |
exit(EXIT_FAILURE); |
420 |
} |
} |
421 |
} |
} |
422 |
|
pVoicePool->clear(); |
423 |
} |
} |
424 |
|
|
425 |
/** |
/** |
446 |
if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream |
if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream |
447 |
iPendingStreamDeletions++; |
iPendingStreamDeletions++; |
448 |
} |
} |
449 |
|
//NOTE: maybe we should call FreeVoice() here, shouldn't cause a harm though I think, since the voices should be freed by RenderActiveVoices() in the render loop, they are probably just freed a bit later than they could/should be |
450 |
} |
} |
451 |
} |
} |
452 |
} |
} |
598 |
// update time of start and end of this audio fragment (as events' time stamps relate to this) |
// update time of start and end of this audio fragment (as events' time stamps relate to this) |
599 |
pEventGenerator->UpdateFragmentTime(Samples); |
pEventGenerator->UpdateFragmentTime(Samples); |
600 |
|
|
601 |
// We only allow a maximum of CONFIG_MAX_VOICES voices to be spawned |
// We only allow the given maximum number of voices to be spawned |
602 |
// in each audio fragment. All subsequent request for spawning new |
// in each audio fragment. All subsequent request for spawning new |
603 |
// voices in the same audio fragment will be ignored. |
// voices in the same audio fragment will be ignored. |
604 |
VoiceSpawnsLeft = CONFIG_MAX_VOICES; |
VoiceSpawnsLeft = MaxVoices(); |
605 |
|
|
606 |
// get all events from the engine's global input event queue which belong to the current fragment |
// get all events from the engine's global input event queue which belong to the current fragment |
607 |
// (these are usually just SysEx messages) |
// (these are usually just SysEx messages) |
1961 |
if (reader.read(&addr[0], 3) != 3) goto free_sysex_data; |
if (reader.read(&addr[0], 3) != 3) goto free_sysex_data; |
1962 |
if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters |
if (addr[0] == 0x40 && addr[1] == 0x00) { // System Parameters |
1963 |
dmsg(3,("\tSystem Parameter\n")); |
dmsg(3,("\tSystem Parameter\n")); |
1964 |
|
if (addr[2] == 0x7f) { // GS reset |
1965 |
|
for (int i = 0; i < engineChannels.size(); ++i) { |
1966 |
|
EngineChannel* pEngineChannel = engineChannels[i]; |
1967 |
|
if (pEngineChannel->GetMidiInputPort() == itSysexEvent->pMidiInputPort) { |
1968 |
|
KillAllVoices(pEngineChannel, itSysexEvent); |
1969 |
|
pEngineChannel->ResetControllers(); |
1970 |
|
} |
1971 |
|
} |
1972 |
|
} |
1973 |
} |
} |
1974 |
else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters |
else if (addr[0] == 0x40 && addr[1] == 0x01) { // Common Parameters |
1975 |
dmsg(3,("\tCommon Parameter\n")); |
dmsg(3,("\tCommon Parameter\n")); |
2134 |
return ActiveVoiceCountMax; |
return ActiveVoiceCountMax; |
2135 |
} |
} |
2136 |
|
|
2137 |
|
int Engine::MaxVoices() { |
2138 |
|
return pVoicePool->poolSize(); |
2139 |
|
} |
2140 |
|
|
2141 |
|
void Engine::SetMaxVoices(int iVoices) throw (Exception) { |
2142 |
|
if (iVoices < 1) |
2143 |
|
throw Exception("Maximum voices for an engine cannot be set lower than 1"); |
2144 |
|
|
2145 |
|
SuspendAll(); |
2146 |
|
|
2147 |
|
// NOTE: we need to clear pDimRegionsInUse before deleting pDimRegionPool, |
2148 |
|
// otherwise memory corruption will occur if there are active voices (see bug #118) |
2149 |
|
for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) { |
2150 |
|
engineChannels[iChannel]->ClearDimRegionsInUse(); |
2151 |
|
} |
2152 |
|
|
2153 |
|
if (pDimRegionPool[0]) delete pDimRegionPool[0]; |
2154 |
|
if (pDimRegionPool[1]) delete pDimRegionPool[1]; |
2155 |
|
|
2156 |
|
pDimRegionPool[0] = new Pool< ::gig::DimensionRegion*>(iVoices); |
2157 |
|
pDimRegionPool[1] = new Pool< ::gig::DimensionRegion*>(iVoices); |
2158 |
|
|
2159 |
|
for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) { |
2160 |
|
engineChannels[iChannel]->ResetDimRegionsInUse(); |
2161 |
|
} |
2162 |
|
|
2163 |
|
try { |
2164 |
|
pVoicePool->resizePool(iVoices); |
2165 |
|
} catch (...) { |
2166 |
|
throw Exception("FATAL: Could not resize voice pool!"); |
2167 |
|
} |
2168 |
|
|
2169 |
|
for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) { |
2170 |
|
iterVoice->SetEngine(this); |
2171 |
|
iterVoice->pDiskThread = this->pDiskThread; |
2172 |
|
} |
2173 |
|
pVoicePool->clear(); |
2174 |
|
|
2175 |
|
ResumeAll(); |
2176 |
|
} |
2177 |
|
|
2178 |
bool Engine::DiskStreamSupported() { |
bool Engine::DiskStreamSupported() { |
2179 |
return true; |
return true; |
2180 |
} |
} |
2187 |
return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; |
return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; |
2188 |
} |
} |
2189 |
|
|
2190 |
|
int Engine::MaxDiskStreams() { |
2191 |
|
return iMaxDiskStreams; |
2192 |
|
} |
2193 |
|
|
2194 |
|
void Engine::SetMaxDiskStreams(int iStreams) throw (Exception) { |
2195 |
|
if (iStreams < 0) |
2196 |
|
throw Exception("Maximum disk streams for an engine cannot be set lower than 0"); |
2197 |
|
|
2198 |
|
SuspendAll(); |
2199 |
|
|
2200 |
|
iMaxDiskStreams = iStreams; |
2201 |
|
|
2202 |
|
// reconnect to audio output device, because that will automatically |
2203 |
|
// recreate the disk thread with the required amount of streams |
2204 |
|
if (pAudioOutputDevice) Connect(pAudioOutputDevice); |
2205 |
|
|
2206 |
|
ResumeAll(); |
2207 |
|
} |
2208 |
|
|
2209 |
String Engine::DiskStreamBufferFillBytes() { |
String Engine::DiskStreamBufferFillBytes() { |
2210 |
return pDiskThread->GetBufferFillBytes(); |
return pDiskThread->GetBufferFillBytes(); |
2211 |
} |
} |
2223 |
} |
} |
2224 |
|
|
2225 |
String Engine::Version() { |
String Engine::Version() { |
2226 |
String s = "$Revision: 1.98 $"; |
String s = "$Revision: 1.104 $"; |
2227 |
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 |
2228 |
} |
} |
2229 |
|
|