src/JackHandler.h
branchv_0
changeset 17 0fcd9944016a
parent 16 d17d70731446
child 18 7a74e9f9e674
equal deleted inserted replaced
16:d17d70731446 17:0fcd9944016a
   153 	static void jackErrorCallback(const char * message) {
   153 	static void jackErrorCallback(const char * message) {
   154 		std::wstring_convert < std::codecvt_utf8<wchar_t>> convertor; // TODO: local system encoding
   154 		std::wstring_convert < std::codecvt_utf8<wchar_t>> convertor; // TODO: local system encoding
   155 		std::wcerr << L"JACK: " << convertor.from_bytes(message) << std::endl;
   155 		std::wcerr << L"JACK: " << convertor.from_bytes(message) << std::endl;
   156 	}
   156 	}
   157 
   157 
       
   158 	void finalize() {
       
   159 		// Close JACK connection:
       
   160 		jack_deactivate(realTimeContext.jackClient);
       
   161 		jack_client_close(realTimeContext.jackClient);
       
   162 		jack_ringbuffer_free(realTimeContext.ringBuffer);
       
   163 	}
       
   164 
       
   165 	void failInConstructor(const relpipe::common::type::StringX& errorMessage) {
       
   166 		finalize();
       
   167 		throw JackException(errorMessage);
       
   168 	}
       
   169 
   158 public:
   170 public:
   159 
   171 
   160 	JackHandler(Configuration& configuration) : configuration(configuration) {
   172 	JackHandler(Configuration& configuration) : configuration(configuration) {
   161 		// Initialize JACK connection:
   173 		// Initialize JACK connection:
   162 		std::string clientName = convertor.to_bytes(configuration.jackClientName);
   174 		std::string clientName = convertor.to_bytes(configuration.jackClientName);
   163 		realTimeContext.jackClient = jack_client_open(clientName.c_str(), JackNullOption, nullptr);
   175 		realTimeContext.jackClient = jack_client_open(clientName.c_str(), JackNullOption, nullptr);
   164 		if (realTimeContext.jackClient == nullptr) throw JackException(L"Could not create JACK client.");
   176 		if (realTimeContext.jackClient == nullptr) failInConstructor(L"Could not create JACK client.");
   165 
   177 
   166 		realTimeContext.ringBuffer = jack_ringbuffer_create(realTimeContext.RING_BUFFER_SIZE * sizeof (MidiMessage));
   178 		realTimeContext.ringBuffer = jack_ringbuffer_create(realTimeContext.RING_BUFFER_SIZE * sizeof (MidiMessage));
   167 
   179 
   168 		jack_set_process_callback(realTimeContext.jackClient, RealTimeContext::processCallback, &realTimeContext);
   180 		jack_set_process_callback(realTimeContext.jackClient, RealTimeContext::processCallback, &realTimeContext);
   169 		jack_set_sync_callback(realTimeContext.jackClient, RealTimeContext::syncCallback, &realTimeContext);
   181 		jack_set_sync_callback(realTimeContext.jackClient, RealTimeContext::syncCallback, &realTimeContext);
   170 		// TODO: report also other events (connections etc.)
   182 		// TODO: report also other events (connections etc.)
   171 		jack_set_error_function(jackErrorCallback);
   183 		jack_set_error_function(jackErrorCallback);
   172 		jack_set_info_function(jackErrorCallback);
   184 		jack_set_info_function(jackErrorCallback);
   173 
   185 
   174 		realTimeContext.jackPort = jack_port_register(realTimeContext.jackClient, "output", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
   186 		realTimeContext.jackPort = jack_port_register(realTimeContext.jackClient, "output", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
   175 		if (realTimeContext.jackPort == nullptr) throw JackException(L"Could not register port.");
   187 		if (realTimeContext.jackPort == nullptr) failInConstructor(L"Could not register the JACK port.");
   176 
   188 
   177 		if (mlockall(MCL_CURRENT | MCL_FUTURE)) fwprintf(stderr, L"Warning: Can not lock memory.\n");
   189 		if (mlockall(MCL_CURRENT | MCL_FUTURE)) fwprintf(stderr, L"Warning: Can not lock memory.\n");
   178 
   190 
   179 		int jackError = jack_activate(realTimeContext.jackClient);
   191 		int jackError = jack_activate(realTimeContext.jackClient);
   180 		if (jackError) throw JackException(L"Could not activate client.");
   192 		if (jackError) failInConstructor(L"Could not activate the JACK client.");
   181 
   193 
   182 
   194 
   183 		// Connect to configured destination ports:
   195 		// Connect to configured destination ports:
   184 		const char* jackPortName = jack_port_name(realTimeContext.jackPort);
   196 		const char* jackPortName = jack_port_name(realTimeContext.jackPort);
   185 		for (auto destinationPort : configuration.portsToConnect) {
   197 		for (auto destinationPort : configuration.portsToConnect) {
   186 			int error = jack_connect(realTimeContext.jackClient, jackPortName, convertor.to_bytes(destinationPort).c_str());
   198 			int error = jack_connect(realTimeContext.jackClient, jackPortName, convertor.to_bytes(destinationPort).c_str());
   187 			if (error) throw JackException(L"Connection to the JACK port failed: " + destinationPort);
   199 			if (error) failInConstructor(L"Connection to the JACK port failed: " + destinationPort);
   188 		}
   200 		}
   189 
   201 
   190 		// Wait for a port connection, because it does not make much sense to send MIDI events nowhere:
   202 		// Wait for a port connection, because it does not make much sense to send MIDI events nowhere:
   191 		while (jack_port_connected(realTimeContext.jackPort) < configuration.requiredJackConnections) usleep(10000);
   203 		while (jack_port_connected(realTimeContext.jackPort) < configuration.requiredJackConnections) usleep(10000);
   192 
   204 
   193 		// TODO: finalize on exceptions
       
   194 	}
   205 	}
   195 
   206 
   196 	void startRelation(const relpipe::common::type::StringX name, std::vector<relpipe::reader::handlers::AttributeMetadata> attributes) override {
   207 	void startRelation(const relpipe::common::type::StringX name, std::vector<relpipe::reader::handlers::AttributeMetadata> attributes) override {
   197 		// TODO: validate metadata and prepare attribute mappings (names and types are important, order does not matter)
   208 		// TODO: validate metadata and prepare attribute mappings (names and types are important, order does not matter)
   198 
   209 
   288 	void finish(int sig) {
   299 	void finish(int sig) {
   289 		continueProcessing = false;
   300 		continueProcessing = false;
   290 	}
   301 	}
   291 
   302 
   292 	virtual ~JackHandler() {
   303 	virtual ~JackHandler() {
   293 		// Close JACK connection:
   304 		finalize();
   294 		jack_deactivate(realTimeContext.jackClient);
       
   295 		jack_client_close(realTimeContext.jackClient);
       
   296 		jack_ringbuffer_free(realTimeContext.ringBuffer);
       
   297 	}
   305 	}
   298 
   306 
   299 };
   307 };
   300 
   308 
   301 }
   309 }