-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmiditoudp.cpp
153 lines (125 loc) · 4.46 KB
/
miditoudp.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include <arpa/inet.h>
#include <netinet/in.h>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdexcept>
#include <iostream>
#include <algorithm>
#include <thread>
#include <RtMidi.h>
#include "rtclock.h"
#include "OurUDPProtocol.hh"
// Handle for the MIDI connection
RtMidiIn *midiin;
// Buffer for the UDP packages
struct OurUDPProtocol::toMusicPackage buffer;
// MIDI event callback function
//
void midiEvent (double timestamp, std::vector<unsigned char>* message, void* voidstate) {
struct OurUDPProtocol::toMusicPackage *package = (struct OurUDPProtocol::toMusicPackage *)voidstate;
if (message->size() > 2) {
switch ((*message)[0]) {
case 144: // Key press
{
int id = (*message)[1] - 21;
if (id >= 0 && id < OurUDPProtocol::KEYBOARDSIZE)
package->keysPressed[id] = (*message)[2] > 0 ? 1.0 : 0.0; // Velocity=0 is interpreted as a key release
}
break;
case 128: // Key release
{
int id = (*message)[1] - 21;
if (id >= 0 && id < OurUDPProtocol::KEYBOARDSIZE)
package->keysPressed[id] = 0.0;
}
break;
case 176: // MIDI Control
if ((*message)[1] == 1)
// Mod key
package->commandKeys[OurUDPProtocol::MODULATECOMMAND] = (*message)[2] > 0 ? 1.0 : 0.0;
else if ((*message)[1] == 64)
// Sustain pedal
package->commandKeys[OurUDPProtocol::SUSTAINCOMMAND] = (*message)[2] > 0 ? 1.0 : 0.0;
else if ((*message)[1] == 7)
// Volume
package->commandKeys[OurUDPProtocol::VOLUMECOMMAND] = (*message)[2] / 127.0;
break;
case 224: // Pitch bend
if ((*message)[2] == 64) {
// No more pitch bend
package->commandKeys[OurUDPProtocol::PITCHBENDDOWNCOMMAND] = 0.0;
package->commandKeys[OurUDPProtocol::PITCHBENDUPCOMMAND] = 0.0;
}
else if ((*message)[2] < 64)
// Pitch down
package->commandKeys[OurUDPProtocol::PITCHBENDDOWNCOMMAND] = 1.0;
else
// Pitch up
package->commandKeys[OurUDPProtocol::PITCHBENDUPCOMMAND] = 1.0;
break;
}
}
}
void init_midi(void) {
midiin = new RtMidiIn(RtMidi::UNSPECIFIED, "Milner Input");
// Check available ports.
unsigned int nPorts = midiin->getPortCount();
if ( nPorts == 0 ) {
std::runtime_error("No ports available!");
}
// Search for a keyboard named Keystation
int selectedPort = 0;
for (int i=0; i<nPorts; i++) {
std::string s = midiin->getPortName(i);
if (s.find("Keystation") != std::string::npos) {
selectedPort = i;
std::cout << "miditoudp: connecting to " << s << std::endl;
break;
}
}
if (selectedPort == 0)
std::cout << "miditoudp: No Keystation port found, using default MIDI input" << std::endl;
midiin->openPort( selectedPort, "Milner Input" );
// Install our MIDI event callback function
midiin->setCallback( midiEvent, &buffer );
}
int
main (int argc, char* argv[])
{
int udpSocket;
struct sockaddr_in udpAddressMe, udpAddress;
unsigned int udpAddressSize = sizeof (udpAddress);
init_midi();
if ((udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
throw std::runtime_error ("miditoudp: couldn't create socket");
memset ((char *) &udpAddressMe, 0, sizeof (udpAddressMe));
udpAddressMe.sin_family = AF_INET;
udpAddressMe.sin_port = htons(OurUDPProtocol::TOMUSICPORT);
udpAddressMe.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind (udpSocket, (struct sockaddr *) &udpAddressMe, sizeof (udpAddressMe)) == -1)
throw std::runtime_error ("miditoudp: could bind socket to port");
// Wait for start message
OurUDPProtocol::startPackage startBuffer;
if (recvfrom (udpSocket, &startBuffer, sizeof (startBuffer), 0, (struct sockaddr *) &udpAddress, &udpAddressSize) == -1)
throw std::runtime_error ("miditoudp: recvfrom()");
else if (startBuffer.magicNumber != OurUDPProtocol::MAGICTOMUSIC)
throw std::runtime_error ("miditoudp: bogus start message");
double stoptime = startBuffer.stopTime;
std::cout << "miditoudp: UDP-connection established." << std::endl;
// This is not needed since buffer is static and therefore cleared from the start
std::fill (buffer.keysPressed.begin(), buffer.keysPressed.end(), 0.0);
RTClock clock (OurUDPProtocol::TIMESTEP);
double t = 0.0;
while (t < stoptime) {
buffer.timestamp = t;
if (sendto (udpSocket, &buffer, sizeof(buffer), 0, (struct sockaddr *) &udpAddress, udpAddressSize) == -1)
throw std::runtime_error ("miditoudp: sendto()");
t += OurUDPProtocol::TIMESTEP;
clock.sleepNext ();
}
close(udpSocket);
return 0;
}