Read multidimensional array blink led.

Hi, first of all i would like to say that i have tried looking for tutorials and on this forum to answer my question, but i have not found a solution yet.

This is my problem: I have a text file which looks like this:

timepoint C C# D D# E F F# G G# A A# B
0.00 0.63 1.00 0.78 0.84 0.83 0.79 0.56 0.56 0.62 0.68 0.53 0.45
0.08 0.99 0.53 0.55 0.41 0.40 0.39 0.67 0.80 0.70 0.68 0.56 1.00
0.34 0.42 1.00 0.97 0.98 0.88 0.97 0.44 0.44 0.29 0.49 0.33 0.30
0.43 1.00 0.68 0.11 0.14 0.12 0.12 0.18 0.23 0.16 0.32 0.15 0.27
0.67 0.66 0.30 0.26 0.34 0.34 0.40 0.58 0.44 0.54 0.72 0.41 1.00
1.09 1.00 0.73 0.28 0.21 0.26 0.26 0.39 0.29 0.58 0.63 0.97 0.35
1.21 0.57 0.49 0.38 0.39 0.54 0.45 0.56 0.49 0.46 0.41 0.27 1.00

As you can see there one column which indicates the "time" starting from 0 to 1.21 seconds.
Than the horizontal line shows a number of values for each note. In each horizontal line (moment in time) there is ONE note (c, c+, d, d+,..) that has a "1" as a value.
What i am trying to do is the following:
I have 12 leds hooked up to my arduino. One for each of the 12 notes from the upper list.
I would like to read the file, and send the data to my arduino, so that for each moment in time, the note (or led) corresponding to the value "1" at a certain timepoint, would go on and than turn off when the next line (timepoint) is being read.
To bad i am a complete noob when it comes to programming, so i really really hope you guys can help me with this! :frowning:

Thanks in advance!! :slight_smile:

These are the ports my leds are hooked up to:
C = 28;
C# = 30;
D = 31;
D# = 32;
E = 33;
F = 36;
F# = 37;
G = 38;
G# = 39;
A = 40;
A# = 42;
B = 43

Is the text file going to change? Do you have to read in the text file and parse it, or can you hard code those values into the program?

They can change, so hard coding is not an option. The text file also contains about 300 lines of information, i just copied a few to explain my problem.

Once the file has been read will the sequence be shown only once or will it repeat ? Should the LED be on for a time corresponding to the difference in timepoint values and, if so, what do they relate to ? Seconds, maybe, but some of them would be of a very short duration. For instance, C# in line one would only be on for 0.08 seconds. Is that right ?

UKHeliBob:
Once the file has been read will the sequence be shown only once or will it repeat ?

it will be only played once, along with the mp3 file. I don't know if i can start the mp3 file at the same moment as my arduino will start it. I do know that it is possible in processing though.

UKHeliBob:
Should the LED be on for a time corresponding to the difference in timepoint values and, if so, what do they relate to ? Seconds, maybe, but some of them would be of a very short duration. For instance, C# in line one would only be on for 0.08 seconds. Is that right ?

That is correct, line one would indeed be just on for 0.08 seconds. I don't know if it's possible, but perhaps the code can be written in such a way that it reads a line with 1 second in between. So that it skips a few lines, untill it reaches the next second?

Thanks, and kind Regards,

Taigo

Than the horizontal line shows a number of values for each note. In each horizontal line (moment in time) there is ONE note (c, c+, d, d+,..) that has a "1" as a value.

I don't see that. I see that each record contains a value of 1.00. Converting each token to a float, and then expecting the float to exactly equal 1 will be an exercise in frustration. You should expect the result to be somewhere between 1.0-someSmallValue and 1.0+someSmallValue.

What is the problem? You were doing so good...

Will any of the values be greater than 1.00 ?

PaulS:

Than the horizontal line shows a number of values for each note. In each horizontal line (moment in time) there is ONE note (c, c+, d, d+,…) that has a “1” as a value.

I don’t see that. I see that each record contains a value of 1.00. Converting each token to a float, and then expecting the float to exactly equal 1 will be an exercise in frustration. You should expect the result to be somewhere between 1.0-someSmallValue and 1.0+someSmallValue.

What is the problem? You were doing so good…

Hmm there is
For time point 0.00 the note with the ‘1’ value is C#
timepoint: 0.08 = note: B
timepoint: 0.34 = note: C#
timepoint: 0.43 = note: C
timepoint: 0.67 = note: B
timepoint: 1.09 = note: C
timepoint: 1.21 = note: B

As i said before, i am the worst programmer in the history of programmers. But i think the could would be something like:

FOR timepoint 0.00
If C = 1 than arduinoport 38 = High
else if C <1 than arduinoport 38 = LOW
else if C# = 1 than blink arduinoport 39 = High
else if C# <1 than arduinoport 39 = LOW
else if D = 1 than blink arduinoport 40 = High
else if D <1 than arduinoport 40 = LOW
else if D# = 1 than blink arduinoport 41 = High
else if D# <1 than arduinoport 41 = LOW
else if E# = 1 than blink arduinoport 42 = High
else if E <1 than arduinoport 42 = LOW

FOR NEXT Timepoint (First All ports = Low) //to turn all leds off
// and than do the exact same thing for the second timepoint (0.34). Of course this would be to fast for the eye to see, so it would have to skip untill the next timepoint where the first number is 1 (1.33). Then skip again untill the 2nd second (2.48)… and so on.

I hope this explains better what i am trying to achieve, but as i said before i am a complete programming noob. :frowning:

UKHeliBob:
Will any of the values be greater than 1.00 ?

Hi UKHeliBob, no no value will ever exceed "1.00"!

Thanks for looking into this! :slight_smile:

So, now we know what you want to accomplish. Seems pretty simple. Read each record. Parse the data. Convert each token to a number. Do something with the pins, setting them all low, except the one that corresponds to a value of 1.0+/-.

So, what does the code you posted actually do? What is the problem you need help with?

It would be faster and maybe easier if you used characters instead of floats. You really only need to look at the first character of each value. If it is a '1', go HIGH. If it is a '0', go LOW. You can ignore the decimal point and the next two digits.

I think your algorithm should work.

PaulS:
So, now we know what you want to accomplish. Seems pretty simple. Read each record. Parse the data. Convert each token to a number. Do something with the pins, setting them all low, except the one that corresponds to a value of 1.0+/-.

So, what does the code you posted actually do? What is the problem you need help with?

Well to be honest, i have no idea on how to even begin with this. :frowning: :frowning:
I have done some tutorials on how to use arduino, and it took me a HUGE amount of time to make a hard coded version of this for playing a simple child song.

this was the code i used, but of course this will be no good when i have to read the data from a file:

int myPins[] = {28, 30, 31, 32, 33, 36, 37, 38, 39, 40, 42, 43};
 int Song[] = { 32, 33, 36, 32, 32, 33, 36, 32, 36, 37, 38, 36, 37, 38, 38, 39, 38, 37, 36, 32, 38, 39, 38, 37, 36, 32, 32, 28, 32, 32, 28, 32}; 
 int NoteDelays[] = { 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 250, 125, 125, 250, 75, 75, 75, 75, 125, 125, 75, 75, 75, 75, 125, 125, 250, 125, 250, 250, 125, 250 };
 int teller = 0;


void setup()
{
// activate all pins
for (int i=0; i <= 10; i++){
pinMode(myPins[i], OUTPUT); 
} 

//32=do 33=re 36=mi 37=fa 38=sol 39=la 40=si 41=do
}
void loop()
{
digitalWrite(Song[teller], HIGH);
delay(NoteDelays[teller]);
digitalWrite(Song[teller], LOW);
delay(NoteDelays[teller]);
teller++;

// End of song
if(teller==32){
teller = 0;
}

// Blink 
digitalWrite(2, HIGH);
delay(250);
digitalWrite(2, LOW);
delay(250);


}

TanHadron:
It would be faster and maybe easier if you used characters instead of floats. You really only need to look at the first character of each value. If it is a '1', go HIGH. If it is a '0', go LOW. You can ignore the decimal point and the next two digits.

I think your algorithm should work.

That is entirely true, but i don't have an algorithm, and i have no idea on how to even begin on setting one up. :frowning:
I can't wait to learn much more about Arduino, and i will, but the problem is that i have to get this thing working by tuesday! :frowning:

Oh, but you DO have an algorithm.

FOR timepoint 0.00
If C = 1 than arduinoport 38 = High
else if C <1 than arduinoport 38 = LOW
else if C# = 1 than blink arduinoport 39 = High
else if C# <1 than arduinoport 39 = LOW
else if D = 1 than blink arduinoport 40 = High
else if D <1 than arduinoport 40 = LOW
else if D# = 1 than blink arduinoport 41 = High
else if D# <1 than arduinoport 41 = LOW
else if E# = 1 than blink arduinoport 42 = High
else if E <1 than arduinoport 42 = LOW

FOR NEXT Timepoint (First All ports = Low) //to turn all leds off

Now all you have to do is figure out how to translate that in to C code. Well, and add the stuff you didn’t mention, like parsing the file and dealing with timing issues.

How do you plan to get the text file to the Arduino? Are you going to copy it into your sketch every time it changes and re-compile the sketch? Are you going to put it on an SD card and insert it into and SD card shield? Are you going to use Serial.read() and paste it into the serial monitor? What?

As far as parsing each line goes, you can throw away most of the data. I seldom use floats, because they’re big and slow and inaccurate. In this case it’s really easy to use integers for all of your data. The timing information can be converted to milliseconds by ignoring the decimal point and multiplying by ten. For example, 0.80 is 800 milliseconds. 1.09 is 1090 milliseconds. 1.21 is 1210 milliseconds. The reason that is important is that the millis() function returns the number of milliseconds that have elapsed since bootup, and it’s really easy to program events to happen at specific millisecond time stamps. See Blink Without Delay or Stanford’s Multi Task Tutorial for more on how that is done.

The only other thing you need from each line is the index of the 1.00. You have this neat myPins array that tells which pin the LED is on that corresponds to each column in your text file. The index of the 1.00 in the first line in your example (where time = 0.00) is 1. This array is 0 based, so the index of the first column would be 0, and the second column is 1. The 1.00 is in the second column, so index = 1. myPins[1] is 30. That corresponds to the C# LED. The next line, where time is 0.08, the 1.00 is in the 12th column, so the index would be 11. myPins[11] is 43, and that corresponds to the B LED. The next line, where time is 0.34, the index is 1 again, C# again. The next line, where time is 0.43, the index of the 1.00 is 0, because it is in the first column. myPins[0] is 28, which is the C LED.

Once you have parsed out the time stamp and the index for each line, you can set the LEDs. You just check millis() until it matches the next time stamp, and then digitalWrite(myPins[index], HIGH) and make sure all the other pins are LOW.

TanHadron:
How do you plan to get the text file to the Arduino? Are you going to copy it into your sketch every time it changes and re-compile the sketch? Are you going to put it on an SD card and insert it into and SD card shield? Are you going to use Serial.read() and paste it into the serial monitor? What?

I have no way what the best way is to do that. I can tell you that i don't have an sd-card shield.
I was thinking that maybe i could copy-paste the code into processing, and upload firmata to the arduino so that i don't have such a big file to upload to arduino? I think that is the only problem, that the file would get too big. I can tell you however that the larges textfile will have 300 lines of data.
I guess the safest way for a noob like me is just change the name within the code to a different text file manually.
Like for example in html source='first.txt' and than change it to source='second.txt'

TanHadron:
As far as parsing each line goes, you can throw away most of the data. I seldom use floats, because they're big and slow and inaccurate. In this case it's really easy to use integers for all of your data. The timing information can be converted to milliseconds by ignoring the decimal point and multiplying by ten. For example, 0.80 is 800 milliseconds. 1.09 is 1090 milliseconds. 1.21 is 1210 milliseconds. The reason that is important is that the millis() function returns the number of milliseconds that have elapsed since bootup, and it's really easy to program events to happen at specific millisecond time stamps. See Blink Without Delay or Stanford's Multi Task Tutorial for more on how that is done.

I have changed the timecode in the textfile so that it reads 800 miliseconds instead of '0.80' i hope that makes things easier.

TanHadron:
The only other thing you need from each line is the index of the 1.00. You have this neat myPins array that tells which pin the LED is on that corresponds to each column in your text file. The index of the 1.00 in the first line in your example (where time = 0.00) is 1. This array is 0 based, so the index of the first column would be 0, and the second column is 1. The 1.00 is in the second column, so index = 1. myPins[1] is 30. That corresponds to the C# LED. The next line, where time is 0.08, the 1.00 is in the 12th column, so the index would be 11. myPins[11] is 43, and that corresponds to the B LED. The next line, where time is 0.34, the index is 1 again, C# again. The next line, where time is 0.43, the index of the 1.00 is 0, because it is in the first column. myPins[0] is 28, which is the C LED.

Once you have parsed out the time stamp and the index for each line, you can set the LEDs. You just check millis() until it matches the next time stamp, and then digitalWrite(myPins[index], HIGH) and make sure all the other pins are LOW.

Okay this is the part where you have absolutely lost me. :frowning:
Oh god, i feel like such a noob, i'm so sory. But it seems like you have almost figured it out. I would be so grateful if someone could write this into code! :frowning:

Anybody? :frowning:

How much control do you have over this text file? Did you create it? Can you change the format of it? Could you change it so it only contains the two pieces of information you need for each line?

Perhaps this might help:

Building on what TanHadron said, your raw data:

timepoint C C# D D# E F F# G G# A A# B
0.00 0.63 1.00 0.78 0.84 0.83 0.79 0.56 0.56 0.62 0.68 0.53 0.45
0.08 0.99 0.53 0.55 0.41 0.40 0.39 0.67 0.80 0.70 0.68 0.56 1.00
0.34 0.42 1.00 0.97 0.98 0.88 0.97 0.44 0.44 0.29 0.49 0.33 0.30
0.43 1.00 0.68 0.11 0.14 0.12 0.12 0.18 0.23 0.16 0.32 0.15 0.27
0.67 0.66 0.30 0.26 0.34 0.34 0.40 0.58 0.44 0.54 0.72 0.41 1.00
1.09 1.00 0.73 0.28 0.21 0.26 0.26 0.39 0.29 0.58 0.63 0.97 0.35
1.21 0.57 0.49 0.38 0.39 0.54 0.45 0.56 0.49 0.46 0.41 0.27 1.00

from a point of interest becomes:

timepoint    C     C#     D      D#     E       F      F#       G      G#       A     	A#    	B    
    0.00    0      1      0	 0	0	0	0	0	0	0	0	0
    0.08    0	   0	  0	 0	0	0	0	0	0	0 	0	1
    0.34    0      1   	  0	 0	0	0	0	0	0	0	0	0
    0.43    1      0	  0	 0	0	0	0	0	0	0	0       0
    0.67    0	   0	  0	 0	0	0	0	0	0	0 	0	1
    1.09    1      0	  0	 0	0	0	0	0	0	0	0       0
    1.21    0	   0	  0	 0	0	0	0	0	0	0 	0	1

Relating this to your myPins array, the "interesting" information from the file becomes:

timepoint
    0.00   myPins[1]
    0.08   myPins[11]
    0.34   myPins[1]
    0.43   myPins[0]
    0.67   myPins[11]
    1.09   myPins[0]
    1.21   myPins[11]

If you have 300 similar lines in a song, then it seems to me you can define a variable named mySong:

byte mySong[300];

and write to it:

timepoint
    0.00   mySong[0] = myPins[1];
    0.08   mySong[1] = myPins[11];
    0.34   mySong[2] = myPins[1];
    0.43   mySong[3] = myPins[0];
    0.67   mySong[4] = myPins[11];
    1.09   mySong[5] = myPins[0];
    1.21   mySong[6] = myPins[11];

When you're done, you can play the song using the content of the mySong array. Therefore, the code
should have methods that:

ReadTheTextFileData()
FindTheProperNoteIndexInMyPinsArray()
MapEachIndexIntoMySongArray()
PlayTheArraySong()

TanHadron:
How much control do you have over this text file? Did you create it? Can you change the format of it? Could you change it so it only contains the two pieces of information you need for each line?

I don't have any control over it. It's a file that gets generated by the program echonest. :frowning:
The only thing i can do with the textfile is import it into excel to change the timepoint into miliseconds, than save it again like a textfile.

Hi Econjack, thanks for the help! :slight_smile:
The main problem is that i can't simplify the textfile to just read 1 or a 0, as i described on the post above this one.

econjack:
When you're done, you can play the song using the content of the mySong array. Therefore, the code
should have methods that:

ReadTheTextFileData()
FindTheProperNoteIndexInMyPinsArray()
MapEachIndexIntoMySongArray()
PlayTheArraySong()

Anyone who can do this? i'd be forever grateful! :blush: