Program Change Befehl in midiusb

Hallo,

ich habe eine Frage: Wie sende ich in einem Sketch für einen USB Midi Controller einen Programm Change Befehl?

Ich bin noch ganz grün im Thema Arduino, habe mal einen Sketch erstellt mit Hilfe des Midi Controller Code Generator von Gustavo (music nerd). Leider erstellt das Programm nur Note-send-Befehle auf Buttondruck.

Ich benutze das Pro Micro ATmega32U4 board mit der midiusb Bibliothek.

LG Hans

Das sollte dir helfen

Ansonsten mal in der Lib die Beispiele ansehen und die Doku durcharbeiten, vermutlich steht da noch was dazu drin.

2 Likes

Ich ergnze mal noch @progger
Das dort verlinkte Projekt / wiki ist umgezogen:

Und die USB-Spec ebenfalls

1 Like

Ah, super! Ich wollte genau das noch nachfragen, wohin das Projekt umgezogen ist! :smiling_face:

1 Like

Frage:
Im verlinkten Text steht als Status byte: 0x0C. Müsste das nicht 0xC0 heißen?

Das ergibt sich aus der Tabelle auf Seite 17 der Spec.

Als Hilfe macht es sich ganz gut, wenn man den Arduino einfach mit Werten füttert und sieht, was dabei rauskommt.

Serial.println(0xC);
Serial.println(0x0C);
Serial.println(0xC0);

Oder man nutzt einen guten Desktop-Taschenrechner :sweat_smile:

1 Like

Das Programm läuft super für die program change Werte 1 bis 9, aber die angedachte "Shift-Funktion" über pin 16 (= button 9) klappt noch nicht.

PS. Ich habe für eine sprachlich breitere "Verbreitung" mein Thema / Problem auch im englischen Teil gepostet.

Siehe hier:

Ich versteh nichts. :flushed:
Vermutlich weil ich nicht weiss was Du da grad besprichst.
Ist nicht weiter schlimm, aber wenn ich DIr helfen soll, muss Du mir schon irgendeinen Ansatz geben.
Die Aussage da oben ist wie, als würde ich schreiben mein Laptop leuchtet orange blinkt gelb und kann auch grün, rot und blau. :joy:

1 Like

Hallo my_xy_projekt!

Oh sorry!

Mein Projekt: EInen Midi Controller bauen und IN eine E-Gitarre einbauen.

Er soll per 9 Buttons verschiedene Presets für Gitarrensounds in meinem Musikprogramm aufrufen (Gig Performer), also Midi Program Change Messages verschicken.
Der 10. Button an pin16 soll eine Art Shift-Funktion darstellen und EINMALIG den NÄCHSTEN PC Befehl um 10 erhöhen (da würde ich in GigPerf die Gitarren-Synth-Sounds platzieren).

Das Senden der Program Change Befehle klappt super, nur diese einmalige Erhöhung der Programmnummer kriege ich noch nicht hin.

LG und Danke für dein Interesse,
Hans

Ah - jetzt versteh ich den Zusammenhang.
dann zeig mal den kompletten Code.
Es könnte am auswerten des PIN liegen, genauso wie an dessen Beschaltung.
Vom Prinzip her recht einfach was die Logik angeht.

Daher sollte das zu schaffen sein :wink:

Der Code:


```cpp
#include <Control_Surface.h>
#include <MIDIUSB.h>
#include <MIDIUSB_Defs.h>

USBMIDI_Interface midi;

/*
  BASED ON: Made by Gustavo Silveira, 2023.
  - This Sketch reads the Arduino's digital and analog ports and send midi notes and midi control change
  MODIFIED to ProgramChanges

*/

/////////////////////////////////////////////
// Choosing your board
// Define your board, choose:


#define ATMEGA32U4 1  // put here the uC you are using, like in the lines above followed by "1", like "ATMEGA328 1", "DEBUG 1", etc.

/////////////////////////////////////////////
// Are you using buttons?
#define USING_BUTTONS 1  // comment if not using buttons


/////////////////////////////////////////////
// BUTTONS


const int N_BUTTONS = 10;                                //  total numbers of buttons
const int BUTTON_ARDUINO_PIN[10] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 16};  // pins of each button connected straight to the Arduino

int buttonCState[N_BUTTONS] = {};  // stores the button current value
int buttonPState[N_BUTTONS] = {};  // stores the button previous value

int button10CState[N_BUTTONS] = {};  // stores the button current value
int button10PState[N_BUTTONS] = {};  // stores the button previous value

// debounce
unsigned long lastDebounceTime[N_BUTTONS] = { 0 };  // the last time the output pin was toggled
unsigned long debounceDelay = 50;                   // the debounce time; increase if the output flickers




/////////////////////////////////////////////
// MIDI
byte midiCh = 0;  // MIDI channel to be used - start with 1 for MIDI.h lib or 0 for MIDIUSB lib



/////////////////////////////////////////////
// SETUP
void setup() {

midi.begin();

Serial.begin(115200);  //



  // Buttons
  // Initialize buttons with pull up resistors
  for (int i = 0; i < N_BUTTONS; i++) {
    pinMode(BUTTON_ARDUINO_PIN[i], INPUT_PULLUP);
  }






}

/////////////////////////////////////////////
// LOOP
void loop() {


  buttons();


}

/////////////////////////////////////////////
// BUTTONS


void buttons() {
 

  for (int i = 0; i < N_BUTTONS-1; i++) {

        if (digitalRead(BUTTON_ARDUINO_PIN[9]) == LOW)  {
        int shift = 10; }

    buttonCState[i] = digitalRead(BUTTON_ARDUINO_PIN[i]);  // read pins from arduino


    if ((millis() - lastDebounceTime[i]) > debounceDelay) {

      if (buttonPState[i] != buttonCState[i]) {
        lastDebounceTime[i] = millis();

        if (buttonCState[i] == LOW)  {

      
          // Send a program change message
          int p = i + shift + 1;
          MIDIAddress program {p, Channel_1};
        
         midi.sendProgramChange(program);
          shift = 0;

        } else {


        }
        buttonPState[i] = buttonCState[i];
        
      }
    }
  }
}



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


**Die Fehlermeldung:**

D:\hg-hg\Documents\Arduino\Arduino_on_guitar_16C\Arduino_on_guitar_16C.ino: In function 'void buttons()':
D:\hg-hg\Documents\Arduino\Arduino_on_guitar_16C\Arduino_on_guitar_16C.ino:109:23: error: 'shift' was not declared in this scope
           int p = i + shift + 1;
                       ^~~~~
D:\hg-hg\Documents\Arduino\Arduino_on_guitar_16C\Arduino_on_guitar_16C.ino:109:23: note: suggested alternative: 'shiftIn'
           int p = i + shift + 1;
                       ^~~~~
                       shiftIn

exit status 1

Compilation error: 'shift' was not declared in this scope


Womit ich nicht klar komme:

Scheinbar kann ich die Variable "shift", die ja zu Beginn von void Buttons evtl. auf 10 gesetzt wird, nicht in die if-Schleife mit rein nehmen! Oder was heißt genau "not declared"?

Oder ist der Fehler, dass er in void Buttons jedes Mal ne neue Variable shift anlegt?

Ich vermute eine Überschreitung des Gültigkeitsbereich - dauert einen kleinen Moment.
Renn mal nicht weg - ich schau gleich drauf, will heute aber früh Schluß machen.

Wie ich vermutet habe:

void buttons()
{
  for (int i = 0; i < N_BUTTONS - 1; i++)
  {
    if (digitalRead(BUTTON_ARDUINO_PIN[9]) == LOW)
    {
      int shift = 10;
    }

mit der schliessenden Klammer verliert shift seine Gültigkeit und ist nicht mehr sichtbar.
Ich bau das mal.... Nicht wegrennen...

1 Like

Ah, ich habe gerade aus dem englischen Teil des Forums von PieterP (von wem sonst! :grinning:) eine Lösung bekommen!

Siehe hier:

post Nr. 10

Der Sketch ist soo genial einfach - obwohl ich ihn überhaupt nicht verstehe! - aber es funktioniert! Hammer!

Dennoch würde es mich aus "Programmier-Interesse" interessieren, wie man in "meinem" Entwurf hätte "shift" sauber nutzen können. Wenn Variablen mit der schließenden Klammer ihre Gültigkeit verlieren, dann kann man sie ja nur in einem ganz begrenzten Abschnitt des Sketches nutzen. (Ist sicher anders, aber so stellt es sich für mich als Newbie gerade dar.)

Aber bitte stecke keine Zeit mehr rein, außer es interessiert Dich selbst, aus "Programmier-Interesse"!

Und vielen Dank für Dein Engagement!

Hans

THE SOLUTION (By PieterP):


```cpp
#include <Control_Surface.h>

USBMIDI_Interface midi;

#define ATMEGA32U4 1

Button pc_buttons[] {
  2, 3, 4, 5, 6, 7, 8, 9, 10,
};
Button bank_switch = 16;
uint8_t offset = 0;

void setup() {
  midi.begin();
  for (auto &b : pc_buttons)
    b.begin();
  bank_switch.begin();
}

void loop() {
  midi.update();
  if (bank_switch.update() == Button::Falling)
    offset = 9;
  for (auto &b : pc_buttons) {
    if (b.update() == Button::Falling) {
      uint8_t index = &b - pc_buttons;
      midi.sendProgramChange(index + 1 + offset);
      offset = 0;
    }
  }
}


Ich hab das mal zerlegt - da sind ncoh viele Baustellen drin.
Aber mein Ansatz sollte dabei zu sehen sein.

#include <Control_Surface.h>
#include <MIDIUSB.h>
#include <MIDIUSB_Defs.h>

USBMIDI_Interface midi;

/*
  BASED ON: Made by Gustavo Silveira, 2023.
  - This Sketch reads the Arduino's digital and analog ports and send midi notes and midi control change
  MODIFIED to ProgramChanges

*/

/////////////////////////////////////////////
// Choosing your board
// Define your board, choose:


#define ATMEGA32U4 1  // put here the uC you are using, like in the lines above followed by "1", like "ATMEGA328 1", "DEBUG 1", etc.

/////////////////////////////////////////////
// Are you using buttons?
#define USING_BUTTONS 1  // comment if not using buttons


/////////////////////////////////////////////
// BUTTONS


const int N_BUTTONS = 10;                                //  total numbers of buttons
const int BUTTON_ARDUINO_PIN[10] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 16};  // pins of each button connected straight to the Arduino

constexpr byte shiftPin {9};
constexpr byte shiftValue {10};

int buttonCState[N_BUTTONS] = {};  // stores the button current value
int buttonPState[N_BUTTONS] = {};  // stores the button previous value

int button10CState[N_BUTTONS] = {};  // stores the button current value
int button10PState[N_BUTTONS] = {};  // stores the button previous value

// debounce
unsigned long lastDebounceTime[N_BUTTONS] = { 0 };  // the last time the output pin was toggled
unsigned long debounceDelay = 50;                   // the debounce time; increase if the output flickers



/////////////////////////////////////////////
// MIDI
byte midiCh = 0;  // MIDI channel to be used - start with 1 for MIDI.h lib or 0 for MIDIUSB lib



/////////////////////////////////////////////
// SETUP
void setup()
{
  midi.begin();
  Serial.begin(115200);  //
  // Buttons
  // Initialize buttons with pull up resistors
  for (int i = 0; i < N_BUTTONS; i++)
  {
    pinMode(BUTTON_ARDUINO_PIN[i], INPUT_PULLUP);
  }
}

/////////////////////////////////////////////
// LOOP
void loop()
{
  buttons();
}

/////////////////////////////////////////////
// BUTTONS


void buttons()
{
  for (int i = 0; i < N_BUTTONS - 1; i++)
  {
    buttonCState[i] = digitalRead(BUTTON_ARDUINO_PIN[i]);  // read pins from arduino
    if ((millis() - lastDebounceTime[i]) > debounceDelay)
    {
      if (buttonPState[i] != buttonCState[i])
      {
        lastDebounceTime[i] = millis();
        if (buttonCState[i] == LOW)
        {
          // Send a program change message
          int p = i + 1 + shiftValue * !digitalRead(BUTTON_ARDUINO_PIN[shiftPin]); // Die Multiplikation ergibt shiftValue * 1 oder 0 ;)
          MIDIAddress program {p, Channel_1};
          midi.sendProgramChange(program);
          shift = 0;
        }
        buttonPState[i] = buttonCState[i];
      }
    }
  }
}

Offensichtlich sind da einige Funktionscodes in der lib. insbesondere das debouncing. Darum wird das Ding kürzer.
Kannst Du mit Deinem auch machen. Dann sieht der nicht viel anders aus...

Danke fürs Bescheid geben. - Passiert auch nciht oft.
Solltest Deinen noch ausdehnen wollen, dann gerne weitermachen udn nur sagen, was Dir fehlt.

Mir ist noch nicht ganz klar, warum ich in der Pindefinition und im Umlöauf PIN 9 sehe und gleichzeitig der Pin fürs Shiften ist....

1 Like

Die internen Pinnummern sind ja von 0 bis 8. Deshalb ist der Pin #16 intern die Nr. 9.
Aber das war vermutlich gar nicht Deine Frage! :thinking:

Meinst Du, dass bei den "const int" Definitionen eigentlich nur 9 Pins (0-8) hätten definiert werden sollen, da der 10. Pin (16) ja extra definiert wird? Sorry, bin leider noch nicht firm in diesen Dingen.

Was ich vielleicht noch brauchen könnte:

Zwei Buttons (also Pin-Belegungen 14 und 15) für CC Befehle. Einer zum Einschalten eines Flangers, der andere für einen Overdrive. Ich arbeite bis jetzt live mit einem 8x8 Novation Midi Launchpad, womit ich ca. 50 PC messages und 9 CC messages sende. Also sehr üppig! Ergibt dann weit über 100 Soundvarianten (die CC Messages schalten eben Flanger, Overdrive, Delay Time Sync, Delay on-off und ein Strip für Gesamtlautstärke). Das Arduino-Projekt soll nun einen kleineren Controller ergeben, der aber IN einer E-Gitarre Platz finden soll!

LG, Hans

Das ist eher kein Problem.
Die Frage ist, was und wie Du Tasten brauchst.
Du kannst auch eine 8x8 Matrix in eine Gitarre kleben :slight_smile:

Wenn Du Taster hast, die wie Schalter funktionieren sollen, ist das ein wenig aufwändiger, da Du Dir den Status merken musst.
Aber ansonsten ist das alles nichts aufregendes.

Hi!

Ich werde wohl (erst mal) zwei Controller bauen:

(1) Einen mit 9 PC + Shift-Taste + 2 CC Tasten, die ich per Bohrungen fest in die Gitarre einbaue. Der Arduino wird dann in ein ausgefräßtes Fach auf der Rückseite seinen Platz finden.

(2) Selbe Button-Belegung, aber "mobil" ausgelegt, kann also an jeder E-Gitarre befestigt werden. Ich liebe es ja, zum imporvisieren, also Sachen zu "zweckentfremden". (Ich habe mal nen RC-Segler aus einem Rumpf aus HT-Rohr und Angelrutenstück gebaut :sweat_smile:).
Hier denke ich daran, Taster zwischen zwei CDs zu platzieren, den Arduino an der Stelle darunter, wo die Gitarre einen Ausschnitt hat.

Was ich hier noch brauche, ist, in das bisherige Programm noch 2 CC Funktionen zu integrieren für einen Flangereffekt und einen Verzerrer. In Gig Performer (meinem Musikprogramm) sind die beiden Funktionen im Moment mit CC24 und CC26 auf CH4 schaltbar.

Ich schreibe mal mit meinem Halbwissen diese beiden CC Funktionen in den Sketch und veröffentliche diesen hier im Thread. Wäre nett, wenn Du mal darüber schaust (vor allem WENN ER NICHT FUNKTIONIERT! :slightly_frowning_face:).

LG Hans

Na mach mal.
Mit 2 CC-Tasten kannste 4 Zustände abbilden :slight_smile:

Zum bauen schau Dir ggfls. den Arduino micro mal an

Ich nutze gerade den Clone arduino atmega32u4.

Also, ich meinte zwei Befehlspaare (127 und 0).

Ich habe mal versucht, die Control Changes in den Sketch zu integrieren, leider gibt es Fehlermeldungen.

Der Sketch:


```cpp
#include <Control_Surface.h>

USBMIDI_Interface midi;

#define ATMEGA32U4 1

Button pc_buttons[] {
  2, 3, 4, 5, 6, 7, 8, 9, 10,
};
Button bank_switch = 16;
uint8_t offset = 0;
Button flanger_switch = 14;
Button OD_switch = 15;


void setup() {
  midi.begin();
  for (auto &b : pc_buttons)
    b.begin();
  bank_switch.begin();
  flanger_switch.begin();
  OD_switch.begin();

}

void loop() {
  midi.update();
  if (bank_switch.update() == Button::Falling)
    offset = 9;


  for (auto &b : pc_buttons) {
    if (b.update() == Button::Falling) {
      uint8_t index = &b - pc_buttons;
      midi.sendProgramChange(index + 1 + offset);
      offset = 0;
    }
  }

  if (flanger_switch.update() == Button::Falling)
  midi.sendControlChange(int 24, int 127, int 4);

  if (OD_switch.update() == Button::Falling)
  midi.sendControlChange(int 26, int 127, int 4);
}



Die Fehlermeldungen:

D:\hg-hg\Documents\Arduino\Arduino_guitar_2-add_flanger_OD\Arduino_guitar_2-add_flanger_OD.ino: In function 'void loop()':
D:\hg-hg\Documents\Arduino\Arduino_guitar_2-add_flanger_OD\Arduino_guitar_2-add_flanger_OD.ino:41:26: error: expected primary-expression before 'int'
   midi.sendControlChange(int 24, int 127, int 4);
                          ^~~
D:\hg-hg\Documents\Arduino\Arduino_guitar_2-add_flanger_OD\Arduino_guitar_2-add_flanger_OD.ino:41:34: error: expected primary-expression before 'int'
   midi.sendControlChange(int 24, int 127, int 4);
                                  ^~~
D:\hg-hg\Documents\Arduino\Arduino_guitar_2-add_flanger_OD\Arduino_guitar_2-add_flanger_OD.ino:41:43: error: expected primary-expression before 'int'
   midi.sendControlChange(int 24, int 127, int 4);
                                           ^~~
D:\hg-hg\Documents\Arduino\Arduino_guitar_2-add_flanger_OD\Arduino_guitar_2-add_flanger_OD.ino:44:31: error: expected primary-expression before numeric constant
   midi.sendControlChange(byte 26, byte 127, byte 4);
                               ^~
D:\hg-hg\Documents\Arduino\Arduino_guitar_2-add_flanger_OD\Arduino_guitar_2-add_flanger_OD.ino:44:40: error: expected primary-expression before numeric constant
   midi.sendControlChange(byte 26, byte 127, byte 4);
                                        ^~~
D:\hg-hg\Documents\Arduino\Arduino_guitar_2-add_flanger_OD\Arduino_guitar_2-add_flanger_OD.ino:44:50: error: expected primary-expression before numeric constant
   midi.sendControlChange(byte 26, byte 127, byte 4);
                                                  ^

exit status 1

Compilation error: expected primary-expression before 'int'