forked from michaelforney/oscmix
-
Notifications
You must be signed in to change notification settings - Fork 0
/
alsaseqio_osx.cpp
129 lines (111 loc) · 3.36 KB
/
alsaseqio_osx.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include "tools/RtMidi.h"
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <fcntl.h>
#include <vector>
#include <string>
void callback(double deltatime, std::vector<unsigned char> *message, void *userData) {
int fd = *reinterpret_cast<int*>(userData);
if (write(fd, message->data(), message->size()) == -1) {
perror("Error writing to pipe in callback");
}
}
void listMidiPorts() {
RtMidiIn tempMidiIn;
RtMidiOut tempMidiOut;
unsigned int nPorts;
// Check MIDI input ports.
nPorts = tempMidiIn.getPortCount();
std::cout << "\n" << nPorts << " MIDI input sources available:\n";
for (unsigned int i = 0; i < nPorts; i++) {
try {
std::string portName = tempMidiIn.getPortName(i);
std::cout << " " << i << ": " << portName << '\n';
} catch (RtMidiError &error) {
error.printMessage();
return;
}
}
// Check MIDI output ports.
nPorts = tempMidiOut.getPortCount();
std::cout << "\n" << nPorts << " MIDI output destinations available:\n";
for (unsigned int i = 0; i < nPorts; i++) {
try {
std::string portName = tempMidiOut.getPortName(i);
std::cout << " " << i << ": " << portName << '\n';
} catch (RtMidiError &error) {
error.printMessage();
return;
}
}
std::cout << "\nRe-run this tool again with the port number or port name of your device.\n\n";
std::cout << "Usage: alsaseqio_osx <input port> <output port> cmd [arg...]\n\n" << std::endl;
}
int main(int argc, char *argv[]) {
if (argc == 1 || (argc > 1 && std::string(argv[1]) == "-l")) {
listMidiPorts();
return 0;
}
if (argc < 4) {
std::cerr << "Usage: " << argv[0] << " <input port> <output port> cmd [arg...]" << std::endl;
return 1;
}
int pipeIn[2], pipeOut[2];
if (pipe(pipeIn) == -1 || pipe(pipeOut) == -1) {
perror("pipe");
return 1;
}
// Open MIDI ports
RtMidiIn midiin;
RtMidiOut midiout;
midiin.openPort(std::atoi(argv[1]));
midiout.openPort(std::atoi(argv[2]));
// Set the MIDIPORT environment variable before forking
std::string inputPortName = midiin.getPortName(std::atoi(argv[1]));
setenv("MIDIPORT", inputPortName.c_str(), 1);
pid_t pid = fork();
if (pid == 0) { // Child process
// Close all unnecessary pipe ends
close(pipeOut[1]); // Close the writing end of pipeOut in the child process
close(pipeIn[0]); // Close the reading end of pipeIn in the child process
// Setup FD 6 as the reading end of pipeOut
if (dup2(pipeOut[0], 6) == -1) {
perror("dup2 failed for FD 6");
exit(1);
}
// Setup FD 7 as the writing end of pipeIn
if (dup2(pipeIn[1], 7) == -1) {
perror("dup2 failed for FD 7");
exit(1);
}
// Close the original file descriptors after dup2
close(pipeOut[0]);
close(pipeIn[1]);
execvp(argv[3], &argv[3]);
perror("execvp failed");
exit(1);
}
// Parent process
close(pipeIn[1]); // Close unused ends
close(pipeOut[0]);
try {
int userData = pipeOut[1]; // Should be the writing end of pipeOut
midiin.setCallback(callback, &userData);
midiin.ignoreTypes(false, false, false);
unsigned char buf[1024];
while (true) {
ssize_t nRead = read(pipeIn[0], buf, sizeof(buf)); // Read from the read end of pipeIn
if (nRead > 0) {
std::vector<unsigned char> message(buf, buf + nRead);
midiout.sendMessage(&message);
} else {
break; // Exit if pipe is closed or read error occurs
}
}
} catch (RtMidiError &error) {
error.printMessage();
return 1;
}
return 0;
}