This music synthesizer accepts user input via a keyboard using a PS/2 interface. The user has the ability to control two parameters: waveforms and octaves. Waveforms are generated by means of the direct digital synthesis algorithm. The user may select from six waveforms: sine, square, sawtooth, triangle, EKG, and sinc. The synthesizer covers the seven octaves present on an 88-key piano in addition to the two incomplete octaves for a total of nine octaves.

Dependencies:   mbed PS2

mbed_synth.c

Committer:
lbaddam3
Date:
2011-02-28
Revision:
0:175ad26d17ce

File content as of revision 0:175ad26d17ce:

/***************************************************************************/
/* mbed_synth.c                                                            */
/*                                                                         */
/* ----------------------------------------------------------------------- */
/* This file defines the lookup tables for sine, square, sawtooth, reverse */
/* reverse sawtooth, triangle, ekg, and sinc waveforms. This file also     */
/* defines the functions needed to implement an interrupt-based DDS        */
/* algorithm.                                                              */
/*                                                                         */
/* ----------------------------------------------------------------------- */
/* The lookup tables are to be read based on the desired frequency by the  */
/* user of the synthesizer (waveFreq). The waveFreq variable will be       */
/* used to create what's known as a frequency tuning word (freqTun). This  */
/* variable inn turn is used to increment the 32-bit phase accumulator     */
/* (phaseAcc) every 40kHz generated by an interrupt.                       */
/* The calculation of freqTun is as follows:                               */
/*                                                                         */
/*       freqTun = ((waveFreq * SAMP_NUM) * (SHFT_FCTR / SAMP_FREQ))       */
/*                                                                         */
/* In this instance, SAMP_NUM is 256, SAMP_FREQ is 40000 and the shift     */
/* factor (SHFT_FCTR) is determined by setting the least significant bit   */
/* of the lookup address to 1. As the top 8 bits of the phase accumulator  */
/* serve as the lookup address. This means SHFT_FCTR must be equal to      */
/* 0x01000000.                                                             */
/*                                                                         */
/* ----------------------------------------------------------------------- */
/* Credit goes to John Luciani for his interrupt-based approach to the DDS */
/* algorithm. It helped massively with this project!                       */
/*                                                                         */
/* Find more about John's project here:                                    */
/* <http://wiblocks.luciani.org/docs/app-notes/nb1a-nco.html>              */
/*                                                                         */
/* Credit goes to Jesper Hansen for his wavetables (sine, square,          */
/* sawtooth, reverse sawtooth, and triangle).                              */
/*                                                                         */
/* Find out more about Jesper's project here:                              */
/* <http://www.myplace.nu/avr/minidds/index.htm>                           */
/*                                                                         */
/* Credit also goes to SPman for his modifications (ekg wavetable).        */
/*                                                                         */
/* Find out more about SPman's project here:                               */
/* <http://www.scienceprog.com/avr-dds-signal-generator-v20/>              */
/*                                                                         */
/* ----------------------------------------------------------------------- */
/* Author: Ron Grier, Lakshmi Baddam                                       */
/* Target: nxp lpc1768                                                     */
/*                                                                         */
/***************************************************************************/
#include "mbed_synth.h"

/* Globals */
volatile uint16_t waveFreq; // Frequency of waveform
volatile uint32_t phaseAcc; // Used to store phase accumulators
volatile uint32_t freqTun; // Frequency tuning words
volatile uint8_t waveIndex; // Top 8 bits of phase accumulator
const uint8_t *waveTable; // Ptr to wavetables
Wave myWave = SAWTOOTH;
volatile Bool rnd; // Rounding to next sample can reduce SNR
volatile Bool sendVals; // When to send next value(s) to DAC(s) set by ISR
volatile Bool waveChange; // Whether waveform has changed
volatile Bool noise;
volatile Wave newWave; // New waveform
volatile Bool freqChange; // Whether frequency has changed
volatile uint16_t newFreq; // New frequency
volatile Bool noteOn = FALSE;
Ticker synth_tick;
AnalogOut synthPin(p18);
PS2Keyboard ps2kb(p12, p11); // CLK, DAT
int octave = 4; // Default to 4th octave

/* Values for Sine Wave */
const uint8_t sinVals[SAMP_NUM] = {
  0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,
  0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,
  0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,
  0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8,
  0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,
  0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5,
  0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,
  0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,
  0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,
  0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,
  0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc,
  0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,
  0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3,
  0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,
  0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83,
  0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,
  0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51,
  0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,
  0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27,
  0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,
  0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a,
  0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,
  0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,
  0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08,
  0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,
  0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23,
  0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,
  0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c,
  0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,
  0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c
};

/* Values for Square Wave */
const uint8_t sqVals[SAMP_NUM] = {
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
};

/* Values for Sawtooth Wave */
const uint8_t sawVals[SAMP_NUM] = {
  0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
  0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
  0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
  0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
  0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
  0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
  0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
  0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
  0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
  0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
  0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
  0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
  0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
  0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
  0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
  0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
  0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
  0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
  0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
  0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
  0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,
  0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
  0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,
  0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
  0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,
  0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
  0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,
  0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
  0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,
  0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
  0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,
  0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
};

/* Values for Reverse Sawtooth Wave */
const uint8_t revSawVals[SAMP_NUM] = {
  0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,
  0xf7,0xf6,0xf5,0xf4,0xf3,0xf2,0xf1,0xf0,
  0xef,0xee,0xed,0xec,0xeb,0xea,0xe9,0xe8,
  0xe7,0xe6,0xe5,0xe4,0xe3,0xe2,0xe1,0xe0,
  0xdf,0xde,0xdd,0xdc,0xdb,0xda,0xd9,0xd8,
  0xd7,0xd6,0xd5,0xd4,0xd3,0xd2,0xd1,0xd0,
  0xcf,0xce,0xcd,0xcc,0xcb,0xca,0xc9,0xc8,
  0xc7,0xc6,0xc5,0xc4,0xc3,0xc2,0xc1,0xc0,
  0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8,
  0xb7,0xb6,0xb5,0xb4,0xb3,0xb2,0xb1,0xb0,
  0xaf,0xae,0xad,0xac,0xab,0xaa,0xa9,0xa8,
  0xa7,0xa6,0xa5,0xa4,0xa3,0xa2,0xa1,0xa0,
  0x9f,0x9e,0x9d,0x9c,0x9b,0x9a,0x99,0x98,
  0x97,0x96,0x95,0x94,0x93,0x92,0x91,0x90,
  0x8f,0x8e,0x8d,0x8c,0x8b,0x8a,0x89,0x88,
  0x87,0x86,0x85,0x84,0x83,0x82,0x81,0x80,
  0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,
  0x77,0x76,0x75,0x74,0x73,0x72,0x71,0x70,
  0x6f,0x6e,0x6d,0x6c,0x6b,0x6a,0x69,0x68,
  0x67,0x66,0x65,0x64,0x63,0x62,0x61,0x60,
  0x5f,0x5e,0x5d,0x5c,0x5b,0x5a,0x59,0x58,
  0x57,0x56,0x55,0x54,0x53,0x52,0x51,0x50,
  0x4f,0x4e,0x4d,0x4c,0x4b,0x4a,0x49,0x48,
  0x47,0x46,0x45,0x44,0x43,0x42,0x41,0x40,
  0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38,
  0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x30,
  0x2f,0x2e,0x2d,0x2c,0x2b,0x2a,0x29,0x28,
  0x27,0x26,0x25,0x24,0x23,0x22,0x21,0x20,
  0x1f,0x1e,0x1d,0x1c,0x1b,0x1a,0x19,0x18,
  0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,
  0x0f,0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,
  0x07,0x06,0x05,0x04,0x03,0x02,0x01,0x00
};

/* Values for Triangle Wave */
const uint8_t triVals[SAMP_NUM] = {
  0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,
  0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,
  0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,
  0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,
  0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,
  0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,
  0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,
  0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,
  0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,
  0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e,
  0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,
  0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe,
  0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce,
  0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde,
  0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee,
  0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe,
  0xff,0xfd,0xfb,0xf9,0xf7,0xf5,0xf3,0xf1,
  0xef,0xef,0xeb,0xe9,0xe7,0xe5,0xe3,0xe1,
  0xdf,0xdd,0xdb,0xd9,0xd7,0xd5,0xd3,0xd1,
  0xcf,0xcf,0xcb,0xc9,0xc7,0xc5,0xc3,0xc1,
  0xbf,0xbd,0xbb,0xb9,0xb7,0xb5,0xb3,0xb1,
  0xaf,0xaf,0xab,0xa9,0xa7,0xa5,0xa3,0xa1,
  0x9f,0x9d,0x9b,0x99,0x97,0x95,0x93,0x91,
  0x8f,0x8f,0x8b,0x89,0x87,0x85,0x83,0x81,
  0x7f,0x7d,0x7b,0x79,0x77,0x75,0x73,0x71,
  0x6f,0x6f,0x6b,0x69,0x67,0x65,0x63,0x61,
  0x5f,0x5d,0x5b,0x59,0x57,0x55,0x53,0x51,
  0x4f,0x4f,0x4b,0x49,0x47,0x45,0x43,0x41,
  0x3f,0x3d,0x3b,0x39,0x37,0x35,0x33,0x31,
  0x2f,0x2f,0x2b,0x29,0x27,0x25,0x23,0x21,
  0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x11,
  0x0f,0x0f,0x0b,0x09,0x07,0x05,0x03,0x01
};

/* Values for EKG Wave */
const uint8_t ekgVals[SAMP_NUM] = {
  0x49,0x4a,0x4b,0x4b,0x4a,0x49,0x49,0x49,
  0x49,0x48,0x47,0x45,0x44,0x43,0x43,0x43,
  0x44,0x44,0x43,0x41,0x3e,0x3d,0x3b,0x39,
  0x38,0x37,0x37,0x36,0x36,0x36,0x37,0x37,
  0x37,0x37,0x37,0x37,0x36,0x35,0x33,0x32,
  0x31,0x31,0x34,0x3d,0x4d,0x65,0x84,0xa9,
  0xcf,0xee,0xff,0xfe,0xea,0xc6,0x9a,0x6d,
  0x44,0x25,0x11,0x05,0x00,0x01,0x06,0x0d,
  0x14,0x1c,0x24,0x2d,0x34,0x39,0x3d,0x40,
  0x41,0x42,0x43,0x44,0x44,0x45,0x46,0x47,
  0x47,0x47,0x47,0x47,0x47,0x47,0x47,0x48,
  0x48,0x48,0x49,0x49,0x4a,0x4b,0x4b,0x4e,
  0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,
  0x56,0x58,0x5B,0x5D,0x60,0x62,0x64,0x66,
  0x68,0x6b,0x6d,0x70,0x73,0x74,0x79,0x7b,
  0x7d,0x7e,0x7f,0x7f,0x7f,0x7f,0x7f,0x7e,
  0x7d,0x7c,0x79,0x77,0x74,0x71,0x6d,0x69,
  0x66,0x62,0x5f,0x5c,0x59,0x57,0x54,0x51,
  0x4f,0x4d,0x4e,0x4b,0x4a,0x49,0x48,0x46,
  0x45,0x44,0x43,0x43,0x43,0x44,0x44,0x44,
  0x45,0x45,0x45,0x45,0x45,0x45,0x45,0x46,
  0x47,0x48,0x49,0x49,0x4a,0x4a,0x4b,0x4b,
  0x4b,0x4b,0x4b,0x4b,0x4a,0x4a,0x49,0x49,
  0x49,0x49,0x48,0x48,0x48,0x47,0x47,0x47,
  0x47,0x47,0x47,0x47,0x46,0x46,0x46,0x45,
  0x45,0x45,0x45,0x45,0x46,0x46,0x46,0x45,
  0x44,0x44,0x43,0x43,0x43,0x43,0x42,0x42,
  0x42,0x41,0x41,0x41,0x41,0x41,0x41,0x41,
  0x41,0x40,0x40,0x3f,0x3f,0x40,0x40,0x41,
  0x41,0x41,0x41,0x41,0x41,0x41,0x40,0x40,
  0x40,0x40,0x40,0x40,0x40,0x40,0x41,0x41,
  0x41,0x42,0x43,0x44,0x45,0x47,0x48,0x49
};

/* Values for Sinc Wave */
const uint8_t sincVals[SAMP_NUM] = {
  0x2d,0x2f,0x31,0x32,0x32,0x32,0x31,0x30,
  0x2e,0x2d,0x2b,0x2a,0x29,0x29,0x29,0x2a,
  0x2c,0x2e,0x2f,0x31,0x32,0x33,0x33,0x32,
  0x30,0x2e,0x2c,0x2a,0x29,0x28,0x28,0x28,
  0x2a,0x2c,0x2e,0x30,0x32,0x33,0x34,0x34,
  0x32,0x31,0x2e,0x2c,0x2a,0x28,0x27,0x27,
  0x27,0x29,0x2b,0x2e,0x31,0x33,0x35,0x35,
  0x35,0x33,0x31,0x2e,0x2b,0x28,0x26,0x25,
  0x25,0x26,0x28,0x2b,0x2e,0x32,0x35,0x37,
  0x38,0x37,0x35,0x32,0x2e,0x2a,0x26,0x23,
  0x22,0x21,0x23,0x26,0x2a,0x2f,0x34,0x38,
  0x3b,0x3c,0x3b,0x39,0x34,0x2e,0x28,0x22,
  0x1e,0x1b,0x1b,0x1d,0x22,0x29,0x31,0x39,
  0x41,0x46,0x48,0x47,0x42,0x3a,0x2e,0x21,
  0x15,0x0a,0x02,0x00,0x04,0x0f,0x21,0x3a,
  0x57,0x78,0x9a,0xba,0xd6,0xec,0xfa,0xff,
  0xfa,0xec,0xd6,0xba,0x9a,0x78,0x57,0x3a,
  0x21,0x0f,0x04,0x00,0x02,0x0a,0x15,0x21,
  0x2e,0x3a,0x42,0x47,0x48,0x46,0x41,0x39,
  0x31,0x29,0x22,0x1d,0x1b,0x1b,0x1e,0x22,
  0x28,0x2e,0x34,0x39,0x3b,0x3c,0x3b,0x38,
  0x34,0x2f,0x2a,0x26,0x23,0x21,0x22,0x23,
  0x26,0x2a,0x2e,0x32,0x35,0x37,0x38,0x37,
  0x35,0x32,0x2e,0x2b,0x28,0x26,0x25,0x25,
  0x26,0x28,0x2b,0x2e,0x31,0x33,0x35,0x35,
  0x35,0x33,0x31,0x2e,0x2b,0x29,0x27,0x27,
  0x27,0x28,0x2a,0x2c,0x2e,0x31,0x32,0x34,
  0x34,0x33,0x32,0x30,0x2e,0x2c,0x2a,0x28,
  0x28,0x28,0x29,0x2a,0x2c,0x2e,0x30,0x32,
  0x33,0x33,0x32,0x31,0x2f,0x2e,0x2c,0x2a,
  0x29,0x29,0x29,0x2a,0x2b,0x2d,0x2e,0x30,
  0x31,0x32,0x32,0x32,0x31,0x2f,0x2d,0x2d
};

/* Notes */
const uint16_t notes[OCT_NUM][NOTE_NUM] = { // Array of Notes
  {C_0, Cs_0, D_0, Ds_0, E_0, F_0, Fs_0, G_0, Gs_0, A_0, As_0, B_0},
  {C_1, Cs_1, D_1, Ds_1, E_1, F_1, Fs_1, G_1, Gs_1, A_1, As_1, B_1},
  {C_2, Cs_2, D_2, Ds_2, E_2, F_2, Fs_2, G_2, Gs_2, A_2, As_2, B_2},
  {C_3, Cs_3, D_3, Ds_3, E_3, F_3, Fs_3, G_3, Gs_3, A_3, As_3, B_3},
  {C_4, Cs_4, D_4, Ds_4, E_4, F_4, Fs_4, G_4, Gs_4, A_4, As_4, B_4},
  {C_5, Cs_5, D_5, Ds_5, E_5, F_5, Fs_5, G_5, Gs_5, A_5, As_5, B_5},
  {C_6, Cs_6, D_6, Ds_6, E_6, F_6, Fs_6, G_6, Gs_6, A_6, As_6, B_6},
  {C_7, Cs_7, D_7, Ds_7, E_7, F_7, Fs_7, G_7, Gs_7, A_7, As_7, B_7},
  {C_8, Cs_8, D_8, Ds_8, E_8, F_8, Fs_8, G_8, Gs_8, A_8, As_8, B_8}
};

/* Function Definitions */

/**
 * This function adds the frequency tuning word present @ index to the 
 * phase accumulator present @ index.
 *
 * param: index - the channel number of oscillator
 */
//inline void acc_inc(const uint8_t index) {
void acc_inc(void) {
  phaseAcc += freqTun;
}

/**
 * This function resets the phase accumulator for the oscillator present
 * @ index. Should be called when switching frequencies.
 *
 * param: index - the channel number of oscillator
 */
//inline void acc_reset(const uint8_t index) {
void acc_reset(void) {
  phaseAcc = 0;
}

/**
 * This function calculates the frequency tuning word of the oscillator
 * present @ index.
 *
 * param: index - the channel number of oscillator
 */
//inline void set_wave(const Wave waveType, const uint8_t index) {
void set_wave(const Wave waveType) {
  switch(waveType) {
  case SINE:
    waveTable = sinVals;
    break;
  case SQUARE:
    waveTable = sqVals;
    break;
  case SAWTOOTH:
    waveTable = sawVals;
    break;
  case REV_SAWTOOTH:
    waveTable = revSawVals;
    break;
  case TRIANGLE:
    waveTable = triVals;
    break;
  case EKG:
    waveTable = ekgVals;
    break;
  case SINC:
    waveTable = sincVals;
    break;
  default:
    break;
  }
}

/**
 * This function calculates the frequency tuning word of the oscillator
 */
void set_freq_tun(void) {
  freqTun = ((((uint32_t)waveFreq) * SAMP_NUM) *
            (SHFT_FCTR / SAMP_FREQ));
}

/**
 * This function sets the frequency of the oscillator. In
 * addition, this function calculates the corresponding frequency tuning word.
 *
 * param: freq - frequency of waveform
 */
//inline void set_freq(const uint16_t freq, const uint8_t index) {
void set_freq(const uint16_t freq) {
  acc_reset();
  waveFreq = freq;
  set_freq_tun();
}

/**
 * This function sends the current waveform value for each channel
 * to the appropriate output port. Checks are made to ensure frequency
 * and waveform values are up to date.
 */
void send_vals(void) {
    if (freqChange == TRUE) {
      set_freq(newFreq); // Set new frequency
      freqChange = FALSE; // Reset freqChange
    }
    
    if (waveChange == TRUE) {
      set_wave(newWave); // Set new waveform
      waveChange = FALSE; // Reset waveChange
    }
    
    acc_inc(); // Increment phase accumulator
    waveIndex = phaseAcc >> 24; // Get address into wavetable    
    
    if (noteOn == TRUE)
      synthPin = waveTable[waveIndex]/((float)(SAMP_NUM-1));
}

void init_synth(void) {
  // Setup initial waveforms
  acc_reset(); // Set all accumulators to 0 initially
  set_wave(myWave); // Set all waveforms to sine wave
  set_freq(notes[octave][A_NOTE]);
  rnd = waveChange = freqChange = FALSE;
}

int main(void) {
  PS2Keyboard::keyboard_event_t evt_kb;
  init_synth(); // Initialize synth

  int samp_us = 1.0/SAMP_FREQ*1e6; // Determine sample period in microseconds

  synth_tick.attach_us(&send_vals, samp_us); // Call send_vals every samp_us
  while (1) { // Loop here forever
    // Process keys and determine which waveform, octave, and note should be
    // played
    if (ps2kb.processing(&evt_kb)) {
      if (!evt_kb.type) {
    switch(evt_kb.scancode[0]) {
    case 0xe0:
      switch(evt_kb.scancode[1]) {
      case Right_key:
        ++octave;
        break;
      case Left_key:
        --octave;
        break;
      default:
        printf("Invalid Octave Entry\n\r");
        break;
      }
    case A_key:
      set_freq(notes[octave][C_NOTE]);
      noteOn = TRUE;
      break;
    case W_key:
      set_freq(notes[octave][Cs_NOTE]);
      noteOn = TRUE;
      break;
    case S_key:
      set_freq(notes[octave][D_NOTE]);
      noteOn = TRUE;
      break;
    case E_key:
      set_freq(notes[octave][Ds_NOTE]);
      noteOn = TRUE;
      break;
    case D_key:
      set_freq(notes[octave][E_NOTE]);
      noteOn = TRUE;
      break;
    case F_key:
      set_freq(notes[octave][F_NOTE]);
      noteOn = TRUE;
      break;
    case T_key:
      set_freq(notes[octave][Fs_NOTE]);
      noteOn = TRUE;
      break;
    case J_key:
      set_freq(notes[octave][G_NOTE]);
      noteOn = TRUE;
      break;
    case I_key:
      set_freq(notes[octave][Gs_NOTE]);
      noteOn = TRUE;
      break;
    case K_key:
      set_freq(notes[octave][A_NOTE]);
      noteOn = TRUE;
      break;
    case O_key:
      set_freq(notes[octave][As_NOTE]);
      noteOn = TRUE;
      break;
    case L_key:
      set_freq(notes[octave][B_NOTE]);
      noteOn = TRUE;
      break;
    case Sc_key:
      if (octave < OCT_NUM-2) {
        set_freq(notes[octave+1][C_NOTE]);
        noteOn = TRUE;
        break;
      }
    case Plus_key:
      switch (myWave){
        case SINE:
          myWave = SQUARE;
          break;
        case SQUARE:
          myWave = SAWTOOTH;
          break;
        case SAWTOOTH:
          myWave = TRIANGLE;
          break;
        case TRIANGLE:
          myWave = EKG;
          break;
        case EKG:
          myWave = SINC;
          break;
        case SINC:
          myWave = SINC;
          break;
        default:
          break;
      }
      set_wave(myWave);
      break;
    case Minus_key:
      switch (myWave){
        case SINE:
          myWave = SINE;
          break;
        case SQUARE:
          myWave = SINE;
          break;
        case SAWTOOTH:
          myWave = SQUARE;
          break;
        case TRIANGLE:
          myWave = SAWTOOTH;
          break;
        case EKG:
          myWave = TRIANGLE;
          break;
        case SINC:
          myWave = EKG;
          break;
        default:
          break;
      }
      set_wave(myWave);
      break;
    default:
      printf("Invalid Key Entry\n\r");
      break;
    }
      }
      else {
        noteOn = FALSE;
      }
      if (octave < 0)
        octave = 0;
      else if (octave > OCT_NUM-1)
        octave = OCT_NUM-1;
    }
  }
  
  return 0;
}