Jump to content

Roland Juno 106 and Alpha Juno 2 sysex translator


julienvoirin
 Share

Recommended Posts

Here is my first custom app using the "new" mios32 environment. :thumbsup:

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 :thumbsup:

    [*]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

Edited by julienvoirin
  • Like 1
Link to comment
Share on other sites

Brilliance!

Combine the above with a control surface and we get Sysex to the MKS-50/JU-1/2 etc plus CCs to anything reasonably modern :flowers:

This could be full of so much win.

I quickly started the new application for my Juno 2 : it converts CC to Alpha Juno2 sysex, as i wanted to know if there is scales effect while moving parameters (I got that on my Oberheim Matrix 1000 and it is shit!). There is no scale effect ! :frantics:

so the next step is to build a dedicated control surface.

This application does convert Control Change messages to Juno 2 sysex messages

so that you can control your synth with a DAW that doesn't support

sysex (e.g Ableton live).

Connect your Juno to Midi in/out sockets 1 of STM32 and USB to your computer.

Midi in/out 2 is the same as USB (e.g to connect to an Akai MPC).

See tables below to edit your Juno parameters (CC84 to CC119).

Have fun !

PS : Am I right we all posess Juno 106 AND Juno2 ?!

/*

 *	Roland Juno 2 SysEx Translator

 *

 *	===============================================================================

 *	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 2 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[10];


	// 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] = 0x36; // Juno 2 in Individual Tone Parameters mode

		stream_sysex[3] = midi_package.evnt0 & 0x0f; // midi channel : 0n

		stream_sysex[4] = 0x23; // format type 

		stream_sysex[5] = 0x20; // unknown 

		stream_sysex[6] = 0x01; // unknown 

		stream_sysex[7] = midi_package.evnt1 - CC_Offset; // Parameter number

		stream_sysex[8] = midi_package.evnt2; // Parameter value

		stream_sysex[9] = 0xf7; // EOX


		// send stream to midi out1

		MIOS32_MIDI_SendSysEx(port, stream_sysex, 10);

		//MIOS32_MIDI_SendSysEx(USB0, stream_sysex, 7); // DEBUG :°)

        }

}


/////////////////////////////////////////////////////////////////////////////

// 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 from Juno to CC : not yet implemented

			//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_2_SysEx_Translator_v0.1.zip

Edited by julienvoirin
Link to comment
Share on other sites

  • 6 months later...

here is the final applications

moreover i did a controller on arduino/ethernet/wifi and iPad/touchOSC for Roland Juno2

ARDUINO CODE for Juno2 sysex translator :


//////////////////////////////////////////////////////////////////////

// OSCClass iOSC(iPhone App) test sketch

// OSCClass version 1.0.1 (Arduino ver0014)

// Copyright (c) recotana(http://recotana.com).  All right reserved.

//////////////////////////////////////////////////////////////////////

/*

TouchOSC is OSCsend Application for iPad



 OSC setting example :

             OSCMessage          type     value     on  off

 button1    /Juno2/button_name    float            1   0   :info-AlternateMode "ON" = toggle sw

 slider1    /Juno2/button_name    float            1   0




 Arduino setting IP address 192.168.1.10 , incoming port : 8000 (server)

 Arduino setting IP address 192.168.1.10 , outgoing port : 8008

 iPad setting IP address 192.168.1.4 , incoming port : 8008 (client)

 iPad setting IP address 192.168.1.4 , outgoing port : 8000




 Parameters on the Juno2 : 


 I. First scroll through the MIDI menu and turn Exclusive Messages ON.


 II. These are the components of the system exclusive message:


 F0 [Exclusive]

 41 [Roland ID#]

 36 [Individual Tone Parameters]

 0N [N=MIDI channel (N=0-F, Chan 1=00 Chan 16=0F)]

 23 [Format type]

 20 [unknown]

 01 [unknown]

 XX [Parameter number (0-23)] see table below

 YY [Value (0-127)] Can be left at 00

 F7 [End of Exclusive]


 III. Here is an example:

 A SysEx message for editing the VCF Resonance Parameter on MIDI channel 1:

 F0 41 36 00 23 20 01 11 00 F7


 "11" Is the SysEx code for the VCF Resonance edit parameter.

 "00" Is the SysEx code for the variable start value of the current edit parameter.


 Parameter Numbers (XX) For The Alpha Juno Synths: 37 parameters

 (Parentheses indicated range of variable values 'YY' possible for the parameter.)


 CODE (XX)	EDIT PARAMETER								COMPLETE SYSEX CODE		CC#

 00	DCO Env. Mode (0=Normal, 1=Inverted, 2=Normal-Dynamic, 3=Inv.-Dynamic)		F0 41 36 00 23 20 01 00 00 F7	84

 01	VCF Env. Mode (0=Normal, 1=Inverted, 2=Normal-Dynamic, 3=Dynamic)		F0 41 36 00 23 20 01 01 00 F7	85

 02	VCA Env. Mode (0=Normal, 1=Gate, 2=Normal-Dynamic, 3=Gate-Dynamic)		F0 41 36 00 23 20 01 02 00 F7	86

 03	DCO Wave Pulse (0..3)								F0 41 36 00 23 20 01 03 00 F7	87

 04	DCO Wave Saw (0..5)								F0 41 36 00 23 20 01 04 00 F7	88	

 05	DCO Wave Sub (0..5)								F0 41 36 00 23 20 01 05 00 F7	89

 06	DCO Range (0=4', 1=8', 2=16', 3=32')						F0 41 36 00 23 20 01 06 00 F7	90

 07	DCO Sub Level (0..3)								F0 41 36 00 23 20 01 07 00 F7	91

 08	DCO Noise (0..3)								F0 41 36 00 23 20 01 08 00 F7	92

 09	HPF Cutoff (0..3)								F0 41 36 00 23 20 01 09 00 F7	93

 0A	Chorus Switch (0=Off, 1=On)							F0 41 36 00 23 20 01 0A 00 F7	94

 0B	DCO LFO Mod. (0..7F)								F0 41 36 00 23 20 01 0B 00 F7	95

 0C	DCO ENV Mod. (0..7F)								F0 41 36 00 23 20 01 0C 00 F7	96

 0D	DCO After Mod. (0..7F)								F0 41 36 00 23 20 01 0D 00 F7	97

 0E	DCO PWM Depth (0..7F)								F0 41 36 00 23 20 01 0E 00 F7	98

 0F	DCO PWM Rate (0..7F) 	0 = Pulse Width Manual 1..7F = PW LFO Rate		F0 41 36 00 23 20 01 0F 00 F7	99

 10	VCF Cutoff (0..7F)								F0 41 36 00 23 20 01 10 00 F7	100

 11	VCF Resonance (0..7F)								F0 41 36 00 23 20 01 11 00 F7	101

 12	VCF LFO Mod. (0..7F)								F0 41 36 00 23 20 01 12 00 F7	102

 13	VCF ENV Mod. (0..7F)								F0 41 36 00 23 20 01 13 00 F7	103

 14	VCF Key Follow (0..7F)								F0 41 36 00 23 20 01 14 00 F7	104

 15	VCF Aftertouch (0..7F)								F0 41 36 00 23 20 01 15 00 F7	105

 16	VCA Level (0..7F)								F0 41 36 00 23 20 01 16 00 F7	106

 17	VCA Aftertouch (0..7F)								F0 41 36 00 23 20 01 17 00 F7	107

 18	LFO Rate (0..7F)								F0 41 36 00 23 20 01 18 00 F7	108

 19	LFO Delay (0..7F)								F0 41 36 00 23 20 01 19 00 F7	109

 1A	ENV T1 (0..7F) Attack Time							F0 41 36 00 23 20 01 1A 00 F7	110

 1B	ENV L1 (0..7F) Attack Level							F0 41 36 00 23 20 01 1B 00 F7	111

 1C	ENV T2 (0..7F) Break Time							F0 41 36 00 23 20 01 1C 00 F7	112

 1D	ENV L2 (0..7F) Break Level							F0 41 36 00 23 20 01 1D 00 F7	113

 1E	ENV T3 (0..7F) Decay Time							F0 41 36 00 23 20 01 1E 00 F7	114

 1F	ENV L3 (0..7F) Sustain Level							F0 41 36 00 23 20 01 1F 00 F7	115

 20	ENV T4 (0..7F) Release Time							F0 41 36 00 23 20 01 20 00 F7	116

 21	ENV Key Follow (0..78)								F0 41 36 00 23 20 01 21 00 F7	117

 22	Chorus Rate (0..7F)								F0 41 36 00 23 20 01 22 00 F7	118

 23	Bender Range (0..C)								F0 41 36 00 23 20 01 23 00 F7	119


 */


#include "Ethernet.h"

#include <OSCClass_018.h>

#include "MIDI.h"


#define _POT_DEBUG_ 0 // set to 1 to debug with pot


#define  LED_PWM 6 // red led of midi shield

#define  POT_PIN  0

#define  SW_PIN  3


#define  note_offset  36

#define  midi_channel  1


OSCMessage recMes;

OSCMessage sendMes; 


OSCClass osc(&recMes);


// server cfg (arduino)

byte serverMac[] = { 

  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

byte serverIp[]  = { // arduino IP

  192, 168, 0, 13 };

int  serverPort  = 8000; // outgoing from iPad, incoming to arduino


//  byte gateway[]   = { 192, 168, 1, 2 };

//  byte subnet[]    = { 255, 255, 255, 0 };


// client cfg

byte destIp[]  = { 

  192, 168, 0, 19}; // iPad IP

int  destPort = 8008; // outgoing from arduino, incoming to iPad


char *Juno2_OSC_name[3] = {

  "/jun",

  "/note",

  "/ctrl"

};

char *Juno2_OSC_param_name[37] = { // 36 parameters

  "/DCO_Env_Mode",   // $00

  "/VCF_Env_Mode",   // $01

  "/VCA_Env_Mode",   // $02

  "/DCO_Wave_Pulse", // $03

  "/DCO_Wave_Saw",   // $04

  "/DCO_Wave_Sub",   // $05

  "/DCO_Range",      // $06

  "/DCO_Sub_Level",  // $07

  "/DCO_Noise_Level",// $08

  "/HPF_CutOff",     // $09

  "/Chorus_Switch",  // $0a

  "/DCO_Lfo_Mod",    // $0b

  "/DCO_Env_Mod",    // $0c

  "/DCO_After_Mod",  // $0d

  "/DCO_Pwm_Depth",  // $0e

  "/DCO_Pwm_Rate",   // $0f

  "/VCF_CutOff",     // $10   d16

  "/VCF_Resonance",  // $11

  "/VCF_Lfo_Mod",    // $12

  "/VCF_Env_Mod",    // $13

  "/VCF_Key_Follow", // $14

  "/VCF_Aftertouch", // $15

  "/VCA_Level",      // $16

  "/VCA_Aftertouch", // $17

  "/LFO_Rate",       // $18

  "/LFO_Delay",      // $19

  "/ENV_T1",         // $1a

  "/ENV_L1",         // $1b

  "/ENV_T2",         // $1c

  "/ENV_L2",         // $1d

  "/ENV_T3",         // $1e

  "/ENV_L3",         // $1f

  "/ENV_T4",         // $20

  "/ENV_Key_Follow", // $21

  "/Chorus_Rate",    // $22

  "/Bender_Range",   // $23

};


// Arrays of patch parameters values

byte Juno2_SysEx_Patch_APR[54]; // whole patch


byte Juno2_SysEx_Patch_IPR[10]; // single parameter


char *midi_note[12] = {

  "/key_0",

  "/key_1",

  "/key_2",

  "/key_3",

  "/key_4",

  "/key_5",

  "/key_6",

  "/key_7",

  "/key_8",

  "/key_9",

  "/key_10",

  "/key_11",/*

  "/key_12",

  "/key_13",

  "/key_14",

  "/key_15",

  "/key_16",

  "/key_17",

  "/key_18",

  "/key_19",

  "/key_20",

  "/key_21",

  "/key_22",

  "/key_23",

  "/key_24",

  "/key_25",

  "/key_26",

  "/key_27",

  "/key_28",

  "/key_29",

  "/key_30",

  "/key_31",

  "/key_32",

  "/key_33",

  "/key_34",

  "/key_35",

  "/key_36",

  "/key_37",

  "/key_38",

  "/key_39",

  "/key_40",

  "/key_41",

  "/key_42",

  "/key_43",

  "/key_44",

  "/key_45",

  "/key_46",

  "/key_47",

  "/key_48",

  "/key_49",

*/

};


// pot, led & switch flags

boolean ledFlag;

boolean  swFlag;

long    oldPotValue;


//////////////////////////////////////////////////

// Init 

//////////////////////////////////////////////////

void setup() {


  // set midi baudsrate

//  Serial.begin(31250);     // old method without midi.h --> don't use 

  //    Serial.print("reset");


  // Initiate MIDI communications, listen to all channels

  MIDI.begin(MIDI_CHANNEL_OMNI);  


  // Connect the HandleSysex function to the library, so it is called upon reception of a sysex.

  MIDI.setHandleSystemExclusive(HandleSystemExclusive);  // Put only the name of the function


  Ethernet.begin(serverMac ,serverIp);

  //    Ethernet.begin(serverMac ,serverIp ,gateway ,subnet);


  // setting osc recieve server

  osc.begin(serverPort);


   // init osc send < --- pose pb si logMessage est compilé

   sendMes.setIp( destIp );

   sendMes.setPort( destPort );



  // LED OFF

  pinMode(LED_PWM, OUTPUT); 

  digitalWrite(LED_PWM, HIGH); 

  // switch and pot

  pinMode(SW_PIN, INPUT);


  ledFlag = false;    

  swFlag = false;


  analogReference(DEFAULT);

  oldPotValue = (long)analogRead(POT_PIN); 


  // osc message buffer clear

  osc.flush();


}


/////////////////////////////////////////////////////

// Mainloop

/////////////////////////////////////////////////////

void loop() 

{

  // osc arrive check

  if ( osc.available() ){

    OSC_SYSEX();

    OSC_NOTE(recMes);

  }

  else{

    //

  }


  // midi arrive check

    if (MIDI.read()) {                    // Is there a MIDI message incoming ?

    switch(MIDI.getType()) {		// Get the type of the message we caught

      case SystemExclusive:               // If it is a sysex

	SYSEX_OSC( MIDI.getData1(), MIDI.getSysExArray() );	// call SYSEX_OSC function

        break;


      // See the online reference for other message types

      default:

        break;

    }

  }


#ifdef _POT_DEBUG_

  // pot active send VCF CutOff  

  POT_OSC(); 

#endif

}



/////////////////////////////////////////////////////////

//

/////////////////////////////////////////////////////////

void HandleSystemExclusive(byte *array, byte size)

{

}


///////////////////////////////////////////////////////

// Convert OSC to Sysex

///////////////////////////////////////////////////////

void OSC_SYSEX(void)

{

    // toplevel address matching

    if( !strcmp( recMes.getAddress(0) , Juno2_OSC_name[0] ) ){    // "/jun"        

      // second level address matching

      if( !strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[0] ) ){

        MIDI_SEND_IPR(0, recMes.getArgFloat(0));

      }

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[1])){

        MIDI_SEND_IPR(1, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[2])){

        MIDI_SEND_IPR(2, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[3])){

        MIDI_SEND_IPR(3, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[4])){

        MIDI_SEND_IPR(4, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[5])){

        MIDI_SEND_IPR(5, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[6])){

        MIDI_SEND_IPR(6, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[7])){

        MIDI_SEND_IPR(7, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[8])){

        MIDI_SEND_IPR(8, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[9])){

        MIDI_SEND_IPR(9, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[10])){

        MIDI_SEND_IPR(10, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[11])){

        MIDI_SEND_IPR(11, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[12])){

        MIDI_SEND_IPR(12, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[13])){

        MIDI_SEND_IPR(13, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[14])){

        MIDI_SEND_IPR(14, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[15])){

        MIDI_SEND_IPR(15, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[16])){

        MIDI_SEND_IPR(16, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[17])){

        MIDI_SEND_IPR(17, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[18])){

        MIDI_SEND_IPR(18, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[19])){

        MIDI_SEND_IPR(19, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[20])){

        MIDI_SEND_IPR(20, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[21])){

        MIDI_SEND_IPR(21, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[22])){

        MIDI_SEND_IPR(22, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[23])){

        MIDI_SEND_IPR(23, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[24])){

        MIDI_SEND_IPR(24, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[25])){

        MIDI_SEND_IPR(25, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[26])){

        MIDI_SEND_IPR(26, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[27])){

        MIDI_SEND_IPR(27, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[28])){

        MIDI_SEND_IPR(28, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[29])){

        MIDI_SEND_IPR(29, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[30])){

        MIDI_SEND_IPR(30, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[31])){

        MIDI_SEND_IPR(31, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[32])){

        MIDI_SEND_IPR(32, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[33])){

        MIDI_SEND_IPR(33, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[34])){

        MIDI_SEND_IPR(34, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[35])){

        MIDI_SEND_IPR(35, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[36])){

        MIDI_SEND_IPR(36, recMes.getArgFloat(0)); 

      } 

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[37])){

        MIDI_SEND_IPR(37, recMes.getArgFloat(0)); 

      }

      else if(!strcmp( recMes.getAddress(1) , Juno2_OSC_param_name[37])){

        MIDI_SEND_IPR(37, recMes.getArgFloat(0)); 

      } 

      else{

        // rien 

      }


    } 

    else if( !strcmp( recMes.getAddress(0) , Juno2_OSC_name[1] ) ){

        // Note On OSC message

    }

    else{

      // to complete

    }


}


//////////////////////////////////////////////////////////////

// Send Juno2 SysEx string

//////////////////////////////////////////////////////////////

void MIDI_SEND_IPR( char osc_param_name, double osc_param_value)

{  

  //byte sysex_param_value = (byte)osc_param_value; // transform that shit !


  // visual feedback LED

  analogWrite(LED_PWM, floor(255 - osc_param_value));


 // set IPR sysex bytes : F0 41 36 00 23 20 01 name value F7

 Juno2_SysEx_Patch_IPR[0] = 0xf0;

 Juno2_SysEx_Patch_IPR[1] = 0x41;

 Juno2_SysEx_Patch_IPR[2] = 0x36;

 Juno2_SysEx_Patch_IPR[3] = 0x00;

 Juno2_SysEx_Patch_IPR[4] = 0x23;

 Juno2_SysEx_Patch_IPR[5] = 0x20;

 Juno2_SysEx_Patch_IPR[6] = 0x01;

 Juno2_SysEx_Patch_IPR[7] = (byte)osc_param_name;

 Juno2_SysEx_Patch_IPR[8] = (byte)osc_param_value; // sysex_param_value

 Juno2_SysEx_Patch_IPR[9] = 0xf7; 


 // send 10 bytes sysex array, including F0 & F7 (true)

 MIDI.sendSysEx( 10, Juno2_SysEx_Patch_IPR, true );

 // ça marche :)

}


///////////////////////////////////////////////////////

// convert SYSEX in OSC 

///////////////////////////////////////////////////////

void SYSEX_OSC( byte size, byte *sysex_array )

{ 

  // if it is a 54 bytes sysex string = APR

  if (size == 54){

    for (char i=0; i<55; i++) 

    Juno2_SysEx_Patch_APR[i] = sysex_array[i]; // extract param values from sysex


    // convert APR to 38xIPR message

    for (char p=0; p<39; p++){

      sendMes.setTopAddress(Juno2_OSC_name[0]); // "/jun"

      sendMes.setSubAddress( (char*)Juno2_OSC_param_name[p] ); // e.g "/VCF_CutOff"

      float f = sysex_array[ 7 + p ] + 0.000; // transform to float shit

      sendMes.setArgs( "f", &(f) );

      osc.sendOsc( &sendMes );

      delay(10); // small delay to see faders moving ;)

    }


  }

  // if it is a 38 bytes sysex string = not implemented

  else if (size == 38){

    // do stuff

  }  


  // if it is a 10 bytes sysex string = IPR

  else if (size == 10){

    // transform array

    for (char j=0; j<11; j++) 

    Juno2_SysEx_Patch_IPR[j] = sysex_array[j];

    //OSC send IPR

    sendMes.setTopAddress(Juno2_OSC_name[0]); // "/jun"

    sendMes.setSubAddress( (char*)Juno2_OSC_param_name[Juno2_SysEx_Patch_IPR[7]] ); // e.g "//VCF_CutOff"

    float f = Juno2_SysEx_Patch_IPR[8] + 0.000; // convert in float

    sendMes.setArgs( "f", &(f) ); // e.g "120."

    osc.sendOsc( &sendMes ); 

  }  

}


#ifdef _POT_DEBUG_

////////////////////////////////////////////////////

// Convert POT to OSC VCF_CutOff message

/////////////////////////////////////////////////////

void POT_OSC(void)

{

  int pot=analogRead(POT_PIN);  //adc data = 10bit data


  long value = (long)(pot >> 3); // 1024 -> 127


  if( oldPotValue != value ){   

    sendMes.setTopAddress(Juno2_OSC_name[0]);

    sendMes.setSubAddress(Juno2_OSC_param_name[16] ); // "/jun/VCF_CutOff"

    sendMes.setArgs( "i", &value );

    osc.sendOsc( &sendMes );


    //    Serial.print("pot:");

    //    Serial.println(value);

   }  

   oldPotValue = value;

}

#endif


////////////////////////////////////////////////////

// Convert OSC Note message

/////////////////////////////////////////////////////

void OSC_NOTE(OSCMessage recMes)

{

  // toplevel address matching

    if( !strcmp( recMes.getAddress(0) , Juno2_OSC_name[1] ) ){    // "/note"       

      // second level address matching

      for(char k=0; k<12; k++){

        if( !strcmp( recMes.getAddress(1) , midi_note[k] ) ){

           MIDI.sendNoteOn((byte)( k + note_offset), (byte)recMes.getArgFloat(0), midi_channel);

          //MIDI.sendNoteOn((byte)(i + 60), (byte)recMes.getArgFloat(0), 1);

        }

      }

    }

}


//////////////////////////////////////////////////////

//// Send Note from OSC

///////////////////////////////////////////////////////

//void MIDI_SEND_NOTE(long note, double velocity)

//{

//  MIDI.sendNoteOn((byte)note, (byte)velocity, 1);

//}

Juno_106_Translator_v1.1.zip

Edited by julienvoirin
Link to comment
Share on other sites

  • 2 years later...
  • 2 years later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

×
×
  • Create New...