@@ -870,24 +870,39 @@ CarlaEngine* CarlaEngine::newDriverByName(const char* const driverName) | |||
if (std::strcmp(driverName, "JACK") == 0) | |||
return newJack(); | |||
#ifndef BUILD_BRIDGE | |||
// common | |||
if (std::strncmp(driverName, "JACK ", 5) == 0) | |||
return newRtAudio(AUDIO_API_JACK); | |||
// linux | |||
#ifdef HAVE_JUCE | |||
if (std::strcmp(driverName, "ALSA") == 0) | |||
return newJuce(AUDIO_API_ALSA); | |||
#else | |||
if (std::strcmp(driverName, "ALSA") == 0) | |||
return newRtAudio(AUDIO_API_ALSA); | |||
#endif | |||
if (std::strcmp(driverName, "OSS") == 0) | |||
return newRtAudio(AUDIO_API_OSS); | |||
if (std::strcmp(driverName, "PulseAudio") == 0) | |||
return newRtAudio(AUDIO_API_PULSE); | |||
// macos | |||
#ifdef HAVE_JUCE | |||
if (std::strcmp(driverName, "CoreAudio") == 0) | |||
return newJuce(AUDIO_API_CORE); | |||
#else | |||
if (std::strcmp(driverName, "CoreAudio") == 0) | |||
return newRtAudio(AUDIO_API_CORE); | |||
#endif | |||
// windows | |||
#ifdef HAVE_JUCE | |||
if (std::strcmp(driverName, "ASIO") == 0) | |||
return newJuce(AUDIO_API_ASIO); | |||
if (std::strcmp(driverName, "DirectSound") == 0) | |||
return newJuce(AUDIO_API_DS); | |||
#else | |||
if (std::strcmp(driverName, "ASIO") == 0) | |||
return newRtAudio(AUDIO_API_ASIO); | |||
if (std::strcmp(driverName, "DirectSound") == 0) | |||
@@ -82,7 +82,7 @@ public: | |||
bool init(const char* const clientName) override | |||
{ | |||
CARLA_ASSERT(clientName != nullptr && clientName[0] != '\0'); | |||
CARLA_SAFE_ASSERT_RETURN(clientName != nullptr && clientName[0] != '\0', false); | |||
carla_debug("CarlaEngineJuce::init(\"%s\")", clientName); | |||
if (pData->options.processMode != ENGINE_PROCESS_MODE_CONTINUOUS_RACK && pData->options.processMode != ENGINE_PROCESS_MODE_PATCHBAY) | |||
@@ -110,7 +110,7 @@ public: | |||
if (deviceName.isEmpty()) | |||
{ | |||
setLastError("something"); | |||
setLastError("Audio device has not been selected yet and a default one is not available"); | |||
return false; | |||
} | |||
@@ -118,12 +118,18 @@ public: | |||
if (fDevice == nullptr) | |||
{ | |||
setLastError("something 2"); | |||
setLastError("Failed to create device"); | |||
return false; | |||
} | |||
StringArray inputNames(fDevice->getInputChannelNames()); | |||
StringArray outputNames(fDevice->getOutputChannelNames()); | |||
BigInteger inputChannels; | |||
inputChannels.setRange(0, inputNames.size(), true); | |||
BigInteger outputChannels; | |||
outputChannels.setRange(0, outputNames.size(), true); | |||
String error = fDevice->open(inputChannels, outputChannels, pData->options.audioSampleRate, static_cast<int>(pData->options.audioBufferSize)); | |||
@@ -134,18 +140,18 @@ public: | |||
return false; | |||
} | |||
fDevice->start(this); | |||
//getActiveOutputChannels(); | |||
//getActiveInputChannels(); | |||
pData->bufferSize = fDevice->getCurrentBufferSizeSamples(); | |||
pData->sampleRate = fDevice->getCurrentSampleRate(); | |||
//pData->bufAudio.inCount = iParams.nChannels; | |||
//pData->bufAudio.outCount = oParams.nChannels; | |||
pData->bufAudio.inCount = inputChannels.countNumberOfSetBits(); | |||
pData->bufAudio.outCount = outputChannels.countNumberOfSetBits(); | |||
CARLA_ASSERT(pData->bufAudio.outCount > 0); | |||
pData->bufAudio.create(pData->bufferSize); | |||
fDevice->start(this); | |||
CarlaEngine::init(clientName); | |||
patchbayRefresh(); | |||
@@ -212,6 +218,7 @@ public: | |||
} | |||
char strBuf[STR_MAX+1]; | |||
strBuf[STR_MAX] = '\0'; | |||
EngineRackBuffers* const rack(pData->bufAudio.rack); | |||
@@ -227,39 +234,59 @@ public: | |||
callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_CARLA, RACK_PATCHBAY_PORT_MIDI_OUT, PATCHBAY_PORT_TYPE_MIDI, 0.0f, "midi-out"); | |||
} | |||
const String& deviceName(fDevice->getName()); | |||
// Audio In | |||
{ | |||
/*if (fDeviceName.isNotEmpty()) | |||
std::snprintf(strBuf, STR_MAX, "Capture (%s)", (const char*)fDeviceName); | |||
else*/ | |||
if (deviceName.isNotEmpty()) | |||
std::snprintf(strBuf, STR_MAX, "Capture (%s)", deviceName.toRawUTF8()); | |||
else | |||
std::strncpy(strBuf, "Capture", STR_MAX); | |||
callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_PATCHBAY_GROUP_AUDIO_IN, 0, 0, 0.0f, strBuf); | |||
/*for (unsigned int i=0; i < fAudioCountIn; ++i) | |||
StringArray inputNames(fDevice->getInputChannelNames()); | |||
CARLA_ASSERT(inputNames.size() == static_cast<int>(pData->bufAudio.inCount)); | |||
for (uint i=0; i < pData->bufAudio.inCount; ++i) | |||
{ | |||
std::snprintf(strBuf, STR_MAX, "capture_%i", i+1); | |||
String inputName(inputNames[i]); | |||
if (inputName.trim().isNotEmpty()) | |||
std::snprintf(strBuf, STR_MAX, "%s", inputName.toRawUTF8()); | |||
else | |||
std::snprintf(strBuf, STR_MAX, "capture_%i", i+1); | |||
callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_AUDIO_IN, RACK_PATCHBAY_GROUP_AUDIO_IN*1000 + i, PATCHBAY_PORT_TYPE_AUDIO, 0.0f, strBuf); | |||
}*/ | |||
} | |||
} | |||
// Audio Out | |||
{ | |||
/*if (fDeviceName.isNotEmpty()) | |||
std::snprintf(strBuf, STR_MAX, "Playback (%s)", (const char*)fDeviceName); | |||
else*/ | |||
if (deviceName.isNotEmpty()) | |||
std::snprintf(strBuf, STR_MAX, "Playback (%s)", deviceName.toRawUTF8()); | |||
else | |||
std::strncpy(strBuf, "Playback", STR_MAX); | |||
callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_PATCHBAY_GROUP_AUDIO_OUT, 0, 0, 0.0f, strBuf); | |||
/*for (unsigned int i=0; i < fAudioCountOut; ++i) | |||
StringArray outputNames(fDevice->getOutputChannelNames()); | |||
CARLA_ASSERT(outputNames.size() == static_cast<int>(pData->bufAudio.outCount)); | |||
for (uint i=0; i < pData->bufAudio.outCount; ++i) | |||
{ | |||
std::snprintf(strBuf, STR_MAX, "playback_%i", i+1); | |||
String outputName(outputNames[i]); | |||
if (outputName.trim().isNotEmpty()) | |||
std::snprintf(strBuf, STR_MAX, "%s", outputName.toRawUTF8()); | |||
else | |||
std::snprintf(strBuf, STR_MAX, "playback_%i", i+1); | |||
callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_AUDIO_OUT, RACK_PATCHBAY_GROUP_AUDIO_OUT*1000 + i, PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, strBuf); | |||
}*/ | |||
} | |||
} | |||
#if 0 // midi-out not implemented yet | |||
#if 0 // midi implemented yet | |||
// MIDI In | |||
{ | |||
callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_PATCHBAY_GROUP_MIDI_IN, 0, 0, 0.0f, "Readable MIDI ports"); | |||
@@ -401,8 +428,8 @@ protected: | |||
void audioDeviceIOCallback(const float** inputChannelData, int numInputChannels, float** outputChannelData, int numOutputChannels, int numSamples) override | |||
{ | |||
// assert juce buffers | |||
CARLA_SAFE_ASSERT_RETURN(numInputChannels == pData->bufAudio.inCount,); | |||
CARLA_SAFE_ASSERT_RETURN(numOutputChannels == pData->bufAudio.outCount,); | |||
CARLA_SAFE_ASSERT_RETURN(numInputChannels == static_cast<int>(pData->bufAudio.inCount),); | |||
CARLA_SAFE_ASSERT_RETURN(numOutputChannels == static_cast<int>(pData->bufAudio.outCount),); | |||
CARLA_SAFE_ASSERT_RETURN(outputChannelData != nullptr,); | |||
CARLA_SAFE_ASSERT_RETURN(numSamples == static_cast<int>(pData->bufferSize),); | |||
@@ -596,7 +623,10 @@ const EngineDriverDeviceInfo* CarlaEngine::getJuceDeviceInfo(const unsigned int | |||
initJuceDevices(); | |||
if (static_cast<int>(index) >= gJuceDeviceTypes.size()) | |||
{ | |||
carla_stderr("here 001"); | |||
return nullptr; | |||
} | |||
AudioIODeviceType* const deviceType(gJuceDeviceTypes[index]); | |||
@@ -37,7 +37,64 @@ static std::vector<RtAudio::Api> gRtAudioApis; | |||
static void initRtApis() | |||
{ | |||
if (gRtAudioApis.size() == 0) | |||
{ | |||
RtAudio::getCompiledApi(gRtAudioApis); | |||
#ifdef HAVE_JUCE | |||
// prefer juce to handle some APIs | |||
std::vector<RtAudio::Api>::iterator it = std::find(gRtAudioApis.begin(), gRtAudioApis.end(), RtAudio::LINUX_ALSA); | |||
if (it != gRtAudioApis.end()) gRtAudioApis.erase(it); | |||
it = std::find(gRtAudioApis.begin(), gRtAudioApis.end(), RtAudio::MACOSX_CORE); | |||
if (it != gRtAudioApis.end()) gRtAudioApis.erase(it); | |||
it = std::find(gRtAudioApis.begin(), gRtAudioApis.end(), RtAudio::WINDOWS_ASIO); | |||
if (it != gRtAudioApis.end()) gRtAudioApis.erase(it); | |||
it = std::find(gRtAudioApis.begin(), gRtAudioApis.end(), RtAudio::WINDOWS_DS); | |||
if (it != gRtAudioApis.end()) gRtAudioApis.erase(it); | |||
#endif | |||
// in case rtaudio has no apis, add dummy one so that size() != 0 | |||
if (gRtAudioApis.size() == 0) | |||
gRtAudioApis.push_back(RtAudio::RTAUDIO_DUMMY); | |||
} | |||
} | |||
const char* getRtAudioApiName(const RtAudio::Api api) | |||
{ | |||
switch (api) | |||
{ | |||
case RtAudio::UNSPECIFIED: | |||
return "Unspecified"; | |||
case RtAudio::LINUX_ALSA: | |||
return "ALSA"; | |||
case RtAudio::LINUX_PULSE: | |||
return "PulseAudio"; | |||
case RtAudio::LINUX_OSS: | |||
return "OSS"; | |||
case RtAudio::UNIX_JACK: | |||
#if defined(CARLA_OS_WIN) | |||
return "JACK with WinMM"; | |||
#elif defined(CARLA_OS_MAC) | |||
return "JACK with CoreMidi"; | |||
#elif defined(CARLA_OS_LINUX) | |||
return "JACK with ALSA-MIDI"; | |||
#else | |||
return "JACK (RtAudio)"; | |||
#endif | |||
case RtAudio::MACOSX_CORE: | |||
return "CoreAudio"; | |||
case RtAudio::WINDOWS_ASIO: | |||
return "ASIO"; | |||
case RtAudio::WINDOWS_DS: | |||
return "DirectSound"; | |||
case RtAudio::RTAUDIO_DUMMY: | |||
return "Dummy"; | |||
} | |||
carla_stderr("CarlaBackend::getRtAudioApiName(%i) - invalid API", api); | |||
return nullptr; | |||
} | |||
RtMidi::Api getMatchedAudioMidiAPi(const RtAudio::Api rtApi) | |||
@@ -88,7 +145,7 @@ public: | |||
fAudio(api), | |||
fAudioBufIn(nullptr), | |||
fAudioBufOut(nullptr), | |||
fAudioIsInterleaved(false), | |||
fIsAudioInterleaved(false), | |||
fLastEventTime(0), | |||
fDummyMidiIn(getMatchedAudioMidiAPi(api), "Carla"), | |||
fDummyMidiOut(getMatchedAudioMidiAPi(api), "Carla") | |||
@@ -121,9 +178,9 @@ public: | |||
bool init(const char* const clientName) override | |||
{ | |||
CARLA_ASSERT(fAudioBufIn == nullptr); | |||
CARLA_ASSERT(fAudioBufOut == nullptr); | |||
CARLA_ASSERT(clientName != nullptr && clientName[0] != '\0'); | |||
CARLA_SAFE_ASSERT_RETURN(fAudioBufIn == nullptr, false); | |||
CARLA_SAFE_ASSERT_RETURN(fAudioBufOut == nullptr, false); | |||
CARLA_SAFE_ASSERT_RETURN(clientName != nullptr && clientName[0] != '\0', false); | |||
carla_debug("CarlaEngineRtAudio::init(\"%s\")", clientName); | |||
if (pData->options.processMode != ENGINE_PROCESS_MODE_CONTINUOUS_RACK && pData->options.processMode != ENGINE_PROCESS_MODE_PATCHBAY) | |||
@@ -168,8 +225,8 @@ public: | |||
{ | |||
iParams.deviceId = fAudio.getDefaultInputDevice(); | |||
oParams.deviceId = fAudio.getDefaultOutputDevice(); | |||
iParams.nChannels = 2; | |||
oParams.nChannels = 2; | |||
iParams.nChannels = fAudio.getDeviceInfo(iParams.deviceId).inputChannels; | |||
oParams.nChannels = fAudio.getDeviceInfo(oParams.deviceId).outputChannels; | |||
} | |||
RtAudio::StreamOptions rtOptions; | |||
@@ -180,35 +237,27 @@ public: | |||
if (fAudio.getCurrentApi() != RtAudio::LINUX_PULSE) | |||
{ | |||
rtOptions.flags |= RTAUDIO_NONINTERLEAVED; | |||
fAudioIsInterleaved = false; | |||
fIsAudioInterleaved = false; | |||
if (fAudio.getCurrentApi() == RtAudio::LINUX_ALSA && ! deviceSet) | |||
rtOptions.flags |= RTAUDIO_ALSA_USE_DEFAULT; | |||
} | |||
else | |||
fAudioIsInterleaved = true; | |||
fIsAudioInterleaved = true; | |||
fLastEventTime = 0; | |||
unsigned int bufferFrames = pData->options.audioBufferSize; | |||
try { | |||
fAudio.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, pData->options.audioSampleRate, &bufferFrames, carla_rtaudio_process_callback, this, &rtOptions); | |||
} | |||
catch (RtError& e) | |||
catch (const RtError& e) | |||
{ | |||
setLastError(e.what()); | |||
return false; | |||
} | |||
try { | |||
fAudio.startStream(); | |||
} | |||
catch (RtError& e) | |||
{ | |||
setLastError(e.what()); | |||
fAudio.closeStream(); | |||
return false; | |||
} | |||
pData->bufferSize = bufferFrames; | |||
pData->sampleRate = fAudio.getStreamSampleRate(); | |||
@@ -219,7 +268,7 @@ public: | |||
if (pData->bufAudio.inCount > 0) | |||
{ | |||
fAudioBufIn = new float*[pData->bufAudio.inCount]; | |||
fAudioBufIn = new float*[pData->bufAudio.inCount]; | |||
for (uint i=0; i < pData->bufAudio.inCount; ++i) | |||
fAudioBufIn[i] = new float[pData->bufferSize]; | |||
@@ -233,10 +282,18 @@ public: | |||
fAudioBufOut[i] = new float[pData->bufferSize]; | |||
} | |||
fLastEventTime = 0; | |||
pData->bufAudio.create(pData->bufferSize); | |||
try { | |||
fAudio.startStream(); | |||
} | |||
catch (const RtError& e) | |||
{ | |||
setLastError(e.what()); | |||
fAudio.closeStream(); | |||
return false; | |||
} | |||
CarlaEngine::init(clientName); | |||
patchbayRefresh(); | |||
@@ -252,40 +309,28 @@ public: | |||
bool hasError = !CarlaEngine::close(); | |||
if (fAudio.isStreamRunning()) | |||
{ | |||
try { | |||
fAudio.stopStream(); | |||
} | |||
catch (RtError& e) | |||
{ | |||
if (! hasError) | |||
{ | |||
setLastError(e.what()); | |||
hasError = true; | |||
} | |||
} | |||
} | |||
if (fAudio.isStreamOpen()) | |||
{ | |||
try { | |||
fAudio.closeStream(); | |||
} | |||
catch (RtError& e) | |||
if (fAudio.isStreamRunning()) | |||
{ | |||
if (! hasError) | |||
try { | |||
fAudio.stopStream(); | |||
} | |||
catch (const RtError& e) | |||
{ | |||
setLastError(e.what()); | |||
hasError = true; | |||
if (! hasError) | |||
{ | |||
setLastError(e.what()); | |||
hasError = true; | |||
} | |||
} | |||
} | |||
fAudio.closeStream(); | |||
} | |||
if (fAudioBufIn != nullptr) | |||
{ | |||
CARLA_ASSERT(pData->bufAudio.inCount > 0); | |||
for (uint i=0; i < pData->bufAudio.inCount; ++i) | |||
delete[] fAudioBufIn[i]; | |||
@@ -295,8 +340,6 @@ public: | |||
if (fAudioBufOut != nullptr) | |||
{ | |||
CARLA_ASSERT(pData->bufAudio.outCount > 0); | |||
for (uint i=0; i < pData->bufAudio.outCount; ++i) | |||
delete[] fAudioBufOut[i]; | |||
@@ -351,39 +394,7 @@ public: | |||
const char* getCurrentDriverName() const noexcept override | |||
{ | |||
const RtAudio::Api api(fAudio.getCurrentApi()); | |||
switch (api) | |||
{ | |||
case RtAudio::UNSPECIFIED: | |||
return "Unspecified"; | |||
case RtAudio::LINUX_ALSA: | |||
return "ALSA"; | |||
case RtAudio::LINUX_PULSE: | |||
return "PulseAudio"; | |||
case RtAudio::LINUX_OSS: | |||
return "OSS"; | |||
case RtAudio::UNIX_JACK: | |||
#if defined(CARLA_OS_WIN) | |||
return "JACK with WinMM"; | |||
#elif defined(CARLA_OS_MAC) | |||
return "JACK with CoreMidi"; | |||
#elif defined(CARLA_OS_LINUX) | |||
return "JACK with ALSA-MIDI"; | |||
#else | |||
return "JACK (RtAudio)"; | |||
#endif | |||
case RtAudio::MACOSX_CORE: | |||
return "CoreAudio"; | |||
case RtAudio::WINDOWS_ASIO: | |||
return "ASIO"; | |||
case RtAudio::WINDOWS_DS: | |||
return "DirectSound"; | |||
case RtAudio::RTAUDIO_DUMMY: | |||
return "Dummy"; | |||
} | |||
return nullptr; | |||
return CarlaBackend::getRtAudioApiName(fAudio.getCurrentApi()); | |||
} | |||
// ------------------------------------------------------------------- | |||
@@ -405,6 +416,7 @@ public: | |||
} | |||
char strBuf[STR_MAX+1]; | |||
strBuf[STR_MAX] = '\0'; | |||
EngineRackBuffers* const rack(pData->bufAudio.rack); | |||
@@ -429,7 +441,7 @@ public: | |||
callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_PATCHBAY_GROUP_AUDIO_IN, 0, 0, 0.0f, strBuf); | |||
for (unsigned int i=0; i < pData->bufAudio.inCount; ++i) | |||
for (uint i=0; i < pData->bufAudio.inCount; ++i) | |||
{ | |||
std::snprintf(strBuf, STR_MAX, "capture_%i", i+1); | |||
callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_AUDIO_IN, RACK_PATCHBAY_GROUP_AUDIO_IN*1000 + i, PATCHBAY_PORT_TYPE_AUDIO, 0.0f, strBuf); | |||
@@ -445,7 +457,7 @@ public: | |||
callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_PATCHBAY_GROUP_AUDIO_OUT, 0, 0, 0.0f, strBuf); | |||
for (unsigned int i=0; i < pData->bufAudio.outCount; ++i) | |||
for (uint i=0; i < pData->bufAudio.outCount; ++i) | |||
{ | |||
std::snprintf(strBuf, STR_MAX, "playback_%i", i+1); | |||
callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_AUDIO_OUT, RACK_PATCHBAY_GROUP_AUDIO_OUT*1000 + i, PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, strBuf); | |||
@@ -603,7 +615,7 @@ protected: | |||
return runPendingRtEvents(); | |||
// initialize rtaudio input | |||
if (fAudioIsInterleaved) | |||
if (fIsAudioInterleaved) | |||
{ | |||
for (unsigned int i=0, j=0, count=nframes*pData->bufAudio.inCount; i < count; ++i) | |||
{ | |||
@@ -666,7 +678,7 @@ protected: | |||
} | |||
// output audio | |||
if (fAudioIsInterleaved) | |||
if (fIsAudioInterleaved) | |||
{ | |||
for (unsigned int i=0, j=0; i < nframes*pData->bufAudio.outCount; ++i) | |||
{ | |||
@@ -716,10 +728,10 @@ protected: | |||
RtMidiEvent midiEvent; | |||
midiEvent.time = pData->timeInfo.frame + uint64_t(timeStamp * (double)pData->bufferSize); | |||
if (midiEvent.time < fLastTime) | |||
midiEvent.time = fLastTime; | |||
if (midiEvent.time < fLastEventTime) | |||
midiEvent.time = fLastEventTime; | |||
else | |||
fLastTime = midiEvent.time; | |||
fLastEventTime = midiEvent.time; | |||
midiEvent.size = static_cast<uint8_t>(messageSize); | |||
@@ -881,7 +893,7 @@ private: | |||
float** fAudioBufOut; | |||
// useful info | |||
bool fAudioIsInterleaved; | |||
bool fIsAudioInterleaved; | |||
uint64_t fLastEventTime; | |||
// current device name | |||
@@ -1019,39 +1031,7 @@ const char* CarlaEngine::getRtAudioApiName(const unsigned int index) | |||
if (index >= gRtAudioApis.size()) | |||
return nullptr; | |||
const RtAudio::Api& api(gRtAudioApis[index]); | |||
switch (api) | |||
{ | |||
case RtAudio::UNSPECIFIED: | |||
return "Unspecified (RtAudio)"; | |||
case RtAudio::LINUX_ALSA: | |||
return "ALSA (RtAudio)"; | |||
case RtAudio::LINUX_PULSE: | |||
return "PulseAudio (RtAudio)"; | |||
case RtAudio::LINUX_OSS: | |||
return "OSS (RtAudio)"; | |||
case RtAudio::UNIX_JACK: | |||
// #if defined(CARLA_OS_WIN) | |||
// return "JACK with WinMM"; | |||
// #elif defined(CARLA_OS_MAC) | |||
// return "JACK with CoreMidi"; | |||
// #elif defined(CARLA_OS_LINUX) | |||
// return "JACK with ALSA-MIDI"; | |||
// #else | |||
return "JACK (RtAudio)"; | |||
// #endif | |||
case RtAudio::MACOSX_CORE: | |||
return "CoreAudio (RtAudio)"; | |||
case RtAudio::WINDOWS_ASIO: | |||
return "ASIO (RtAudio)"; | |||
case RtAudio::WINDOWS_DS: | |||
return "DirectSound (RtAudio)"; | |||
case RtAudio::RTAUDIO_DUMMY: | |||
return "Dummy (RtAudio)"; | |||
} | |||
return nullptr; | |||
return CarlaBackend::getRtAudioApiName(gRtAudioApis[index]); | |||
} | |||
const char* const* CarlaEngine::getRtAudioApiDeviceNames(const unsigned int index) | |||
@@ -1104,8 +1084,13 @@ const EngineDriverDeviceInfo* CarlaEngine::getRtAudioDeviceInfo(const unsigned i | |||
{ | |||
initRtApis(); | |||
carla_stderr("here 000"); | |||
if (index >= gRtAudioApis.size()) | |||
{ | |||
carla_stderr("here 001"); | |||
return nullptr; | |||
} | |||
const RtAudio::Api& api(gRtAudioApis[index]); | |||
@@ -1114,7 +1099,10 @@ const EngineDriverDeviceInfo* CarlaEngine::getRtAudioDeviceInfo(const unsigned i | |||
const unsigned int devCount(rtAudio.getDeviceCount()); | |||
if (devCount == 0) | |||
{ | |||
carla_stderr("here 002"); | |||
return nullptr; | |||
} | |||
unsigned int i; | |||
RtAudio::DeviceInfo rtAudioDevInfo; | |||
@@ -1128,7 +1116,10 @@ const EngineDriverDeviceInfo* CarlaEngine::getRtAudioDeviceInfo(const unsigned i | |||
} | |||
if (i == devCount) | |||
{ | |||
carla_stderr("here 003"); | |||
return nullptr; | |||
} | |||
static EngineDriverDeviceInfo devInfo = { 0x0, nullptr, nullptr }; | |||
static uint32_t dummyBufferSizes[11] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 0 }; | |||
@@ -1160,6 +1151,8 @@ const EngineDriverDeviceInfo* CarlaEngine::getRtAudioDeviceInfo(const unsigned i | |||
devInfo.sampleRates = dummySampleRates; | |||
} | |||
carla_stderr("here 004"); | |||
return &devInfo; | |||
} | |||
@@ -99,14 +99,14 @@ def numPtrToList(numPtr): | |||
return [] | |||
i = 0 | |||
num = numPtr[0].value | |||
num = numPtr[0] #.value | |||
numList = [] | |||
while num not in (0, 0.0): | |||
numList.append(num) | |||
i += 1 | |||
num = numPtr[i].value | |||
num = numPtr[i] #.value | |||
return numList | |||
@@ -1216,7 +1216,7 @@ class Host(object): | |||
# @param index Driver index | |||
# @param name Device name | |||
def get_engine_driver_device_info(self, index, name): | |||
return structToDict(self.lib.carla_get_engine_driver_device_info(index, name).contents) | |||
return structToDict(self.lib.carla_get_engine_driver_device_info(index, name.encode("utf-8")).contents) | |||
# Get how many internal plugins are available. | |||
def get_internal_plugin_count(self): | |||
@@ -292,8 +292,7 @@ class HostWindow(QMainWindow): | |||
# ------------------------------------------------------------- | |||
# Final setup | |||
if Carla.isPlugin: | |||
QTimer.singleShot(0, self.slot_engineStart) | |||
QTimer.singleShot(0, self.slot_engineStart) | |||
# ----------------------------------------------------------------- | |||
# Called by containers | |||
@@ -326,10 +325,6 @@ class HostWindow(QMainWindow): | |||
if not self.fProjectFilename: | |||
return qCritical("ERROR: loading project without filename set") | |||
# TESTING | |||
if not Carla.host.is_engine_running(): | |||
self.slot_engineStart() | |||
self.fIsProjectLoading = True | |||
Carla.host.load_project(self.fProjectFilename) | |||
self.fIsProjectLoading = False | |||
@@ -358,46 +353,67 @@ class HostWindow(QMainWindow): | |||
if settings is None: settings = QSettings() | |||
forceStereo = settings.value("Engine/ForceStereo", CARLA_DEFAULT_FORCE_STEREO, type=bool) | |||
preferPluginBridges = settings.value("Engine/PreferPluginBridges", CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES, type=bool) | |||
preferUiBridges = settings.value("Engine/PreferUiBridges", CARLA_DEFAULT_PREFER_UI_BRIDGES, type=bool) | |||
uisAlwaysOnTop = settings.value("Engine/OscUiTimeout", CARLA_DEFAULT_UIS_ALWAYS_ON_TOP, type=bool) | |||
uiBridgesTimeout = settings.value("Engine/OscUiTimeout", CARLA_DEFAULT_UI_BRIDGES_TIMEOUT, type=int) | |||
# ------------------------------------------------------------- | |||
# read settings | |||
Carla.maxParameters = settings.value("Engine/MaxParameters", CARLA_DEFAULT_MAX_PARAMETERS, type=int) | |||
# bool values | |||
forceStereo = settings.value(CARLA_KEY_ENGINE_FORCE_STEREO, CARLA_DEFAULT_FORCE_STEREO, type=bool) | |||
preferPluginBridges = settings.value(CARLA_KEY_ENGINE_PREFER_PLUGIN_BRIDGES, CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES, type=bool) | |||
preferUiBridges = settings.value(CARLA_KEY_ENGINE_PREFER_UI_BRIDGES, CARLA_DEFAULT_PREFER_UI_BRIDGES, type=bool) | |||
uisAlwaysOnTop = settings.value(CARLA_KEY_ENGINE_UIS_ALWAYS_ON_TOP, CARLA_DEFAULT_UIS_ALWAYS_ON_TOP, type=bool) | |||
audioDriver = settings.value("Engine/AudioDriver", CARLA_DEFAULT_AUDIO_DRIVER, type=str) | |||
# int values | |||
maxParameters = settings.value(CARLA_KEY_ENGINE_MAX_PARAMETERS, CARLA_DEFAULT_MAX_PARAMETERS, type=int) | |||
uiBridgesTimeout = settings.value(CARLA_KEY_ENGINE_UI_BRIDGES_TIMEOUT, CARLA_DEFAULT_UI_BRIDGES_TIMEOUT, type=int) | |||
if audioDriver == "JACK": | |||
transportMode = ENGINE_TRANSPORT_MODE_JACK | |||
else: | |||
transportMode = ENGINE_TRANSPORT_MODE_INTERNAL | |||
# enums | |||
processMode = settings.value(CARLA_KEY_ENGINE_PROCESS_MODE, CARLA_DEFAULT_PROCESS_MODE, type=int) | |||
transportMode = settings.value(CARLA_KEY_ENGINE_TRANSPORT_MODE, CARLA_DEFAULT_TRANSPORT_MODE, type=int) | |||
# driver name | |||
audioDriver = settings.value(CARLA_KEY_ENGINE_AUDIO_DRIVER, CARLA_DEFAULT_AUDIO_DRIVER, type=str) | |||
audioNumPeriods = settings.value("Engine/AudioBufferSize", CARLA_DEFAULT_AUDIO_NUM_PERIODS, type=int) | |||
audioBufferSize = settings.value("Engine/AudioBufferSize", CARLA_DEFAULT_AUDIO_BUFFER_SIZE, type=int) | |||
audioSampleRate = settings.value("Engine/AudioSampleRate", CARLA_DEFAULT_AUDIO_SAMPLE_RATE, type=int) | |||
audioDevice = settings.value("Engine/AudioDevice", "", type=str) | |||
# driver options | |||
audioDevice = settings.value("%s%s/Device" % (CARLA_KEY_ENGINE_DRIVER_PREFIX, audioDriver), "", type=str) | |||
audioNumPeriods = settings.value("%s%s/NumPeriods" % (CARLA_KEY_ENGINE_DRIVER_PREFIX, audioDriver), CARLA_DEFAULT_AUDIO_NUM_PERIODS, type=int) | |||
audioBufferSize = settings.value("%s%s/BufferSize" % (CARLA_KEY_ENGINE_DRIVER_PREFIX, audioDriver), CARLA_DEFAULT_AUDIO_BUFFER_SIZE, type=int) | |||
audioSampleRate = settings.value("%s%s/SampleRate" % (CARLA_KEY_ENGINE_DRIVER_PREFIX, audioDriver), CARLA_DEFAULT_AUDIO_SAMPLE_RATE, type=int) | |||
Carla.host.set_engine_option(ENGINE_OPTION_AUDIO_NUM_PERIODS, audioNumPeriods, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_AUDIO_BUFFER_SIZE, audioBufferSize, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_AUDIO_SAMPLE_RATE, audioSampleRate, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_AUDIO_DEVICE, 0, audioDevice) | |||
# ------------------------------------------------------------- | |||
# fix things if needed | |||
if Carla.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK: | |||
if processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK: | |||
forceStereo = True | |||
elif Carla.processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS and LADISH_APP_NAME: | |||
elif processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS and LADISH_APP_NAME: | |||
print("LADISH detected but using multiple clients (not allowed), forcing single client now") | |||
Carla.processMode = ENGINE_PROCESS_MODE_SINGLE_CLIENT | |||
processMode = ENGINE_PROCESS_MODE_SINGLE_CLIENT | |||
if audioDriver != "JACK" and transportMode == ENGINE_TRANSPORT_MODE_JACK: | |||
transportMode = ENGINE_TRANSPORT_MODE_INTERNAL | |||
# ------------------------------------------------------------- | |||
# apply to engine | |||
Carla.host.set_engine_option(ENGINE_OPTION_FORCE_STEREO, forceStereo, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_PREFER_PLUGIN_BRIDGES, preferPluginBridges, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_PREFER_UI_BRIDGES, preferUiBridges, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_UIS_ALWAYS_ON_TOP, uisAlwaysOnTop, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_MAX_PARAMETERS, maxParameters, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_UI_BRIDGES_TIMEOUT, uiBridgesTimeout, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_PROCESS_MODE, Carla.processMode, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_MAX_PARAMETERS, Carla.maxParameters, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_PROCESS_MODE, processMode, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE, transportMode, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_AUDIO_NUM_PERIODS, audioNumPeriods, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_AUDIO_BUFFER_SIZE, audioBufferSize, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_AUDIO_SAMPLE_RATE, audioSampleRate, "") | |||
Carla.host.set_engine_option(ENGINE_OPTION_AUDIO_DEVICE, 0, audioDevice) | |||
# save this for later | |||
Carla.maxParameters = maxParameters | |||
# return selected driver name | |||
return audioDriver | |||
def startEngine(self): | |||
@@ -112,18 +112,15 @@ class DriverSettingsW(QDialog): | |||
self.fDriverName = driverName | |||
self.fDeviceNames = Carla.host.get_engine_driver_device_names(driverIndex) if Carla.host is not None else [] | |||
self.fBufferSizes = BUFFER_SIZE_LIST | |||
self.fSampleRates = SAMPLE_RATE_LIST | |||
# ------------------------------------------------------------- | |||
# Set-up GUI | |||
for name in self.fDeviceNames: | |||
self.ui.cb_device.addItem(name) | |||
for bsize in BUFFER_SIZE_LIST: | |||
self.ui.cb_buffersize.addItem(str(bsize)) | |||
for srate in SAMPLE_RATE_LIST: | |||
self.ui.cb_samplerate.addItem(str(srate)) | |||
# ------------------------------------------------------------- | |||
# Load settings | |||
@@ -133,6 +130,7 @@ class DriverSettingsW(QDialog): | |||
# Set-up connections | |||
self.accepted.connect(self.slot_saveSettings) | |||
self.ui.cb_device.currentIndexChanged.connect(self.slot_updateDeviceInfo) | |||
# ------------------------------------------------------------- | |||
@@ -149,20 +147,27 @@ class DriverSettingsW(QDialog): | |||
else: | |||
self.ui.cb_device.setCurrentIndex(-1) | |||
# fill combo-boxes first | |||
self.slot_updateDeviceInfo() | |||
if 2 < audioNumPeriods < 3: | |||
self.ui.sb_numperiods.setValue(audioNumPeriods) | |||
else: | |||
self.ui.sb_numperiods.setValue(CARLA_DEFAULT_AUDIO_NUM_PERIODS) | |||
if audioBufferSize and audioBufferSize in BUFFER_SIZE_LIST: | |||
self.ui.cb_buffersize.setCurrentIndex(BUFFER_SIZE_LIST.index(audioBufferSize)) | |||
else: | |||
if audioBufferSize and audioBufferSize in self.fBufferSizes: | |||
self.ui.cb_buffersize.setCurrentIndex(self.fBufferSizes.index(audioBufferSize)) | |||
elif self.fBufferSizes == BUFFER_SIZE_LIST: | |||
self.ui.cb_buffersize.setCurrentIndex(BUFFER_SIZE_LIST.index(CARLA_DEFAULT_AUDIO_BUFFER_SIZE)) | |||
if audioSampleRate and audioSampleRate in SAMPLE_RATE_LIST: | |||
self.ui.cb_samplerate.setCurrentIndex(SAMPLE_RATE_LIST.index(audioSampleRate)) | |||
else: | |||
self.ui.cb_buffersize.setCurrentIndex(len(self.fBufferSizes)/2) | |||
if audioSampleRate and audioSampleRate in self.fSampleRates: | |||
self.ui.cb_samplerate.setCurrentIndex(self.fSampleRates.index(audioSampleRate)) | |||
elif self.fSampleRates == SAMPLE_RATE_LIST: | |||
self.ui.cb_samplerate.setCurrentIndex(SAMPLE_RATE_LIST.index(CARLA_DEFAULT_AUDIO_SAMPLE_RATE)) | |||
else: | |||
self.ui.cb_samplerate.setCurrentIndex(len(self.fSampleRates)/2) | |||
@pyqtSlot() | |||
def slot_saveSettings(self): | |||
@@ -173,6 +178,28 @@ class DriverSettingsW(QDialog): | |||
settings.setValue("%s%s/BufferSize" % (CARLA_KEY_ENGINE_DRIVER_PREFIX, self.fDriverName), self.ui.cb_buffersize.currentText()) | |||
settings.setValue("%s%s/SampleRate" % (CARLA_KEY_ENGINE_DRIVER_PREFIX, self.fDriverName), self.ui.cb_samplerate.currentText()) | |||
@pyqtSlot() | |||
def slot_updateDeviceInfo(self): | |||
deviceName = self.ui.cb_device.currentText() | |||
self.ui.cb_buffersize.clear() | |||
self.ui.cb_samplerate.clear() | |||
if deviceName and Carla.host is not None: | |||
driverDeviceInfo = Carla.host.get_engine_driver_device_info(self.fDriverIndex, deviceName) | |||
self.fBufferSizes = numPtrToList(driverDeviceInfo['bufferSizes']) | |||
self.fSampleRates = numPtrToList(driverDeviceInfo['sampleRates']) | |||
else: | |||
self.fBufferSizes = BUFFER_SIZE_LIST | |||
self.fSampleRates = SAMPLE_RATE_LIST | |||
for bsize in self.fBufferSizes: | |||
self.ui.cb_buffersize.addItem(str(bsize)) | |||
for srate in self.fSampleRates: | |||
self.ui.cb_samplerate.addItem(str(int(srate))) | |||
def done(self, r): | |||
QDialog.done(self, r) | |||
self.close() | |||
@@ -315,6 +315,7 @@ CARLA_KEY_CANVAS_HQ_ANTIALIASING = "Canvas/HQAntialiasing" # bool | |||
CARLA_KEY_ENGINE_DRIVER_PREFIX = "Engine/Driver-" | |||
CARLA_KEY_ENGINE_AUDIO_DRIVER = "Engine/AudioDriver" # str | |||
CARLA_KEY_ENGINE_PROCESS_MODE = "Engine/ProcessMode" # enum | |||
CARLA_KEY_ENGINE_TRANSPORT_MODE = "Engine/TransportMode" # enum | |||
CARLA_KEY_ENGINE_FORCE_STEREO = "Engine/ForceStereo" # bool | |||
CARLA_KEY_ENGINE_PREFER_PLUGIN_BRIDGES = "Engine/PreferPluginBridges" # bool | |||
CARLA_KEY_ENGINE_PREFER_UI_BRIDGES = "Engine/PreferUiBridges" # bool | |||