Browse Source

Add start of OSC output

master
cancel 6 years ago
parent
commit
18e8675003
  1. 103
      osc_out.c
  2. 15
      osc_out.h
  3. 2
      tool
  4. 53
      tui_main.c

103
osc_out.c

@ -0,0 +1,103 @@
#include "osc_out.h"
//#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
struct Oosc_dev {
int fd;
struct sockaddr_in addr;
};
Oosc_udp_create_error oosc_dev_create_udp(Oosc_dev** out_ptr, U16 port) {
int udpfd = socket(AF_INET, SOCK_DGRAM, 0);
if (udpfd < 0) {
fprintf(stderr, "Failed to open UDP socket, error number: %d\n", errno);
return Oosc_udp_create_error_couldnt_open_socket;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons((U16)port);
Oosc_dev* dev = malloc(sizeof(Oosc_dev));
dev->fd = udpfd;
dev->addr = addr;
*out_ptr = dev;
return Oosc_udp_create_error_ok;
}
void oosc_dev_destroy(Oosc_dev* dev) {
close(dev->fd);
free(dev);
}
void oosc_send_datagram(Oosc_dev* dev, char const* data, Usz size) {
ssize_t res = sendto(dev->fd, data, size, 0, (struct sockaddr*)&dev->addr,
sizeof(dev->addr));
if (res < 0) {
fprintf(stderr, "UDP message send failed\n");
exit(1);
}
}
static bool oosc_write_strn(char* restrict buffer, Usz buffer_size,
Usz* buffer_pos, char const* restrict in_str,
Usz in_str_len) {
// no overflow check, should be fine
Usz in_plus_null = in_str_len + 1;
Usz null_pad = in_plus_null % 4;
Usz needed = in_plus_null + null_pad;
Usz cur_pos = *buffer_pos;
if (cur_pos + needed >= buffer_size)
return false;
for (Usz i = 0; i < in_str_len; ++i) {
buffer[cur_pos + i] = in_str[i];
}
buffer[cur_pos + in_str_len] = 0;
cur_pos += in_str_len;
for (Usz i = 0; i < null_pad; ++i) {
buffer[cur_pos + i] = 0;
}
*buffer_pos = cur_pos + null_pad;
return true;
}
void oosc_send_int32s(Oosc_dev* dev, char const* osc_address, I32 const* vals,
Usz count) {
char buffer[2048];
Usz buf_pos = 0;
if (!oosc_write_strn(buffer, sizeof(buffer), &buf_pos, osc_address,
strlen(osc_address)))
return;
Usz typetag_str_size = 1 + count + 1; // comma, 'i'... , null
Usz typetag_str_null_pad = typetag_str_size % 4;
if (buf_pos + typetag_str_size + typetag_str_null_pad > sizeof(buffer))
return;
buffer[buf_pos] = ',';
++buf_pos;
for (Usz i = 0; i < count; ++i) {
buffer[buf_pos + i] = 'i';
}
buffer[buf_pos + count] = 0;
buf_pos += count + 1;
for (Usz i = 0; i < typetag_str_null_pad; ++i) {
buffer[buf_pos + i] = 0;
}
buf_pos += typetag_str_null_pad;
Usz ints_size = count * sizeof(I32);
if (buf_pos + ints_size > sizeof(buffer))
return;
for (Usz i = 0; i < count; ++i) {
union {
I32 i;
U32 u;
} pun;
pun.i = vals[i];
U32 u_ne = htonl(pun.u);
memcpy(buffer + buf_pos, &u_ne, sizeof(u_ne));
}
buf_pos += count;
oosc_send_datagram(dev, buffer, buf_pos);
}

15
osc_out.h

@ -0,0 +1,15 @@
#include "base.h"
typedef struct Oosc_dev Oosc_dev;
typedef enum {
Oosc_udp_create_error_ok = 0,
Oosc_udp_create_error_couldnt_open_socket = 1,
} Oosc_udp_create_error;
Oosc_udp_create_error oosc_dev_create_udp(Oosc_dev** out_dev_ptr, U16 port);
void oosc_dev_destroy(Oosc_dev* dev);
// raw UDP datagram
void oosc_send_datagram(Oosc_dev* dev, char const* data, Usz size);
void oosc_send_int32s(Oosc_dev* dev, char const* osc_address, I32 const* vals,
Usz count);

2
tool

@ -226,7 +226,7 @@ build_target() {
out_exe=cli out_exe=cli
;; ;;
orca|tui) orca|tui)
add source_files tui_main.c add source_files osc_out.c tui_main.c
add cc_flags -D_XOPEN_SOURCE_EXTENDED=1 add cc_flags -D_XOPEN_SOURCE_EXTENDED=1
# thirdparty headers (like sokol_time.h) should get -isystem for their # thirdparty headers (like sokol_time.h) should get -isystem for their
# include dir so that any warnings they generate with our warning flags # include dir so that any warnings they generate with our warning flags

53
tui_main.c

@ -3,6 +3,7 @@
#include "field.h" #include "field.h"
#include "gbuffer.h" #include "gbuffer.h"
#include "mark.h" #include "mark.h"
#include "osc_out.h"
#include "sim.h" #include "sim.h"
#include <getopt.h> #include <getopt.h>
#include <locale.h> #include <locale.h>
@ -18,10 +19,14 @@ static void usage() {
// clang-format off // clang-format off
fprintf(stderr, fprintf(stderr,
"Usage: orca [options] [file]\n\n" "Usage: orca [options] [file]\n\n"
"Options:\n" "General options:\n"
" --margins <number> Set cosmetic margins.\n" " --margins <number> Set cosmetic margins.\n"
" Default: 2\n" " Default: 2\n"
" -h or --help Print this message and exit.\n" " -h or --help Print this message and exit.\n"
"\n"
"OSC options:\n"
" --osc-port <number> UDP Port to send OSC messages to\n"
" Default: none\n"
); );
// clang-format on // clang-format on
} }
@ -471,6 +476,7 @@ typedef struct {
Usz bpm; Usz bpm;
double accum_secs; double accum_secs;
char const* filename; char const* filename;
Oosc_dev* oosc_dev;
bool needs_remarking; bool needs_remarking;
bool is_draw_dirty; bool is_draw_dirty;
bool is_playing; bool is_playing;
@ -494,6 +500,7 @@ void app_init(App_state* a) {
a->bpm = 120; a->bpm = 120;
a->accum_secs = 0.0; a->accum_secs = 0.0;
a->filename = NULL; a->filename = NULL;
a->oosc_dev = NULL;
a->needs_remarking = true; a->needs_remarking = true;
a->is_draw_dirty = false; a->is_draw_dirty = false;
a->is_playing = false; a->is_playing = false;
@ -508,6 +515,9 @@ void app_deinit(App_state* a) {
undo_history_deinit(&a->undo_hist); undo_history_deinit(&a->undo_hist);
oevent_list_deinit(&a->oevent_list); oevent_list_deinit(&a->oevent_list);
oevent_list_deinit(&a->scratch_oevent_list); oevent_list_deinit(&a->scratch_oevent_list);
if (a->oosc_dev) {
oosc_dev_destroy(a->oosc_dev);
}
} }
bool app_is_draw_dirty(App_state* a) { bool app_is_draw_dirty(App_state* a) {
@ -532,6 +542,18 @@ void app_apply_delta_secs(App_state* a, double secs) {
} }
} }
bool app_set_osc_udp_port(App_state* a, U16 port) {
if (a->oosc_dev) {
oosc_dev_destroy(a->oosc_dev);
a->oosc_dev = NULL;
}
Oosc_udp_create_error err = oosc_dev_create_udp(&a->oosc_dev, port);
if (err) {
return false;
}
return true;
}
void app_do_stuff(App_state* a) { void app_do_stuff(App_state* a) {
double secs_span = 60.0 / (double)a->bpm / 4.0; double secs_span = 60.0 / (double)a->bpm / 4.0;
while (a->accum_secs > secs_span) { while (a->accum_secs > secs_span) {
@ -743,15 +765,20 @@ void app_input_cmd(App_state* a, App_input_cmd ev) {
} }
} }
enum { Argopt_margins = UCHAR_MAX + 1 }; enum {
Argopt_margins = UCHAR_MAX + 1,
Argopt_osc_port,
};
int main(int argc, char** argv) { int main(int argc, char** argv) {
static struct option tui_options[] = { static struct option tui_options[] = {
{"margins", required_argument, 0, Argopt_margins}, {"margins", required_argument, 0, Argopt_margins},
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"osc-port", required_argument, 0, Argopt_osc_port},
{NULL, 0, NULL, 0}}; {NULL, 0, NULL, 0}};
char* input_file = NULL; char* input_file = NULL;
int margin_thickness = 2; int margin_thickness = 2;
U16 osc_port = 0;
for (;;) { for (;;) {
int c = getopt_long(argc, argv, "h", tui_options, NULL); int c = getopt_long(argc, argv, "h", tui_options, NULL);
if (c == -1) if (c == -1)
@ -760,7 +787,7 @@ int main(int argc, char** argv) {
case 'h': case 'h':
usage(); usage();
return 0; return 0;
case Argopt_margins: case Argopt_margins: {
margin_thickness = atoi(optarg); margin_thickness = atoi(optarg);
if (margin_thickness == 0 && strcmp(optarg, "0")) { if (margin_thickness == 0 && strcmp(optarg, "0")) {
fprintf(stderr, fprintf(stderr,
@ -769,7 +796,18 @@ int main(int argc, char** argv) {
optarg); optarg);
return 1; return 1;
} }
break; } break;
case Argopt_osc_port: {
int osc_port0 = atoi(optarg);
if (osc_port0 <= 0) {
fprintf(stderr, "OSC port must be greater than 0.\n");
return 1;
} else if (osc_port0 > UINT16_MAX) {
fprintf(stderr, "OSC port must be <= %d\n", (int)UINT16_MAX);
return 1;
}
osc_port = (U16)osc_port0;
} break;
case '?': case '?':
usage(); usage();
return 1; return 1;
@ -792,6 +830,13 @@ int main(int argc, char** argv) {
App_state app_state; App_state app_state;
app_init(&app_state); app_init(&app_state);
if (osc_port != 0) {
if (!app_set_osc_udp_port(&app_state, osc_port)) {
fprintf(stderr, "Failed to open OSC UDP port %d\n", (int)osc_port);
exit(1);
}
}
if (input_file) { if (input_file) {
Field_load_error fle = field_load_file(input_file, &app_state.field); Field_load_error fle = field_load_file(input_file, &app_state.field);
if (fle != Field_load_error_ok) { if (fle != Field_load_error_ok) {

Loading…
Cancel
Save