Music Box

Hi all,

I’m trying to make a music box.
I’ve programmed the arduino to play the music I want, and can get the motor spinning for the ornament on the inside. The problem is, both work well alone, but I’m not sure how to get both to work at the same time…

Can anyone help?

Thanks.

This is the code so far…


#include <Stepper.h>
#include <pitches.h>

#define STEPS_PER_MOTOR_REVOLUTION 32   

#define STEPS_PER_OUTPUT_REVOLUTION 32 * 64



int speaker = 3;
int ldr = A0;

int Steps2Take;


Stepper small_stepper(STEPS_PER_MOTOR_REVOLUTION, 8, 10, 9, 11);


int melody[]=
{
  NOTE_E5, NOTE_G5, NOTE_D6,
  NOTE_C6, NOTE_G5, NOTE_F5,
  NOTE_E5, NOTE_E5, NOTE_E5, NOTE_F5, NOTE_G5, NOTE_A5, NOTE_G5,
  NOTE_E5, NOTE_G5, NOTE_D6,
  NOTE_C6, NOTE_G5, NOTE_F5,
  NOTE_E5, NOTE_G5, NOTE_G5,NOTE_A5, NOTE_B5, NOTE_C6, NOTE_C6, END 
};

int noteDurations[]=
{
  8,4,12,
  8,4,12,
  8,4,4,4,4,12,12,
  8,4,12,
  8,4,12,
  8,4,4,4,4,12,12,
};


void playMusic()
{
   small_stepper.setSpeed(200);  

  small_stepper.step(HIGH);

  for(int thisNote = 0; melody[thisNote] !=-1; thisNote++)
  {
    int speed = 90;
    int noteDuration = speed*noteDurations[thisNote];
    tone(speaker, melody[thisNote], noteDuration*.95);

    delay(noteDuration);

    noTone(speaker);
  }
}


void setup() {
  // put your setup code here, to run once:
  pinMode(speaker, OUTPUT);
  pinMode(ldr, INPUT);
  Serial.begin(9600);

}
 

void loop() {
  // put your main code here, to run repeatedly:

  int ldrValue = analogRead(ldr);


  if(ldrValue > 1)
  {
    
    playMusic();
  }
  else
 {
    small_stepper.step(LOW);
    pinMode(speaker, LOW);
 }
 
}

Don't use delay.
Have you even tried looking it up? This is literally the first post on this forum: Demonstration code for several things at the same time.

Pieter

Hi,

Yeah I did....sorry. I just didn't understand it. Will try again.
Thanks.

I’m just not having any success with this yet… I can get it to play the one note from the example (plays a 550), but any attempts at substituting in my code isn’t working… I’ve been reading other posts but just can’t quite grasp it…

#include <Stepper.h>
#include <pitches.h>

#define STEPS_PER_MOTOR_REVOLUTION 32   

#define STEPS_PER_OUTPUT_REVOLUTION 32 * 64

const byte speakerPin=3;
unsigned long lastPeriodStart;
const int onDuration=1000;
const int periodDuration=6000;
int play;

int ldr = A0;



Stepper small_stepper(STEPS_PER_MOTOR_REVOLUTION, 8, 10, 9, 11);


int melody[]=
{
  NOTE_E5, NOTE_G5, NOTE_D6,
  NOTE_C6, NOTE_G5, NOTE_F5,
  NOTE_E5, NOTE_E5, NOTE_E5, NOTE_F5, NOTE_G5, NOTE_A5, NOTE_G5,
  NOTE_E5, NOTE_G5, NOTE_D6,
  NOTE_C6, NOTE_G5, NOTE_F5,
  NOTE_E5, NOTE_G5, NOTE_G5,NOTE_A5, NOTE_B5, NOTE_C6, NOTE_C6, END 
};

int noteDurations[]=
{
  8,4,12,
  8,4,12,
  8,4,4,4,4,12,12,
  8,4,12,
  8,4,12,
  8,4,4,4,4,12,12,
};

void setup() {
  // put your setup code here, to run once:
  pinMode(speakerPin, OUTPUT);
  pinMode(ldr, INPUT);
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  
  if (millis()-lastPeriodStart>=periodDuration)
  {
    lastPeriodStart+=periodDuration;
    for(play = 0; play < 27; play++)
    {
      tone(speakerPin,melody[play], onDuration[play]); 
    }
  
    small_stepper.setSpeed(200);
    small_stepper.step(HIGH);
  }
}

redlight150:
I'm just not having any success with this yet... I can get it to play the one note from the example (plays a 550), but any attempts at substituting in my code isn't working.. I've been reading other posts but just can't quite grasp it...

You still don't understand how to use millis(). You should try the example "Blink without delay" in the IDE.

Here is also a tutorial.

Another take on the technique is here:- http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html

Hi,
Am still struggling with this.

Do I at least have the right idea by using the for loop to cycle through the melody and note durations?

Thanks

redlight150:
Do I at least have the right idea by using the for loop to cycle through the melody and note durations?

No. Nothing else can happen until that loop finishes, so it is "blocking" just as delay() was. That loop has to go too.

It's ok to have delay() and for() loops in code that is doing many things, but they have to be very short, so that the code is not held up for long and can move on to doing other things.

redlight150:
Am still struggling with this.

Looks like you are not ready for such a project yet. I would suggest that you do some more tutorials and try to understand exactly what is happening in them.

Will do, thank you both :wink:

I've been reading up on millis();

It is so much easier to use with just blinking leds....I think what has me caught is the different timings needed for producing different notes. Which would be the best approach??....Do I call millis() before playing each note? Or is there an easier way?

If someone would throw me a bone (example of a couple of notes so I can figure the rest out) it would be
much appreciated, I'm currently in hospital and want to have it working to show my nurses before I leave.

It is exactly the same as blinking an LED. You set the tone to play continuously, and use the value from millis to find out when it is time to change the tone or to turn it off. The time the tone plays you have is the duration you are using at the moment.
Just get that bit going first before trying to add your motor.

I’ve still been trying to build this music box. I think I’m getting closer but do not know where the mistake is in the current code.
Normally I would want to know exactly what the code is doing but this project of mine is time sensitive.
There are people I want to give this to as a farewell present and I’m running out of time.
Is anyone willing/able to write the code I need?
I’ve commented out some of the current code at the moment while I focus on getting the music working without using ‘delay()’ etc…

//#include <Stepper.h>
#include <pitches.h>
//#define STEPS_PER_MOTOR_REVOLUTION 32   

//#define STEPS_PER_OUTPUT_REVOLUTION 32 * 64

const int tonePin = 4;
unsigned long previousMillis = 0;
uint8_t currentNote = 0; 
unsigned long currentMillis;

//int ldr = A0;

//Stepper small_stepper(STEPS_PER_MOTOR_REVOLUTION, 8, 10, 9, 11);
//pauseBetweenNotes = noteDuration;

void setup() {
  // put your setup code here, to run once:
  pinMode(tonePin, OUTPUT);
}

int melody[]=
{
  NOTE_E5, NOTE_G5, NOTE_D6,
  NOTE_C6, NOTE_G5, NOTE_F5,
  NOTE_E5, NOTE_E5, NOTE_E5, NOTE_F5, NOTE_G5, NOTE_A5, NOTE_G5,
  NOTE_E5, NOTE_G5, NOTE_D6,
  NOTE_C6, NOTE_G5, NOTE_F5,
  NOTE_E5, NOTE_G5, NOTE_G5,NOTE_A5, NOTE_B5, NOTE_C6, NOTE_C6, END 
};

int noteDuration[]=
{
  8,4,12,
  8,4,12,
  8,4,4,4,4,12,12,
  8,4,12,
  8,4,12,
  8,4,4,4,4,12,12,
};

void loop() {
  // put your main code here, to run repeatedly:
  //small_stepper.setSpeed(200);
  //small_stepper.step(HIGH);
  
  currentMillis = millis();

  if(currentMillis - previousMillis >= noteDuration[currentNote])
  {
    tone(tonePin, melody[currentNote], noteDuration[currentNote]);
    previousMillis = currentMillis;
  }
  if(currentNote > 26-1)
  {
    currentNote = 0;
  }
  currentNote++;
}

The duration of your tones are between 4 and 12 ms,
at 4 ms your frequency has to be 250 kHz to get one square wave cycle.

If the used frequency is below 40 kHz (cycle of 25 ms) you will only see the first half of the cycle,
before switching frequency, basically leaving you with a pin not changing at all.

And all this only if tone were capable of switching frequencies instantly.

You need much longer durations...

You probably lost the factor from the OP...

    int speed = 90;
    int noteDuration = speed*noteDurations[thisNote];

Yes what Whandall said. Plus you have not included your pitches.h file so I can’t check the code but this is what you should do. I have multiplied all your duration by a songTempo variable to get a reasonable tempo.

#include <pitches.h>
const int tonePin = 4;
unsigned long previousMillis = 0;
uint8_t currentNote = 0;
int songTempo = 90;

void setup() {
  // put your setup code here, to run once:
  pinMode(tonePin, OUTPUT);
}

int melody[]=
{
  NOTE_E5, NOTE_G5, NOTE_D6,
  NOTE_C6, NOTE_G5, NOTE_F5,
  NOTE_E5, NOTE_E5, NOTE_E5, NOTE_F5, NOTE_G5, NOTE_A5, NOTE_G5,
  NOTE_E5, NOTE_G5, NOTE_D6,
  NOTE_C6, NOTE_G5, NOTE_F5,
  NOTE_E5, NOTE_G5, NOTE_G5,NOTE_A5, NOTE_B5, NOTE_C6, NOTE_C6
};

int noteDuration[]=
{
  8,4,12,
  8,4,12,
  8,4,4,4,4,12,12,
  8,4,12,
  8,4,12,
  8,4,4,4,4,12,12,
};

void loop() {
  if(millis() - previousMillis >= songTempo*noteDuration[currentNote]+100){
  playNextNote();
  }
  // put motor stuff here in a similar fashion
}

void playNextNote(){   
    currentNote++;
  if(currentNote >= 26)
  {
    currentNote = 0;
  }
    tone(tonePin, melody[currentNote], songTempo*noteDuration[currentNote]);
    previousMillis = millis();
}

Oh my gosh! Yes, sounds perfect!

Thanks so much for your input.
My current residence is a psychiatric hospital and this music box is a present for my nurses..
I normally don't take on such big projects, and know what I'm doing when I do it....I don't plan to be in here much longer (hence the 'time sensitive comment').

They're gonna be stoked!

Thanks again :wink:

Man...I thought this was going to be the easy part.

Where you have written "// put motor stuff here in a similar fashion"
I put in

      Stepper small_stepper(STEPS_PER_MOTOR_REVOLUTION, 8, 10, 9, 11);
               small_stepper.setSpeed(200);
               small_stepper.step(HIGH);

Now I can't get the motor working at all...
Probably doesn't help that I'm getting my brain fried 3 times a week.....might be able to retain information better if I wasn't ....lol

yay! sorry about that, silly mistake.
Got it working now :slight_smile:
Just have to add ldr :smiley: