AlsaBridge.cpp
branchv_0
changeset 18 358a601bfe81
parent 16 63154f9d24a2
     1.1 --- a/AlsaBridge.cpp	Fri May 09 23:17:36 2025 +0200
     1.2 +++ b/AlsaBridge.cpp	Sun May 11 00:30:03 2025 +0200
     1.3 @@ -43,9 +43,14 @@
     1.4  	std::recursive_mutex midiMutex;
     1.5  	std::atomic<bool> stopped{false};
     1.6  
     1.7 -	std::string findDeviceName(std::regex cardNamePattern) {
     1.8 +	struct FoundDevice {
     1.9 +		std::string id;
    1.10 +		std::string name;
    1.11 +	};
    1.12  
    1.13 +	FoundDevice findDeviceName(std::regex cardNamePattern) {
    1.14  		std::vector<int> cardNumbers;
    1.15 +		std::vector<std::string> cardNames;
    1.16  
    1.17  		logger->log(L::INFO, "Looking for available cards:");
    1.18  
    1.19 @@ -58,6 +63,7 @@
    1.20  
    1.21  			if (std::regex_match(longName, cardNamePattern)) {
    1.22  				cardNumbers.push_back(card);
    1.23 +				cardNames.push_back(longName);
    1.24  				logMessage << " [matches]";
    1.25  			}
    1.26  
    1.27 @@ -69,7 +75,7 @@
    1.28  		if (cardNumbers.size() == 1) {
    1.29  			const auto n = std::to_string(cardNumbers[0]);
    1.30  			logger->log(L::INFO, "Going to fix card #" + n);
    1.31 -			return "hw:" + n;
    1.32 +			return {"hw:" + n, cardNames[0]};
    1.33  		} else if (cardNumbers.empty()) {
    1.34  			throw std::invalid_argument(
    1.35  					"No card with matching name found. Is the card connected? "
    1.36 @@ -89,6 +95,7 @@
    1.37  	}
    1.38  
    1.39  	void run() {
    1.40 +		MidiMessage msg;
    1.41  		while (!stopped) {
    1.42  			{
    1.43  				std::lock_guard<std::recursive_mutex> lock(midiMutex);
    1.44 @@ -96,8 +103,32 @@
    1.45  				uint8_t buf[256];
    1.46  				ssize_t length = snd_rawmidi_read(input, buf, sizeof (buf));
    1.47  				if (length > 0 && length <= sizeof (buf)) {
    1.48 -					// TODO: multiple messages combined together?
    1.49 -					djmFix->receive(MidiMessage(buf, buf + length));
    1.50 +					// Parse MIDI messages and ignore/skip unwanted data.
    1.51 +					// Needed for DJM-V10 that sends annoying amounts of 0xF8.
    1.52 +					for (int i = 0; i < length; i++) {
    1.53 +						uint8_t b = buf[i];
    1.54 +						if (b == MIDI_CMD_COMMON_SYSEX) {
    1.55 +							// start of MIDI SysEx message
    1.56 +							msg.clear();
    1.57 +							msg.push_back(b);
    1.58 +						} else if (b == MIDI_CMD_COMMON_SYSEX_END) {
    1.59 +							// end of MIDI SysEx message
    1.60 +							msg.push_back(b);
    1.61 +							djmFix->receive(msg);
    1.62 +							msg.clear();
    1.63 +						} else if (b == MIDI_CMD_COMMON_CLOCK) {
    1.64 +							logger->log(L::FINEST, "timing clock ignored");
    1.65 +						} else if (b == MIDI_CMD_COMMON_SENSING) {
    1.66 +							logger->log(L::FINEST, "active sensing ignored");
    1.67 +						} else if (b & 0x80) {
    1.68 +							// unknown status, drop previous data
    1.69 +							msg.clear();
    1.70 +							logger->log(L::FINER, "unknown message ignored");
    1.71 +						} else {
    1.72 +							// message data
    1.73 +							msg.push_back(b);
    1.74 +						}
    1.75 +					}
    1.76  				}
    1.77  			}
    1.78  			std::this_thread::sleep_for(std::chrono::milliseconds(100));
    1.79 @@ -114,12 +145,13 @@
    1.80  		if (djmFix == nullptr)
    1.81  			throw std::invalid_argument("Need a djmFix for AlsaBridge.");
    1.82  
    1.83 -		std::string deviceName = findDeviceName(std::regex(cardNamePattern));
    1.84 +		FoundDevice found = findDeviceName(std::regex(cardNamePattern));
    1.85  
    1.86  		int mode = SND_RAWMIDI_NONBLOCK;
    1.87 -		int error = snd_rawmidi_open(&input, &output, deviceName.c_str(), mode);
    1.88 +		int error = snd_rawmidi_open(&input, &output, found.id.c_str(), mode);
    1.89  		if (error) throw std::invalid_argument("Unable to open ALSA device.");
    1.90  
    1.91 +		djmFix->setDeviceName(found.name);
    1.92  		djmFix->setMidiSender(this);
    1.93  	}
    1.94