I am working on a crate to implement the opendeck midi controller firmware.
I would like to decouple in the crate the logic to handle user interaction from the final firmware. So the specific firmware implements handling the user inputs and midi output, but the create should implement the opendeck specificiation.
Example: An opendeck button can be configured to send different types of midi messages when the button is activated. The number of messages and the types of the messages are different, depending on the configuration. The configuration of the button is stored in a struct and this part is already solved. Now I am working on implementing the handle
function which return the MIDI messages when a user activates the buttons.
In opendeck, there are not only buttons, but also other types of user input (e.g Analog inputs, or Encoders). Each type of input has different configuration options, which are stored in different structs.
What I am struggling is to define a generec handle fn which then returns the the midi messages depending o the structs configuration state.
The current attempt looks like the following:
impl Button {
pub fn handle<'a>(
&mut self,
action: Action,
buffer: &'a mut [u8],
) -> Result<Option<BytesMessage<&'a mut [u8]>>, BufferOverflow> {
match self.message_type {
ButtonMessageType::NoteOffOnly => {
if let Action::Pressed = action {
let mut m = NoteOff::try_new_with_buffer(buffer)?;
m.set_velocity(u7::new(self.value));
m.set_note_number(u7::new(self.midi_id));
m.set_channel(self.channel.into_midi());
return Ok(Some(m.into()));
}
Ok(None)
}
// create messages for other messages types
}
}
But what I want to achieve now is to return an Iterator which will then defer the message creation to the iterator.next() call.
This way we could reuse the same message buffer for each call of the iterator.next() call. I would like to avoid having to create a big buffer which is capable to store all the messages. In the worst case I need to create up to 16 different messages on a single user input.
The midi2 crate wrappes the buffer for the different types of messages it can create by using the try_new_with_buffer
function.
I am struggling to define an API which returns an iterator. Is GAT the solution to look into for such a use case? I am still pretty new to Rust and struggling to find the best approach.
The source code I am working on can be found here. Its very much WIP
Thanks in advance for any help or guidance.