static struct libusb_transfer *noct_read_xfer;
static bool noct_read_pending;
+char noct_rotary_touched[10];
+char noct_button_pressed[16];
static void noct_read_done(struct libusb_transfer *xfer)
{
if (arg < 0x80)
{
DBG("Noct: Slider value = %d", arg);
+ notify_rotary(9, arg);
continue;
}
break;
{
int state = !!arg;
DBG("Noct: Center touch = %d", state);
+ noct_rotary_touched[8] = state;
+ notify_touch(8, state);
continue;
}
break;
{
int state = !!arg;
DBG("Noct: Slider touch = %d", state);
+ noct_rotary_touched[9] = state;
+ notify_touch(9, state);
continue;
}
break;
int r = cmd - 0x60;
int state = !!arg;
DBG("Noct: Rotary %d touch = %d", r, state);
+ noct_rotary_touched[r] = state;
+ notify_touch(r, state);
continue;
}
break;
int b = cmd - 0x70;
int state = !!arg;
DBG("Noct: Button %d = %d", b, state);
+ noct_button_pressed[b] = state;
notify_button(b, state);
continue;
}
noct_read_pending = 1;
}
-static byte noct_button_state[16];
+static byte noct_button_light[16];
static byte noct_ring_mode[8]; // RING_MODE_xxx
static byte noct_ring_val[9];
{
int i = bit_ffs(noct_dirty_button);
noct_dirty_button ^= 1U << i;
- noct_do_write(0x70 + i, noct_button_state[i]);
+ noct_do_write(0x70 + i, noct_button_light[i]);
}
else if (noct_dirty_ring_mode)
{
{
ASSERT(button >= 0 && button < 16);
ASSERT(val == 0 || val == 1);
- if (noct_button_state[button] != val)
+ if (noct_button_light[button] != val)
{
- noct_button_state[button] = val;
+ noct_button_light[button] = val;
noct_dirty_button |= 1U << button;
noct_sched_write();
}
noct_write_xfer = libusb_alloc_transfer(0);
libusb_fill_interrupt_transfer(noct_write_xfer, usb_dev, 0x02, xmalloc(8), 0, noct_write_done, NULL, 1000);
+ bzero(noct_button_pressed, sizeof(noct_button_pressed));
+ bzero(noct_rotary_touched, sizeof(noct_rotary_touched));
noct_dirty_button = 0xffff;
noct_dirty_ring_mode = 0xff;
noct_dirty_ring_val = 0x1ff;
PULSE_ASYNC_RUN(pa_context_set_sink_input_mute, idx, mute, pulse_success_cb);
}
+void pulse_sink_input_move(int input_idx, int sink_idx)
+{
+ PULSE_ASYNC_RUN(pa_context_move_sink_input_by_index, input_idx, sink_idx, pulse_success_cb);
+}
+
/*** Sinks ***/
#define HASH_NODE struct pulse_sink
return NULL;
}
+struct pulse_sink *pulse_sink_by_idx(int idx)
+{
+ return pulse_sink_lookup(idx);
+}
+
void pulse_sink_set_volume(int idx, pa_cvolume *cvol)
{
PULSE_ASYNC_RUN(pa_context_set_sink_volume_by_index, idx, cvol, pulse_success_cb);
}
}
+static int find_touched_client(void)
+{
+ int touched = -1;
+
+ for (uns i=0; i < NUM_CLIENTS; i++)
+ if (noct_rotary_touched[client_map[i].rotary])
+ {
+ if (touched >= 0)
+ return -1;
+ touched = i;
+ }
+ return touched;
+}
+
/*** Default sink controls ***/
+static const char *get_client_sink(int i)
+{
+ const char *sink = NULL;
+
+ CLIST_FOR_EACH(struct pulse_sink_input *, s, pulse_sink_input_list)
+ if (s->noct_client_idx == i)
+ {
+ struct pulse_sink *sk = (s->sink_idx >= 0) ? pulse_sink_by_idx(s->sink_idx) : NULL;
+ const char *ss = sk ? sk->name : NULL;
+ if (!sink)
+ sink = ss;
+ else if (strcmp(sink, ss))
+ sink = "?";
+ }
+ return sink ? : "?";
+}
+
static void update_default_sink(void)
{
- const char *def = pulse_default_sink_name ? : "?";
- if (!strcmp(def, "ursarium"))
+ int i = find_touched_client();
+ const char *sink;
+ if (i >= 0)
+ sink = get_client_sink(i);
+ else
+ sink = pulse_default_sink_name ? : "?";
+
+ if (!strcmp(sink, "ursarium"))
{
noct_set_button(8, 1);
noct_set_button(9, 0);
}
- else if (!strcmp(def, "catarium"))
+ else if (!strcmp(sink, "catarium"))
{
noct_set_button(8, 0);
noct_set_button(9, 1);
if (!on)
return;
- const char *def = pulse_default_sink_name ? : "?";
+ int i = find_touched_client();
+ const char *sink;
+ if (i >= 0)
+ sink = get_client_sink(i);
+ else
+ sink = pulse_default_sink_name ? : "?";
+
const char *switch_to = NULL;
if (button == 8)
{
- if (!strcmp(def, "ursarium"))
+ if (!strcmp(sink, "ursarium"))
switch_to = "burrow";
else
switch_to = "ursarium";
}
else if (button == 9)
{
- if (!strcmp(def, "catarium"))
+ if (!strcmp(sink, "catarium"))
switch_to = "burrow";
else
switch_to = "catarium";
if (!switch_to)
return;
- DBG("Switching default sink to %s", switch_to);
- pulse_server_set_default_sink(switch_to);
+ if (i >= 0)
+ {
+ struct pulse_sink *sk = pulse_sink_by_name(switch_to);
+ if (!sk)
+ return;
+
+ CLIST_FOR_EACH(struct pulse_sink_input *, s, pulse_sink_input_list)
+ if (s->noct_client_idx == i)
+ {
+ DBG("Moving input #%d to sink #%d", s->idx, sk->idx);
+ pulse_sink_input_move(s->idx, sk->idx);
+ }
+ }
+ else
+ {
+ DBG("Switching default sink to %s", switch_to);
+ pulse_server_set_default_sink(switch_to);
+ }
}
/*** Main update routines ***/
}
}
+void notify_touch(int rotary, int on UNUSED)
+{
+ if (pulse_state != PS_ONLINE)
+ {
+ DBG("## NOTIFY: Pulse is not online");
+ return;
+ }
+
+ // Rotary touches switch meaning of LEDs, this is handled inside display updates
+ if (rotary >= 4 && rotary < 8)
+ schedule_update();
+}
+
/*** Main entry point ***/
int main(int argc UNUSED, char **argv)
void schedule_update(void);
void notify_rotary(int rotary, int delta);
+void notify_touch(int rotary, int on);
void notify_button(int button, int on);
/* nocturn.c */
void noct_set_ring(int ring, int mode, int val);
void noct_set_button(int button, int val);
+extern char noct_rotary_touched[10]; // 8=center, 9=slider
+extern char noct_button_pressed[16];
+
enum ring_mode {
RING_MODE_LEFT,
RING_MODE_RIGHT,
void pulse_init(void);
void pulse_dump(void);
struct pulse_sink *pulse_sink_by_name(const char *name);
+struct pulse_sink *pulse_sink_by_idx(int idx);
void pulse_sink_set_volume(int idx, pa_cvolume *cvol);
void pulse_sink_set_mute(int idx, bool mute);
void pulse_sink_input_set_volume(int idx, pa_cvolume *cvol);
void pulse_sink_input_set_mute(int idx, bool mute);
+void pulse_sink_input_move(int input_idx, int sink_idx);
struct pulse_client *pulse_client_by_idx(int idx);
void pulse_server_set_default_sink(const char *name);