You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
3.6 KiB

/** @file squeaker.h
@author M. P. Hayes, UCECE
@date 14 April 2007
@brief Play simple tunes with PWM.
*/
#ifndef SQUEAKER_H
#define SQUEAKER_H
#include "system.h"
#include "ticker.h"
typedef uint8_t squeaker_speed_t;
typedef uint8_t squeaker_scale_t;
typedef uint8_t squeaker_note_t;
typedef uint8_t squeaker_duration_t;
typedef uint8_t squeaker_period_t;
typedef uint8_t squeaker_volume_t;
enum {SQUEAKER_OCTAVE_DEFAULT = 4};
enum {SQUEAKER_SPEED_DEFAULT = 200};
/* Could calculate scale divisors at run time. 2^(1/2) is approx
1.0594631. A reasonable rational approximation is 267/252 =
1.0595238. Let's save memory and provide a macro to compute the
divisors. */
#define SQUEAKER_DIVISOR(POLL_RATE, FREQ) (POLL_RATE / FREQ + 0.5)
#if 0
enum {SQUEAKER_NOTE_MIN = 60};
/* Define divisors for chromatic scale C4 -> C5. For better accuracy
this should be defined for the lowest frequency scale, however,
this may need 16 bits per note. */
#define SQUEAKER_SCALE_TABLE(POLL_RATE) \
{SQUEAKER_DIVISOR (POLL_RATE, 261.6256), \
SQUEAKER_DIVISOR (POLL_RATE, 277.1826), \
SQUEAKER_DIVISOR (POLL_RATE, 293.6648), \
SQUEAKER_DIVISOR (POLL_RATE, 311.1270), \
SQUEAKER_DIVISOR (POLL_RATE, 329.6276), \
SQUEAKER_DIVISOR (POLL_RATE, 349.2282), \
SQUEAKER_DIVISOR (POLL_RATE, 369.9944), \
SQUEAKER_DIVISOR (POLL_RATE, 391.9954), \
SQUEAKER_DIVISOR (POLL_RATE, 415.3047), \
SQUEAKER_DIVISOR (POLL_RATE, 440.0000), \
SQUEAKER_DIVISOR (POLL_RATE, 466.1638), \
SQUEAKER_DIVISOR (POLL_RATE, 493.8833)}
#else
enum {SQUEAKER_NOTE_MIN = 40};
/* Define divisors for chromatic scale E2 -> D#3. For better accuracy
this should be defined for the lowest frequency scale, however,
this may need 16 bits per note. */
#define SQUEAKER_SCALE_TABLE(POLL_RATE) \
{SQUEAKER_DIVISOR (POLL_RATE, 82.41), \
SQUEAKER_DIVISOR (POLL_RATE, 87.31), \
SQUEAKER_DIVISOR (POLL_RATE, 92.50), \
SQUEAKER_DIVISOR (POLL_RATE, 98.00), \
SQUEAKER_DIVISOR (POLL_RATE, 103.83), \
SQUEAKER_DIVISOR (POLL_RATE, 110.0), \
SQUEAKER_DIVISOR (POLL_RATE, 116.54), \
SQUEAKER_DIVISOR (POLL_RATE, 123.47), \
SQUEAKER_DIVISOR (POLL_RATE, 130.81), \
SQUEAKER_DIVISOR (POLL_RATE, 138.59), \
SQUEAKER_DIVISOR (POLL_RATE, 146.83), \
SQUEAKER_DIVISOR (POLL_RATE, 155.56)}
#endif
typedef struct
{
uint8_t note_clock;
uint8_t note_period;
uint8_t note_duty;
uint8_t note_holdoff;
/* Pointer to start of string. */
const char *start;
/* Pointer to current position in string. */
const char *cur;
uint8_t holdoff;
uint16_t poll_rate;
const char *loop_start;
int8_t loop_count;
uint8_t prescaler;
uint8_t note_fraction;
squeaker_speed_t speed;
squeaker_volume_t volume;
ticker8_t ticker;
squeaker_scale_t *scale_table;
uint8_t octave;
} squeaker_private_t;
typedef squeaker_private_t squeaker_obj_t;
typedef squeaker_obj_t *squeaker_t;
/* The scale table is usually defined with:
static squeaker_scale_t scale_table[] = SQUEAKER_SCALE_TABLE (LOOP_POLL_RATE);
*/
extern squeaker_t
squeaker_init (squeaker_obj_t *dev,
uint16_t poll_rate,
squeaker_scale_t *scale_table);
extern void
squeaker_play (squeaker_t squeaker, const char *str);
extern int8_t
squeaker_update (squeaker_t squeaker);
/* Set (base) speed in beats per minute (BPM). */
extern void
squeaker_speed_set (squeaker_t squeaker, squeaker_speed_t speed);
/* Set volume as percentage of maximum. */
extern void
squeaker_volume_set (squeaker_t squeaker, squeaker_volume_t volume);
#endif