Send note off messages
This commit is contained in:
@@ -124,7 +124,6 @@ static void display_task_init (void)
|
|||||||
{
|
{
|
||||||
tinygl_init (DISPLAY_TASK_RATE);
|
tinygl_init (DISPLAY_TASK_RATE);
|
||||||
tinygl_font_set (&font3x5_1);
|
tinygl_font_set (&font3x5_1);
|
||||||
tinygl_text_speed_set (MESSAGE_RATE);
|
|
||||||
tinygl_text_mode_set (TINYGL_TEXT_MODE_ROTATE_STEP);
|
tinygl_text_mode_set (TINYGL_TEXT_MODE_ROTATE_STEP);
|
||||||
|
|
||||||
display_note ();
|
display_note ();
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
/* Define polling rates in Hz. */
|
/* Define polling rates in Hz. */
|
||||||
#define TWEETER_TASK_RATE 20000
|
#define TWEETER_TASK_RATE 20000
|
||||||
|
|
||||||
#define TUNE_TASK_RATE 100
|
#define TUNE_TASK_RATE 200
|
||||||
|
|
||||||
#define BUTTON_TASK_RATE 10
|
#define BUTTON_TASK_RATE 10
|
||||||
|
|
||||||
|
|||||||
+73
-12
@@ -69,6 +69,13 @@
|
|||||||
<ABC]1DE]2FG> represents ABCDEABCFG where ]n denotes alternate
|
<ABC]1DE]2FG> represents ABCDEABCFG where ]n denotes alternate
|
||||||
endings.
|
endings.
|
||||||
|
|
||||||
|
With 8 bits for the tempo (in bpm), the max tempo is 255 bpm.
|
||||||
|
This corresponds to 4.25 beats per second. If the minimum time
|
||||||
|
to release a note is 1 / 8 of a quarter note, then we need
|
||||||
|
to poll at a rate of at least 4.25 * 8 = 34 times per second.
|
||||||
|
|
||||||
|
This could be made a lot more flexible but the orginal
|
||||||
|
implementation had a tight memory constraint.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum {MMELODY_SCALE_SIZE = 12};
|
enum {MMELODY_SCALE_SIZE = 12};
|
||||||
@@ -79,17 +86,34 @@ mmelody_ticker_set (mmelody_t mmelody)
|
|||||||
{
|
{
|
||||||
uint16_t speed;
|
uint16_t speed;
|
||||||
|
|
||||||
|
/* Notes per four minutes. */
|
||||||
speed = mmelody->speed * mmelody->note_fraction;
|
speed = mmelody->speed * mmelody->note_fraction;
|
||||||
|
|
||||||
TICKER_INIT (&mmelody->ticker, mmelody->poll_rate * 60 * 4 / speed);
|
mmelody->beat_duration = mmelody->poll_rate * 60 * 4 / speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mmelody_note_play (mmelody_t mmelody, mmelody_note_t note)
|
mmelody_note_on (mmelody_t mmelody, mmelody_note_t note, uint8_t duration)
|
||||||
{
|
{
|
||||||
mmelody->play_callback (mmelody->play_callback_data, note,
|
mmelody->play_callback (mmelody->play_callback_data, note,
|
||||||
mmelody->volume);
|
mmelody->volume);
|
||||||
|
mmelody->note = note;
|
||||||
|
|
||||||
|
/* Determine ticks between sounding notes. */
|
||||||
|
mmelody->ticks2 = (mmelody->beat_duration + 8) / 16;
|
||||||
|
|
||||||
|
/* Determine ticks before turning the note off. */
|
||||||
|
mmelody->ticks1 = mmelody->beat_duration * duration - mmelody->ticks2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
mmelody_note_off (mmelody_t mmelody)
|
||||||
|
{
|
||||||
|
mmelody->play_callback (mmelody->play_callback_data,
|
||||||
|
mmelody->note, 0);
|
||||||
|
mmelody->note = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -125,11 +149,12 @@ mmelody_scan (mmelody_t mmelody, const char *str)
|
|||||||
bool have_hash;
|
bool have_hash;
|
||||||
bool have_num;
|
bool have_num;
|
||||||
mmelody_note_t note;
|
mmelody_note_t note;
|
||||||
|
uint8_t duration = 1;
|
||||||
|
|
||||||
/* Play rest at end of melody. */
|
/* Play rest at end of melody. */
|
||||||
if (! *str)
|
if (! *str)
|
||||||
{
|
{
|
||||||
mmelody_note_play (mmelody, 0);
|
mmelody_note_off (mmelody);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +220,12 @@ mmelody_scan (mmelody_t mmelody, const char *str)
|
|||||||
|
|
||||||
/* Play rest. */
|
/* Play rest. */
|
||||||
case ' ':
|
case ' ':
|
||||||
mmelody_note_play (mmelody, 0);
|
while (*str == '/')
|
||||||
|
{
|
||||||
|
duration++;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
mmelody_note_on (mmelody, 0, duration);
|
||||||
return str;
|
return str;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -233,12 +263,16 @@ mmelody_scan (mmelody_t mmelody, const char *str)
|
|||||||
/* Convert note to MIDI note number. */
|
/* Convert note to MIDI note number. */
|
||||||
note += (mmelody->octave + 1) * MMELODY_SCALE_SIZE;
|
note += (mmelody->octave + 1) * MMELODY_SCALE_SIZE;
|
||||||
|
|
||||||
mmelody_note_play (mmelody, note);
|
while (*str == '/')
|
||||||
|
{
|
||||||
|
duration++;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
mmelody_note_on (mmelody, note, duration);
|
||||||
return str;
|
return str;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* Continue with previous note. */
|
|
||||||
case '/':
|
|
||||||
default:
|
default:
|
||||||
return str;
|
return str;
|
||||||
break;
|
break;
|
||||||
@@ -258,7 +292,10 @@ mmelody_play (mmelody_t mmelody, const char *str)
|
|||||||
/* Default to quarter notes. */
|
/* Default to quarter notes. */
|
||||||
mmelody_note_fraction_set (mmelody, 4);
|
mmelody_note_fraction_set (mmelody, 4);
|
||||||
/* Stop what is currently sounding. */
|
/* Stop what is currently sounding. */
|
||||||
mmelody_note_play (mmelody, 0);
|
mmelody_note_off (mmelody);
|
||||||
|
|
||||||
|
mmelody->ticks1 = 0;
|
||||||
|
mmelody->ticks2 = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -266,6 +303,14 @@ mmelody_play (mmelody_t mmelody, const char *str)
|
|||||||
void
|
void
|
||||||
mmelody_speed_set (mmelody_t mmelody, mmelody_speed_t speed)
|
mmelody_speed_set (mmelody_t mmelody, mmelody_speed_t speed)
|
||||||
{
|
{
|
||||||
|
/* The duration of a beat varies with the time signature:
|
||||||
|
2/2 : minum (half note)
|
||||||
|
4/4 : crotchet (quarter note)
|
||||||
|
6/8, 9/8, 12/8 : dotted crotchet (one and a half quarter notes)
|
||||||
|
|
||||||
|
Currently, there is no time signature support so we assume 4/4.
|
||||||
|
This means a beat is quarter note and a bar is four quarter notes.
|
||||||
|
*/
|
||||||
mmelody->speed = speed;
|
mmelody->speed = speed;
|
||||||
mmelody_ticker_set (mmelody);
|
mmelody_ticker_set (mmelody);
|
||||||
}
|
}
|
||||||
@@ -289,10 +334,23 @@ mmelody_active_p (mmelody_t mmelody)
|
|||||||
void
|
void
|
||||||
mmelody_update (mmelody_t mmelody)
|
mmelody_update (mmelody_t mmelody)
|
||||||
{
|
{
|
||||||
if (TICKER_UPDATE (&mmelody->ticker))
|
if (!mmelody->cur)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mmelody->ticks1)
|
||||||
{
|
{
|
||||||
if (mmelody->cur)
|
mmelody->ticks1--;
|
||||||
mmelody->cur = mmelody_scan (mmelody, mmelody->cur);
|
if (!mmelody->ticks1)
|
||||||
|
mmelody_note_off (mmelody);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mmelody->ticks2)
|
||||||
|
{
|
||||||
|
mmelody->ticks2--;
|
||||||
|
if (!mmelody->ticks2)
|
||||||
|
mmelody->cur = mmelody_scan (mmelody, mmelody->cur);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,7 +366,10 @@ mmelody_init (mmelody_obj_t *mmelody,
|
|||||||
mmelody->play_callback_data = play_callback_data;
|
mmelody->play_callback_data = play_callback_data;
|
||||||
mmelody->volume = 100;
|
mmelody->volume = 100;
|
||||||
mmelody->note_fraction = 1;
|
mmelody->note_fraction = 1;
|
||||||
|
mmelody->note = 0;
|
||||||
|
mmelody->ticks1 = 0;
|
||||||
|
mmelody->ticks2 = 0;
|
||||||
mmelody_speed_set (mmelody, MMELODY_SPEED_DEFAULT);
|
mmelody_speed_set (mmelody, MMELODY_SPEED_DEFAULT);
|
||||||
mmelody_play (mmelody, 0);
|
|
||||||
return mmelody;
|
return mmelody;
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-2
@@ -7,7 +7,6 @@
|
|||||||
#define MMELODY_H
|
#define MMELODY_H
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "ticker.h"
|
|
||||||
|
|
||||||
typedef uint8_t mmelody_speed_t;
|
typedef uint8_t mmelody_speed_t;
|
||||||
typedef uint8_t mmelody_scale_t;
|
typedef uint8_t mmelody_scale_t;
|
||||||
@@ -21,7 +20,9 @@ enum {MMELODY_SPEED_DEFAULT = 200};
|
|||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
ticker_t ticker;
|
uint16_t beat_duration;
|
||||||
|
uint16_t ticks1;
|
||||||
|
uint16_t ticks2;
|
||||||
/* Pointer to current position in string. */
|
/* Pointer to current position in string. */
|
||||||
const char *cur;
|
const char *cur;
|
||||||
/* Pointer to start of string. */
|
/* Pointer to start of string. */
|
||||||
@@ -29,6 +30,8 @@ typedef struct
|
|||||||
const char *loop_start;
|
const char *loop_start;
|
||||||
int8_t loop_count;
|
int8_t loop_count;
|
||||||
uint8_t note_fraction;
|
uint8_t note_fraction;
|
||||||
|
uint8_t note;
|
||||||
|
/* Tempo in beats per minute. */
|
||||||
mmelody_speed_t speed;
|
mmelody_speed_t speed;
|
||||||
mmelody_volume_t volume;
|
mmelody_volume_t volume;
|
||||||
uint8_t octave;
|
uint8_t octave;
|
||||||
|
|||||||
+2
-16
@@ -7,8 +7,6 @@
|
|||||||
#include "tweeter.h"
|
#include "tweeter.h"
|
||||||
|
|
||||||
|
|
||||||
#define TWEETER_HOLDOFF_TIME 50e-3
|
|
||||||
|
|
||||||
enum {TWEETER_SCALE_SIZE = 12};
|
enum {TWEETER_SCALE_SIZE = 12};
|
||||||
|
|
||||||
|
|
||||||
@@ -19,12 +17,6 @@ tweeter_note_set (tweeter_t tweeter,
|
|||||||
{
|
{
|
||||||
tweeter->note_period = period;
|
tweeter->note_period = period;
|
||||||
tweeter->note_duty = duty;
|
tweeter->note_duty = duty;
|
||||||
|
|
||||||
/* To distinguish between two quarter notes and a half note of the
|
|
||||||
same pitch we have a short hold off period at the start of each
|
|
||||||
note. */
|
|
||||||
tweeter->note_holdoff = tweeter->poll_rate
|
|
||||||
/ (uint16_t)(1 / TWEETER_HOLDOFF_TIME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -40,9 +32,9 @@ tweeter_note_play (tweeter_t tweeter, tweeter_note_t note, uint8_t velocity)
|
|||||||
uint8_t index;
|
uint8_t index;
|
||||||
uint8_t octave;
|
uint8_t octave;
|
||||||
|
|
||||||
if (note == 0)
|
if (note == 0 || velocity == 0)
|
||||||
{
|
{
|
||||||
/* Play a rest. */
|
/* Stop playing. */
|
||||||
tweeter_note_set (tweeter, 0, 0);
|
tweeter_note_set (tweeter, 0, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -70,12 +62,6 @@ tweeter_note_play (tweeter_t tweeter, tweeter_note_t note, uint8_t velocity)
|
|||||||
bool
|
bool
|
||||||
tweeter_update (tweeter_t tweeter)
|
tweeter_update (tweeter_t tweeter)
|
||||||
{
|
{
|
||||||
if (tweeter->note_holdoff)
|
|
||||||
{
|
|
||||||
tweeter->note_holdoff--;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (++tweeter->note_clock >= tweeter->note_period)
|
if (++tweeter->note_clock >= tweeter->note_period)
|
||||||
tweeter->note_clock = 0;
|
tweeter->note_clock = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,6 @@ typedef struct
|
|||||||
uint8_t note_clock;
|
uint8_t note_clock;
|
||||||
uint8_t note_period;
|
uint8_t note_period;
|
||||||
uint8_t note_duty;
|
uint8_t note_duty;
|
||||||
uint16_t note_holdoff;
|
|
||||||
uint16_t poll_rate;
|
uint16_t poll_rate;
|
||||||
tweeter_scale_t *scale_table;
|
tweeter_scale_t *scale_table;
|
||||||
} tweeter_private_t;
|
} tweeter_private_t;
|
||||||
|
|||||||
Reference in New Issue
Block a user