From c9d9cfd88eb91596505b71bd669e16b7d1713007 Mon Sep 17 00:00:00 2001 From: Zack Date: Fri, 12 Jan 2024 09:56:31 -0800 Subject: [PATCH] Update onewiremidi.h --- doth/onewiremidi.h | 177 +++++++++++++++++++++++++++------------------ 1 file changed, 107 insertions(+), 70 deletions(-) diff --git a/doth/onewiremidi.h b/doth/onewiremidi.h index 089a553..6259797 100644 --- a/doth/onewiremidi.h +++ b/doth/onewiremidi.h @@ -1,15 +1,47 @@ +// MIDI code adapted from Jacob Vosmaer +// MIT License +// +// Copyright (c) 2020 andrewikenberry +// Copyright (c) 2023 Jacob Vosmaer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include #include "onewiremidi.pio.h" -#define MIDI_NOTE_ON_MIN 0x90 -#define MIDI_NOTE_ON_MAX 0x9F -#define MIDI_NOTE_OFF_MIN 0x80 -#define MIDI_NOTE_OFF_MAX 0x8F -#define MIDI_TIMING_CLOCK 0xF8 -#define MIDI_ACTIVE_SENSE 0xFE -#define MIDI_START 0xFA -#define MIDI_CONTINUE 0xFB -#define MIDI_STOP 0xFC +enum { + MIDI_NOTE_OFF = 0x80, + MIDI_NOTE_ON = 0x90, + MIDI_AFTERTOUCH = 0xa0, + MIDI_CONTROL_CHANGE = 0xb0, + MIDI_PROGRAM_CHANGE = 0xc0, + MIDI_CHANNEL_PRESSURE = 0xd0, + MIDI_PITCH_BEND = 0xe0, + MIDI_SYSEX = 0xf0, + MIDI_SYSEX_END = 0xf7, + MIDI_TIMING_CLOCK = 0xf8, + MIDI_ACTIVE_SENSE = 0xfe, + MIDI_START = 0xfa, + MIDI_CONTINUE = 0xfb, + MIDI_STOP = 0xfc, +}; typedef void (*callback_int_int)(uint8_t, uint8_t); typedef void (*callback_int)(uint8_t); @@ -18,9 +50,8 @@ typedef void (*callback_void)(); typedef struct Onewiremidi { PIO pio; unsigned char sm; - uint8_t rbs[3]; - uint8_t rbi; - bool ready; + uint8_t status; + uint8_t previous; uint32_t last_time; callback_int_int midi_note_on; callback_int midi_note_off; @@ -37,19 +68,17 @@ Onewiremidi *Onewiremidi_new(PIO pio, unsigned char sm, const uint pin, callback_void midi_continue, callback_void midi_stop, callback_void midi_timing) { - Onewiremidi *om = (Onewiremidi *)malloc(sizeof(Onewiremidi)); - om->pio = pio; - om->sm = sm; - om->rbi = 0; - for (uint8_t i = 0; i < 3; i++) { - om->rbs[i] = 0; - } - om->midi_note_on = midi_note_on; - om->midi_note_off = midi_note_off; - om->midi_start = midi_start; - om->midi_continue = midi_continue; - om->midi_stop = midi_stop; - om->midi_timing = midi_timing; + Onewiremidi *self = (Onewiremidi *)malloc(sizeof(Onewiremidi)); + self->pio = pio; + self->sm = sm; + self->status = 0; + self->previous = 0; + self->midi_note_on = midi_note_on; + self->midi_note_off = midi_note_off; + self->midi_start = midi_start; + self->midi_continue = midi_continue; + self->midi_stop = midi_stop; + self->midi_timing = midi_timing; uint offset = pio_add_program(pio, &midi_rx_program); pio_sm_config c = midi_rx_program_get_default_config(offset); @@ -61,7 +90,7 @@ Onewiremidi *Onewiremidi_new(PIO pio, unsigned char sm, const uint pin, pio_sm_set_clkdiv(pio, sm, (float)clock_get_hz(clk_sys) / 1000000.0f); // 1 us/cycle pio_sm_set_enabled(pio, sm, true); - return om; + return self; } uint8_t Onewiremidi_reverse_uint8_t(uint8_t b) { @@ -71,59 +100,67 @@ uint8_t Onewiremidi_reverse_uint8_t(uint8_t b) { return b; } -void Onewiremidi_receive(Onewiremidi *om) { - if (pio_sm_is_rx_fifo_empty(om->pio, om->sm)) { +typedef struct midi_message { + uint8_t status; + uint8_t data[2]; +} midi_message; + +void Onewiremidi_receive(Onewiremidi *self) { + if (pio_sm_is_rx_fifo_empty(self->pio, self->sm)) { return; } uint32_t t = time_us_32(); - if (t - om->last_time > 1000) { - om->rbi = 0; + if (t - self->last_time > 1000) { + self->status = 0; + self->previous = 0; } - om->last_time = t; - uint8_t value = Onewiremidi_reverse_uint8_t(pio_sm_get(om->pio, om->sm)); - om->rbs[om->rbi] = ~value; - // printf("%d: %x\n", om->rbi, om->rbs[om->rbi]); + self->last_time = t; + uint8_t b = Onewiremidi_reverse_uint8_t(pio_sm_get(self->pio, self->sm)); + b = ~b; - if (om->rbs[om->rbi] == MIDI_START) { - if (om->midi_start != NULL) om->midi_start(); - om->rbi = 0; - } else if (om->rbs[om->rbi] == MIDI_CONTINUE) { - if (om->midi_continue != NULL) om->midi_continue(); - om->rbi = 0; - } else if (om->rbs[om->rbi] == MIDI_STOP) { - if (om->midi_stop != NULL) om->midi_stop(); - om->rbi = 0; - } else if (om->rbs[om->rbi] == MIDI_ACTIVE_SENSE) { - om->rbi = 0; - } else if (om->rbs[om->rbi] == MIDI_TIMING_CLOCK) { - if (om->midi_timing != NULL) om->midi_timing(); - om->rbi = 0; - } else if (om->rbi < 2 && (om->rbs[0] >= MIDI_NOTE_OFF_MIN || - om->rbs[0] <= MIDI_NOTE_ON_MAX)) { - // iterater for not on/off - om->rbi++; - } else if (om->rbi == 2) { - om->rbi = 0; - // printf("%02X %02X %02X\n", om->rbs[0], om->rbs[1], om->rbs[2]); - if (om->rbs[0] >= MIDI_NOTE_ON_MIN && om->rbs[0] <= MIDI_NOTE_ON_MAX) { - if (om->midi_note_on != NULL) { - om->midi_note_on(om->rbs[1], om->rbs[2]); + enum { DATA0_PRESENT = 0x80 }; + midi_message msg = {0}; + + if (b >= 0xf8) { + msg.status = b; + if (msg.status == MIDI_TIMING_CLOCK && self->midi_timing != NULL) { + self->midi_timing(); + } else if (msg.status == MIDI_START && self->midi_start != NULL) { + self->midi_start(); + } else if (b == MIDI_CONTINUE && self->midi_continue != NULL) { + self->midi_continue(); + } else if (b == MIDI_STOP && self->midi_stop != NULL) { + self->midi_stop(); + } + } else if (b >= 0xf4) { + msg.status = b; + self->status = 0; + } else if (b >= 0x80) { + self->status = b; + self->previous = b == 0xf0 ? b : 0; + } else if ((self->status >= 0xc0 && self->status < 0xe0) || + (self->status >= 0xf0 && self->status != 0xf2)) { + msg.status = self->status; + msg.data[0] = b; + msg.data[1] = self->previous; + self->previous = 0; + } else if (self->status && self->previous & DATA0_PRESENT) { + msg.status = self->status; + msg.data[0] = self->previous ^ DATA0_PRESENT; + msg.data[1] = b; + self->previous = 0; + if (msg.status == MIDI_NOTE_ON) { + if (self->midi_note_on != NULL) { + self->midi_note_on(msg.data[0], msg.data[1]); } - } else if (om->rbs[0] >= MIDI_NOTE_OFF_MIN && - om->rbs[0] <= MIDI_NOTE_OFF_MAX) { - if (om->midi_note_off != NULL) { - om->midi_note_off(om->rbs[1]); + } else if (msg.status == MIDI_NOTE_OFF) { + if (self->midi_note_off != NULL) { + self->midi_note_off(msg.data[0]); } - } else { -#ifdef DEBUG_MIDI - printf("%02X %02X %02X\n", om->rbs[0], om->rbs[1], om->rbs[2]); -#endif } } else { -#ifdef DEBUG_MIDI - printf("??? %d: %x\n", om->rbi, om->rbs[om->rbi]); -#endif - om->rbi = 0; + self->previous = b | DATA0_PRESENT; } + return; }