String to an RTTTL char*

So, I'm making a little RTTTL player, and the player executes RTTTL char* variables that look like this:char *song = "SMBUndergr:d=16,o=6,b=100:c,c5,a5,a,a#5,a#,2p,8p,c,c5,a5,a,a#5,a#,2p,8p,f5,f,d5,d,d#5,d#,2p,8p,f5,f,d5,d,d#5,d#,2p,32d#,d,32c#,c,p,d#,p,d,p,g#5,p,g5,p,c#,p,32c,f#,32f,32e,a#,32a,g#,32p,d#,b5,32p,a#5,32p,a5,g#5"; I have a string that i receive via serial , that i want to store on that char *song variable so i can play different songs without having to change on the code everytime. How can i do this? Serial String:

String serial_str()
{
    String content ="";
   char character;

  while(Serial.available()) {
      character = Serial.read();
      content.concat(character);
      delay(10);
  }

  if (content != "") {
    return(content);
  }
}
char *song
String serial_str()

char * and String aren't the same thing. Pick one way to represent a collection of characters and stick with it.

Ok, so i should change the way my serial_str() function returns data? I wondered if i couldent do a datatype conversion to put the string inside the char* variable.

Ok, so i should change the way my serial_str() function returns data?

Yes.

I wondered if i couldent do a datatype conversion to put the string inside the char* variable.

A string is a char array. A String is not. Proper capitalization matters. Yes, you should write the code to put the characters in an array, followed by a NULL.

Ok, mine is a String. But i’m confused, i looked the documentation but couldnt get anything out of the String.toCharArray method. I’m going to post the whole code, and see what you guys think would be a nice solution.

#include <Tone.h>

Tone tone1;

#define OCTAVE_OFFSET 0

int notes[] = { 0,
NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4,
NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5,
NOTE_C6, NOTE_CS6, NOTE_D6, NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, NOTE_B6,
NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7
};
char *song = "";
void setup()
{
    pinMode(2,OUTPUT);
    pinMode(3,OUTPUT);
    pinMode(4,OUTPUT);
    pinMode(5,OUTPUT);
    pinMode(6,OUTPUT);
    pinMode(7,OUTPUT);
    pinMode(8,OUTPUT);
    pinMode (9,OUTPUT);
    Serial.begin(9600);
    tone1.begin(11); 
}
#define isdigit(n) (n >= '0' && n <= '9')
void loop()
{
  // put your main code here, to run repeatedly:

  if (Serial.available())
  {
    if (Serial.read() == 'p')
    {
      Serial.println("Input RTTTL");
      String SNG = serial_str();
       song = 
      play_rtttl(song);
        digitalWrite (2,LOW);
        digitalWrite (3,LOW);
        digitalWrite (4,LOW);
        digitalWrite (5,LOW);
        digitalWrite (6,LOW);
        digitalWrite (7,LOW);
        digitalWrite (8,LOW);
        digitalWrite (9,LOW);
        Serial.println("Done.");
    }
    else 
    {

    }
}
}
String serial_str()
{
    String content ="";
   char character;

  while(Serial.available()) {
      character = Serial.read();
      content.concat(character);
      delay(10);
  }

  if (content != "") {
    return(content);
  }
}
void play_rtttl(char *p)
{
  // Absolutely no error checking in here

  byte default_dur = 4;
  byte default_oct = 6;
  int bpm = 63;
  int num;
  long wholenote;
  long duration;
  byte note;
  byte scale;

  // format: d=N,o=N,b=NNN:
  // find the start (skip name, etc)

  while(*p != ':') p++;    // ignore name
  p++;                     // skip ':'

  // get default duration
  if(*p == 'd')
  {
    p++; p++;              // skip "d="
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    if(num > 0) default_dur = num;
    p++;                   // skip comma
  }

  Serial.print("ddur: "); Serial.println(default_dur, 10);

  // get default octave
  if(*p == 'o')
  {
    p++; p++;              // skip "o="
    num = *p++ - '0';
    if(num >= 3 && num <=7) default_oct = num;
    p++;                   // skip comma
  }

  Serial.print("doct: "); Serial.println(default_oct, 10);

  // get BPM
  if(*p == 'b')
  {
    p++; p++;              // skip "b="
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    bpm = num;
    p++;                   // skip colon
  }

  Serial.print("bpm: "); Serial.println(bpm, 10);

  // BPM usually expresses the number of quarter notes per minute
  wholenote = (60 * 1000L / bpm) * 4;  // this is the time for whole note (in milliseconds)

  Serial.print("wn: "); Serial.println(wholenote, 10);


  // now begin note loop
  while(*p)
  {
    // first, get note duration, if available
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
   
    if(num) duration = wholenote / num;
    else duration = wholenote / default_dur;  // we will need to check if we are a dotted note after

    // now get the note
    note = 0;

    switch(*p)
    {
      case 'c':
        note = 1;
        digitalWrite (2,HIGH);
        digitalWrite (3,LOW);
        digitalWrite (4,LOW);
        digitalWrite (5,LOW);
        digitalWrite (6,LOW);
        digitalWrite (7,LOW);
        digitalWrite (8,LOW);
        digitalWrite (9,LOW);
        break;
      case 'd':
        note = 3;
        digitalWrite (2,LOW);
        digitalWrite (3,HIGH);
        digitalWrite (4,LOW);
        digitalWrite (5,LOW);
        digitalWrite (6,LOW);
        digitalWrite (7,LOW);
        digitalWrite (8,LOW);
        digitalWrite (9,LOW);
        break;
      case 'e':
        note = 5;
        digitalWrite (2,LOW);
        digitalWrite (3,LOW);
        digitalWrite (4,HIGH);
        digitalWrite (5,LOW);
        digitalWrite (6,LOW);
        digitalWrite (7,LOW);
        digitalWrite (8,LOW);
        digitalWrite (9,LOW);
        break;
      case 'f':
        note = 6;
        digitalWrite (2,LOW);
        digitalWrite (3,LOW);
        digitalWrite (4,LOW);
        digitalWrite (5,HIGH);
        digitalWrite (6,LOW);
        digitalWrite (7,LOW);
        digitalWrite (8,LOW);
        digitalWrite (9,LOW);
        break;
      case 'g':
        note = 8;
        digitalWrite (2,LOW);
        digitalWrite (3,LOW);
        digitalWrite (4,LOW);
        digitalWrite (5,LOW);
        digitalWrite (6,HIGH);
        digitalWrite (7,LOW);
        digitalWrite (8,LOW);
        digitalWrite (9,LOW);
        break;
      case 'a':
        note = 10;
        digitalWrite (2,LOW);
        digitalWrite (3,LOW);
        digitalWrite (4,LOW);
        digitalWrite (5,LOW);
        digitalWrite (6,LOW);
        digitalWrite (7,HIGH);
        digitalWrite (8,LOW);
        digitalWrite (9,LOW);
        break;
      case 'b':
        note = 12;
        digitalWrite (2,LOW);
        digitalWrite (3,LOW);
        digitalWrite (4,LOW);
        digitalWrite (5,LOW);
        digitalWrite (6,LOW);
        digitalWrite (7,LOW);
        digitalWrite (8,HIGH);
        digitalWrite (9,LOW);
        break;
      case 'p':
      default:
        note = 0;
        digitalWrite (2,LOW);
        digitalWrite (3,LOW);
        digitalWrite (4,LOW);
        digitalWrite (5,LOW);
        digitalWrite (6,LOW);
        digitalWrite (7,LOW);
        digitalWrite (8,LOW);
        digitalWrite (9,HIGH);
    }
    p++;

    // now, get optional '#' sharp
    if(*p == '#')
    {
      note++;
      p++;
    }

    // now, get optional '.' dotted note
    if(*p == '.')
    {
      duration += duration/2;
      p++;
    }
 
    // now, get scale
    if(isdigit(*p))
    {
      scale = *p - '0';
      p++;
    }
    else
    {
      scale = default_oct;
    }

    scale += OCTAVE_OFFSET;

    if(*p == ',')
      p++;       // skip comma for next note (or we may be at the end)

    // now play the note

    if(note)
    {
      Serial.print("Playing: ");
      Serial.print(scale, 10); Serial.print(' ');
      Serial.print(note, 10); Serial.print(" (");
      Serial.print(notes[(scale - 4) * 12 + note], 10);
      Serial.print(") ");
      Serial.println(duration, 10);
      tone1.play(notes[(scale - 4) * 12 + note]);
      delay(duration);
      tone1.stop();
    }
    else
    {
      Serial.print("Pausing: ");
      Serial.println(duration, 10);
      delay(duration);
    }
  }
}
char *song = "";

A 1 element array containing a NULL isn’t going to get you far. strings are not dynamically sized.

    pinMode(2,OUTPUT);
    pinMode(3,OUTPUT);
    pinMode(4,OUTPUT);
    pinMode(5,OUTPUT);
    pinMode(6,OUTPUT);
    pinMode(7,OUTPUT);
    pinMode(8,OUTPUT);
    pinMode (9,OUTPUT);

For loop can cut this down to only two lines.

  if (Serial.available())
  {
    if (Serial.read() == 'p')
    {
      Serial.println("Input RTTTL");
      String SNG = serial_str();
      ...
  while(Serial.available()) {
      character = Serial.read();
      content.concat(character);
      delay(10);

It’s very unlikely that a second character will be available when you hit this while loop. Serial communication is SLOW compared to how fast the Arduino runs. Here is the proper, deliminated, non-blocking way or reading Serial data:

const char stopByte = '\n';
// Maximum characters in an int + null terminated character
const byte maxBuffer = 6;

void setup() 
{
  Serial.begin(115200);
  Serial.println("[Serial2Int]");
}

void loop() 
{
  // Stores the characters between the start and stop bytes
  static char buffer[maxBuffer + 1];
  // Keeps track of spot in buffer
  static byte index=0;
  
  if (Serial.available() > 0 ) {
    char inChar = Serial.read();
    
    if (inChar==stopByte)  // If stop byte is received
    {
      processData(buffer); // process the data
      index=0; // reset the array
      buffer[0] = '\0';
    } 
    else if (index < maxBuffer - 1) // only if we have enough space
    {
      buffer[index] = inChar; // put the character into our array
      index++; // and move to the next key in the array
      buffer[index] = '\0'; // then null terminate
    }
  }
}

void processData(char buffer[]) 
{
  unsigned int value = atoi(buffer); // convert string to int
  Serial.print("Value: ");
  Serial.println(value);
}

1.Ok, the 1 element array containing a NULL wasn't there by purpose, sorry, there was a song for testing there before. 2.Did the for loop, great idea, it look a lot smaller now, thanks. 3.I'm trying to get that code you gave into one function to replace mine, thanks for that code, it really is unlikely that we have another character at the loop.

Ok, but I hope now I'll able to get that song from serial and put it to play!

For loop can cut this down to only two lines.

Four, if you properly use and position the curly braces, which, of course, you should.

Ok, so i think i’m on the right track, i wrote an still incomplete loop function, could you guys tell me what you think?

void loop()
{
  if (Serial.available())
  {
    if (Serial.read() == 'p')
    {
      Serial.println("Input RTTTL");
      String SNG = serial_str();  //Still need to improve reading
       char *song = SNG //Convert SNG to char somehow 
      play_rtttl(song);
      for (int w=2;w<10;w++)
      {
         digitalWrite(w,LOW);
      }
        Serial.println("Done.");
    }
    else 
    {

    }
}
}

I think it's pointless to receive the serial data as a String object, only to convert it to a string before passing it to a function. Why not cutout the pointless middle man and save the serial data as a string?

PaulS: A string is a char array. A String is not. Proper capitalization matters. Yes, you should write the code to put the characters in an array, followed by a NULL.

A "string" is a collection of bytes, usually in a specific order. A "c-string" string is a char array.