/* * Brickworks * * Copyright (C) 2023 Orastron Srl unipersonale * * Brickworks is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License. * * Brickworks is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Brickworks. If not, see . * * File author: Stefano D'Angelo */ /*! * module_type {{{ utility }}} * version {{{ 0.5.0 }}} * requires {{{ bw_common bw_config }}} * description {{{ * Note queue. * * ... * }}} * changelog {{{ * * }}} */ #ifndef _BW_NOTE_QUEUE_H #define _BW_NOTE_QUEUE_H #ifdef __cplusplus extern "C" { #endif #include /*! api {{{ * #### bw_note_queue_status * ```>>> */ typedef struct { char pressed; float velocity; // negative = unknown / not available } bw_note_queue_status; /*! <<<``` * #### bw_note_queue_event * ```>>> */ typedef struct { unsigned char note; bw_note_queue_status status; char went_off; } bw_note_queue_event; /*! <<<``` * #### bw_note_queue * ```>>> */ typedef struct { bw_note_queue_event events[128]; unsigned char n_events; bw_note_queue_status status[128]; unsigned char n_pressed; } bw_note_queue; /*! <<<``` * #### bw_note_queue_reset() * ```>>> */ static inline void bw_note_queue_reset(bw_note_queue *BW_RESTRICT queue); /*! <<<``` * #### bw_note_queue_clear() * ```>>> */ static inline void bw_note_queue_clear(bw_note_queue *BW_RESTRICT queue); /*! <<<``` * #### bw_note_queue_add() * ```>>> */ static inline void bw_note_queue_add(bw_note_queue *BW_RESTRICT queue, unsigned char note, char pressed, float velocity, char force_went_off); /*! <<<``` * }}} */ /*** Implementation ***/ /* WARNING: This part of the file is not part of the public API. Its content may * change at any time in future versions. Please, do not use it directly. */ static inline void bw_note_queue_reset(bw_note_queue *BW_RESTRICT queue) { for (int i = 0; i < 128; i++) queue->status[i] = (bw_note_queue_status){ .pressed = 0, .velocity = 0.f }; queue->n_pressed = 0; queue->n_events = 0; } static inline void bw_note_queue_clear(bw_note_queue *BW_RESTRICT queue) { queue->n_events = 0; } static inline void bw_note_queue_add(bw_note_queue *BW_RESTRICT queue, unsigned char note, char pressed, float velocity, char force_went_off) { if (!pressed && !queue->status[note].pressed) return; unsigned char i; for (i = 0; i < queue->n_events; i++) if (queue->events[i].note == note) break; char went_off = 0; if (i == queue->n_events) queue->n_events++; else went_off = queue->events[i].went_off || !queue->events[i].status.pressed; queue->events[i] = (bw_note_queue_event){ .note = note, .status = { pressed, velocity }, .went_off = went_off || force_went_off }; if (pressed && !queue->status[note].pressed) queue->n_pressed++; else if (!pressed && queue->status[note].pressed) queue->n_pressed--; queue->status[note] = (bw_note_queue_status){ .pressed = pressed, .velocity = velocity }; } #ifdef __cplusplus } #endif #endif