24 namespace alsa { |
27 namespace alsa { |
25 |
28 |
26 class AlsaBridgeImpl : public AlsaBridge, private djmfix::MidiSender { |
29 class AlsaBridgeImpl : public AlsaBridge, private djmfix::MidiSender { |
27 private: |
30 private: |
28 djmfix::DJMFix* djmFix; |
31 djmfix::DJMFix* djmFix; |
|
32 snd_rawmidi_t* input; |
|
33 snd_rawmidi_t* output; |
|
34 std::thread receivingThread; |
|
35 std::atomic<bool> stopped{false}; |
|
36 |
|
37 void run() { |
|
38 while (!stopped) { |
|
39 // TODO: poll |
|
40 uint8_t buffer[256]; |
|
41 ssize_t length = snd_rawmidi_read(input, buffer, sizeof (buffer)); |
|
42 if (length > 0 && length <= sizeof (buffer)) { |
|
43 // TODO: multiple messages combined together? |
|
44 djmFix->receive(MidiMessage(buffer, buffer + length)); |
|
45 } |
|
46 |
|
47 std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
|
48 } |
|
49 } |
29 public: |
50 public: |
30 |
51 |
31 AlsaBridgeImpl(djmfix::DJMFix* djmFix) : djmFix(djmFix) { |
52 AlsaBridgeImpl(djmfix::DJMFix* djmFix, const std::string& deviceName) : djmFix(djmFix) { |
|
53 if (djmFix == nullptr) throw std::invalid_argument("need a djmFix for AlsaBridge"); |
|
54 |
|
55 int error = snd_rawmidi_open(&input, &output, deviceName.c_str(), SND_RAWMIDI_NONBLOCK); |
|
56 if (error) throw std::invalid_argument("unable to open ALSA device"); |
|
57 |
|
58 |
32 djmFix->setMidiSender(this); |
59 djmFix->setMidiSender(this); |
33 } |
60 } |
34 |
61 |
35 virtual ~AlsaBridgeImpl() { |
62 virtual ~AlsaBridgeImpl() { |
|
63 // TODO: do not use raw/exclusive access to the device |
|
64 snd_rawmidi_close(input); |
|
65 snd_rawmidi_close(output); |
36 std::cerr << "~AlsaBridgeImpl()" << std::endl; // TODO: do not mess STDIO |
66 std::cerr << "~AlsaBridgeImpl()" << std::endl; // TODO: do not mess STDIO |
37 } |
67 } |
38 |
68 |
39 virtual void start() override { |
69 virtual void start() override { |
40 djmFix->start(); |
70 djmFix->start(); |
|
71 receivingThread = std::thread(&AlsaBridgeImpl::run, this); |
41 } |
72 } |
42 |
73 |
43 virtual void stop() override { |
74 virtual void stop() override { |
|
75 stopped = true; |
|
76 receivingThread.join(); |
44 djmFix->stop(); |
77 djmFix->stop(); |
45 } |
78 } |
46 |
79 |
47 virtual void send(MidiMessage midiMessage) override { |
80 virtual void send(MidiMessage midiMessage) override { |
48 std::cerr << "AlsaBridgeImpl::send()" << std::endl; // TODO: do not mess STDIO |
81 ssize_t length = snd_rawmidi_write(output, midiMessage.data(), midiMessage.size()); |
|
82 std::cerr << "AlsaBridgeImpl::send(): length = " << length << std::endl; // TODO: do not mess STDIO |
49 } |
83 } |
50 |
84 |
51 }; |
85 }; |
52 |
86 |
53 AlsaBridge* create(djmfix::DJMFix* djmFix) { |
87 AlsaBridge* create(djmfix::DJMFix* djmFix, const std::string& deviceName) { |
54 return new AlsaBridgeImpl(djmFix); |
88 return new AlsaBridgeImpl(djmFix, deviceName); |
55 } |
89 } |
56 |
90 |
57 } |
91 } |
58 } |
92 } |