87 memcpy(midiData, m.buffer, m.size); |
87 memcpy(midiData, m.buffer, m.size); |
88 } |
88 } |
89 return 0; |
89 return 0; |
90 } |
90 } |
91 |
91 |
92 static int processCallback(jack_nframes_t frames, void* arg) { |
92 int syncCallback(jack_transport_state_t state, jack_position_t* position) { |
93 return static_cast<RealTimeContext*> (arg)->processCallback(frames); |
93 std::wcerr << L"syncCallback()" << std::endl; |
|
94 return true; |
|
95 } |
|
96 |
|
97 static int processCallback(jack_nframes_t frames, void* instance) { |
|
98 return static_cast<RealTimeContext*> (instance)->processCallback(frames); |
|
99 } |
|
100 |
|
101 static int syncCallback(jack_transport_state_t state, jack_position_t* position, void* instance) { |
|
102 return static_cast<RealTimeContext*> (instance)->syncCallback(state, position); |
94 } |
103 } |
95 |
104 |
96 } realTimeContext; |
105 } realTimeContext; |
97 |
106 |
98 /** |
107 /** |
159 if (realTimeContext.jackClient == nullptr) throw JackException(L"Could not create JACK client."); |
168 if (realTimeContext.jackClient == nullptr) throw JackException(L"Could not create JACK client."); |
160 |
169 |
161 realTimeContext.ringBuffer = jack_ringbuffer_create(realTimeContext.RING_BUFFER_SIZE * sizeof (MidiMessage)); |
170 realTimeContext.ringBuffer = jack_ringbuffer_create(realTimeContext.RING_BUFFER_SIZE * sizeof (MidiMessage)); |
162 |
171 |
163 jack_set_process_callback(realTimeContext.jackClient, RealTimeContext::processCallback, &realTimeContext); |
172 jack_set_process_callback(realTimeContext.jackClient, RealTimeContext::processCallback, &realTimeContext); |
|
173 jack_set_sync_callback(realTimeContext.jackClient, RealTimeContext::syncCallback, &realTimeContext); |
164 // TODO: report also other events (connections etc.) |
174 // TODO: report also other events (connections etc.) |
165 jack_set_error_function(jackErrorCallback); |
175 jack_set_error_function(jackErrorCallback); |
166 jack_set_info_function(jackErrorCallback); |
176 jack_set_info_function(jackErrorCallback); |
167 |
177 |
168 realTimeContext.jackPort = jack_port_register(realTimeContext.jackClient, "output", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); |
178 realTimeContext.jackPort = jack_port_register(realTimeContext.jackClient, "output", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); |
171 if (mlockall(MCL_CURRENT | MCL_FUTURE)) fwprintf(stderr, L"Warning: Can not lock memory.\n"); |
181 if (mlockall(MCL_CURRENT | MCL_FUTURE)) fwprintf(stderr, L"Warning: Can not lock memory.\n"); |
172 |
182 |
173 int jackError = jack_activate(realTimeContext.jackClient); |
183 int jackError = jack_activate(realTimeContext.jackClient); |
174 if (jackError) throw JackException(L"Could not activate client."); |
184 if (jackError) throw JackException(L"Could not activate client."); |
175 |
185 |
|
186 |
|
187 // Connect to configured destination ports: |
|
188 const char* jackPortName = jack_port_name(realTimeContext.jackPort); |
|
189 for (auto destinationPort : configuration.portsToConnect) { |
|
190 int error = jack_connect(realTimeContext.jackClient, jackPortName, convertor.to_bytes(destinationPort).c_str()); |
|
191 if (error) throw JackException(L"Connection to the JACK port failed: " + destinationPort); |
|
192 } |
|
193 |
176 // Wait for a port connection, because it does not make much sense to send MIDI events nowhere: |
194 // Wait for a port connection, because it does not make much sense to send MIDI events nowhere: |
177 while (jack_port_connected(realTimeContext.jackPort) < configuration.requiredJackConnections) usleep(10000); |
195 while (jack_port_connected(realTimeContext.jackPort) < configuration.requiredJackConnections) usleep(10000); |
178 |
196 |
179 // TODO: configurable auto-connection to another client/port |
197 // TODO: finalize on exceptions |
180 } |
198 } |
181 |
199 |
182 void startRelation(const relpipe::common::type::StringX name, std::vector<relpipe::reader::handlers::AttributeMetadata> attributes) override { |
200 void startRelation(const relpipe::common::type::StringX name, std::vector<relpipe::reader::handlers::AttributeMetadata> attributes) override { |
183 // TODO: validate metadata and prepare attribute mappings (names and types are important, order does not matter) |
201 // TODO: validate metadata and prepare attribute mappings (names and types are important, order does not matter) |
184 |
202 |