diff --git a/source/backend/Makefile.mk b/source/backend/Makefile.mk index 58597782a..9b06125a4 100644 --- a/source/backend/Makefile.mk +++ b/source/backend/Makefile.mk @@ -8,8 +8,9 @@ include ../../Makefile.mk # -------------------------------------------------------------- -BUILD_C_FLAGS += -fvisibility=hidden -fPIC -I. -I.. -I../../includes -BUILD_CXX_FLAGS += -fvisibility=hidden -fPIC -I. -I.. -I../../includes -I../../libs -I../../utils +BUILD_C_FLAGS += -pthread -fvisibility=hidden -fPIC -I. -I.. -I../../includes +BUILD_CXX_FLAGS += -pthread -fvisibility=hidden -fPIC -I. -I.. -I../../includes -I../../libs -I../../utils +LINK_FLAGS += -lpthread # -------------------------------------------------------------- diff --git a/source/backend/engine/CarlaEngineRtAudio.cpp b/source/backend/engine/CarlaEngineRtAudio.cpp index 96a114f16..b14d71685 100644 --- a/source/backend/engine/CarlaEngineRtAudio.cpp +++ b/source/backend/engine/CarlaEngineRtAudio.cpp @@ -77,8 +77,8 @@ public: fAudioInBuf2(nullptr), fAudioOutBuf1(nullptr), fAudioOutBuf2(nullptr), - fMidiIn(getMatchedAudioMidiAPi(api)), - fMidiOut(getMatchedAudioMidiAPi(api)) + fMidiIn(getMatchedAudioMidiAPi(api), "CarlaIn"), + fMidiOut(getMatchedAudioMidiAPi(api), "CarlaOut") { carla_debug("CarlaEngineRtAudio::CarlaEngineRtAudio(%i)", api); @@ -106,6 +106,7 @@ public: CARLA_ASSERT(fAudioInBuf2 == nullptr); CARLA_ASSERT(fAudioOutBuf1 == nullptr); CARLA_ASSERT(fAudioOutBuf2 == nullptr); + CARLA_ASSERT(clientName != nullptr); if (fAudio.getDeviceCount() == 0) { @@ -145,7 +146,13 @@ public: } catch (RtError& e) { - setLastError(e.what()); + carla_stderr2("RtAudio::openStream() failed"); + if (e.getType() == RtError::SYSTEM_ERROR) + setLastError("Stream cannot be opened with the specified parameters"); + else if (e.getType() == RtError::INVALID_USE) + setLastError("Invalid device ID"); + else + setLastError("Unknown error"); return false; } @@ -154,7 +161,9 @@ public: } catch (RtError& e) { + carla_stderr2("RtAudio::startStream() failed"); setLastError(e.what()); + fAudio.closeStream(); return false; } @@ -192,10 +201,20 @@ public: fAudioIsReady = false; if (fAudio.isStreamRunning()) - fAudio.stopStream(); + { + try { + fAudio.stopStream(); + } + catch (...) {} + } if (fAudio.isStreamOpen()) - fAudio.closeStream(); + { + try { + fAudio.closeStream(); + } + catch (...) {} + } fMidiIn.cancelCallback(); fMidiIn.closePort(); @@ -259,9 +278,10 @@ protected: CARLA_ASSERT(insPtr != nullptr); CARLA_ASSERT(outsPtr != nullptr); - if (currentPluginCount() == 0 || ! fAudioIsReady) + if (! fAudioIsReady) { - carla_zeroFloat(outsPtr, sizeof(float)*nframes*2); + carla_zeroFloat(outsPtr, nframes*2); + proccessPendingEvents(); return; } @@ -280,21 +300,102 @@ protected: { std::memcpy(fAudioInBuf1, insPtr, sizeof(float)*nframes); std::memcpy(fAudioInBuf2, insPtr+nframes, sizeof(float)*nframes); - - //for (unsigned int i=0; i < nframes; i++) - // fAudioInBuf1[i] = insPtr[i]; - //for (unsigned int i=0, j=nframes; i < nframes; i++, j++) - // fAudioInBuf2[i] = insPtr[j]; } // initialize audio output carla_zeroFloat(fAudioOutBuf1, fBufferSize); carla_zeroFloat(fAudioOutBuf2, fBufferSize); - // initialize events input - //memset(rackEventsIn, 0, sizeof(EngineEvent)*MAX_EVENTS); + // initialize input events + carla_zeroMem(kData->rack.in, sizeof(EngineEvent)*RACK_EVENT_COUNT); + + if (fMidiInEvents.mutex.tryLock()) { - // TODO + uint32_t engineEventIndex = 0; + fMidiInEvents.splice(); + + while (! fMidiInEvents.data.isEmpty()) + { + const RtMidiEvent& midiEvent = fMidiInEvents.data.getLast(true); + + EngineEvent* const engineEvent = &kData->rack.in[engineEventIndex++]; + engineEvent->clear(); + + const uint8_t midiStatus = MIDI_GET_STATUS_FROM_DATA(midiEvent.data); + const uint8_t midiChannel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent.data); + + engineEvent->channel = midiChannel; + + if (midiEvent.time < fTimeInfo.frame) + engineEvent->time = 0; + else if (midiEvent.time >= fTimeInfo.frame + nframes) + { + engineEvent->time = fTimeInfo.frame + nframes-1; + carla_stderr("MIDI Event in the future!, %i vs %i", engineEvent->time, fTimeInfo.frame); + } + else + engineEvent->time = midiEvent.time - fTimeInfo.frame; + + //carla_stdout("Got midi, time %f vs %i", midiEvent.time, engineEvent->time); + + if (MIDI_IS_STATUS_CONTROL_CHANGE(midiStatus)) + { + const uint8_t midiControl = midiEvent.data[1]; + engineEvent->type = kEngineEventTypeControl; + + if (MIDI_IS_CONTROL_BANK_SELECT(midiControl)) + { + const uint8_t midiBank = midiEvent.data[2]; + + engineEvent->ctrl.type = kEngineControlEventTypeMidiBank; + engineEvent->ctrl.param = midiBank; + engineEvent->ctrl.value = 0.0; + } + else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF) + { + engineEvent->ctrl.type = kEngineControlEventTypeAllSoundOff; + engineEvent->ctrl.param = 0; + engineEvent->ctrl.value = 0.0; + } + else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF) + { + engineEvent->ctrl.type = kEngineControlEventTypeAllNotesOff; + engineEvent->ctrl.param = 0; + engineEvent->ctrl.value = 0.0; + } + else + { + const uint8_t midiValue = midiEvent.data[2]; + + engineEvent->ctrl.type = kEngineControlEventTypeParameter; + engineEvent->ctrl.param = midiControl; + engineEvent->ctrl.value = double(midiValue)/127.0; + } + } + else if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus)) + { + const uint8_t midiProgram = midiEvent.data[1]; + engineEvent->type = kEngineEventTypeControl; + + engineEvent->ctrl.type = kEngineControlEventTypeMidiProgram; + engineEvent->ctrl.param = midiProgram; + engineEvent->ctrl.value = 0.0; + } + else + { + engineEvent->type = kEngineEventTypeMidi; + + engineEvent->midi.data[0] = midiStatus; + engineEvent->midi.data[1] = midiEvent.data[1]; + engineEvent->midi.data[2] = midiEvent.data[2]; + engineEvent->midi.size = midiEvent.size; + } + + if (engineEventIndex >= RACK_EVENT_COUNT) + break; + } + + fMidiInEvents.mutex.unlock(); } // create audio buffers @@ -318,11 +419,6 @@ protected: { std::memcpy(outsPtr, fAudioOutBuf1, sizeof(float)*nframes); std::memcpy(outsPtr+nframes, fAudioOutBuf2, sizeof(float)*nframes); - - //for (unsigned int i=0; i < nframes; i++) - // outsPtr[i] = fAudioOutBuf1[i]; - //for (unsigned int i=0, j=nframes; i < nframes; i++, j++) - // outsPtr[j] = fAudioOutBuf2[i]; } // output events @@ -331,37 +427,61 @@ protected: //fMidiOut.sendMessage(); } + // TESTING + fTimeInfo.playing = true; + fTimeInfo.frame += nframes; + + proccessPendingEvents(); + + return; + + // unused (void)streamTime; (void)status; } - void handleMidiCallback(const double timeStamp, std::vector* const message) + void handleMidiCallback(double timeStamp, std::vector* const message) { const size_t messageSize = message->size(); + static uint32_t lastTime = 0; if (messageSize == 0 || messageSize > 3) return; + timeStamp /= 2; + + if (timeStamp > 0.95) + timeStamp = 0.95; + RtMidiEvent midiEvent; - midiEvent.time = timeStamp; + midiEvent.time = fTimeInfo.frame + (timeStamp*(double)fBufferSize); + carla_stdout("Put midi, frame:%09i/%09i, stamp:%g", fTimeInfo.frame, midiEvent.time, timeStamp); + + if (midiEvent.time < lastTime) + midiEvent.time = lastTime; + else + lastTime = midiEvent.time; if (messageSize == 1) { midiEvent.data[0] = message->at(0); midiEvent.data[1] = 0; midiEvent.data[2] = 0; + midiEvent.size = 1; } else if (messageSize == 2) { midiEvent.data[0] = message->at(0); midiEvent.data[1] = message->at(1); midiEvent.data[2] = 0; + midiEvent.size = 2; } else { midiEvent.data[0] = message->at(0); midiEvent.data[1] = message->at(1); midiEvent.data[2] = message->at(2); + midiEvent.size = 3; } fMidiInEvents.append(midiEvent); @@ -382,8 +502,9 @@ private: RtMidiOut fMidiOut; struct RtMidiEvent { - double time; + uint32_t time; unsigned char data[3]; + unsigned char size; }; struct RtMidiEvents { @@ -417,13 +538,9 @@ private: mutex.unlock(); } - void trySplice() + void splice() { - if (mutex.tryLock()) - { - dataPending.splice(data, true); - mutex.unlock(); - } + dataPending.splice(data, true); } }; diff --git a/source/backend/native/Makefile b/source/backend/native/Makefile index 875962de6..381fe2863 100644 --- a/source/backend/native/Makefile +++ b/source/backend/native/Makefile @@ -14,8 +14,8 @@ LINK_FLAGS += $(shell pkg-config --libs QtGui gl) ifeq ($(HAVE_AF_DEPS),true) AF_CXX_FLAGS = $(BUILD_CXX_FLAGS) -AF_CXX_FLAGS += $(shell pkg-config --cflags libavcodec libavformat sndfile) -pthread -LINK_FLAGS += $(shell pkg-config --libs libavcodec libavformat sndfile) -lpthread +AF_CXX_FLAGS += $(shell pkg-config --cflags libavcodec libavformat sndfile) +LINK_FLAGS += $(shell pkg-config --libs libavcodec libavformat sndfile) endif ifeq ($(HAVE_ZYN_DEPS),true) diff --git a/source/backend/standalone/CarlaStandalone.cpp b/source/backend/standalone/CarlaStandalone.cpp index e9737dfff..cfd3d41d5 100644 --- a/source/backend/standalone/CarlaStandalone.cpp +++ b/source/backend/standalone/CarlaStandalone.cpp @@ -266,6 +266,7 @@ bool carla_engine_init(const char* driverName, const char* clientName) } else { + standalone.lastError = standalone.engine->getLastError(); delete standalone.engine; standalone.engine = nullptr; } diff --git a/source/backend/standalone/Makefile b/source/backend/standalone/Makefile index 6bee89ec3..4af165a9a 100644 --- a/source/backend/standalone/Makefile +++ b/source/backend/standalone/Makefile @@ -43,11 +43,11 @@ endif LINK_FLAGS += $(shell pkg-config --libs gl) ifeq ($(HAVE_AF_DEPS),true) -LINK_FLAGS += $(shell pkg-config --libs libavcodec libavformat sndfile) -lpthread +LINK_FLAGS += $(shell pkg-config --libs libavcodec libavformat sndfile) endif ifeq ($(HAVE_ZYN_DEPS),true) -LINK_FLAGS += $(shell pkg-config --libs fftw3 mxml) -lpthread +LINK_FLAGS += $(shell pkg-config --libs fftw3 mxml) endif # -------------------------------------------------------------- diff --git a/source/bridges/Makefile b/source/bridges/Makefile index 0796832ce..04eab8a7d 100644 --- a/source/bridges/Makefile +++ b/source/bridges/Makefile @@ -13,10 +13,10 @@ HAVE_GTK3 = $(shell pkg-config --exists gtk+-3.0 && echo true) # -------------------------------------------------------------- -BUILD_CXX_FLAGS += -DBUILD_BRIDGE +BUILD_CXX_FLAGS += -DBUILD_BRIDGE -pthread BUILD_CXX_FLAGS += -I. -I../backend -I../includes -I../utils BUILD_CXX_FLAGS += $(shell pkg-config --cflags liblo QtCore QtXml) -LINK_FLAGS += $(shell pkg-config --libs liblo QtCore QtXml) +LINK_FLAGS += $(shell pkg-config --libs liblo QtCore QtXml) -lpthread ifeq ($(CARLA_PLUGIN_SUPPORT),true) BUILD_CXX_FLAGS += -DWANT_LADSPA -DWANT_DSSI diff --git a/source/carla.py b/source/carla.py index e8d373cfd..f2b32c4c3 100755 --- a/source/carla.py +++ b/source/carla.py @@ -649,7 +649,7 @@ class CarlaMainW(QMainWindow): audioError = cString(Carla.host.get_last_error()) if audioError: - QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s', possible reasons: %s" % (audioDriver, audioError))) + QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s', possible reasons:\n%s" % (audioDriver, audioError))) else: QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s'" % audioDriver)) return @@ -1179,8 +1179,10 @@ class CarlaMainW(QMainWindow): self.saveSettings() - Carla.host.set_engine_about_to_close() - self.removeAllPlugins() + if Carla.host.is_engine_running(): + Carla.host.set_engine_about_to_close() + self.removeAllPlugins() + self.stopEngine() QMainWindow.closeEvent(self, event)