Here is my first custom app using the “new” mios32 environment. ![]()
It only uses a STM 32 board : Juno 106 is connected to Midi in/out 1 and the core32 can be connected to your computer via USB or Midi in/out 2
The purpose is to convert the sysex from the Juno 106 to Control change messages (CC) (and vice versa), in order to edit automations in DAW that don’t support sysex (e.g Ableton Live). Moreover it is really easier to edit CC messages (curves) than sysex ones (list of numbers) !
It does also convert CC messages received on USB and Midi in/out 2 to juno 106 sysex.
-
In Control mode (meaning just moving the faders of the Juno), it sends simple CC.
-
In Patch mode (e.g recalling patch A45 on the Juno), it sends a program change message and all the data of the controls via 18 CC so that you will ever get the patch parameters ; playing the record will transmit those CC and your Juno will return to its original tone

-
[*]In Manual mode it only sends all 18 parameters when you press the Manual button on the Juno. Moving faders sends sysex as in Control mode.
Notice that you have to be in Midi Mode III on the Juno. (the only mode that produce sysex)
Control change messages are the following :
Control number of control change message
00 = LFO rate CC 102
01 = LFO delay time CC 103
02 = DCO LFO CC 104
03 = DCO PWM CC 105
04 = DCO Noise CC 106
05 = VCF Freq CC 107
06 = VCF Res etc …
07 = VCF Env
08 = VCF LFO
09 = VCF Kybd
0A = VCA Level
0B = ENV A
0C = ENV D
0D = ENV S …
0E = ENV R CC 116
0F = DCO SUB CC 117
10 = Switches 1 (see below) CC 118
11 = Switches 2 (see below) CC 119
You can change it in app.h by editing CC_Offset. The 102 value has been retained because I needed 18 adjacent numbers.
Enjoy !
Rq : For those curious of some code routines :
/*
* Juno 106 SysEx Translator v1.0
*
* ==========================================================================
*
* Copyright (C) 2011 Julien Voirin (julien.voirin@free.fr)
* Licensed for personal non-commercial use only.
* All other rights reserved.
*
* ==========================================================================
*/
/////////////////////////////////////////////////////////////////////////////
// Include files
/////////////////////////////////////////////////////////////////////////////
#include <mios32.h>
#include "app.h"
#include "mios32_config.h"
/////////////////////////////////////////////////////////////////////////////
// Translate a DAW CC string from a Juno 106 SysEx string on a destination port
/////////////////////////////////////////////////////////////////////////////
void Translate_CC_SysEx(mios32_midi_package_t midi_package, mios32_midi_port_t port)
{
static u8 stream_sysex[7];
// convert CC:USB0 -> Sysex:UART0 : translate CC to SysEx
if( midi_package.type == 0xb){
// define sysex stream
stream_sysex[0] = 0xf0; // header
stream_sysex[1] = 0x41; // Roland
stream_sysex[2] = 0x32; // Juno 106 Control mode
stream_sysex[3] = midi_package.evnt0 & 0x0f; // midi channel : 0n
stream_sysex[4] = midi_package.evnt1 - CC_Offset; // Control number
stream_sysex[5] = midi_package.evnt2; // Control value
stream_sysex[6] = 0xf7; // EOX
// send stream to midi out1
MIOS32_MIDI_SendSysEx(port, stream_sysex, 7);
//MIOS32_MIDI_SendSysEx(USB0, stream_sysex, 7); // DEBUG :°)
}
}
/////////////////////////////////////////////////////////////////////////////
// Translate a Juno SysEx string from a midi port to a Control change string
/////////////////////////////////////////////////////////////////////////////
void Translate_SysEx_CC(mios32_midi_port_t port, mios32_midi_package_t midi_package)
{
static u8 editbufferstatus;
static u8 midi_channel;
static u8 cc_param;
static u8 cc_value;
// static u8 patch_param[24]; // 24 bytes for a patch
static u8 bank_patch_number; // for PC
static u8 patch_value[24]; // Header + midi channel + PgChg + 18 values of controller + EOX
// convert Sysex:UART0 -> CC:USB0 & CC:UART1
switch(editbufferstatus){
unsigned char i; // for the loop
case 0: // Juno 106 Header
// Control mode
if( midi_package.type == 0x4 && midi_package.evnt0 == 0xf0 && midi_package.evnt1 == 0x41 && midi_package.evnt2 == 0x32){
#if DEBUG
MIOS32_MIDI_SendCC(USB0, 15, 50, 50);
#endif
editbufferstatus = 1;
}
// Patch mode
else if( midi_package.type == 0x4 && midi_package.evnt0 == 0xf0 && midi_package.evnt1 == 0x41 && midi_package.evnt2 == 0x30){
#if DEBUG
MIOS32_MIDI_SendCC(USB0, 15, 40, 40);
#endif
editbufferstatus = 30;
//editbufferstatus = 4;
}
// Manual mode
else if( midi_package.type == 0x4 && midi_package.evnt0 == 0xf0 && midi_package.evnt1 == 0x41 && midi_package.evnt2 == 0x31){
#if DEBUG
MIOS32_MIDI_SendCC(USB0, 15, 30, 30);
#endif
editbufferstatus = 40;
//editbufferstatus = 4;
}
else
editbufferstatus = 0;
break;
case 1: // 2nd block (3 bytes) : Control
if( midi_package.type == 0x4) {
midi_channel = midi_package.evnt0; // CC 1st byte
cc_param = midi_package.evnt1; // CC 2nd byte (+2 avoid pb with bender)
cc_value = midi_package.evnt2; // CC 3rd byte
#if DEBUG
MIOS32_MIDI_SendCC(USB0, 15, 60, 60); // debug OK
#endif
editbufferstatus = 2;
}
else
editbufferstatus = 0;
break;
case 2: // EOX Control
if( midi_package.type == 0x5 && midi_package.evnt0 == 0xF7){
MIOS32_MIDI_SendCC(USB0, midi_channel, cc_param + CC_Offset, cc_value); // USB Port
MIOS32_MIDI_SendCC(UART1, midi_channel, cc_param + CC_Offset, cc_value); // Midi Out2 Port
#if DEBUG
MIOS32_MIDI_SendCC(USB0, 15, 70, 70); // debug OK :)
#endif
editbufferstatus = 0;
}
else
editbufferstatus = 0;
break;
case 30: // blocks patch 0n pp dd
if(midi_package.type == 0x04){
patch_value[3] = midi_package.evnt0; // midi channel
patch_value[4] = midi_package.evnt1; // bank patch number
patch_value[5] = midi_package.evnt2; // ctrl 01 LFO Rate
// notice that :
midi_channel = patch_value[3];
bank_patch_number = patch_value[4];
// send PC over USB et midi out2
MIOS32_MIDI_SendProgramChange(USB0, midi_channel, bank_patch_number);
MIOS32_MIDI_SendProgramChange(UART1, midi_channel, bank_patch_number);
// next step
editbufferstatus = 31;
}
else
editbufferstatus = 0;
break;
case 31: // blocks patch dd dd dd
if(midi_package.type == 0x04){
patch_value[6] = midi_package.evnt0; // ctrl 02 LFO delay time
patch_value[7] = midi_package.evnt1; // ctrl 03 DCO LFO
patch_value[8] = midi_package.evnt2; // ctrl 04 DCO PWM
// next step
editbufferstatus = 32;
}
else
editbufferstatus = 0;
break;
case 32: // blocks patch dd dd dd
if(midi_package.type == 0x04){
patch_value[9] = midi_package.evnt0; // ctrl 05 DCO noise
patch_value[10] = midi_package.evnt1; // ctrl 06 VCF Freq
patch_value[11] = midi_package.evnt2; // ctrl 07 VCF Res
// next step
editbufferstatus = 33;
}
else
editbufferstatus = 0;
break;
case 33: // blocks patch dd dd dd
if(midi_package.type == 0x04){
patch_value[12] = midi_package.evnt0; // ctrl 08 VCF env
patch_value[13] = midi_package.evnt1; // ctrl 09 VCF LFO
patch_value[14] = midi_package.evnt2; // ctrl 10 BCF kbd
// next step
editbufferstatus = 34;
}
else
editbufferstatus = 0;
break;
case 34: // blocks patch dd dd dd
if(midi_package.type == 0x04){
patch_value[15] = midi_package.evnt0; // ctrl 11 VCA Level
patch_value[16] = midi_package.evnt1; // ctrl 12 Env A
patch_value[17] = midi_package.evnt2; // ctrl 13 Env D
// next step
editbufferstatus = 35;
}
else
editbufferstatus = 0;
break;
case 35: // blocks patch dd dd dd
if(midi_package.type == 0x04){
patch_value[18] = midi_package.evnt0; // ctrl 14 Env S
patch_value[19] = midi_package.evnt1; // ctrl 15 Env R
patch_value[20] = midi_package.evnt2; // ctrl 16 DCO Sub
// next step
editbufferstatus = 36;
}
else
editbufferstatus = 0;
break;
case 36: // blocks patch dd dd F7
if(midi_package.type == 0x07){
patch_value[21] = midi_package.evnt0; // ctrl 17 Switches 1
patch_value[22] = midi_package.evnt1; // ctrl 18 Switches 2
patch_value[23] = midi_package.evnt2; // ctrl EOX
/* // send PC over USB et midi out2
MIOS32_MIDI_SendProgramChange(USB0, midi_channel, bank_patch_number);
MIOS32_MIDI_SendProgramChange(UART1, midi_channel, bank_patch_number);
*/
// send the patch param via CC
for(i=5; i < 23; i++){
MIOS32_MIDI_SendCC(USB0, midi_channel, (i-5)+CC_Offset, patch_value[i]);
MIOS32_MIDI_SendCC(UART1, midi_channel, (i-5)+CC_Offset, patch_value[i]);
editbufferstatus = 0;
}
// return to start
editbufferstatus = 0;
}
else
editbufferstatus = 0;
break;
case 40: // blocks MANUAL 0n pp dd !NO PROGRAM CHANGE!
if(midi_package.type == 0x04){
patch_value[3] = midi_package.evnt0; // midi channel
patch_value[4] = midi_package.evnt1; // bank patch number
patch_value[5] = midi_package.evnt2; // ctrl 01 LFO Rate
// notice that :
midi_channel = patch_value[3];
bank_patch_number = patch_value[4];
// DON'T send PC over USB et midi out2
//MIOS32_MIDI_SendProgramChange(USB0, midi_channel, bank_patch_number);
//MIOS32_MIDI_SendProgramChange(UART1, midi_channel, bank_patch_number);
// next step
editbufferstatus = 31;
}
else
editbufferstatus = 0;
break;
case 4 : // end of Blocks
break;
}
}
/////////////////////////////////////////////////////////////////////////////
// This hook is called after startup to initialize the application
/////////////////////////////////////////////////////////////////////////////
void APP_Init(void)
{
// initialize all LEDs
MIOS32_BOARD_LED_Init(0xffffffff);
}
/////////////////////////////////////////////////////////////////////////////
// This task is running endless in background
/////////////////////////////////////////////////////////////////////////////
void APP_Background(void)
{
/* // endless loop
while( 1 ) {
// toggle the state of all LEDs (allows to measure the execution speed with a scope)
MIOS32_BOARD_LED_Set(0xffffffff, ~MIOS32_BOARD_LED_Get());
}
*/
}
/////////////////////////////////////////////////////////////////////////////
// This hook is called when a MIDI package has been received
/////////////////////////////////////////////////////////////////////////////
void APP_MIDI_NotifyPackage(mios32_midi_port_t port, mios32_midi_package_t midi_package)
{
// toggle Status LED on each incoming MIDI package
MIOS32_BOARD_LED_Set(1, ~MIOS32_BOARD_LED_Get());
#if TERM_DEBUG // send received MIDI package to MIOS Terminal
MIOS32_MIDI_SendDebugMessage("Port:%02X Type:%X Evnt0:%02X Evnt1:%02X Evnt2:%02X\n", port, midi_package.type, midi_package.evnt0, midi_package.evnt1, midi_package.evnt2);
#endif
// forward USB0->UART0 and UART0->USB0
switch( port ) {
case USB0:
// convert CC:USB0 -> Sysex:UART0 : translate CC to SysEx
Translate_CC_SysEx(midi_package, UART0);
MIOS32_MIDI_SendPackage( UART0, midi_package); // forward all messages
break;
case UART1:
// convert CC:UART1 -> Sysex:UART0 : translate CC to SysEx
Translate_CC_SysEx(midi_package, UART0);
MIOS32_MIDI_SendPackage( UART0, midi_package); // forward all messages
break;
case UART0:
// translate sysex
Translate_SysEx_CC( port, midi_package);
// passthrough midi messages except SysEx
if (midi_package.type > 0x7 && midi_package.type < 0xf) // all except SysEx
MIOS32_MIDI_SendPackage(USB0, midi_package); // USB Port
MIOS32_MIDI_SendPackage(UART1, midi_package); // Midi Out2 Port
break;
}
}
[Juno_106_Translator_v1.0.zip](< base_url >/applications/core/interface/file/attachment.php?id=9362)