/// \file PinballGame/ToneSpeaker.h

/// \brief Play musical tones on a speaker.

/// \copyright No copyright, 2016, Garth Zeglin.  This file is explicitly placed in the public domain.

/// \details This file contains support code for implementing audio effects for
/// the Arduino pinball machine demo, playing tone sequences at constant volume.

/****************************************************************/
class ToneSpeaker {

private:
  /// Number of the digital pin to use for output.  The hardware is assumed to
  /// be active-high, i.e., idling at a low voltage with no speaker current, and
  /// driven high when driving the speaker.
  int output_pin;

  /// Countdown for the current note or silence period, in microseconds.
  long note_timer;

  /// Tempo multiplier: duration in microseconds of a single MIDI 'tick' which
  /// is 1/24 of a quarter note.
  long tick_duration;
  
  /// True if currently playing a tone sequence.
  bool playing;

  /// Count of the total number of notes played.
  long event_count;

  /// Pointer to the next note to play.  A melody is specified as a series of
  /// pairs of bytes: note value, duration.  Invalid notes will play as a rest
  /// (silence).  A zero note ends the sequence.
  const unsigned char *playhead;

  /// Private function to begin a new note.
  void _start_note(unsigned char note, unsigned char value);
  
public:

  /// Constructor to initialize an instance of the class.  Note that this only
  /// initializes object state, it does not configure the hardware, which should
  /// be performed directly by the user.
  ToneSpeaker(int pin);    

  /// Set the tempo in beats per minute.  The desired units are microseconds per MIDI tick:
  ///   (microseconds / tick) = (microseconds / minute) / (ticks/minute)
  ///   (ticks / minute)      = (ticks / beat) * (beat / minute)
  //  So:
  ///   (microseconds / tick) = (microseconds / minute) / ((ticks / beat) * (beat / minute))
  ///   (microseconds / tick) = 60000000 / (24 * (beat / minute))
  ///   (microseconds / tick) =  2500000 / (beat / minute)
  void setTempo(int bpm)  { tick_duration = 2500000L / bpm; }
		
  /// Update function to be called as frequently as possible to operate the
  /// output state machine. It requires the number of microseconds elapsed since
  /// the last update.
  void update(unsigned long interval);

  /// Start the player on a new melody.  A melody is specified as a series of pairs of
  /// bytes: note value, duration.  The melody ends with a zero note.  Invalid notes are rests.
  void start_melody(const unsigned char melody[]);
  
  /// Debugging function to print a representation of the current state to the serial port.
  void send_debug(void);

  /// Access function to check whether a melody is currently playing.
  bool isPlaying(void) { return playing; }
};

/****************************************************************/
// Convenient symbols for the MIDI pitch scale.  Each value is a half-step.  For details of the tone
// definitions, see pitch_table.h.

#define MIDI_MIDDLE_C 60

#define MIDI_END 0
#define MIDI_REST 1

#define MIDI_C1 24
#define MIDI_C2 36
#define MIDI_C3 48

#define MIDI_C4 60
#define MIDI_D4 62
#define MIDI_E4 64
#define MIDI_F4 65
#define MIDI_G4 67
#define MIDI_A4 69
#define MIDI_B4 71

#define MIDI_C5 72
#define MIDI_D5 74
#define MIDI_E5 76
#define MIDI_F5 77
#define MIDI_G5 79
#define MIDI_A5 81
#define MIDI_B5 83

// Define note durations in units of MIDI beat clock 'ticks', each 1/24 of a
// quarter note.  This multiplier allows even triplets, e.g. three
// eighth-triplets equals one quarter note.
#define HALF                48
#define QUARTER             24
#define EIGHTH              12
#define SIXTEENTH            6
#define THIRTYSECOND         3

#define EIGHTH_TRIPLET       8
#define SIXTEENTH_TRIPLET    4
#define THIRTYSECOND_TRIPLET 2

/****************************************************************/
