Music Engine plays Music Macro Language compositions in the background

Dependents:   RETRO_BallsAndPaddle RETRO_BallAndHoles MusicBoxForFathersDay USBSec_mbed-os_dev

Music Engine is a simply library to execute Music Macro Language sequences asynchronously. Learn more about MML on wikipedia http://en.wikipedia.org/wiki/Music_Macro_Language

The following sample plays a simple tune

#include "mbed.h"
#include "MusicEngine.h"

// Play music on MCU Pin 0.18
// The pin should support PWM
MusicEngine music(P0_18);

main()
{
    music.play("T224L8O5CL16>C<P16GP16L8EL16P16>C<GP16L8E.L16P16L8C#L16>C#<P16G#P16L8FL16P16>C#<G#P16L8F.L16P16L8CL16>C<P16GP16L8EL16P16>C<GP16L8E.L16P16D#EFP16FF#GP16GG#AP16L8>C<P8L4>C");
    
    while(1)
    {
    }
}

MusicEngine.h

Committer:
taylorza
Date:
2015-02-06
Revision:
2:4f7c4255997a
Parent:
1:7eb27d971c01

File content as of revision 2:4f7c4255997a:

///////////////////////////////////////////////////////////////////////////////
// Retro  Music Engine
// Author: Chris Taylor (taylorza)

#include "mbed.h"

#ifndef __MUSICENGINE_H__
#define __MUSICENGINE_H__

/** MusicEngine provides a means to play Music Macro Language sequences asynchronously.
 *  Learn more about Music Macro Language (MML) on wikipedia
 *  http://en.wikipedia.org/wiki/Music_Macro_Language
*/
class MusicEngine
{
public:
    /** Creates an instance of the MusicEngine
      * @param pin pin used to generate the note frequencies
    */ 
    MusicEngine(PinName pin);
    
    /** Starts playing a new MML sequence. If one is already playing it is stopped and the new sequences started. 
      * @param mml string of MML commands to be played
     */
    void play(char *mml);
    
    /** Stop a currently playing sequence */     
    void stop();
    
    /** Query the engine to determine if a MML sequence is currently being played. */    
    bool getIsPlaying() { return _isPlaying; }
    
    /** Setup a callback function that will be executed when the music sequence ends. */
    void setCompletionCallback(void (*function)(void))
    {
        _completionCallback.attach(function);
    }
    
    /** Setup a callback function that will be executed when the music sequence ends.
     * @note This override is used if the callback is a class member
     */
    template<typename T>
    void setCompletionCallback(T *object, void (T::*member)(void))
    {
        _completionCallback.attach(object, member);       
    }

private:
    void executeCommand();
    void skipWhiteSpace();
    char getChar();
    char peekChar();
    void rewind();
    int getNumber(int min, int max);
    
private:
    PwmOut      _pwm;
    bool        _isPlaying;
    char        *_mml;
    int         _mmlIndex;    
    int         _octave;
    float       _duration;
    float       _durationRatio;
    float       _pause;
    int         _tempo;
    Timeout     _scheduler;
    
    FunctionPointer _completionCallback;
    
    static const float PERIOD_TABLE[];
    
    static const float WHOLE_NOTE_DURATION;
    static const float QUARTER_NOTE_DURATION;
    static const float QUARTER_NOTES_PER_MINUTE;
    
    static const float DEFAULT_TIMING;
    static const float LEGATO_TIMING;
    static const float STACCATO_TIMING;
    
    static const int NOTE_REST;
    static const int NOTE_C;
    static const int NOTE_CS;
    static const int NOTE_D;
    static const int NOTE_DS;
    static const int NOTE_E;
    static const int NOTE_F;
    static const int NOTE_FS;
    static const int NOTE_G;
    static const int NOTE_GS;
    static const int NOTE_A;
    static const int NOTE_AS;
    static const int NOTE_B;
};
#endif //__MUSICENGINE_H__