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

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

#include "Arduino.h"
#include "ToneSpeaker.h"
#include "pitch_table.h"

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

ToneSpeaker::ToneSpeaker(int pin)
{
  output_pin = pin;
  note_timer = 0;
  setTempo(120);
  playing = false;
  event_count = 0;
  playhead = NULL;
}

void ToneSpeaker::_start_note(unsigned char note, unsigned char value)
{
  if (note < FIRST_MIDI_NOTE || note > LAST_MIDI_NOTE) {
    noTone(output_pin);
  } else {
    // Use the AVR pgmspace.h API to read a value from the table in FLASH.
    // Reference: https://www.arduino.cc/en/Reference/PROGMEM
    int pitch = pgm_read_word_near( midi_freq_table + (note - FIRST_MIDI_NOTE));
    tone(output_pin, pitch);
  }
  note_timer += value * tick_duration;
  event_count++;
}

void ToneSpeaker::update(unsigned long interval)
{
  if (playing) {
    note_timer -= interval;
    if (note_timer < 0) {
      // start the next note
      if (*playhead == 0) {
	// if end of sequence
	noTone(output_pin);
	playing = false;
      } else {
	_start_note(playhead[0], playhead[1]);
	playhead += 2;
      }
    }
  }
}

void ToneSpeaker::start_melody(const unsigned char melody[])
{
  Serial.print("entering start_melody, first value is ");
  Serial.println(melody[0]);
  
  if (melody[0] != 0) {
    // Reset any existing melody timing.
    note_timer = 0;

    // Kick off the sequence; the update() function will continue it.
    playing = true;
    _start_note( melody[0], melody[1] );
    playhead = &melody[2];
  }
}

/****************************************************************/  
void ToneSpeaker::send_debug(void)
{
  Serial.print("speaker pin:");
  Serial.print(output_pin);

  Serial.print("  playing: ");
  Serial.print(playing);

  Serial.print("  events: ");
  Serial.print(event_count);

  Serial.print("  tick duration: ");
  Serial.print(tick_duration);
  
  Serial.println();
}

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