Modules Reference
This document describes each module in PolyBoard, its responsibilities, and key functions.
app.c - Application Entry Point
Section titled “app.c - Application Entry Point”The main module that handles SDK callbacks and routes events to appropriate handlers.
Key Callbacks
Section titled “Key Callbacks”// Called once at startupvoid app_init(const u16 *adc_raw);
// Called every 1msvoid app_timer_event(void);
// Called on button/pad press/releasevoid app_surface_event(u8 type, u8 index, u8 value);
// Called on pad pressure changevoid app_aftertouch_event(u8 index, u8 value);
// Called on MIDI input (not used)void app_midi_event(u8 port, u8 status, u8 d1, u8 d2);Event Routing
Section titled “Event Routing”void app_surface_event(u8 type, u8 index, u8 value) { // Setup button toggles setup mode if (type == TYPESETUP) { ... }
// Mode buttons (Circle, Double) work in all modes if (index == BTN_CIRCLE) { ... } if (index == BTN_DOUBLE) { ... }
// Route to mode-specific handler switch (get_mode()) { case MODE_PLAY: handle_play_mode(index, value); break; case MODE_ROOT_SELECT: handle_root_select(index, value); break; case MODE_SCALE_SELECT: handle_scale_select(index, value); break; case MODE_SETUP: handle_setup_mode(index, value); break; }}MIDI Sending
Section titled “MIDI Sending”static void send_note_on(unsigned short channels, u8 note, u8 velocity) { for (u8 ch = 0; ch < 16; ch++) { if (channels & (1 << ch)) { u8 status = NOTEON | ch; hal_send_midi(USBSTANDALONE, status, note, velocity); hal_send_midi(USBMIDI, status, note, velocity); hal_send_midi(DINMIDI, status, note, velocity); } }}app_state.c - Runtime State
Section titled “app_state.c - Runtime State”Manages volatile runtime state that doesn’t persist across power cycles.
State Structure
Section titled “State Structure”typedef struct AppState { AppMode mode; // MODE_PLAY, MODE_ROOT_SELECT, etc. unsigned char active_notes[16]; // 128-bit bitmask for MIDI notes unsigned char dirty; // Flash needs saving unsigned char held_page; // Which page button is held (0xFF = none) unsigned char held_shift; // Shift button state unsigned char held_arrow_left; unsigned char held_arrow_right; unsigned char scale_lock; // Global (not per-page) unsigned char in_setup_mode; unsigned char pad_notes[100]; // Maps pad index to MIDI note} AppState;Note Tracking
Section titled “Note Tracking”Active notes are tracked with a 128-bit bitmask (16 bytes):
void set_note_active(unsigned char note) { g_state.active_notes[note / 8] |= (1 << (note % 8));}
void clear_note_active(unsigned char note) { g_state.active_notes[note / 8] &= ~(1 << (note % 8));}
unsigned char is_note_active(unsigned char note) { return (g_state.active_notes[note / 8] >> (note % 8)) & 1;}Pad-to-Note Mapping
Section titled “Pad-to-Note Mapping”Maps each pad to its currently playing MIDI note:
void set_pad_note(unsigned char index, unsigned char note);unsigned char get_pad_note(unsigned char index); // Returns 0xFF if inactivevoid clear_pad_note(unsigned char index);page.c - Page Management
Section titled “page.c - Page Management”Manages the four configurable pages, each with independent settings.
Page Structure
Section titled “Page Structure”typedef struct Page { unsigned char root; // 0-11 (C=0, C#=1, ... B=11) unsigned char scale_type; // 0-9 (see note.h) unsigned char octave; // 0-10 unsigned char interval_index; // 0-3 → [3, 4, 5, 7] semitones unsigned short midi_channels; // Bitmask: bit 0 = ch1, bit 15 = ch16 unsigned char aftertouch_mode; // 0=channel, 1=poly unsigned char velocity_curve; // 0=linear, 1=soft, 2=hard, 3=fixed signed char transpose; // -7 to +7 scale degrees} Page;Key Functions
Section titled “Key Functions”// Change active page (0-3)const Page *change_page(unsigned char page);
// Get page by indexconst Page *get_page(unsigned char page);
// Get current page indexunsigned char get_current_page();
// Copy settings between pagesvoid copy_page(unsigned char from, unsigned char to);// Musical settingsvoid change_page_root(unsigned char root);void change_page_scale_type(unsigned char scale_type);void change_page_octave(unsigned char octave);void change_page_interval(unsigned char interval_index);
// Transposevoid increase_page_transpose(void);void decrease_page_transpose(void);void reset_page_transpose(void);
// MIDI settingsvoid toggle_page_midi_channel(unsigned char channel);void set_page_midi_channels(unsigned short channels);void toggle_page_aftertouch_mode(void);void set_page_velocity_curve(unsigned char curve);Intervals
Section titled “Intervals”Four row intervals available:
| Index | Semitones | Interval Name |
|---|---|---|
| 0 | 3 | Minor 3rd |
| 1 | 4 | Major 3rd |
| 2 | 5 | Perfect 4th (default) |
| 3 | 7 | Perfect 5th |
note.c - Scale & Note Calculations
Section titled “note.c - Scale & Note Calculations”Handles scale definitions and note calculations.
Scale Definitions
Section titled “Scale Definitions”// 10 scales availableenum ScaleIndex { SCALE_MAJOR, SCALE_MINOR, SCALE_PENT_MAJOR, SCALE_PENT_MINOR, SCALE_DORIAN, SCALE_MIXOLYDIAN, SCALE_HARMONIC_MINOR, SCALE_BLUES, SCALE_LYDIAN, SCALE_PHRYGIAN};
// Scale membership: 1=root, 0=in scale, -1=chromaticstatic const short scales[SCALE_COUNT][12] = { // Major: W W H W W W H {1, -1, 0, -1, 0, 0, -1, 0, -1, 0, -1, 0}, // ... etc};Scale Membership Check
Section titled “Scale Membership Check”short is_note_in_scale(unsigned char note, unsigned char root, int scale_index);// Returns: 1 = root note, 0 = in scale, -1 = chromaticScale-Relative Transposition
Section titled “Scale-Relative Transposition”int transpose_semitone_by_degree(int semitone_offset, unsigned char scale_index, signed char transpose);This function:
- Converts semitone offset to scale degree
- Adds transpose value
- Converts back to semitones
- Handles octave wrapping
layout.c - LED Rendering
Section titled “layout.c - LED Rendering”Manages all LED output and visual feedback.
LED Cache
Section titled “LED Cache”Dirty-region tracking to minimize HAL calls:
#define LED_CACHE_INVALID 0xFFFFFFFFUstatic u32 led_cache[GRID_SIZE];static volatile u8 render_pending;
void set_pad_color(u8 index, u32 color) { if (led_cache[index] != color) { led_cache[index] = color; PLOT_LED_FAST(TYPEPAD, index, color); }}Rendering Functions
Section titled “Rendering Functions”// Full display refresh based on current modevoid refresh_display(void);
// Mode-specific renderersvoid render_play_grid(const Page *page);void render_controls(unsigned char page, unsigned char interval, signed char transpose, unsigned char octave);void render_root_select(unsigned char current_root);void render_scale_select(unsigned char current_scale);void render_setup_grid(const Page *page);
// Single pad update (more efficient for note on/off)void update_pad_color(u8 index, const Page *page);Deferred Rendering
Section titled “Deferred Rendering”// Request render on next timer tickvoid request_render(void);
// Process pending render (called from app_timer_event)void process_pending_render(void);
// Force full refresh (e.g., on mode change)void invalidate_led_cache(void);Color Constants
Section titled “Color Constants”// Note colors#define COLOR_ROOT 0x3F003FU // Full magenta (root note)#define COLOR_IN_SCALE 0x0F000FU // Dim magenta (in scale)#define COLOR_CHROMATIC 0x0F0F0FU // Dim white (chromatic)#define COLOR_CYAN 0x003F3FU // Active note
// Control colors#define COLOR_ORANGE 0x3F1F00U // Active page#define COLOR_WHITE 0x3F3F3FU // Quantise off#define COLOR_CTRL_HINT 0x0F0F0FU // Button hintsflash.c - Persistence
Section titled “flash.c - Persistence”Handles saving and loading configuration from flash memory.
Flash Data Structure
Section titled “Flash Data Structure”#define FLASH_MAGIC 0x000B0A4DUL#define FLASH_VERSION 7
typedef struct FlashData { unsigned long magic; // Validation marker unsigned char version; // Schema version unsigned char current_page; unsigned char reserved[2]; Page pages[PAGE_COUNT];} __attribute__((packed)) FlashData;Save/Load
Section titled “Save/Load”void flash_save(void); // Write current state to flashvoid flash_load(void); // Load state from flash (or defaults)unsigned char flash_is_valid(void); // Check if flash has valid dataVersioning
Section titled “Versioning”When adding new fields:
- Increment
FLASH_VERSION - Handle migration in
flash_load() - Preserve valid ranges for existing fields
void flash_load(void) { FlashData data; hal_read_flash(0, (u8*)&data, sizeof(data));
if (data.magic != FLASH_MAGIC) { // No valid data - use defaults return; }
// Validate and migrate old versions if (data.version < FLASH_VERSION) { // Handle migration... }}surface.c - Button Detection
Section titled “surface.c - Button Detection”Utility functions for working with the button/pad surface.
Surface Types
Section titled “Surface Types”enum SurfaceKeyType { SURFACE_PAD, // 8x8 main grid SURFACE_CTRL // Control buttons};
enum SurfaceKeyType index_to_surface_key_type(unsigned char index);Index Regions
Section titled “Index Regions”// Check if index is a grid pad (not control)static unsigned char is_grid_pad(u8 index) { u8 row = index / 10; u8 col = index % 10; return (row >= 1 && row <= 8 && col >= 1 && col <= 8);}velocity.c - Velocity Curves
Section titled “velocity.c - Velocity Curves”Applies velocity curves to pad pressure values.
Available Curves
Section titled “Available Curves”| Curve | Description |
|---|---|
| Linear | Direct mapping (default) |
| Soft | Emphasizes light touches |
| Hard | Requires more force |
| Fixed | Always maximum velocity |
typedef enum { VELOCITY_LINEAR = 0, VELOCITY_SOFT, VELOCITY_HARD, VELOCITY_FIXED} VelocityCurve;
unsigned char apply_velocity_curve(VelocityCurve curve, unsigned char value);buttons.h - Button Constants
Section titled “buttons.h - Button Constants”Defines button indices for cleaner code:
// Top row controls#define BTN_OCTAVE_UP 91#define BTN_OCTAVE_DOWN 92#define BTN_ARROW_LEFT 93#define BTN_ARROW_RIGHT 94#define BTN_SESSION_1 95#define BTN_SESSION_2 96#define BTN_SESSION_3 97#define BTN_SESSION_4 98
// Left column controls#define BTN_SHIFT 80#define BTN_CLICK 70#define BTN_UNDO 60#define BTN_DELETE 50#define BTN_QUANTISE 40#define BTN_DUPLICATE 30#define BTN_DOUBLE 20#define BTN_CIRCLE 10
// Scene buttons (right column)#define BTN_SCENE_1 89// ... through BTN_SCENE_8 = 19Module Dependencies
Section titled “Module Dependencies”app.c├── app_state.c (runtime state)├── page.c (configuration)├── layout.c (display)├── flash.c (persistence)├── note.c (calculations)├── surface.c (utilities)└── velocity.c (curves)
layout.c├── app_state.c├── page.c├── note.c└── buttons.h
flash.c├── page.c└── app_state.cSee Also
Section titled “See Also”- Architecture Overview - High-level design
- Contributing Guide - Adding features