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 }