miércoles, 11 de diciembre de 2013

Código controlador MIDI

Para poder compilar el código debo en primer lugar indicar que utilizo las siguientes librerias:

MIDI: http://playground.arduino.cc/Main/MIDILibrary

U8glib: http://code.google.com/p/u8glib/

M2tklib: http://code.google.com/p/m2tklib/  ( no es imprescindible, pero si alguien se anima a modificar cosas, esta es sin duda una herramienta de gran ayuda )

El código lo hice en diferentes archivos, teneis el principal y a continuación los ".h" que componen el total del código. Podeis añadir con el IDE que viene por defecto en Arduino los archivos .h tal y como se indica aqui:

http://arduino.cc/es/Guide/Environment

To compile the code I must first state that I use the following libraries:

MIDI: http://playground.arduino.cc/Main/MIDILibrary

U8glib: http://code.google.com/p/u8glib/

M2tklib: http://code.google.com/p/m2tklib/ (not required, but if anyone is encouraged to change things, this is definitely a useful tool)

I did the code in different files, you have the main and then. "H" that make up the total code. . IDE you can add to the default one h files in Arduino as shown here:


http://arduino.cc/es/Guide/Environment



                                   Código principal / Main code:



//
//
// Changelog:
// 20120818: fixes
// 20120813: cleanup
// 2012????.Albert: implementation

// http://en.wikipedia.org/wiki/The_C_Programming_Language

#include
#include "avr/pgmspace.h"
#include "potenciometros_y_display.h"
#include "CC_defs.h"
#include "constants.h"
#include "U8glib.h"

U8GLIB_ST7920_128X64 u8g(3, 5, 6, 9, 10, 11, 7, 8, 13, U8G_PIN_NONE, U8G_PIN_NONE, 12, 4); // 8Bit Com: D0..D7: 3, 5, 6, 9, 10, 11, 7, 8 en=13, di=12,rw=4

ControlStatus current_status;

//#define DEBUG_MENU
//#define DEBUG_KNOBS
//#define DEBUG_MIDI
//#define ENCODER
//#define ENCODER_PRIMER_PASO
//#define ENCODER_SEGUNDO_PASO
//#define BOTON_PULSADO
//#define SALIDA

void setup() // -----------------------------------------------------------------------------------------------------------------------------------
{
#if defined(DEBUG_MENU) || defined(DEBUG_MIDI) || defined(ENCODER) || defined(SALIDA) || defined(ENCODER_PRIMER_PASO) || defined(ENCODER_SEGUNDO_PASO) || defined(BOTON_PULSADO) || defined(DEBUG_KNOBS)
Serial.begin(9600);
#else
MIDI.begin(MIDI_CHANNEL_OMNI); // de esta manera recibe os 16 canales
#endif
ControlStatus_Init(&current_status);
}

void loop()
{
static unsigned int clock = 0;
const unsigned int period = 100;

input_update(&current_status);

if ((clock % period) == 0) // trigger every 'period' (e.g. 1 every 5 times)
{
input_update(&current_status);//zz!
// clock: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// clock % period: 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4 0
screen_update(&current_status);
output_update(&current_status);

}
}

//------------- EMPIEZAN LAS FUNCIONES-------------------------------------------


void input_update(ControlStatus *cs)
{
// Menu and submenu handling:

#ifdef ENCODER

char btmp[127];
sprintf(btmp, "cs->encoder.encoder_target %i", cs->encoder.encoder_target);
Serial.println(btmp);//zz

#endif

switch ( cs->encoder.encoder_target ) // Vale 0
{
case MenuEncoderNdx:

cs->encoder.positions[cs->encoder.encoder_target] = update_from_encoder(cs, cs->encoder.positions[cs->encoder.encoder_target], NUM_MENUS);//NUM_MENUS

/*
int update_from_encoder(ControlStatus *cs, int enc_pos, int x);

int update_from_encoder = ( Paso de la estructura, parametro del valor de la funcion de encoder, valor maximo que puede alcanzar en este caso NUM_MENUS )

ejemplo:

update_from_encoder(cs, cs->encoder.positions[cs->encoder.encoder_target], NUM_MENUS): 3
cs->encoder.positions[cs->encoder.encoder_target]: 3
Valor de cs->encoder.encoder_target: 0

update_from_encoder(cs, cs->encoder.positions[cs->encoder.encoder_target], NUM_MENUS): 4
cs->encoder.positions[cs->encoder.encoder_target]: 4
Valor de cs->encoder.encoder_target: 0

*/

#ifdef ENCODER_PRIMER_PASO

char btmp[127];
char btmp1[127];
char btmp2[127];
sprintf(btmp, "cs->encoder.positions[cs->encoder.encoder_target]: %i", cs->encoder.positions[cs->encoder.encoder_target]);
sprintf(btmp1, "update_from_encoder(cs, cs->encoder.positions[cs->encoder.encoder_target], NUM_MENUS): %i", update_from_encoder(cs, cs->encoder.positions[cs->encoder.encoder_target], NUM_MENUS));
sprintf(btmp2, "Valor de cs->encoder.encoder_target: %i", cs->encoder.encoder_target );
Serial.println(btmp1);//zz
Serial.println(btmp);
Serial.println(btmp2);
Serial.println("\n");
,
#endif



if (update_from_button(&current_status) == BUTTON_PRESSED)
{
switch (cs->encoder.positions[MenuEncoderNdx]
{
case ME_KnobGroup:
cs->encoder.encoder_target = KnobGroupEncoderNdx;
break;

case ME_Knob:
cs->encoder.encoder_target = KnobEncoderNdx;
break;

case ME_ControlChange:
cs->encoder.encoder_target = ControlChangeEncoderNdx;
break;

case ME_MidiChannel:
cs->encoder.encoder_target = MidiChannelNdx;
break;

case ME_Behavior:
cs->encoder.encoder_target = BehaviorNdx;
break;
}

#ifdef ENCODER_SEGUNDO_PASO

char btmp[127];
char btmp1[127];
char btmp2[127];
sprintf(btmp, "cs->encoder.positions[cs->encoder.encoder_target]: %i", cs->encoder.positions[cs->encoder.encoder_target]);
sprintf(btmp1, "update_from_encoder(cs, cs->encoder.positions[cs->encoder.encoder_target], NUM_MENUS): %i", update_from_encoder(cs, cs->encoder.positions[cs->encoder.encoder_target], NUM_MENUS));
sprintf(btmp2, "Valor de cs->encoder.encoder_target: %i", cs->encoder.encoder_target );
Serial.println(btmp1);//zz
Serial.println(btmp);
Serial.println(btmp2);
Serial.println("\n");

#endif



}
update_encoder_targets(cs);
break;

case KnobGroupEncoderNdx:// ----------------------------------------------------------------------------------Case-0

// Serial.println("Knob group");
cs->encoder.positions[cs->encoder.encoder_target] =
update_from_encoder(&current_status, cs->encoder.positions[cs->encoder.encoder_target], NUM_KNOB_GROUPS);

#ifdef DEBUG_MENU
sprintf(btmp, "KnobGroupEncoderNdx: %i", cs->encoder.positions[cs->encoder.encoder_target]);
Serial.println(btmp);//zz
#endif

if (update_from_button(&current_status) == BUTTON_RELEASED) // pressed
{

cs->encoder.encoder_target = MenuEncoderNdx; // Return to menu.
}
break;

case KnobEncoderNdx: // --------------------------------------------------------------------------------------Case-1

// Serial.println("Knob");
cs->encoder.positions[cs->encoder.encoder_target] =
update_from_encoder(&current_status, cs->encoder.positions[cs->encoder.encoder_target], NUM_KNOBS);

#ifdef DEBUG_MENU
sprintf(btmp, "KnobEncoderNdx: %i", cs->encoder.positions[cs->encoder.encoder_target]);
Serial.println(btmp);//zz
#endif

if (update_from_button(&current_status) == BUTTON_RELEASED) // pressed
{
cs->encoder.encoder_target = MenuEncoderNdx; // Return to menu.
}
break;

case MidiChannelNdx: // --------------------------------------------------------------------------Case-2
// Canal Midi
// #include"canalMIDI.h"

// Serial.println("Canal Midi");
cs->encoder.positions[cs->encoder.encoder_target] =
update_from_encoder(&current_status, cs->encoder.positions[cs->encoder.encoder_target], NUM_MIDI);

#ifdef DEBUG_MENU
sprintf(btmp, "MidiChannelNdx: %i", cs->encoder.positions[cs->encoder.encoder_target]);
Serial.println(btmp);//zz
#endif

if (update_from_button(&current_status) == BUTTON_RELEASED)
{
// Assign midi channel
int group = cs->encoder.positions[KnobGroupEncoderNdx];
int knob = cs->encoder.positions[KnobEncoderNdx];
cs->knobs[group].channel[knob] = cs->encoder.positions[cs->encoder.encoder_target];
// Return to menu:
cs->encoder.encoder_target = MenuEncoderNdx;
}
break;

case ControlChangeEncoderNdx: // -------------------------------------------------------------------------Case-3
// Control Change
// Serial.println("Control Change");

cs->encoder.positions[cs->encoder.encoder_target] =
update_from_encoder(&current_status, cs->encoder.positions[cs->encoder.encoder_target], NUM_CONTROL_CHANGE);

#ifdef DEBUG_MENU
sprintf(btmp, "ControlChangeEncoderNdx: %i", cs->encoder.positions[cs->encoder.encoder_target]);
Serial.println(btmp);//zz
#endif


if (update_from_button(&current_status) == BUTTON_RELEASED) // pressed
{
// Assign control change:
int group = cs->encoder.positions[KnobGroupEncoderNdx];
int knob = cs->encoder.positions[KnobEncoderNdx];
cs->knobs[group].control_change[knob] = cs->encoder.positions[cs->encoder.encoder_target];
// Return to menu:
cs->encoder.encoder_target = MenuEncoderNdx;
}
break;

case BehaviorNdx: // --------------------------------------------------------------------------------------Case-4

#ifdef DEBUG_MENU
sprintf(btmp, "BehaviorNdx: %i", cs->encoder.positions[cs->encoder.encoder_target]);
Serial.println(btmp);//zz
#endif

cs->encoder.encoder_target = MenuEncoderNdx; // Unimplemented:
// return to menu.
break;

}//switch

// Read knob data:
input_update_knobs(cs);

}



void output_update(ControlStatus *cs)
{
// Update MIDI parameters, if required:
output_update_midi(cs);
}



void screen_update(ControlStatus *cs)
{
// Prepare LCD for drawing:
u8g.firstPage();

// Draw frame and constant parts:
do
{
// Draw frame and constant parts:

lcd_draw_header();

// Dynamic data:
lcd_draw_menu(cs);
lcd_draw_knob(cs);
input_update(cs);
}
while (u8g.nextPage());
}




int update_from_button(ControlStatus * cs)
{
// read the pushbutton input pin:
int salida = BUTTON_IDLE; // Initialize, always

if (cs)
{
cs->button.buttonState = digitalRead(PIN_Button); // PIN_Button = 2;

// compare the buttonState to its previous state
if (cs->button.buttonState != cs->button.lastButtonState)
{
// if the state has changed, increment the counter
if (cs->button.buttonState == HIGH)
{
// if the current state is HIGH then the button
// wend from off to on:
cs->button.buttonPushCounter++;

#ifdef BOTON_PULSADO
Serial.println("on");
Serial.print("number of button pushes: ");
Serial.println(cs->button.buttonPushCounter);
#endif
salida = BUTTON_PRESSED;

}
else
{
// if the current state is LOW then the button
// wend from on to off:
#ifdef DEBUG_MENU
Serial.println("off");
#endif
salida = BUTTON_RELEASED;


}
}
// save the current state as the last state,
// for next time through the loop
cs->button.lastButtonState = cs->button.buttonState;

#ifdef SALIDA
Serial.print(salida == BUTTON_PRESSED? "BUTTON_PRESSED" : salida == BUTTON_RELEASED? "BUTTON_RELEASED" : "" );
#endif

}

return salida;
}





int update_from_encoder(ControlStatus *cs, int enc_pos, int x)
{
if (cs)
{
int lecturaPin = digitalRead(PIN_Encoder0A);
if ((cs->encoder.ultimaPosicionPinA == HIGH) && (lecturaPin == LOW))
{
if (digitalRead(PIN_Encoder0B) == HIGH)
{
#ifdef DEBUG_MENU
Serial.println("-");
#endif

enc_pos--;
// lcd.clear();
}
else
{
#ifdef DEBUG_MENU
Serial.println("+");//zz!
#endif
enc_pos++;
// lcd.clear();
}
}
cs->encoder.ultimaPosicionPinA = lecturaPin;
if (enc_pos < 0)
{
#ifdef DEBUG_MENU
Serial.println("- [0]");//zz!
#endif
enc_pos = 0;
}
if (enc_pos > x)
{
enc_pos = x;
}
}
return enc_pos;
}



void input_update_knobs(ControlStatus * cs)
{
const int inputs[NUM_KNOBS] = { A3, A2, A1, A0 };
const int knob_group = cs->encoder.positions[KnobGroupEncoderNdx];

for ( int i = 0; i < NUM_KNOBS; i++ )
{
const int raw_input = analogRead(inputs[i]);
const int ADC_res_bits = 10;
const int meaning_adc_bits = 4; // Use 4 of the 10 ADC bits (e.g. 2**4 = 16 steps instead of 2**10 = 1024)
const int remove_mask = ~(1 << (ADC_res_bits - meaning_adc_bits)) - 1;
const int knob_current_value = raw_input & remove_mask; // = (raw_input / 64) * 64;
if ( cs->knobs[knob_group].knob[i] != knob_current_value ) // knob changed?
{
delay(10);
cs->knobs[knob_group].knob[i] = knob_current_value;
#ifdef DEBUG_KNOBS

char btmp[32];
sprintf(btmp, "knob[%i, %i]: %i",
knob_group, i, knob_current_value);
Serial.println(btmp);//zz!
#endif
}
}
}


void lcd_draw_knob(ControlStatus * cs)
{
const int knob_group = cs->encoder.positions[KnobGroupEncoderNdx];

u8g.setFont(u8g_font_micro);

for ( int i = 0; i < NUM_KNOBS; i++ )
{
const int value = map(cs->knobs[knob_group].knob[i], 0, 1023, 0, 20);
const int pct = map(cs->knobs[knob_group].knob[i], 0, 1023, 0, 107);

// X, Y ; ancho , alto Linea vertical mas estrcha (debajo del restangulo )
// rectangulo que sube o baja

u8g.drawLine(2 + 20 * i, 60, 2 + 20 * i, 40);
u8g.drawBox(1 + 20 * i, (60 - value), 3, 100);

// Knob %
u8g.drawStr(1 + 20 * i + 6, 64 - value, strcpy_P(buzzer, (char *)pgm_read_word(&(strin_table[pct])))); // sample
}
}




void lcd_draw_header()
{
u8g.drawFrame(79, 0, 49, 64); // X, Y ; ancho , alto Recuadro grupo
u8g.drawLine(0, 30, 79, 30); // linea entre el texto y los potes
u8g.drawLine(0, 37, 79, 37); // "" ""
u8g.drawLine(79, 24, 128, 24); // linea separadora grupo y auto
}


void indicador_de_pulsacion(ControlStatus * cs)
{

//u8g.setFont(u8g_font_6x10);
u8g.drawStr( 80, 15,"d" );
}



void lcd_draw_menu(ControlStatus *cs)
{
u8g.setFont(u8g_font_micro);
const int font_width = 4; // 4 point-wide font
const int font_height = 6; // 6 point-tall font
const int menu_pos = cs->encoder.positions[MenuEncoderNdx];

// Draw cursor:
u8g.drawStr(1, 5 + (menu_pos * font_height), ">");

// Draw menu entries:
for ( int i = 0; i < ME_Elems; i++ )
{
// Draw text:



u8g.drawStr(8, 5 + i*font_height, menu_labels[i]);
if ( i != ME_ControlChange ) // Draw all except CC
{

// Draw value:
//const int text_offset = (strlen(menu_labels[i]) ) * font_width;

const int text_offset = (strlen(menu_labels[i]) ) * font_width;



const int value = cs->encoder.positions[i+1];
const char *text = value >= 0 && value <= MAX_strin? (char *)pgm_read_word(&(strin_table[value])) : "???!";
u8g.drawStr(8 + text_offset, 5 + i*font_height, strcpy_P(buzzer, text));
}
}
// Draw extra elements:

const int cc_text_offset = (strlen(menu_labels[ME_ControlChange]) + 1) * font_width;
const int value = cs->encoder.positions[ControlChangeEncoderNdx];
const char *cc_text = value >= 0 && value <= MAX_string? (char *)pgm_read_word(&(string_table[value])) : "???!";
u8g.drawStr(8 + cc_text_offset, 5 + ME_ControlChange*font_height, strcpy_P(buffer, cc_text)); // Muestra el porcentaje que se mueve


}



void output_update_midi(ControlStatus *cs)
{
const int knob_group = cs->encoder.positions[KnobGroupEncoderNdx];

for ( int i = 0; i < NUM_KNOBS; i++ )
{
const int midi_channel = cs->knobs[knob_group].channel[i];
const int cc = cs->knobs[knob_group].control_change[i];
const int value = map(cs->knobs[knob_group].knob[i], 0, 1023, 0, 137);

if ( midi_channel >= 0 && midi_channel < NUM_MIDI && cs->midi_status[midi_channel].cc != cc || cs->midi_status[midi_channel].knob_value != value )
{
cs->midi_status[midi_channel].cc = cc;
cs->midi_status[midi_channel].knob_value = value;
MIDI.sendControlChange(cc,value,midi_channel);
//sendControlChange (byte ControlNumber, byte ControlValue, byte Channel)

}
}
}


void ControlStatus_Init(ControlStatus * cs)
{
memset(cs, 0, sizeof(ControlStatus));

cs->button.buttonPushCounter = 1; // Counter for the number of button presses
cs->button.buttonState = 1; // Current state of the button
cs->button.lastButtonState = 0; // Previous state of the button

cs->encoder.encoder_target = 0;
cs->encoder.ultimaPosicionPinA = LOW;
for ( int i = 0; i < NUM_KNOB_GROUPS; i++ )
{
for ( int j = 0; j < NUM_KNOBS; j++ )
{
cs->knobs[i].knob[j] = 0;
cs->knobs[i].behavior[j] = 0;
cs->knobs[i].control_change[j] = 0;
cs->knobs[i].channel[j] = 0;
}
}
for ( int i = 0; i < NUM_MIDI; i++ )
{
cs->midi_status[i].cc = 0;
cs->midi_status[i].knob_value = 0;
}
}


void update_encoder_targets(ControlStatus *cs)
{
const int knob_group = MAX(0, cs->encoder.positions[KnobGroupEncoderNdx]);
const int knob = MAX(0, cs->encoder.positions[KnobEncoderNdx]);
cs->encoder.positions[ControlChangeEncoderNdx] = MAX(0, cs->knobs[knob_group].control_change[knob]);
cs->encoder.positions[MidiChannelNdx] = MAX(0, cs->knobs[knob_group].channel[knob]);

cs->encoder.positions[BehaviorNdx] = MAX(0, cs->knobs[knob_group].behavior[knob]);
}


------------------------------------------------------------------  CC_defs.h



// Changelog:
// 20120813: cleanup
// 2012????.Albert: implementation


#ifndef CC_defs_h
#define CC_defs_h


char buffer[16];

prog_char string_0[] PROGMEM = "00-BankSelMSB"; // "String 0" etc are strings to store - change to suit.
prog_char string_1[] PROGMEM = "01-Mod Wheel";
prog_char string_2[] PROGMEM = "02-Breath Cntrl";
prog_char string_3[] PROGMEM = "03-CC 03";
prog_char string_4[] PROGMEM = "04-Foot Cntrl";
prog_char string_5[] PROGMEM = "05-Porta Time";
prog_char string_6[] PROGMEM = "06-Data Entry"; // "String 0" etc are strings to store - change to suit.
prog_char string_7[] PROGMEM = "07-Volume";
prog_char string_8[] PROGMEM = "08-Balance";
prog_char string_9[] PROGMEM = "09-CC 09";
prog_char string_10[] PROGMEM = "10-Pan";
prog_char string_11[] PROGMEM = "11-Expression ";
prog_char string_12[] PROGMEM = "12-fx Cntrl 1";
prog_char string_13[] PROGMEM = "13-fx Cntrl 2";
prog_char string_14[] PROGMEM = "14-CC 14";
prog_char string_15[] PROGMEM = "15-CC 15";
prog_char string_16[] PROGMEM = "16-GPCntrl1LSB1";
prog_char string_17[] PROGMEM = "17-GPCntrl1LSB2";
prog_char string_18[] PROGMEM = "18-GPCntrl1LSB3";
prog_char string_19[] PROGMEM = "19-GPCntrl1LSB3";
prog_char string_20[] PROGMEM = "20-CC 20";
prog_char string_21[] PROGMEM = "21-CC 21";
prog_char string_22[] PROGMEM = "22-CC 22";
prog_char string_23[] PROGMEM = "23-CC 23";
prog_char string_24[] PROGMEM = "24-CC 24";
prog_char string_25[] PROGMEM = "25-CC 25";
prog_char string_26[] PROGMEM = "26-CC 26";
prog_char string_27[] PROGMEM = "27-CC 27";
prog_char string_28[] PROGMEM = "28-CC 28";
prog_char string_29[] PROGMEM = "29-CC 29";
prog_char string_30[] PROGMEM = "30-CC 30";
prog_char string_31[] PROGMEM = "31-CC 31";
prog_char string_32[] PROGMEM = "32-BankSelLSB";
prog_char string_33[] PROGMEM = "33-Mod Wheel LSB";
prog_char string_34[] PROGMEM = "34-Breath Cntrl LSB";
prog_char string_35[] PROGMEM = "35-CC 35";
prog_char string_36[] PROGMEM = "36-Foot Cntrl LSB";
prog_char string_37[] PROGMEM = "37-Porta Time LSB";
prog_char string_38[] PROGMEM = "38-Data Entry LSB";
prog_char string_39[] PROGMEM = "39-Volume LSB";
prog_char string_40[] PROGMEM = "40-Balance LSB";
prog_char string_41[] PROGMEM = "41-CC 41";
prog_char string_42[] PROGMEM = "42-Pan LSB ";
prog_char string_43[] PROGMEM = "43-Expression LSB";
prog_char string_44[] PROGMEM = "44-fx 1 LSB ";
prog_char string_45[] PROGMEM = "45-fx 2 LSB";
prog_char string_46[] PROGMEM = "46-CC 46";
prog_char string_47[] PROGMEM = "47-CC 47";
prog_char string_48[] PROGMEM = "48-GPCntrl1LSB ";
prog_char string_49[] PROGMEM = "49-GPCntrl2LSB ";
prog_char string_50[] PROGMEM = "50-GPCntrl3LSB ";
prog_char string_51[] PROGMEM = "51-GPCntrl4LSB";
prog_char string_52[] PROGMEM = "52-CC 52";
prog_char string_53[] PROGMEM = "53-CC 53";
prog_char string_54[] PROGMEM = "54-CC 54";
prog_char string_55[] PROGMEM = "55-CC 55";
prog_char string_56[] PROGMEM = "56-CC 56";
prog_char string_57[] PROGMEM = "57-CC 57";
prog_char string_58[] PROGMEM = "58-CC 58";
prog_char string_59[] PROGMEM = "59-CC 59";
prog_char string_60[] PROGMEM = "60-CC 60";
prog_char string_61[] PROGMEM = "61-CC 61";
prog_char string_62[] PROGMEM = "62-CC 62";
prog_char string_63[] PROGMEM = "63-CC 63";
prog_char string_64[] PROGMEM = "64-Damper Pedal";
prog_char string_65[] PROGMEM = "65-Porta Pedal";
prog_char string_66[] PROGMEM = "66-Sostenuto";
prog_char string_67[] PROGMEM = "67-Soft Pedal";
prog_char string_68[] PROGMEM = "68-Legato Foot Sw";
prog_char string_69[] PROGMEM = "69-Hold-2";
prog_char string_70[] PROGMEM = "70-Sound Vari";
prog_char string_71[] PROGMEM = "71-Timbre/Harmonics";
prog_char string_72[] PROGMEM = "72-Realease Time";
prog_char string_73[] PROGMEM = "73-Attack Time";
prog_char string_74[] PROGMEM = "74-Brighness";
prog_char string_75[] PROGMEM = "75-Decay Time";
prog_char string_76[] PROGMEM = "76-Vib.Rate";
prog_char string_77[] PROGMEM = "77-Vib.Depth";
prog_char string_78[] PROGMEM = "78-Vib.Delay";
prog_char string_79[] PROGMEM = "79-Sound Ctrl10";
prog_char string_80[] PROGMEM = "80-GeneralPurp10 ";
prog_char string_81[] PROGMEM = "81-GeneralPurp6";
prog_char string_82[] PROGMEM = "82-GeneralPurp7";
prog_char string_83[] PROGMEM = "83-GeneralPurp8";
prog_char string_84[] PROGMEM = "84-PortaCntrl";
prog_char string_85[] PROGMEM = "85-CC 85";
prog_char string_86[] PROGMEM = "86-CC 86";
prog_char string_87[] PROGMEM = "87-CC 87";
prog_char string_88[] PROGMEM = "88-CC 88";
prog_char string_89[] PROGMEM = "89-CC 89";
prog_char string_90[] PROGMEM = "90-CC 90";
prog_char string_91[] PROGMEM = "91-Reverb Depth";
prog_char string_92[] PROGMEM = "92-Tremolo Depth";
prog_char string_93[] PROGMEM = "93-Chorus Depth";
prog_char string_94[] PROGMEM = "94-Detune Depth";
prog_char string_95[] PROGMEM = "95-Phaser Depth";
prog_char string_96[] PROGMEM = "96-Data Inc";
prog_char string_97[] PROGMEM = "97-Data Dec";
prog_char string_98[] PROGMEM = "98-NRPN LSB";
prog_char string_99[] PROGMEM = "99-NRPN-MSB";
prog_char string_100[] PROGMEM = "100-RPN LSB";
prog_char string_101[] PROGMEM = "101-RPN MSB";
prog_char string_102[] PROGMEM = "102-CC 102";
prog_char string_103[] PROGMEM = "103-CC 103";
prog_char string_104[] PROGMEM = "104-CC 104";
prog_char string_105[] PROGMEM = "105-CC 105";
prog_char string_106[] PROGMEM = "106-CC 106";
prog_char string_107[] PROGMEM = "107-CC 107";
prog_char string_108[] PROGMEM = "108-CC 108";
prog_char string_109[] PROGMEM = "109-CC 108";
prog_char string_110[] PROGMEM = "110-CC 110 ";
prog_char string_111[] PROGMEM = "111-CC 111";
prog_char string_112[] PROGMEM = "112-CC 112";
prog_char string_113[] PROGMEM = "113-CC 113";
prog_char string_114[] PROGMEM = "114-CC 114";
prog_char string_115[] PROGMEM = "115-CC 115";
prog_char string_116[] PROGMEM = "116-CC 116";
prog_char string_117[] PROGMEM = "117-CC 117";
prog_char string_118[] PROGMEM = "118-CC 118";
prog_char string_119[] PROGMEM = "119-CC 119";
prog_char string_120[] PROGMEM = "120-All Sound OFF";
prog_char string_121[] PROGMEM = "121-RST all Cntrl";
prog_char string_122[] PROGMEM = "122-Local Cntrl";
prog_char string_123[] PROGMEM = "123-All note Off";
prog_char string_124[] PROGMEM = "124-Omni Off";
prog_char string_125[] PROGMEM = "125-Omni On";
prog_char string_126[] PROGMEM = "126-Mono Mode On";

#define MAX_string 126

PROGMEM PGM_P string_table[] = // change "string_table" name to suit
{
string_0,
string_1,
string_2,
string_3,
string_4,
string_5,
string_6,
string_7,
string_8,
string_9,
string_10,
string_11,
string_12,
string_13,
string_14,
string_15,
string_16,
string_17,
string_18,
string_19,
string_20,
string_21,
string_22,
string_23,
string_24,
string_25,
string_26,
string_27,
string_28,
string_29,
string_30,
string_31,
string_32,
string_33,
string_34,
string_35,
string_36,
string_37,
string_38,
string_39,
string_40,
string_41,
string_42,
string_43,
string_44,
string_45,
string_46,
string_47,
string_48,
string_49,
string_50,
string_51,
string_52,
string_53,
string_54,
string_55,
string_56,
string_57,
string_58,
string_59,
string_60,
string_61,
string_62,
string_63,
string_64,
string_65,
string_66,
string_67,
string_68,
string_69,
string_70,
string_71,
string_72,
string_73,
string_74,
string_75,
string_76,
string_77,
string_78,
string_79,
string_80,
string_81,
string_82,
string_83,
string_84,
string_85,
string_86,
string_87,
string_88,
string_89,
string_90,
string_91,
string_92,
string_93,
string_94,
string_95,
string_96,
string_97,
string_98,
string_99,
string_100,
string_101,
string_102,
string_103,
string_104,
string_105,
string_106,
string_107,
string_108,
string_109,
string_110,
string_111,
string_112,
string_113,
string_114,
string_115,
string_116,
string_117,
string_118,
string_119,
string_120,
string_121,
string_122,
string_123,
string_124,
string_125,
string_126,
};




#endif /* #ifndef CC_defs_h */


------------------------------------------------------------------ constants.h


// Changelog:
// 20120813: cleanup
// 2012????.Albert: implementation



#ifndef constants_h
#define constants_h

#include "Arduino.h"


char buzzer[16];

prog_char strin_0[] PROGMEM = "0"; // "String 0" etc are strings to store // change to suit.
prog_char strin_1[] PROGMEM = "1";
prog_char strin_2[] PROGMEM = "2";
prog_char strin_3[] PROGMEM = "3";
prog_char strin_4[] PROGMEM = "4";
prog_char strin_5[] PROGMEM = "5";
prog_char strin_6[] PROGMEM = "6"; // "String 0" etc are strings to store - // change to suit.
prog_char strin_7[] PROGMEM = "7";
prog_char strin_8[] PROGMEM = "8";
prog_char strin_9[] PROGMEM = "9";
prog_char strin_10[] PROGMEM = "10";
prog_char strin_11[] PROGMEM = "11";
prog_char strin_12[] PROGMEM = "12";
prog_char strin_13[] PROGMEM = "13";
prog_char strin_14[] PROGMEM = "14";
prog_char strin_15[] PROGMEM = "15";
prog_char strin_16[] PROGMEM = "16";
prog_char strin_17[] PROGMEM = "17";
prog_char strin_18[] PROGMEM = "18";
prog_char strin_19[] PROGMEM = "19";
prog_char strin_20[] PROGMEM = "20";
prog_char strin_21[] PROGMEM = "21";
prog_char strin_22[] PROGMEM = "22";
prog_char strin_23[] PROGMEM = "23";
prog_char strin_24[] PROGMEM = "24";
prog_char strin_25[] PROGMEM = "25";
prog_char strin_26[] PROGMEM = "26";
prog_char strin_27[] PROGMEM = "27";
prog_char strin_28[] PROGMEM = "28";
prog_char strin_29[] PROGMEM = "29";
prog_char strin_30[] PROGMEM = "30";
prog_char strin_31[] PROGMEM = "31";
prog_char strin_32[] PROGMEM = "32";
prog_char strin_33[] PROGMEM = "33";
prog_char strin_34[] PROGMEM = "34";
prog_char strin_35[] PROGMEM = "35";
prog_char strin_36[] PROGMEM = "36";
prog_char strin_37[] PROGMEM = "37";
prog_char strin_38[] PROGMEM = "38";
prog_char strin_39[] PROGMEM = "39";
prog_char strin_40[] PROGMEM = "40";
prog_char strin_41[] PROGMEM = "41";
prog_char strin_42[] PROGMEM = "42";
prog_char strin_43[] PROGMEM = "43";
prog_char strin_44[] PROGMEM = "44";
prog_char strin_45[] PROGMEM = "45";
prog_char strin_46[] PROGMEM = "46";
prog_char strin_47[] PROGMEM = "47";
prog_char strin_48[] PROGMEM = "48";
prog_char strin_49[] PROGMEM = "49";
prog_char strin_50[] PROGMEM = "50";
prog_char strin_51[] PROGMEM = "51";
prog_char strin_52[] PROGMEM = "52";
prog_char strin_53[] PROGMEM = "53";
prog_char strin_54[] PROGMEM = "54";
prog_char strin_55[] PROGMEM = "55";
prog_char strin_56[] PROGMEM = "56";
prog_char strin_57[] PROGMEM = "57";
prog_char strin_58[] PROGMEM = "58";
prog_char strin_59[] PROGMEM = "59";
prog_char strin_60[] PROGMEM = "60";
prog_char strin_61[] PROGMEM = "61";
prog_char strin_62[] PROGMEM = "62";
prog_char strin_63[] PROGMEM = "63";
prog_char strin_64[] PROGMEM = "64";
prog_char strin_65[] PROGMEM = "65";
prog_char strin_66[] PROGMEM = "66";
prog_char strin_67[] PROGMEM = "67";
prog_char strin_68[] PROGMEM = "68";
prog_char strin_69[] PROGMEM = "69";
prog_char strin_70[] PROGMEM = "70";
prog_char strin_71[] PROGMEM = "71";
prog_char strin_72[] PROGMEM = "72";
prog_char strin_73[] PROGMEM = "73";
prog_char strin_74[] PROGMEM = "74";
prog_char strin_75[] PROGMEM = "75";
prog_char strin_76[] PROGMEM = "76";
prog_char strin_77[] PROGMEM = "77";
prog_char strin_78[] PROGMEM = "78";
prog_char strin_79[] PROGMEM = "79";
prog_char strin_80[] PROGMEM = "80";
prog_char strin_81[] PROGMEM = "81";
prog_char strin_82[] PROGMEM = "82";
prog_char strin_83[] PROGMEM = "83";
prog_char strin_84[] PROGMEM = "84";
prog_char strin_85[] PROGMEM = "85";
prog_char strin_86[] PROGMEM = "86";
prog_char strin_87[] PROGMEM = "87";
prog_char strin_88[] PROGMEM = "88";
prog_char strin_89[] PROGMEM = "89";
prog_char strin_90[] PROGMEM = "90";
prog_char strin_91[] PROGMEM = "91";
prog_char strin_92[] PROGMEM = "92";
prog_char strin_93[] PROGMEM = "93";
prog_char strin_94[] PROGMEM = "94";
prog_char strin_95[] PROGMEM = "95";
prog_char strin_96[] PROGMEM = "96";
prog_char strin_97[] PROGMEM = "97";
prog_char strin_98[] PROGMEM = "98";
prog_char strin_99[] PROGMEM = "99";
prog_char strin_100[] PROGMEM = "100";

#define MAX_strin 100

PROGMEM PGM_P strin_table[] = // change "string_table" name to suit
{
strin_0,
strin_1,
strin_2,
strin_3,
strin_4,
strin_5,
strin_6,
strin_7,
strin_8,
strin_9,
strin_10,
strin_11,
strin_12,
strin_13,
strin_14,
strin_15,
strin_16,
strin_17,
strin_18,
strin_19,
strin_20,
strin_21,
strin_22,
strin_23,
strin_24,
strin_25,
strin_26,
strin_27,
strin_28,
strin_29,
strin_30,
strin_31,
strin_32,
strin_33,
strin_34,
strin_35,
strin_36,
strin_37,
strin_38,
strin_39,
strin_40,
strin_41,
strin_42,
strin_43,
strin_44,
strin_45,
strin_46,
strin_47,
strin_48,
strin_49,
strin_50,
strin_51,
strin_52,
strin_53,
strin_54,
strin_55,
strin_56,
strin_57,
strin_58,
strin_59,
strin_60,
strin_61,
strin_62,
strin_63,
strin_64,
strin_65,
strin_66,
strin_67,
strin_68,
strin_69,
strin_70,
strin_71,
strin_72,
strin_73,
strin_74,
strin_75,
strin_76,
strin_77,
strin_78,
strin_79,
strin_80,
strin_81,
strin_82,
strin_83,
strin_84,
strin_85,
strin_86,
strin_87,
strin_88,
strin_89,
strin_90,
strin_91,
strin_92,
strin_93,
strin_94,
strin_95,
strin_96,
strin_97,
strin_98,
strin_99,
strin_100,

};


#endif // #ifndef constants_h


------------------------------------------------------------- potenciometros_y_display.h


// Changelog:
// 20120813: cleanup
// 2012????.Albert: implementation

#ifndef potenciometros_y_display_h


// Definitions and constants:

#define NUM_KNOB_GROUPS 8
#define NUM_KNOBS 4 // 4 knobs * 4 knobs/bank = 16 total knobs
#define NUM_MENUS 4
#define NUM_MIDI 16
#define NUM_CONTROL_CHANGE 127

#define BUTTON_IDLE 0
#define BUTTON_RELEASED 1
#define BUTTON_PRESSED 2
/*
Version para Mega
const int PIN_Encoder0A = 30;
const int PIN_Encoder0B = 31;
const int PIN_Button = 22;
*/
// version para UNO
/*const int PIN_Encoder0A = 0;
const int PIN_Encoder0B = 2;
*/

const int PIN_Encoder0A = 19;
const int PIN_Encoder0B = 18;
const int PIN_Button = 2;


enum EncoderIndexes
{
MenuEncoderNdx = 0,
KnobGroupEncoderNdx,
KnobEncoderNdx,
ControlChangeEncoderNdx,
MidiChannelNdx,
BehaviorNdx,
KnobEncoderElems
};


enum MenuElems
{
ME_KnobGroup = 0,
ME_Knob,
ME_ControlChange,
ME_MidiChannel,
ME_Behavior,
ME_Elems
};

const char *menu_labels[ME_Elems] = { "K group:", "Knob:", "CC:", "Channel:", "lin/exp/log:" };


// Data structures:

typedef struct
{
int knob[NUM_KNOBS];
int behavior[NUM_KNOBS];
int control_change[NUM_KNOBS];
int channel[NUM_KNOBS];
} KnobStatus;


typedef struct
{
int buttonPushCounter; // counter for the number of button presses
int buttonState; // current state of the button
int lastButtonState; // previous state of the button
} Button;

typedef struct
{
int encoder_target; // it will point to knob_ndx/control_change_ndx/menu_ndx.
int positions[KnobEncoderElems];
int ultimaPosicionPinA;
} Encoder;

typedef struct
{
int cc;
int knob_value;
} MIDI_STATUS;

typedef struct
{
KnobStatus knobs[NUM_KNOB_GROUPS];
Encoder encoder;
Button button;
MIDI_STATUS midi_status[NUM_MIDI];
} ControlStatus;


// Function prototypes:

void input_update(ControlStatus *cs);
void output_update(ControlStatus *cs);
void screen_update(ControlStatus *cs);
int update_from_button(ControlStatus *cs); // pulsador()
int update_from_encoder(ControlStatus *cs, int enc_pos, int x); // Paso de la estructura, retorno del valor de la funcion de encoder, valor maximo que puede alcanzar )
void input_update_knobs(ControlStatus *cs);
void lcd_draw_knob(ControlStatus *cs);
void lcd_draw_header();
void indicador_de_pulsacion(ControlStatus *cs);
void lcd_draw_menu(ControlStatus *cs);
void output_update_midi(ControlStatus *cs);
void ControlStatus_Init(ControlStatus *cs);
void update_encoder_targets(ControlStatus *cs);

// Macros:

#define MAX(x, y) (x > y? x : y)


#endif // potenciometros_y_display_h




Pido de antemano disculpas por cualquier error u omisión que afecte al código, si tenéis alguna duda respecto al código hacédmela saber.

Espero que disfrutéis con vuestro nuevo controlador MIDI.

I ask in advance apologies for any errors or omissions affecting the code, if you have any questions regarding hacédmela know code.

I hope you enjoy with your new MIDI Controller.




lunes, 9 de diciembre de 2013

Material

Este es el listado de material de la última versión que tengo en marcha del controlador que sale en la foto.

Hubo una versión anterior con un display de 16×2 y otra versión posterior con un display de 16×4 caracteres, pero debido a que se me quedaba corto decidí implementar un display GLCD de 128X64 píxeles con la posibilidad de añadir gráficos.

A continuación describo los elementos que he utilizado en esta última (¿?) versión.

This is the list of material that I have latest version of the driver up in the photo.

There was an earlier version with a display of 16 × 2 and a later version with a display of 16 × 4 character, but because I fell short I decided to implement a 128X64 GLCD display pixels with the ability to add graphics.

Below I describe the items that I have used in the last (?) Version.



Núcleo / Core :

Arduino UNO y su IDE.



Medio para visualizar la información:

Pantalla 128X64 GLCD ( permite visualizar gráficos )

Means for displaying the information:

128X64 GLCD display (used to display graphics)




Control:

4 potenciómetros ( lineales no importa el valor), un encoder y un pulsador.

Control:

4 sliders (linear no matter the value), an encoder and a button.
















Esquemático donde se puede apreciar los diferentes módulos MIDI IN, OUT y TRHU que lo conforman y sus componentes.

Schematic where you can see the different modules MIDI IN, OUT and THRU comprising it and its components.





Conectores DIN 5 hembra (hay muchos modelos, yo escogí el que NO era aéreo y podia soldarlo en la PCB).

5 female DIN connectors (there are many models, I chose the one that was NO air and I could solder on the PCB).




Opto-acoplador Sharp PC-900 o equivalente para el modulo MIDI IN.

Optocoupler Sharp PC-900 or equivalent to the MIDI IN module.

 
HCF4069UBE inversor hexadecimal para el modulo MIDI OUT.

HCF4069UBE hex inverter module to the MIDI OUT.





Resistencias de 220  y 280 Ohms y diodo 1N914, tal y como se indica en el esquemático.

Pcb con pistas y agujeros para trabajar con mas facilidad a la hora de soldar, evitando pegotes de estaño y por ende falsos contactos.

Resistors 220 and 280 Ohms and 1N914 diode, as indicated in the schematic.

Pcb with tracks and holes to work more easily when welding, avoiding globs of tin and therefore false contacts.




Cable rígido y las herramientas que corresponda.

Espadines, para poder hacer las conexiones




Como elemento final, elegí reunir todos estos elementos en una pieza de metacrilato por varios motivos:

  • Elegante.
  • Relativamente fácil de manipular.

Hard wire and tools appropriate.

Sprats, to make connections

As a final element, I chose to bring all these elements in a piece of acrylic for several reasons:

     Elegant.

     Relatively easy to manipulate.




Pero también caro si lo cortas con laser.

But also expensive if you cut with laser.



Edit