From 77277419bac45f5166aeef77c245b593d20b3911 Mon Sep 17 00:00:00 2001 From: Alex Montgomery Date: Mon, 24 Nov 2008 09:39:03 +0000 Subject: [PATCH] code cleanup in preparation of separating out the core loop/functionality --- main.c | 615 ++++++++++++++++++++++++++++++++++------------------------------- 1 file changed, 320 insertions(+), 295 deletions(-) rewrite main.c (92%) diff --git a/main.c b/main.c dissimilarity index 92% index 86a3bba..5044439 100644 --- a/main.c +++ b/main.c @@ -1,295 +1,320 @@ -#include -#include -#include - -#include -#include -#include -#include - -snd_seq_t * g_seq_ptr; -lash_client_t * g_lashc; -jack_client_t * g_jack_client; - -// these values can be passed on the command line -// frame rate (frames per second) of the MMC controlling device -uint32_t g_device_frame_rate = 30; // command line equivalent: -f 30 -// jitter tolerance in milliseconds -uint32_t g_jitter_tolerance = 50; //command line: -t 50 -int g_verbose = 0; // pass -v on the command line to turn this on - -/* a flag which will be set by our signal handler when it's time to exit */ -int g_quit = 0; - -/* the signal handler */ -void -signalled(int signal) -{ - g_quit = 1; -} - -void -process_lash_event(lash_event_t * event_ptr) -{ - enum LASH_Event_Type type; - const char * str; - - type = lash_event_get_type(event_ptr); - str = lash_event_get_string(event_ptr); - - switch (type) - { - case LASH_Quit: - printf("LASH_Quit received.\n"); - g_lashc = NULL; - g_quit = 1; - break; - case LASH_Save_File: - case LASH_Restore_File: - case LASH_Save_Data_Set: - default: - printf("LASH Event. Type = %u, string = \"%s\"\n", - (unsigned int)type, - (str == NULL)?"":str); - } -} - -void -process_lash_config(lash_config_t * config_ptr) -{ - const char * key; - const void * data; - size_t data_size; - - key = lash_config_get_key(config_ptr); - data = lash_config_get_value(config_ptr); - data_size = lash_config_get_value_size(config_ptr); - - printf("LASH Config. Key = \"%s\"\n", key); -} - -int -main(int argc, char *argv[]) -{ - - int parameter; - while ((parameter = getopt(argc, argv, "f:t:v")) != -1) - switch (parameter) - { - case 'v': - g_verbose = 1; - break; - case 'f': - g_device_frame_rate = atoi(optarg); - break; - case 't': - g_jitter_tolerance = atoi(optarg); - break; - case '?': - fprintf(stderr, "usage: %s -f -t \n", argv[0]); - exit(1); - break; - } - - printf("%s starting with a jitter tolerance of %d milliseconds and a device frame rate of %d per second.\n", - argv[0], g_jitter_tolerance, g_device_frame_rate); - - int ret; - lash_event_t * lash_event_ptr; - lash_config_t * lash_config_ptr; - snd_seq_port_info_t * seq_port_info = NULL; - snd_seq_event_t * seq_event_ptr; - int npfd; - struct pollfd * pfd; - - /* setup our signal handler signalled() above, so we can exit cleanly (see end of main()) */ - signal(SIGINT, signalled); - - /* LASH setup */ - g_lashc = lash_init( - lash_extract_args(&argc, &argv), - "jackctlmmc", - 0, - LASH_PROTOCOL_VERSION); - - if (g_lashc == NULL) - { - printf("Failed to connect to LASH. Session management will not occur.\n"); - } - else - { - lash_event_ptr = lash_event_new_with_type(LASH_Client_Name); - lash_event_set_string(lash_event_ptr, "jackctlmmc"); - lash_send_event(g_lashc, lash_event_ptr); - } - - /* naturally we need to become a jack client :) */ - g_jack_client = jack_client_new("jackctlmmc"); - if (!g_jack_client) - { - printf("couldn't connect to jack server. Either it's not running or the client name is already taken\n"); - goto exit; - } - - lash_jack_client_name(g_lashc, "jackctlmmc"); - - /* ALSA sequencer initialisation */ - ret = snd_seq_open( - &g_seq_ptr, - "default", - SND_SEQ_OPEN_INPUT, - 0); - if (ret < 0) - { - printf("Cannot open sequncer, %s\n", snd_strerror(ret)); - goto close_jack; - } - - snd_seq_set_client_name(g_seq_ptr, "jackctlmmc"); - - lash_alsa_client_id(g_lashc, snd_seq_client_id(g_seq_ptr)); - - snd_seq_port_info_alloca(&seq_port_info); - - snd_seq_port_info_set_capability( - seq_port_info, - SND_SEQ_PORT_CAP_WRITE | - SND_SEQ_PORT_CAP_SUBS_WRITE); - snd_seq_port_info_set_type( - seq_port_info, - SND_SEQ_PORT_TYPE_APPLICATION); - snd_seq_port_info_set_midi_channels(seq_port_info, 16); - snd_seq_port_info_set_port_specified(seq_port_info, 1); - - snd_seq_port_info_set_name(seq_port_info, "midi in"); - snd_seq_port_info_set_port(seq_port_info, 0); - - ret = snd_seq_create_port(g_seq_ptr, seq_port_info); - if (ret < 0) - { - printf("Error creating ALSA sequencer port, %s\n", snd_strerror(ret)); - goto close_seq; - } - - /* tell jack that we are ready to do our thing */ - jack_activate(g_jack_client); - - npfd = snd_seq_poll_descriptors_count(g_seq_ptr, POLLIN); - pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd)); - snd_seq_poll_descriptors(g_seq_ptr, pfd, npfd, POLLIN); - - /* wait until this app receives a SIGINT (i.e. press ctrl-c in the terminal) see signalled() above */ - while(!g_quit) - { - if (poll(pfd, npfd, 250) > 0 && snd_seq_event_input(g_seq_ptr, &seq_event_ptr) >= 0) - { - if (seq_event_ptr->type == SND_SEQ_EVENT_SYSEX && - ((uint8_t *)seq_event_ptr->data.ext.ptr)[0] == 0xF0 && - ((uint8_t *)seq_event_ptr->data.ext.ptr)[1] == 0x7F && - ((uint8_t *)seq_event_ptr->data.ext.ptr)[2] == 0x7F && /* All devices */ - ((uint8_t *)seq_event_ptr->data.ext.ptr)[3] == 0x06) - { - switch (((char *)seq_event_ptr->data.ext.ptr)[4]) - { - case 1: /* stop */ - if (g_verbose) - printf("MMC Stop -> JACK transport stop\n"); - jack_transport_stop(g_jack_client); - break; - case 2: /* play */ - case 3: /* deferred play */ - if (g_verbose) - printf("MMC Play -> JACK transport start\n"); - jack_transport_start(g_jack_client); - break; - case 5: /* rewind */ - if (g_verbose) - printf("MMC Play -> JACK transport locate to 0\n"); - jack_transport_locate(g_jack_client, 0); - break; - case 0x44: - if (((uint8_t*)seq_event_ptr->data.ext.ptr)[5] == 0x06 && - ((uint8_t*)seq_event_ptr->data.ext.ptr)[6] == 0x01) - { - // some devices call hour 0 "60". Mask off the upper bits - uint8_t hour = ((uint8_t*)seq_event_ptr->data.ext.ptr)[7] & 0x1f; - uint8_t minute = ((uint8_t*)seq_event_ptr->data.ext.ptr)[8]; - uint8_t second = ((uint8_t*)seq_event_ptr->data.ext.ptr)[9]; - uint8_t frame = ((uint8_t*)seq_event_ptr->data.ext.ptr)[10]; - uint8_t subframe = ((uint8_t*)seq_event_ptr->data.ext.ptr)[11]; // percentage of a frame: 0 - 99 - jack_position_t jack_pos; - - if (g_verbose) - printf("MMC locate to hour: %d, minute: %d, second: %d, frame: %d, subframe: %d\n", - hour, - minute, - second, - frame, - subframe); - - // get Jack's current framerate and position - jack_transport_query(g_jack_client, &jack_pos); - const uint32_t jack_frame_rate = jack_pos.frame_rate; - const uint32_t jack_time_ms = (jack_pos.frame * 1000) / jack_frame_rate; - const uint32_t device_time_ms = ((subframe * 10) /g_device_frame_rate + // subframe == 1/100th of a frame - (frame * 1000) / g_device_frame_rate + - (second * 1000) + - (minute * 60 * 1000) + - (hour * 60 * 60 * 1000)); - const uint32_t jitter = (device_time_ms > jack_time_ms ? (device_time_ms - jack_time_ms) : (jack_time_ms - device_time_ms)); - - if (g_verbose) - printf("difference between JACK time and MMC destination time in ms: %d\n", jitter); - - // check if the JACK clock is far enough away from the MMC time to care - if (jitter > g_jitter_tolerance) - { // it is, change it. - jack_pos.valid = 0; // only the frame number will be valid since that's all we're changing - jack_pos.frame = device_time_ms * jack_frame_rate / 1000; - jack_transport_reposition(g_jack_client, &jack_pos); - } - - } - break; - default: - if (g_verbose) - printf("unsupported MMC command: 0x%x\n", ((char *)seq_event_ptr->data.ext.ptr)[4]); - } - } - } - - /* Process LASH events */ - while ((lash_event_ptr = lash_get_event(g_lashc)) != NULL) - { - process_lash_event(lash_event_ptr); - lash_event_destroy(lash_event_ptr); - } - - /* Process LASH configs */ - while ((lash_config_ptr = lash_get_config(g_lashc)) != NULL) - { - process_lash_config(lash_config_ptr); - lash_config_destroy(lash_config_ptr); - } - } - - /* so we shall quit, eh? ok, cleanup time. otherwise jack would probably produce an xrun - * on shutdown */ - jack_deactivate(g_jack_client); - -close_seq: - ret = snd_seq_close(g_seq_ptr); - if (ret < 0) - { - printf("Cannot close sequncer, %s\n", snd_strerror(ret)); - } - -close_jack: - /* shutdown cont. */ - jack_client_close(g_jack_client); - -exit: - if (g_verbose) - printf("exited normally\n"); - return 0; -} +#include +#include +#include + +#include +#include +#include +#include + +snd_seq_t * g_seq_ptr = NULL; +lash_client_t * g_lashc = NULL; +jack_client_t * g_jack_client = NULL; + +// frame rate (frames per second) of the MMC controlling device +uint32_t g_device_frame_rate = 30; // command line equivalent: -f 30 + +// jitter tolerance in milliseconds +uint32_t g_jitter_tolerance = 50; //command line: -t 50 + +int g_verbose = 0; // pass -v on the command line to turn this on + +/* a flag which will be set by our signal handler when it's time to exit */ +int g_quit = 0; + +/* the signal handler */ +void signalled(int signal) +{ + g_quit = 1; +} + +// foward declares +void process_lash_event(lash_event_t * event_ptr); +void process_lash_config(lash_config_t * config_ptr); +int init_alsa_sequencer(); +void init_lash(); +void process_command_line(int argc, char *argv[]); +void cleanup(); + +int main(int argc, char *argv[]) +{ + int ret = 0; + lash_event_t * lash_event_ptr = NULL; + lash_config_t * lash_config_ptr = NULL; + snd_seq_event_t * seq_event_ptr = NULL; + + int npfd; + struct pollfd * pfd; + + // read the jitter tolerance, verbose setting, and device frame rate from command line + process_command_line(argc, argv); + + printf("%s starting with a jitter tolerance of %d milliseconds and a device frame rate of %d per second.\n\n", + argv[0], g_jitter_tolerance, g_device_frame_rate); + + /* setup our signal handler signalled() above, so we can exit cleanly (see end of main()) */ + signal(SIGINT, signalled); + + /* ALSA sequencer initialization */ + ret = init_alsa_sequencer(); + if (ret < 0) + { + printf("Error with alsa sequencer initialization, %s\n", snd_strerror(ret)); + cleanup(); + exit(0); + } + else + { + snd_seq_set_client_name(g_seq_ptr, "jackctlmmc"); + } + + /* naturally we need to become a jack client :) */ + g_jack_client = jack_client_new("jackctlmmc"); + if (!g_jack_client) + { + printf("couldn't connect to jack server. Either it's not running or the client name is already taken\n"); + cleanup(); + exit(0); + } + + init_lash(argc, argv); + + /* tell jack that we are ready to do our thing */ + jack_activate(g_jack_client); + + npfd = snd_seq_poll_descriptors_count(g_seq_ptr, POLLIN); + pfd = (struct pollfd *)alloca(npfd * sizeof(struct pollfd)); + snd_seq_poll_descriptors(g_seq_ptr, pfd, npfd, POLLIN); + + /* wait until this app receives a SIGINT (i.e. press ctrl-c in the terminal) see signalled() above */ + while(!g_quit) + { + if (poll(pfd, npfd, 250) > 0 && snd_seq_event_input(g_seq_ptr, &seq_event_ptr) >= 0) + { + if (seq_event_ptr->type == SND_SEQ_EVENT_SYSEX && + ((uint8_t *)seq_event_ptr->data.ext.ptr)[0] == 0xF0 && + ((uint8_t *)seq_event_ptr->data.ext.ptr)[1] == 0x7F && + ((uint8_t *)seq_event_ptr->data.ext.ptr)[2] == 0x7F && /* All devices */ + ((uint8_t *)seq_event_ptr->data.ext.ptr)[3] == 0x06) + { + switch (((char *)seq_event_ptr->data.ext.ptr)[4]) + { + case 1: /* stop */ + if (g_verbose) + printf("MMC Stop -> JACK transport stop\n"); + jack_transport_stop(g_jack_client); + break; + case 2: /* play */ + case 3: /* deferred play */ + if (g_verbose) + printf("MMC Play -> JACK transport start\n"); + jack_transport_start(g_jack_client); + break; + case 5: /* rewind */ + if (g_verbose) + printf("MMC Play -> JACK transport locate to 0\n"); + jack_transport_locate(g_jack_client, 0); + break; + case 0x44: + if (((uint8_t*)seq_event_ptr->data.ext.ptr)[5] == 0x06 && + ((uint8_t*)seq_event_ptr->data.ext.ptr)[6] == 0x01) + { + // some devices call hour 0 "60". Mask off the upper bits + uint8_t hour = ((uint8_t*)seq_event_ptr->data.ext.ptr)[7] & 0x1f; + uint8_t minute = ((uint8_t*)seq_event_ptr->data.ext.ptr)[8]; + uint8_t second = ((uint8_t*)seq_event_ptr->data.ext.ptr)[9]; + uint8_t frame = ((uint8_t*)seq_event_ptr->data.ext.ptr)[10]; + uint8_t subframe = ((uint8_t*)seq_event_ptr->data.ext.ptr)[11]; // percentage of a frame: 0 - 99 + jack_position_t jack_pos; + + if (g_verbose) + printf("MMC locate to hour: %d, minute: %d, second: %d, frame: %d, subframe: %d\n", + hour, + minute, + second, + frame, + subframe); + + // get Jack's current framerate and position + jack_transport_query(g_jack_client, &jack_pos); + const uint32_t jack_frame_rate = jack_pos.frame_rate; + const uint32_t jack_time_ms = (jack_pos.frame * 1000) / jack_frame_rate; + const uint32_t device_time_ms = ((subframe * 10) /g_device_frame_rate + // subframe == 1/100th of a frame + (frame * 1000) / g_device_frame_rate + + (second * 1000) + + (minute * 60 * 1000) + + (hour * 60 * 60 * 1000)); + const uint32_t jitter = (device_time_ms > jack_time_ms ? (device_time_ms - jack_time_ms) : (jack_time_ms - device_time_ms)); + + if (g_verbose) + printf("difference between JACK time and MMC destination time in ms: %d\n", jitter); + + // check if the JACK clock is far enough away from the MMC time to care + if (jitter > g_jitter_tolerance) + { // it is, change it. + jack_pos.valid = 0; // only the frame number will be valid since that's all we're changing + jack_pos.frame = device_time_ms * jack_frame_rate / 1000; + jack_transport_reposition(g_jack_client, &jack_pos); + } + + } + break; + default: + if (g_verbose) + printf("unsupported MMC command: 0x%x\n", ((char *)seq_event_ptr->data.ext.ptr)[4]); + } + } + } + + /* Process LASH events */ + while ((lash_event_ptr = lash_get_event(g_lashc)) != NULL) + { + process_lash_event(lash_event_ptr); + lash_event_destroy(lash_event_ptr); + } + + /* Process LASH configs */ + while ((lash_config_ptr = lash_get_config(g_lashc)) != NULL) + { + process_lash_config(lash_config_ptr); + lash_config_destroy(lash_config_ptr); + } + } + + /* so we shall quit, eh? ok, cleanup time. otherwise jack would probably produce an xrun + * on shutdown */ + jack_deactivate(g_jack_client); + cleanup(); + + if (g_verbose) + printf("exited normally\n"); + return 0; +} + +int init_alsa_sequencer() +{ + snd_seq_port_info_t * seq_port_info = NULL; + int ret = 0; + + /* ALSA sequencer initialisation */ + ret = snd_seq_open( &g_seq_ptr, "default", SND_SEQ_OPEN_INPUT, 0); + if (ret < 0) + { + return ret; + } + + // setup alsa sequencer port + snd_seq_port_info_alloca(&seq_port_info); + snd_seq_port_info_set_capability(seq_port_info, SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE); + snd_seq_port_info_set_type( seq_port_info, SND_SEQ_PORT_TYPE_APPLICATION); + snd_seq_port_info_set_midi_channels(seq_port_info, 16); + snd_seq_port_info_set_port_specified(seq_port_info, 1); + snd_seq_port_info_set_name(seq_port_info, "midi in"); + snd_seq_port_info_set_port(seq_port_info, 0); + + return snd_seq_create_port(g_seq_ptr, seq_port_info); +} + +void init_lash(int argc, char* argv[]) +{ + lash_event_t * lash_event_ptr = NULL; + + /* LASH setup */ + g_lashc = lash_init( lash_extract_args(&argc, &argv), "jackctlmmc", 0, LASH_PROTOCOL_VERSION); + + if (g_lashc == NULL) + { + printf("Failed to connect to LASH. Session management will not occur.\n"); + } + else + { + lash_event_ptr = lash_event_new_with_type(LASH_Client_Name); + lash_event_set_string(lash_event_ptr, "jackctlmmc"); + lash_send_event(g_lashc, lash_event_ptr); + } + + // register JACK and ALSA clients with lash + lash_alsa_client_id(g_lashc, snd_seq_client_id(g_seq_ptr)); + lash_jack_client_name(g_lashc, "jackctlmmc"); +} + +void process_lash_event(lash_event_t * event_ptr) +{ + enum LASH_Event_Type type; + const char * str; + + type = lash_event_get_type(event_ptr); + str = lash_event_get_string(event_ptr); + + switch (type) + { + case LASH_Quit: + printf("LASH_Quit received.\n"); + g_lashc = NULL; + g_quit = 1; + break; + case LASH_Save_File: + case LASH_Restore_File: + case LASH_Save_Data_Set: + default: + printf("LASH Event. Type = %u, string = \"%s\"\n", + (unsigned int)type, + (str == NULL)?"":str); + } +} + +void process_lash_config(lash_config_t * config_ptr) +{ + const char * key; + const void * data; + size_t data_size; + + key = lash_config_get_key(config_ptr); + data = lash_config_get_value(config_ptr); + data_size = lash_config_get_value_size(config_ptr); + + printf("LASH Config. Key = \"%s\"\n", key); +} + +void process_command_line(int argc, char *argv[]) +{ + int parameter; + while ((parameter = getopt(argc, argv, "f:t:v")) != -1) + { + switch (parameter) + { + case 'v': + g_verbose = 1; + break; + case 'f': + g_device_frame_rate = atoi(optarg); + break; + case 't': + g_jitter_tolerance = atoi(optarg); + break; + case '?': + fprintf(stderr, "usage: %s -f -t \n", argv[0]); + exit(1); + break; + } + } +} + +void cleanup() +{ + printf("cleaning up\n"); + int ret = 0; + if (g_seq_ptr) + { + ret = snd_seq_close(g_seq_ptr); + if (ret < 0) + { + printf("Cannot close sequncer, %s\n", snd_strerror(ret)); + } + } + + if (g_jack_client) + { + jack_client_close(g_jack_client); + } +} -- 2.11.4.GIT