// sound_puzzle.h — melody-recognition puzzle consuming MIC_P1_SOUND frames
// from the mic broker.
//
// Prerequisites: mic_broker_init() must have been called before
// sound_puzzle_start().
//
// Callback contract: the solved callback runs on the mic_broker task
// (8 KiB stack). It must not block nor allocate large buffers. It must not
// call sound_puzzle_start(). sound_puzzle_stop() is safe to call from the
// callback (it is a thin alias for mic_broker_set_mode(MIC_IDLE), which is
// a safe volatile write from the broker task). Note: the puzzle self-stops
// on solve (MIC_IDLE is set before the callback fires), so calling
// sound_puzzle_stop() from the callback is redundant but harmless.
//
// Note on repeated notes: melodies with immediately repeated notes require
// an intervening silence between them (the per-frame debounce suppresses
// consecutive identical notes).
//
// Concurrency: sound_puzzle_start() must be called only while the broker is
// MIC_IDLE; calling it while MIC_P1_SOUND is active is undefined behaviour.
#pragma once
#include <stdbool.h>
#include <stddef.h>

typedef void (*sound_solved_cb_t)(void);

// Register on the mic broker (MIC_P1_SOUND mode) and start routing frames to
// the melody validator. expected[0..count-1] are MIDI note numbers; tol is the
// accepted semitone deviation. cb is invoked once the full melody is matched.
void sound_puzzle_start(const int *expected, size_t count, int tol,
                        sound_solved_cb_t cb);

// Return the broker to MIC_IDLE, stopping frame delivery.  Safe to call from
// the solved callback; the puzzle self-stops on solve so this is redundant then.
void sound_puzzle_stop(void);
// True while the broker is in MIC_P1_SOUND mode.
bool sound_puzzle_is_running(void);
