AlsaBridge.cpp
branchv_0
changeset 5 ef8f4023e32e
parent 3 e238528eb19c
child 9 ee976a1d1f0a
     1.1 --- a/AlsaBridge.cpp	Fri Dec 18 23:58:03 2020 +0100
     1.2 +++ b/AlsaBridge.cpp	Sat Dec 19 17:33:16 2020 +0100
     1.3 @@ -15,6 +15,9 @@
     1.4   * along with this program. If not, see <http://www.gnu.org/licenses/>.
     1.5   */
     1.6  #include <iostream>
     1.7 +#include <stdexcept>
     1.8 +#include <thread>
     1.9 +#include <atomic>
    1.10  
    1.11  #include <alsa/asoundlib.h>
    1.12  
    1.13 @@ -26,32 +29,63 @@
    1.14  class AlsaBridgeImpl : public AlsaBridge, private djmfix::MidiSender {
    1.15  private:
    1.16  	djmfix::DJMFix* djmFix;
    1.17 +	snd_rawmidi_t* input;
    1.18 +	snd_rawmidi_t* output;
    1.19 +	std::thread receivingThread;
    1.20 +	std::atomic<bool> stopped{false};
    1.21 +
    1.22 +	void run() {
    1.23 +		while (!stopped) {
    1.24 +			// TODO: poll
    1.25 +			uint8_t buffer[256];
    1.26 +			ssize_t length = snd_rawmidi_read(input, buffer, sizeof (buffer));
    1.27 +			if (length > 0 && length <= sizeof (buffer)) {
    1.28 +				// TODO: multiple messages combined together?
    1.29 +				djmFix->receive(MidiMessage(buffer, buffer + length));
    1.30 +			}
    1.31 +
    1.32 +			std::this_thread::sleep_for(std::chrono::milliseconds(100));
    1.33 +		}
    1.34 +	}
    1.35  public:
    1.36  
    1.37 -	AlsaBridgeImpl(djmfix::DJMFix* djmFix) : djmFix(djmFix) {
    1.38 +	AlsaBridgeImpl(djmfix::DJMFix* djmFix, const std::string& deviceName) : djmFix(djmFix) {
    1.39 +		if (djmFix == nullptr) throw std::invalid_argument("need a djmFix for AlsaBridge");
    1.40 +
    1.41 +		int error = snd_rawmidi_open(&input, &output, deviceName.c_str(), SND_RAWMIDI_NONBLOCK);
    1.42 +		if (error) throw std::invalid_argument("unable to open ALSA device");
    1.43 +
    1.44 +
    1.45  		djmFix->setMidiSender(this);
    1.46  	}
    1.47  
    1.48  	virtual ~AlsaBridgeImpl() {
    1.49 +		// TODO: do not use raw/exclusive access to the device
    1.50 +		snd_rawmidi_close(input);
    1.51 +		snd_rawmidi_close(output);
    1.52  		std::cerr << "~AlsaBridgeImpl()" << std::endl; // TODO: do not mess STDIO
    1.53  	}
    1.54  
    1.55  	virtual void start() override {
    1.56  		djmFix->start();
    1.57 +		receivingThread = std::thread(&AlsaBridgeImpl::run, this);
    1.58  	}
    1.59  
    1.60  	virtual void stop() override {
    1.61 +		stopped = true;
    1.62 +		receivingThread.join();
    1.63  		djmFix->stop();
    1.64  	}
    1.65  
    1.66  	virtual void send(MidiMessage midiMessage) override {
    1.67 -		std::cerr << "AlsaBridgeImpl::send()" << std::endl; // TODO: do not mess STDIO
    1.68 +		ssize_t length = snd_rawmidi_write(output, midiMessage.data(), midiMessage.size());
    1.69 +		std::cerr << "AlsaBridgeImpl::send(): length = " << length << std::endl; // TODO: do not mess STDIO
    1.70  	}
    1.71  
    1.72  };
    1.73  
    1.74 -AlsaBridge* create(djmfix::DJMFix* djmFix) {
    1.75 -	return new AlsaBridgeImpl(djmFix);
    1.76 +AlsaBridge* create(djmfix::DJMFix* djmFix, const std::string& deviceName) {
    1.77 +	return new AlsaBridgeImpl(djmFix, deviceName);
    1.78  }
    1.79  
    1.80  }