Skip to content

Instantly share code, notes, and snippets.

@jamesb93
Created September 28, 2025 13:29
Show Gist options
  • Select an option

  • Save jamesb93/d5662bb757dc1d678cf3b874d9e48d86 to your computer and use it in GitHub Desktop.

Select an option

Save jamesb93/d5662bb757dc1d678cf3b874d9e48d86 to your computer and use it in GitHub Desktop.
#include "ext.h"
#include "ext_obex.h"
#include "ext_time.h"
typedef struct _note_state t_note_state;
typedef struct _note_debounce {
t_object x_obj;
double threshold;
void *out_midi;
t_note_state *note_states[128];
} t_note_debounce;
struct _note_state {
t_note_debounce *owner;
long pitch;
long velocity;
t_clock *clock;
char is_pending;
};
void *note_debounce_new(t_symbol *s, long argc, t_atom *argv);
void note_debounce_free(t_note_debounce *x);
void note_debounce_assist(t_note_debounce *x, void *b, long m, long a, char *s);
void note_debounce_list(t_note_debounce *x, t_symbol *s, long argc, t_atom *argv);
void note_debounce_clock_tick(t_note_state *note_state);
static t_class *s_note_debounce_class;
void ext_main(void *r) {
t_class *c = class_new("note.debounce", (method)note_debounce_new, (method)note_debounce_free,
(long)sizeof(t_note_debounce), 0L, A_GIMME, 0);
class_addmethod(c, (method)note_debounce_list, "list", A_GIMME, 0);
class_addmethod(c, (method)note_debounce_assist, "assist", A_CANT, 0);
CLASS_ATTR_DOUBLE(c, "threshold", 0, t_note_debounce, threshold);
CLASS_ATTR_LABEL(c, "threshold", 0, "Debounce Threshold (ms)");
CLASS_ATTR_FILTER_MIN(c, "threshold", 0.0);
CLASS_ATTR_DEFAULT(c, "threshold", 0, "50.0");
CLASS_ATTR_STYLE_LABEL(c, "threshold", 0, "text", "Threshold:");
class_register(CLASS_BOX, c);
s_note_debounce_class = c;
}
void *note_debounce_new(t_symbol *s, long argc, t_atom *argv) {
t_note_debounce *x = (t_note_debounce *)object_alloc(s_note_debounce_class);
if (!x) {
return NULL;
}
x->out_midi = listout((t_object *)x);
for (int i = 0; i < 128; i++) {
t_note_state *ns = (t_note_state *)sysmem_newptr(sizeof(t_note_state));
if (ns) {
ns->owner = x;
ns->pitch = i;
ns->velocity = 0;
ns->is_pending = 0;
ns->clock = clock_new(ns, (method)note_debounce_clock_tick);
x->note_states[i] = ns;
} else {
object_error((t_object *)x, "failed to allocate memory for note state %d", i);
x->note_states[i] = NULL;
}
}
attr_args_process(x, argc, argv);
return x;
}
void note_debounce_free(t_note_debounce *x) {
for (int i = 0; i < 128; i++) {
if (x->note_states[i]) {
clock_free(x->note_states[i]->clock);
sysmem_freeptr(x->note_states[i]);
}
}
}
void note_debounce_assist(t_note_debounce *x, void *b, long m, long a, char *s) {
if (m == ASSIST_INLET) {
switch (a) {
case 0: snprintf(s, 256, "(list) MIDI Note (pitch, velocity)"); break;
}
} else {
snprintf(s, 256, "(list) Debounced MIDI Note");
}
}
void note_debounce_list(t_note_debounce *x, t_symbol *s, long argc, t_atom *argv) {
if (argc < 2) {
object_warn((t_object *)x, "list must contain at least pitch and velocity");
return;
}
long pitch = atom_getlong(argv);
long velocity = atom_getlong(argv + 1);
if (pitch < 0 || pitch > 127) {
object_warn((t_object *)x, "pitch %ld is out of MIDI range (0-127)", pitch);
return;
}
t_note_state *note = x->note_states[pitch];
if (!note) return;
if (velocity > 0) {
if (note->is_pending) {
clock_unset(note->clock);
}
note->velocity = velocity;
note->is_pending = 1;
clock_delay(note->clock, x->threshold);
} else {
if (note->is_pending) {
clock_unset(note->clock);
note->is_pending = 0;
note->velocity = 0;
} else {
t_atom out_atoms[2];
atom_setlong(&out_atoms[0], pitch);
atom_setlong(&out_atoms[1], 0);
outlet_list(x->out_midi, NULL, 2, out_atoms);
note->velocity = 0;
}
}
}
void note_debounce_clock_tick(t_note_state *note_state) {
if (!note_state) return;
if (note_state->is_pending) {
note_state->is_pending = 0;
t_note_debounce *x = note_state->owner;
t_atom out_atoms[2];
atom_setlong(&out_atoms[0], note_state->pitch);
atom_setlong(&out_atoms[1], note_state->velocity);
outlet_list(x->out_midi, NULL, 2, out_atoms);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment