src/JackHandler.h
branchv_0
changeset 19 dcd98589f4b8
parent 18 7a74e9f9e674
child 20 ccc4e509c1f0
equal deleted inserted replaced
18:7a74e9f9e674 19:dcd98589f4b8
    26 #include <locale>
    26 #include <locale>
    27 #include <codecvt>
    27 #include <codecvt>
    28 #include <sys/mman.h>
    28 #include <sys/mman.h>
    29 #include <signal.h>
    29 #include <signal.h>
    30 #include <unistd.h>
    30 #include <unistd.h>
       
    31 #include <pthread.h>
    31 
    32 
    32 #include <jack/jack.h>
    33 #include <jack/jack.h>
    33 #include <jack/midiport.h>
    34 #include <jack/midiport.h>
    34 #include <jack/ringbuffer.h>
    35 #include <jack/ringbuffer.h>
    35 
    36 
    70 	class RealTimeContext {
    71 	class RealTimeContext {
    71 	public:
    72 	public:
    72 		jack_client_t* jackClient = nullptr;
    73 		jack_client_t* jackClient = nullptr;
    73 		jack_port_t* jackPort = nullptr;
    74 		jack_port_t* jackPort = nullptr;
    74 		jack_ringbuffer_t* ringBuffer = nullptr;
    75 		jack_ringbuffer_t* ringBuffer = nullptr;
       
    76 
       
    77 		pthread_mutex_t processingLock = PTHREAD_MUTEX_INITIALIZER;
       
    78 		pthread_cond_t processingDone = PTHREAD_COND_INITIALIZER;
    75 
    79 
    76 		const int RING_BUFFER_SIZE = 100;
    80 		const int RING_BUFFER_SIZE = 100;
    77 
    81 
    78 		int processCallback(jack_nframes_t frames) {
    82 		int processCallback(jack_nframes_t frames) {
    79 			const size_t queuedMessages = jack_ringbuffer_read_space(ringBuffer) / sizeof (MidiMessage);
    83 			const size_t queuedMessages = jack_ringbuffer_read_space(ringBuffer) / sizeof (MidiMessage);
    84 				MidiMessage m;
    88 				MidiMessage m;
    85 				jack_ringbuffer_read(ringBuffer, (char*) &m, sizeof (MidiMessage));
    89 				jack_ringbuffer_read(ringBuffer, (char*) &m, sizeof (MidiMessage));
    86 				jack_midi_data_t* midiData = jack_midi_event_reserve(jackPortBuffer, m.time, m.size);
    90 				jack_midi_data_t* midiData = jack_midi_event_reserve(jackPortBuffer, m.time, m.size);
    87 				memcpy(midiData, m.buffer, m.size);
    91 				memcpy(midiData, m.buffer, m.size);
    88 			}
    92 			}
       
    93 
       
    94 			if (pthread_mutex_trylock(&processingLock) == 0) {
       
    95 				pthread_cond_signal(&processingDone);
       
    96 				pthread_mutex_unlock(&processingLock);
       
    97 			}
       
    98 
    89 			return 0;
    99 			return 0;
    90 		}
   100 		}
    91 
   101 
    92 		int syncCallback(jack_transport_state_t state, jack_position_t* position) {
   102 		int syncCallback(jack_transport_state_t state, jack_position_t* position) {
    93 			std::wcerr << L"syncCallback()" << std::endl;
       
    94 			return true;
   103 			return true;
    95 		}
   104 		}
    96 
   105 
    97 		static int processCallback(jack_nframes_t frames, void* instance) {
   106 		static int processCallback(jack_nframes_t frames, void* instance) {
    98 			return static_cast<RealTimeContext*> (instance)->processCallback(frames);
   107 			return static_cast<RealTimeContext*> (instance)->processCallback(frames);
   158 	void finalize() {
   167 	void finalize() {
   159 		// Close JACK connection:
   168 		// Close JACK connection:
   160 		jack_deactivate(realTimeContext.jackClient);
   169 		jack_deactivate(realTimeContext.jackClient);
   161 		jack_client_close(realTimeContext.jackClient);
   170 		jack_client_close(realTimeContext.jackClient);
   162 		jack_ringbuffer_free(realTimeContext.ringBuffer);
   171 		jack_ringbuffer_free(realTimeContext.ringBuffer);
       
   172 		pthread_mutex_unlock(&realTimeContext.processingLock);
   163 	}
   173 	}
   164 
   174 
   165 	void failInConstructor(const relpipe::common::type::StringX& errorMessage) {
   175 	void failInConstructor(const relpipe::common::type::StringX& errorMessage) {
   166 		finalize();
   176 		finalize();
   167 		throw JackException(errorMessage);
   177 		throw JackException(errorMessage);
   168 	}
   178 	}
   169 
   179 
   170 public:
   180 public:
   171 
   181 
   172 	JackHandler(Configuration& configuration) : configuration(configuration) {
   182 	JackHandler(Configuration& configuration) : configuration(configuration) {
       
   183 		pthread_mutex_unlock(&realTimeContext.processingLock);
       
   184 
   173 		// Initialize JACK connection:
   185 		// Initialize JACK connection:
   174 		std::string clientName = convertor.to_bytes(configuration.jackClientName);
   186 		std::string clientName = convertor.to_bytes(configuration.jackClientName);
   175 		realTimeContext.jackClient = jack_client_open(clientName.c_str(), JackNullOption, nullptr);
   187 		realTimeContext.jackClient = jack_client_open(clientName.c_str(), JackNullOption, nullptr);
   176 		if (realTimeContext.jackClient == nullptr) failInConstructor(L"Could not create JACK client.");
   188 		if (realTimeContext.jackClient == nullptr) failInConstructor(L"Could not create JACK client.");
   177 
   189 
   282 		}
   294 		}
   283 
   295 
   284 	}
   296 	}
   285 
   297 
   286 	void endOfPipe() {
   298 	void endOfPipe() {
   287 		// Wait until the ring buffer is empty
       
   288 		while (continueProcessing && jack_ringbuffer_read_space(realTimeContext.ringBuffer)) usleep(1000);
       
   289 		usleep(1000000);
       
   290 		// TODO: better waiting (ringBuffer might be empty, but events have not been sent to JACK yet)
       
   291 		// TODO: optionally mute all; probably enabled by default
   299 		// TODO: optionally mute all; probably enabled by default
       
   300 
       
   301 		// Wait until the ring buffer is empty (messages dequeued from the buffer) and real-time cycle was finished (messages passed to JACK)
       
   302 		while (continueProcessing && jack_ringbuffer_read_space(realTimeContext.ringBuffer)) pthread_cond_wait(&realTimeContext.processingDone, &realTimeContext.processingLock);
   292 	}
   303 	}
   293 
   304 
   294 	void finish(int sig) {
   305 	void finish(int sig) {
   295 		continueProcessing = false;
   306 		continueProcessing = false;
   296 	}
   307 	}