Being new to coding Arduino and finding it anything but easy, I've tried to have ChatGPT create an Arduino sketch just by telling it wat I wanted.
The first project was succesful: having one potmeter playing a range of 12 midi notes.
However I had to find out myself that I had to remove all references to the serial monitor, as these seemed to generate unwanted data resulting in erratic note production.
However the second project did not give the desired result. two potmeters producing midi notes simultaneously on separate midi channels. The skech (the 10th version) still produces random notes.
What I thought very strange is that from a certain point on, ChatGPT gave code that was obviously incomplete, with lines missing at the end. It apologised an again produced incomplete code multiple times.
I do like that ChatGPT gives lots of comment lines in the code explaining exactly what each line of code is doing.
This AI could potentially open up the world of Arduino for many interested people who find programming difficult.
Just in case anyone would like to spot why the code isn't working, or to see how ChatGPT uses comment lines, here it is:
#include <MIDI.h>
// Define the analog input pins
const int potentiometer1Pin = A0;
const int potentiometer2Pin = A1;
// Define the MIDI note ranges for each potentiometer
const int potentiometer1MinNote = 70;
const int potentiometer1MaxNote = 81;
const int potentiometer2MinNote = 60;
const int potentiometer2MaxNote = 71;
// Initialize the MIDI libraries for each potentiometer
MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI1); // MIDI library for potentiometer 1
MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI2); // MIDI library for potentiometer 2
// Variables to store the previous potentiometer values and note states
int prevAnalogValue1 = 0;
int prevAnalogValue2 = 0;
bool noteState1 = false;
bool noteState2 = false;
// Threshold value for potentiometer fluctuations
const int threshold = 10;
void setup() {
// Set the baud rate for the MIDI interfaces
MIDI1.begin(31250); // Potentiometer 1 MIDI channel
MIDI2.begin(31250); // Potentiometer 2 MIDI channel
}
void loop() {
// Read the analog input of potentiometer 1
int analogValue1 = analogRead(potentiometer1Pin);
// Map the analog value to the MIDI note range for potentiometer 1
int note1 = map(analogValue1, 0, 1023, potentiometer1MinNote, potentiometer1MaxNote + 1);
// Ensure the note is within the valid range for potentiometer 1
note1 = constrain(note1, potentiometer1MinNote, potentiometer1MaxNote);
// Send note-off message if the potentiometer value changes beyond the threshold and the note is playing
if (abs(analogValue1 - prevAnalogValue1) > threshold && noteState1) {
MIDI1.sendNoteOff(note1, 0, 1); // MIDI channel 1 for potentiometer 1
noteState1 = false;
}
// Send note-on message if the potentiometer value changes beyond the threshold and the note is not playing
if (abs(analogValue1 - prevAnalogValue1) > threshold && !noteState1) {
MIDI1.sendNoteOn(note1, 127, 1); // MIDI channel 1 for potentiometer 1
noteState1 = true;
}
// Update the previous analog value for potentiometer 1
prevAnalogValue1 = analogValue1;
// Add a small delay to avoid interference between potentiometers
delay(2);
// Read the analog input of potentiometer 2
int analogValue2 = analogRead(potentiometer2Pin);
// Map the analog value to the MIDI note range for potentiometer 2
int note2 = map(analogValue2, 0, 1023, potentiometer2MinNote, potentiometer2MaxNote + 1);
// Ensure the note is within the valid range for potentiometer 2
note2 = constrain(note2, potentiometer2MinNote, potentiometer2MaxNote);
// Send note-off message for potentiometer 2 if the potentiometer value changes beyond the threshold and the note is playing
if (abs(analogValue2 - prevAnalogValue2) > threshold && noteState2) {
MIDI2.sendNoteOff(note2, 0, 2); // MIDI channel 2 for potentiometer 2
noteState2 = false;
}
if (abs(analogValue2 - prevAnalogValue2) > threshold && !noteState2) {
MIDI2.sendNoteOn(note2, 127, 2); // MIDI channel 2 for potentiometer 2
noteState2 = true;
}
// Update the previous analog value for potentiometer 2
prevAnalogValue2 = analogValue2;
}
I'm sorry, but I for one basically stopped reading after this point.
There is no instant gratification in programming, and there is no AI that will short cut you through to anything significant if you are not able to meet it way more than halfway.
Toss chatGPT in the trash. Postpone your ambitious projects and start where we all start - knowing nothing, and finding a wealth of help all over the inernet but epsecially right within the IDE.
Start working through the examples on offer there. Read the code. Understand what it is doing.
It will take time and work, like anything. If you knew enough to make good use of chatGPT, you would be able to read the code it produced and see where it went off the rails.
I'll use the word "read" again. No writer of anything is not also a reader. Please start with easy things, get them working and read read read as much as you can. Read about the things that make up a program, that are parts of the programming language you are using, and read as many sketches as you can, line by line. Which is the way programs run and why they end up doing what they do.
ChatGPT is a conman that plagiarizes snippets of working code together in order to BS it’s way into your attention.
If you are patient enough to continue to wade through the BS and skilled enough to detect the BS, you might get to something that functions, but the end result is often lacking.
Are these droves of new users skilled enough to recognize good code? If not, how will they recognize the BS?
As a complete noob in midi, the complete BS I see is assuming that the way to do polyphony is to duplicate instruments—Many instruments are capable of playing multiple notes at once, (eg pianos) so any interface designed to work with them (midi) wouldn’t need to bodge together three pianos to play a three-note chord. It’s BS built of BS.
The common opinion seems to be that taking shortcuts doesn't work. For the record: I don't believe it would be possible for someone not knowing anything about programming to get good results out of ChatGPT for tailormade projects.
However, I found the experience a lot of fun because it forced me to keep refining the exact formulation of how I wanted my hardware setup to work.
Also, it was fun studying the code and the comment lines, which taught me a bit about coding.
Using two separate midi channels was not an invention of GPT but I asked for that feature, having seen a midi controller with three ribbon softpots that works that way.
It is usually more productive to study working code, written by people, rather than chatGPT hallucinations. But, I agree that chatGPT code can be an interesting challenge, like spotting all the stupid errors.
I have found the same thing, not just with code. It is fun trying to get chatGPT to write, say, a good argument for something of a political nature, or to work with it until it agrees with you about a matter of grammar or whatever.
But that just makes the point made over and over here and elsewhere, which boils down to the fact that the more you know, the better you can do with it.
Like so many tools and resources.
addded: you can do the same thing here with real ppl, but it can take longer and sometimes you might get beat up quite a bit by impatient humans. Read a few threads and see how too often it takes quite a number of posts to zero in on 'xactly what someone is seeking to accomplish.
I would agree 100 percent with
and add not just any working code but good code - you can learn from crappy code no matter who or what wrote it, but studying exemplary code as presented in the context of learning to program is probably best.
We once used books which were presumably full of good code heavily scrutinized before being printed and often arriving with an errata sheet mopping up the last discovered problems.
The problem with code is that it can work and be simply horrible. In so many ways.
but pots can have very slight spontaneous fluctuations in their output. In the code I used to produce midi notes I asked gpt for a provision to ingnore very small output fluctuations. Maybe that is similar to the debouncing code you saw?
I thought this gpt generated code to be rather tidy and effective:
#include <MIDI.h>
// Define the analog input pins
const int potentiometer1Pin = A0;
const int potentiometer2Pin = A1;
// Define the MIDI output channel
const int midiChannel = 1;
// Define the MIDI note range
const int minNote = 58;
const int maxNote = 81;
// Initialize the MIDI library
MIDI_CREATE_DEFAULT_INSTANCE();
// Variables to track the previous notes and potentiometer values
int previousNote1 = -1;
int previousNote2 = -1;
int previousValue1 = -1;
int previousValue2 = -1;
bool isPotentiometer1Turned = false;
bool isPotentiometer2Turned = false;
void setup() {
// Initialize the MIDI library
MIDI.begin(midiChannel);
}
void loop() {
// Read the analog input of potentiometer 1
int analogValue1 = analogRead(potentiometer1Pin);
// Map the analog value to the MIDI note range for potentiometer 1
int note1 = map(analogValue1, 0, 1023, minNote, maxNote + 1);
// Ensure the note is within the valid range for potentiometer 1
note1 = constrain(note1, minNote, maxNote);
// Check if potentiometer 1 is turned
if (!isPotentiometer1Turned && analogValue1 != previousValue1) {
isPotentiometer1Turned = true;
}
// Check if potentiometer 1 is at an extreme position
if (isPotentiometer1Turned && (analogValue1 >= 0 && analogValue1 <= 5 || analogValue1 >= 1018 && analogValue1 <= 1023)) {
// Turn off the currently playing note for potentiometer 1, if any
if (previousNote1 != -1) {
MIDI.sendNoteOff(previousNote1, 0, midiChannel);
previousNote1 = -1;
}
isPotentiometer1Turned = false;
}
// Check if potentiometer 1 value has changed and note is different
if (isPotentiometer1Turned && analogValue1 != previousValue1 && note1 != previousNote1) {
// Turn off the previously played note for potentiometer 1, if any
if (previousNote1 != -1) {
MIDI.sendNoteOff(previousNote1, 0, midiChannel);
}
// Play the new note for potentiometer 1
MIDI.sendNoteOn(note1, 127, midiChannel);
// Update the previous note and potentiometer value for potentiometer 1
previousNote1 = note1;
previousValue1 = analogValue1;
}
// Read the analog input of potentiometer 2
int analogValue2 = analogRead(potentiometer2Pin);
// Map the analog value to the MIDI note range for potentiometer 2
int note2 = map(analogValue2, 0, 1023, minNote, maxNote + 1);
// Ensure the note is within the valid range for potentiometer 2
note2 = constrain(note2, minNote, maxNote);
// Check if potentiometer 2 is turned
if (!isPotentiometer2Turned &&analogValue2 != previousValue2) {
isPotentiometer2Turned = true;
// Check if potentiometer 2 is at an extreme position
if (isPotentiometer2Turned && (analogValue2 >= 0 && analogValue2 <= 5 || analogValue2 >= 1018 && analogValue2 <= 1023)) {
// Turn off the currently playing note for potentiometer 2, if any
if (previousNote2 != -1) {
MIDI.sendNoteOff(previousNote2, 0, midiChannel);
previousNote2 = -1;
}
isPotentiometer2Turned = false;
}
}
// Check if potentiometer 2 value has changed and note is different
if (isPotentiometer2Turned && analogValue2 != previousValue2 && note2 != previousNote2) {
// Turn off the previously played note for potentiometer 2, if any
if (previousNote2 != -1) {
MIDI.sendNoteOff(previousNote2, 0, midiChannel);
}
// Play the new note for potentiometer 2
MIDI.sendNoteOn(note2, 127, midiChannel);
// Update the previous note and potentiometer value for potentiometer 2
previousNote2 = note2;
previousValue2 = analogValue2;
}
}
Too small to make any difference. The electrical noise from an internal A/D converter is going to swamp any variation from the pot themselves. And anyway the hysteresis code will more than cope with that, especially if it was implemented correctly, which it is not.
Just to point out the usefulness of GPT as a tool: with my limited knowledge of coding I was able to have GPT produce another code for the two pots, this time using the second pot to transpose the note range up or down in half steps to max one octave.
Also, I added a joystick which now handles pitch bend and modulation.
I'm not sure I would have come to the level of coding skill I could have done this myself at some point. As I wrote earlier, for me the Arduino is a means to a goal.
GPT saved me a lot of time so far.
here's the code, in case anyone wonders:
#include <MIDI.h>
// Define the analog input pins
const int potPin1 = A0; // Potentiometer for note range
const int potPin2 = A1; // Potentiometer for transposition
const int joyPinX = A2; // Joystick X-axis pin
const int joyPinY = A3; // Joystick Y-axis pin
// Define the MIDI output channel
const int midiChannel = 1;
// Define the MIDI note range
const int minNote = 58;
const int maxNote = 81;
// Define the maximum transposition range in half tones
const int transpositionRange = 12;
// Define the MIDI pitch bend range
const int pitchBendRange = 8192; // The correct range for MIDI pitch bend is actually from 0 to 16383, with the center position being 8192.
// Define the MIDI modulation range
const int modulationRange = 127;
// Define the threshold for ignoring small fluctuations
const int threshold = 10;
// Initialize the MIDI library
MIDI_CREATE_DEFAULT_INSTANCE();
// Variables to track the previous note and potentiometer values
int previousNote = -1;
int previousValue1 = -1;
int previousValue2 = -1;
int previousJoyX = -1;
int previousJoyY = -1;
void setup() {
// Initialize the MIDI library
MIDI.begin(midiChannel);
}
void loop() {
// Read the potentiometer values
int potValue1 = analogRead(potPin1);
int potValue2 = analogRead(potPin2);
// Read the joystick values
int joyValueX = analogRead(joyPinX);
int joyValueY = analogRead(joyPinY);
// Map the potentiometer values to the note range and transposition range
int noteRange1 = map(potValue1, 0, 1023, minNote, maxNote + 1);
int transposition = map(potValue2, 0, 1023, -transpositionRange, transpositionRange + 1);
// Ensure the note range and transposition are within the valid ranges
noteRange1 = constrain(noteRange1, minNote, maxNote);
transposition = constrain(transposition, -transpositionRange, transpositionRange);
// Calculate the resulting note range
int noteRange2 = noteRange1 + transposition;
// Check if the potentiometer values or the resulting note range have changed significantly
if (abs(noteRange2 - previousNote) >= threshold || abs(potValue1 - previousValue1) >= threshold || abs(potValue2 - previousValue2) >= threshold) {
// Turn off the previously played note, if any
if (previousNote != -1) {
MIDI.sendNoteOff(previousNote, 0, midiChannel);
}
// Play the new note
MIDI.sendNoteOn(noteRange2, 127, midiChannel);
// Update the previous note and potentiometer values
previousNote = noteRange2;
previousValue1 = potValue1;
previousValue2 = potValue2;
}
// Map the joystick values to MIDI pitch bend range and modulation range
int pitchBendValue = map(joyValueX, 0, 1023, -pitchBendRange / 2, pitchBendRange / 2);
int modulationValue = map(joyValueY, 0, 1023, 0, modulationRange + 1);
// Check if the joystick values have changed significantly
if (abs(pitchBendValue - previousJoyX) >= threshold || abs(modulationValue - previousJoyY) >= threshold) {
// Send MIDI pitch bend message
MIDI.sendPitchBend(pitchBendValue + pitchBendRange / 2, midiChannel);
// Send MIDI modulation message
MIDI.sendControlChange(1, modulationValue, midiChannel);
// Update the previous joystick values
previousJoyX = pitchBendValue;
previousJoyY = modulationValue;
}
// Delay or perform any other required operations
delay(10);
}
Well lack of any sort of sensible hysteresis code on reading the pots, for a start.
Exactly, this is the problem with all computer languages. The art of programming is the art of getting the right instructions in the right order.
I believe the old computer language COBOL, was first advertised by saying something like:-
"You no longer have to be a computer programmer to program a computer."
But what it did was simply shift the skill set needed to program a computer. Computer languages have been doing that for years, in fact it is one of the main aims of all computer languages.
It seems to me that ChatGPT is just another computer language that requires a very fuzzy skill set in order for it to actually function. The testing involved in the code it generates becomes exponentially longer the more code that is generated, and I would suspect exceed a person's lifetime to complete.
I think there are other, better skill sets to learn, in order to get a bunch of hardware to do what you want it to do.
So begins the fuzzy process of building up experience without actually knowing the cause, and more importantly, the cure to this problem. You take a "throwing the baby out with the bathwater" approach and call that learning.