Sending 7bit MIDI Events on Rotary Encoder movements

We want to send absolute 7bit values on encoder movements in following format: CC <encoder> <value>.

Copy the SDCC skeleton into a new directory, open the main.c file and enhance the hooks like described below. Thereafter type "make" in the command shell, and upload the new project.hex file to the core.

At the top of the main.c file, we have to specify an array of "unsigned char" (8bit values) which hold the absolute value:

// absolute values are stored in this array
unsigned char enc_value[8];

Within the Init() function, you have to specify, how many shift registers are connected to the core, and which encoder speed mode should be taken:

/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS after startup to initialize the 
// application
/////////////////////////////////////////////////////////////////////////////
void Init(void) __wparam
{
  unsigned char i;

  // set shift register update frequency
  MIOS_SRIO_UpdateFrqSet(1); // ms

  // we need to set at least one IO shift register pair
  MIOS_SRIO_NumberSet(16); // for 128 pins

  // set speed mode for 8 encoders
  for(i=0; i<8; ++i) {
    // available speed modes: SLOW, NORMAL and FAST
    MIOS_ENC_SpeedSet(i, MIOS_ENC_SPEED_FAST, 2); // encoder, speed mode, divider
  }
}

We add the code which should be executed on rotary encoder movements to the ENC_NotifyChange() function. It increments/decrements the absolute value depending on the encoder turn direction and sends the new value over the MIDI interface, if it has been changed:

/////////////////////////////////////////////////////////////////////////////
// This function is called by MIOS when an encoder has been moved
// incrementer is positive when encoder has been turned clockwise, else
// it is negative
/////////////////////////////////////////////////////////////////////////////
void ENC_NotifyChange(unsigned char encoder, char incrementer) __wparam
{
  unsigned char new_value;

  // do nothing if encoder number greater than array size
  if( encoder >= sizeof(enc_value) )
    return;

  // add incrementer to absolute value, store result in new_value
  new_value = enc_value[encoder] + incrementer;

  // branch depending on direction
  if( incrementer >= 0 ) {
    // overrun check: if new value >= 0x80, force to 0x7f (127)
    if( new_value >= 0x80 )
      new_value = 0x7f;
  } else {
    // underrun check: if new value >= 0x80, force to 0x00 (0)
    if( new_value >= 0x80 )
      new_value = 0x00;
  }

  // store and send absolute value if it has been changed
  if( new_value != enc_value[encoder] ) {
    enc_value[encoder] = new_value;
    MIOS_MIDI_TxBufferPut(0xb0);           // CC at MIDI Channel #1
    MIOS_MIDI_TxBufferPut(0x10 + encoder); // CC# is 0x10 (16) for first encoder
    MIOS_MIDI_TxBufferPut(new_value);
  }
}

Note: by using the MIOS_HLP_16bitAddSaturate() help function, this routine can be simplified like shown below:

void ENC_NotifyChange(unsigned char encoder, char incrementer) __wparam
{
  unsigned int value;

  // do nothing if encoder number greater than array size
  if( encoder >= sizeof(enc_value) )
    return;

  // add incrementer to absolute value by using a MIOS help function
  value = (unsigned int)enc_value[encoder];
  if( MIOS_HLP_16bitAddSaturate(incrementer, &value, 0x7f) ) {
    // store new value and send it
    enc_value[encoder] = (unsigned char)value;

    MIOS_MIDI_TxBufferPut(0xb0);           // CC at MIDI Channel #1
    MIOS_MIDI_TxBufferPut(0x10 + encoder); // CC# is 0x10 (16) for first encoder
    MIOS_MIDI_TxBufferPut((unsigned char)value);
  }
}

The pins to which the encoders are connected must be specified in MIOS_ENC_TABLE, which can be placed at the top of your main.c file:

MIOS_ENC_TABLE {
             //  sr pin mode
  MIOS_ENC_ENTRY( 1, 0, MIOS_ENC_MODE_NON_DETENTED), // V-Pot 1
  MIOS_ENC_ENTRY( 1, 2, MIOS_ENC_MODE_NON_DETENTED), // V-Pot 2
  MIOS_ENC_ENTRY( 1, 4, MIOS_ENC_MODE_NON_DETENTED), // V-Pot 3
  MIOS_ENC_ENTRY( 1, 6, MIOS_ENC_MODE_NON_DETENTED), // V-Pot 4
  MIOS_ENC_ENTRY( 2, 0, MIOS_ENC_MODE_NON_DETENTED), // V-Pot 5
  MIOS_ENC_ENTRY( 2, 2, MIOS_ENC_MODE_NON_DETENTED), // V-Pot 6
  MIOS_ENC_ENTRY( 2, 4, MIOS_ENC_MODE_NON_DETENTED), // V-Pot 7
  MIOS_ENC_ENTRY( 2, 6, MIOS_ENC_MODE_NON_DETENTED), // V-Pot 8

  MIOS_ENC_EOT
};

IMPORTANT: the default encoder table has to be disabled in the Makefile via -DDONT_INCLUDE_MIOS_ENC_TABLE. You could add this define to the MIOS_WRAPPER_DEFINES variable:

MIOS_WRAPPER_DEFINES = -DSTACK_HEAD=0x37f -DSTACK_IRQ_HEAD=0x33f -DDONT_INCLUDE_MIOS_ENC_TABLE

A list of available MIOS function can be found here.



Last update: 2023-11-04

Copyright © 1998-2023, Thorsten Klose. All rights reserved.