Help with using data from an array

The project im working on now is a little music playing library.
The goal is to take a submitted array for the notes and one for the rhythm and play the song using the tone library.

So I've created a Song class that sort of compiles song data into playing instructions.

Ive got it mostly sorted out but there is a problem i have with submitting arrays.
Take this an small example of my code:

class Song {
 public:
    Song(int notesArray, int rythmArray, int pin);
    void play();
 private:
    int _notesArray;
    int _rythmArray;
    int _pin;
    int _songCount;
};

//constructor
Song::Song(int notesArray, int rythmArray, int pin) 
{
    _notesArray = notesArray;
    _rythmArray = rythmArray;
    _songCount = 0;
}

void Song::play()  //actually plays one note
{
    tone(_pin, _notesArray[_songCount]);
    delay(_rythmArray[_songCount]);
    noTone(_pin);
    _songCount = _songCount++;
    delay(50);
}

Someone may have spotted it early on, but my error was in trying to copy the submitted array into the _notes/rythm var.

For one thing I didn't declare _notesArray as an array (eg int _notesArray[]:wink:
but also the whole statement:
_notesArray = notesArray;
doesn't point to any slot in either array.
So either i copy each point individually, or I access the submitted array differently.

I must be missing something because it would be dumb to have a copy of each of the huge arrays.
The thing is though I cant think of another way to point to that data from inside my class functions.
Any ideas?

You need to learn about pointers (and arrays if you haven't) but you're on the right track, IMO.

I see little on pointers (outside masses of forum posts) at the Arduino site, but here's

"A TUTORIAL ON POINTERS AND ARRAYS IN C" that looks pretty complete:
http://pw1.netcom.com/~tjensen/ptr/pointers.htm

Good Sir! I thank you for that literature. VERY informative stuff. I haven't finished reading through it but i just got an idea.

consider this approach:

class Song
{
 public:
    Song(int notesArray, int pin);
    void play();
 private"
    int *_notesArray;
    int _songCount;
    int _pin;
};

Song::Song(int notesArray, int pin)
{
    _notesArray = notesArray;
    _pin = pin;
}

Before I go on, My question now is, if I made an instance as such:

int piezzo = 2;
int notesArrayNyan[] = {1,2,3,4} ///and so on...
Song nyanCat(notesArrayNyan, piezzo);

will my _notesArray pointer now point to the address of notesArrayNyan[0]?

Song::Song(int *notesArray, int pin)
{
    _notesArray = notesArray;
    _pin = pin;
}

also 'private' needs a ' : ' not ' " '

Greenbean209:
Before I go on, My question now is, if I made an instance as such:

int piezzo = 2;

int notesArrayNyan[] = {1,2,3,4} ///and so on...
Song nyanCat(notesArrayNyan, piezzo);




will my _notesArray pointer now point to the address of notesArrayNyan[0]?

Where is this code going to go? notesArrayNyan may go out of scope and then the pointer to it will be invalid.

You could try the following (using memcpy):

#include "Arduino.h"
#define MAXSONGCOUNT 10
class Song {
 public:
    Song(int* notesArray, int sizeOfNotesArray, int* rythmArray, int sizeOfRythmArray, int pin);
    void play();
 private:
    int _notesArray[MAXSONGCOUNT];
    int _rythmArray[MAXSONGCOUNT];
    int _pin;
    int _songCount;
    int _totalSongs;
};

//constructor
Song::Song(int* notesArray, int sizeOfNotesArray, int* rythmArray, int sizeOfRythmArray, int pin) 
{
    //determine how many songs there are
    if(sizeOfRythmArray < sizeOfNotesArray){
      _totalSongs = sizeOfRythmArray; //use the one with the fewest to avoid out of bounds errors on the other
    } else {
      _totalSongs = sizeOfNotesArray; //use the one with the fewest to avoid out of bounds errors on the other
    }
    
    //Copy the both arrays, ensuring that they don't go out of bounds.
    if(_totalSongs > MAXSONGCOUNT){
      _totalSongs = MAXSONGCOUNT;
      memcpy(_notesArray,notesArray,MAXSONGCOUNT*sizeof(int)); //out of bounds, so only copy the maximum amount
      memcpy(_rythmArray,rythmArray,MAXSONGCOUNT*sizeof(int)); //out of bounds, so only copy the maximum amount
    } else {
      memcpy(_notesArray,notesArray,_totalSongs*sizeof(int)); //copy the required amount from notesArray
      memset(_notesArray + _totalSongs, 0, (MAXSONGCOUNT - _totalSongs)*sizeof(int)); //fill the rest with 0's
      memcpy(_rythmArray,rythmArray,_totalSongs*sizeof(int)); //copy the required amount from rythmArray
      memset(_rythmArray + _totalSongs, 0, (MAXSONGCOUNT - _totalSongs)*sizeof(int)); //fill the rest with 0's
    }
    
    _songCount = 0; //on song 0
}

void Song::play()  //actually plays one note
{
    tone(_pin, _notesArray[_songCount]);
    delay(_rythmArray[_songCount]);
    noTone(_pin);
    _songCount = _songCount++; //move to the next
    if (_songCount >= _totalSongs){
      _songCount = 0; //reset back to the beginning maybe?
    }
    delay(50);
}

Test code:

#include "Song.h"
void setup()
{
  // This code will only run once, after each powerup or reset of board
  int boo[5] = {1,2,3,4,5};
  int baa[7] = {1,2,3,4,5,6,7};
  byte sizeOfboo = (sizeof(boo)/sizeof(int));
  byte sizeOfbaa = (sizeof(baa)/sizeof(int));
  Song hello(boo,sizeOfboo,baa,sizeOfbaa,1);
  hello.play();
}

void loop()
{
  // This code loops consecutively 
  
}

Note that that code accounts for any mismatch in the size of the two arrays. If you know both arrays will always be the same size, then it can be simplified to the following:

#include "Arduino.h"
#define MAXSONGCOUNT 10
class Song {
 public:
    Song(int* notesArray, int* rythmArray, int sizeOfArray, int pin);
    void play();
 private:
    int _notesArray[MAXSONGCOUNT];
    int _rythmArray[MAXSONGCOUNT];
    int _pin;
    int _songCount;
    int _totalSongs;
};

//constructor
Song::Song(int* notesArray, int* rythmArray, int sizeOfArray, int pin) 
{
    //determine how many songs there are
    _totalSongs = sizeOfArray;
    
    //Copy the both arrays, ensuring that they don't go out of bounds.
    if(_totalSongs > MAXSONGCOUNT){
      _totalSongs = MAXSONGCOUNT;
      memcpy(_notesArray,notesArray,MAXSONGCOUNT*sizeof(int)); //out of bounds, so only copy the maximum amount
      memcpy(_rythmArray,rythmArray,MAXSONGCOUNT*sizeof(int)); //out of bounds, so only copy the maximum amount
    } else {
      memcpy(_notesArray,notesArray,_totalSongs*sizeof(int)); //copy the required amount from notesArray
      memset(_notesArray + _totalSongs, 0, (MAXSONGCOUNT - _totalSongs)*sizeof(int)); //fill the rest with 0's
      memcpy(_rythmArray,rythmArray,_totalSongs*sizeof(int)); //copy the required amount from rythmArray
      memset(_rythmArray + _totalSongs, 0, (MAXSONGCOUNT - _totalSongs)*sizeof(int)); //fill the rest with 0's
    }
    
    _songCount = 0; //on song 0
}

void Song::play()  //actually plays one note
{
    tone(_pin, _notesArray[_songCount]);
    delay(_rythmArray[_songCount]);
    noTone(_pin);
    _songCount = _songCount++; //move to the next
    if (_songCount >= _totalSongs){
      _songCount = 0; //reset back to the beginning maybe?
    }
    delay(50);
}

Test code:

#include "Song.h"
void setup()
{
  // This code will only run once, after each powerup or reset of board
  int boo[5] = {1,2,3,4,5};
  int baa[5] = {1,2,3,4,5};
  Song hello(boo,baa,5,1);
  hello.play();
}

void loop()
{
  // This code loops consecutively 
  
}

I wouldn't copy the array just to use part of it. I'd set a pointer to the start of the part I want to use then iterate the pointer to the end.

No time to go into detail right now, be back later to see how the thread develops.

--- back again and got more time

Song::Song(int notesArray, int pin)
{
    _notesArray = notesArray;
    _pin = pin;
}

I dunno what that's supposed to do for you but (int notesArray) is just 1 int no matter what name you give it.

You can set up the array as global or as a data member of the Song class.

If the song is expected to get big then look into storing the song data in flash memory (PROGMEM) and copying short stretches into a small array if not a note at a time.
If you go that way; it takes time to play one note, much-much-etc longer than to copy the next from PROGMEM, at least if you don't waste that time with delay().

Well true int notesArray isn't necessarily an arr. but if i provide my instance with an array won't notesArray be an array.

Also I messed up I meant to type this.

Song::Song(int notesArray)
{ 
    _notesArray = &notesArray;
}

Provided _notesArray is defined like so:

int *_notesArray;

Would the pointer I created point to the beginning of an array that I would input?

I think you have it addressing itself there.

Try making a global int array named songNotes[ numberOfNotes ] and notesArray = songNotes will point to the start of that. The names must be different and should be far enough different to keep humans reading the code from confusing the two.

Just to check, you know what global is?

Also, how many notes to your song and are they all full/half/quarter/etc notes? Is that what you call rythm?

Greenbean209:
Well true int notesArray isn't necessarily an arr. but if i provide my instance with an array won't notesArray be an array.

No.

Greenbean209:
Also I messed up I meant to type this.

Song::Song(int notesArray)

{
    _notesArray = ¬esArray;
}




Would the pointer I created point to the beginning of an array that I would input?

No, because you are not inputting an array, you are inputting a single int, which is passed by value.