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.
Ich versteh nichts.
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.
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.
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.
```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.
Ah, ich habe gerade aus dem englischen Teil des Forums von PieterP (von wem sonst! ) 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"!
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....
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!
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!
Das ist eher kein Problem.
Die Frage ist, was und wie Du Tasten brauchst.
Du kannst auch eine 8x8 Matrix in eine Gitarre kleben
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.
(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 ).
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! ).
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'