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
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
|