AlsaBridge.cpp
branchv_0
changeset 5 ef8f4023e32e
parent 3 e238528eb19c
child 9 ee976a1d1f0a
--- a/AlsaBridge.cpp	Fri Dec 18 23:58:03 2020 +0100
+++ b/AlsaBridge.cpp	Sat Dec 19 17:33:16 2020 +0100
@@ -15,6 +15,9 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 #include <iostream>
+#include <stdexcept>
+#include <thread>
+#include <atomic>
 
 #include <alsa/asoundlib.h>
 
@@ -26,32 +29,63 @@
 class AlsaBridgeImpl : public AlsaBridge, private djmfix::MidiSender {
 private:
 	djmfix::DJMFix* djmFix;
+	snd_rawmidi_t* input;
+	snd_rawmidi_t* output;
+	std::thread receivingThread;
+	std::atomic<bool> stopped{false};
+
+	void run() {
+		while (!stopped) {
+			// TODO: poll
+			uint8_t buffer[256];
+			ssize_t length = snd_rawmidi_read(input, buffer, sizeof (buffer));
+			if (length > 0 && length <= sizeof (buffer)) {
+				// TODO: multiple messages combined together?
+				djmFix->receive(MidiMessage(buffer, buffer + length));
+			}
+
+			std::this_thread::sleep_for(std::chrono::milliseconds(100));
+		}
+	}
 public:
 
-	AlsaBridgeImpl(djmfix::DJMFix* djmFix) : djmFix(djmFix) {
+	AlsaBridgeImpl(djmfix::DJMFix* djmFix, const std::string& deviceName) : djmFix(djmFix) {
+		if (djmFix == nullptr) throw std::invalid_argument("need a djmFix for AlsaBridge");
+
+		int error = snd_rawmidi_open(&input, &output, deviceName.c_str(), SND_RAWMIDI_NONBLOCK);
+		if (error) throw std::invalid_argument("unable to open ALSA device");
+
+
 		djmFix->setMidiSender(this);
 	}
 
 	virtual ~AlsaBridgeImpl() {
+		// TODO: do not use raw/exclusive access to the device
+		snd_rawmidi_close(input);
+		snd_rawmidi_close(output);
 		std::cerr << "~AlsaBridgeImpl()" << std::endl; // TODO: do not mess STDIO
 	}
 
 	virtual void start() override {
 		djmFix->start();
+		receivingThread = std::thread(&AlsaBridgeImpl::run, this);
 	}
 
 	virtual void stop() override {
+		stopped = true;
+		receivingThread.join();
 		djmFix->stop();
 	}
 
 	virtual void send(MidiMessage midiMessage) override {
-		std::cerr << "AlsaBridgeImpl::send()" << std::endl; // TODO: do not mess STDIO
+		ssize_t length = snd_rawmidi_write(output, midiMessage.data(), midiMessage.size());
+		std::cerr << "AlsaBridgeImpl::send(): length = " << length << std::endl; // TODO: do not mess STDIO
 	}
 
 };
 
-AlsaBridge* create(djmfix::DJMFix* djmFix) {
-	return new AlsaBridgeImpl(djmFix);
+AlsaBridge* create(djmfix::DJMFix* djmFix, const std::string& deviceName) {
+	return new AlsaBridgeImpl(djmFix, deviceName);
 }
 
 }