merged in GPL header
[jackctlmmc.git] / common.c
blob6a25dd4104563e084a450badc24149e4619b17aa
1 #include "common.h"
3 // common globals
4 snd_seq_t* g_seq_ptr = NULL;
5 lash_client_t* g_lashc = NULL;
6 jack_client_t* g_jack_client = NULL;
7 int g_quit = 0; // a flag which will be set by our signal handler when it's time to exit
9 void process_lash_event(lash_event_t * event_ptr)
11 enum LASH_Event_Type type;
12 const char * str;
14 type = lash_event_get_type(event_ptr);
15 str = lash_event_get_string(event_ptr);
17 switch (type)
19 case LASH_Quit:
20 printf("LASH_Quit received.\n");
21 g_lashc = NULL;
22 g_quit = 1;
23 break;
24 case LASH_Save_File:
25 case LASH_Restore_File:
26 case LASH_Save_Data_Set:
27 default:
28 printf("LASH Event. Type = %u, string = \"%s\"\n",
29 (unsigned int)type,
30 (str == NULL)?"":str);
34 void process_lash_config(lash_config_t * config_ptr)
36 const char * key;
37 const void * data;
38 size_t data_size;
40 key = lash_config_get_key(config_ptr);
41 data = lash_config_get_value(config_ptr);
42 data_size = lash_config_get_value_size(config_ptr);
44 printf("LASH Config. Key = \"%s\"\n", key);
47 int init_alsa_sequencer(const char* appName)
49 snd_seq_port_info_t * seq_port_info = NULL;
50 int ret = 0;
52 /* ALSA sequencer initialisation */
53 ret = snd_seq_open( &g_seq_ptr, "default", SND_SEQ_OPEN_INPUT, 0);
54 if (ret < 0)
55 return ret;
57 // setup alsa sequencer port
58 snd_seq_port_info_alloca(&seq_port_info);
59 snd_seq_port_info_set_capability(seq_port_info, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE);
60 snd_seq_port_info_set_type( seq_port_info, SND_SEQ_PORT_TYPE_APPLICATION);
61 snd_seq_port_info_set_midi_channels(seq_port_info, 16);
62 snd_seq_port_info_set_port_specified(seq_port_info, 1);
63 snd_seq_port_info_set_name(seq_port_info, "midi in");
64 snd_seq_port_info_set_port(seq_port_info, 0);
66 ret = snd_seq_create_port(g_seq_ptr, seq_port_info);
68 if (ret < 0)
69 printf("Error with alsa sequencer initialization, %s\n", snd_strerror(ret));
70 else // all is well, register the sequencer with whatever name was passed in
71 snd_seq_set_client_name(g_seq_ptr, appName);
73 return ret;
76 void init_lash(int argc, char* argv[])
78 lash_event_t * lash_event_ptr = NULL;
80 /* LASH setup */
81 g_lashc = lash_init( lash_extract_args(&argc, &argv), "jackctlmmc", 0, LASH_PROTOCOL_VERSION);
83 if (g_lashc == NULL)
85 printf("Failed to connect to LASH. Session management will not occur.\n");
87 else
89 lash_event_ptr = lash_event_new_with_type(LASH_Client_Name);
90 lash_event_set_string(lash_event_ptr, "jackctlmmc");
91 lash_send_event(g_lashc, lash_event_ptr);
94 // register JACK and ALSA clients with lash
95 lash_alsa_client_id(g_lashc, snd_seq_client_id(g_seq_ptr));
96 lash_jack_client_name(g_lashc, "jackctlmmc");
99 int init_jack(const char* appName)
101 jack_status_t status;
102 g_jack_client = jack_client_open(appName, JackNoStartServer, &status);
104 if (!g_jack_client) // something went wrong
105 return -1; // todo: check status to see exactly what happened
107 return 0;
110 void activate_jack()
112 /* tell jack that we are ready to do our thing */
113 jack_activate(g_jack_client);
116 void listen_loop (uint32_t frameRate, uint32_t jitterTolerance, int verbose)
118 lash_event_t * lash_event_ptr = NULL;
119 lash_config_t * lash_config_ptr = NULL;
120 snd_seq_event_t * seq_event_ptr = NULL;
122 int npfd = snd_seq_poll_descriptors_count(g_seq_ptr, POLLIN);
123 struct pollfd * pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd));
124 snd_seq_poll_descriptors(g_seq_ptr, pfd, npfd, POLLIN);
126 while(!g_quit)
128 if (poll(pfd, npfd, 250) > 0 && snd_seq_event_input(g_seq_ptr, &seq_event_ptr) >= 0)
130 if (seq_event_ptr->type == SND_SEQ_EVENT_SYSEX &&
131 ((uint8_t *)seq_event_ptr->data.ext.ptr)[0] == 0xF0 &&
132 ((uint8_t *)seq_event_ptr->data.ext.ptr)[1] == 0x7F &&
133 ((uint8_t *)seq_event_ptr->data.ext.ptr)[2] == 0x7F && /* All devices */
134 ((uint8_t *)seq_event_ptr->data.ext.ptr)[3] == 0x06)
136 switch (((char *)seq_event_ptr->data.ext.ptr)[4])
138 case 1: /* stop */
139 if (verbose)
140 printf("MMC Stop -> JACK transport stop\n");
141 jack_transport_stop(g_jack_client);
142 break;
143 case 2: /* play */
144 case 3: /* deferred play */
145 if (verbose)
146 printf("MMC Play -> JACK transport start\n");
147 jack_transport_start(g_jack_client);
148 break;
149 case 5: /* rewind */
150 if (verbose)
151 printf("MMC Play -> JACK transport locate to 0\n");
152 jack_transport_locate(g_jack_client, 0);
153 break;
154 case 0x44: /* goto */
155 if (((uint8_t*)seq_event_ptr->data.ext.ptr)[5] == 0x06 &&
156 ((uint8_t*)seq_event_ptr->data.ext.ptr)[6] == 0x01)
158 // some devices call hour 0 "60". Mask off the upper bits
159 uint8_t hour = ((uint8_t*)seq_event_ptr->data.ext.ptr)[7] & 0x1f;
160 uint8_t minute = ((uint8_t*)seq_event_ptr->data.ext.ptr)[8];
161 uint8_t second = ((uint8_t*)seq_event_ptr->data.ext.ptr)[9];
162 uint8_t frame = ((uint8_t*)seq_event_ptr->data.ext.ptr)[10];
163 uint8_t subframe = ((uint8_t*)seq_event_ptr->data.ext.ptr)[11]; // percentage of a frame: 0 - 99
164 jack_position_t jack_pos;
166 if (verbose)
167 printf("MMC locate to hour: %d, minute: %d, second: %d, frame: %d, subframe: %d\n",
168 hour,
169 minute,
170 second,
171 frame,
172 subframe);
174 // get Jack's current framerate and position
175 jack_transport_query(g_jack_client, &jack_pos);
176 const uint32_t jack_frame_rate = jack_pos.frame_rate;
177 const uint32_t jack_time_ms = (jack_pos.frame * 1000) / jack_frame_rate;
178 const uint32_t device_time_ms = ((subframe * 10) / frameRate + // subframe == 1/100th of a frame
179 (frame * 1000) / frameRate +
180 (second * 1000) +
181 (minute * 60 * 1000) +
182 (hour * 60 * 60 * 1000));
184 // difference in milliseconds from JACK's reported transport to the MIDI goto's time
185 const uint32_t jitter = (device_time_ms > jack_time_ms ? (device_time_ms - jack_time_ms) : (jack_time_ms - device_time_ms));
187 if (verbose)
188 printf("difference between JACK time and MMC destination time in ms: %d\n", jitter);
190 // check if the JACK clock is far enough away from the MMC time to care
191 if (jitter > jitterTolerance)
192 { // it is, change it.
193 jack_pos.valid = 0; // only the frame number will be valid since that's all we're changing
194 jack_pos.frame = device_time_ms * jack_frame_rate / 1000;
195 jack_transport_reposition(g_jack_client, &jack_pos);
199 break;
200 default:
201 if (verbose)
202 printf("unsupported MMC command: 0x%x\n", ((char *)seq_event_ptr->data.ext.ptr)[4]);
207 /* Process LASH events */
208 while ((lash_event_ptr = lash_get_event(g_lashc)) != NULL)
210 process_lash_event(lash_event_ptr);
211 lash_event_destroy(lash_event_ptr);
214 /* Process LASH configs */
215 while ((lash_config_ptr = lash_get_config(g_lashc)) != NULL)
217 process_lash_config(lash_config_ptr);
218 lash_config_destroy(lash_config_ptr);
223 void cleanup_globals()
225 int ret = 0;
226 jack_deactivate(g_jack_client);
228 if (g_seq_ptr)
230 ret = snd_seq_close(g_seq_ptr);
231 if (ret < 0)
233 printf("Cannot close sequncer, %s\n", snd_strerror(ret));
237 if (g_jack_client)
239 jack_client_close(g_jack_client);