diff --git a/apps/squeak3/squeak3.c b/apps/squeak3/squeak3.c index 7454f1f..643b2bf 100644 --- a/apps/squeak3/squeak3.c +++ b/apps/squeak3/squeak3.c @@ -124,7 +124,6 @@ static void display_task_init (void) { tinygl_init (DISPLAY_TASK_RATE); tinygl_font_set (&font3x5_1); - tinygl_text_speed_set (MESSAGE_RATE); tinygl_text_mode_set (TINYGL_TEXT_MODE_ROTATE_STEP); display_note (); diff --git a/apps/squeak4/squeak4.c b/apps/squeak4/squeak4.c index f512bbc..22b9218 100644 --- a/apps/squeak4/squeak4.c +++ b/apps/squeak4/squeak4.c @@ -21,7 +21,7 @@ /* Define polling rates in Hz. */ #define TWEETER_TASK_RATE 20000 -#define TUNE_TASK_RATE 100 +#define TUNE_TASK_RATE 200 #define BUTTON_TASK_RATE 10 diff --git a/extra/mmelody.c b/extra/mmelody.c index adfb41a..3760f18 100644 --- a/extra/mmelody.c +++ b/extra/mmelody.c @@ -69,6 +69,13 @@ represents ABCDEABCFG where ]n denotes alternate 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}; @@ -79,17 +86,34 @@ mmelody_ticker_set (mmelody_t mmelody) { uint16_t speed; + /* Notes per four minutes. */ 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 -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->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_num; mmelody_note_t note; + uint8_t duration = 1; /* Play rest at end of melody. */ if (! *str) { - mmelody_note_play (mmelody, 0); + mmelody_note_off (mmelody); return str; } @@ -195,7 +220,12 @@ mmelody_scan (mmelody_t mmelody, const char *str) /* Play rest. */ case ' ': - mmelody_note_play (mmelody, 0); + while (*str == '/') + { + duration++; + str++; + } + mmelody_note_on (mmelody, 0, duration); return str; break; @@ -233,12 +263,16 @@ mmelody_scan (mmelody_t mmelody, const char *str) /* Convert note to MIDI note number. */ note += (mmelody->octave + 1) * MMELODY_SCALE_SIZE; - mmelody_note_play (mmelody, note); + while (*str == '/') + { + duration++; + str++; + } + + mmelody_note_on (mmelody, note, duration); return str; break; - /* Continue with previous note. */ - case '/': default: return str; break; @@ -258,7 +292,10 @@ mmelody_play (mmelody_t mmelody, const char *str) /* Default to quarter notes. */ mmelody_note_fraction_set (mmelody, 4); /* 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 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_ticker_set (mmelody); } @@ -289,10 +334,23 @@ mmelody_active_p (mmelody_t mmelody) void mmelody_update (mmelody_t mmelody) { - if (TICKER_UPDATE (&mmelody->ticker)) + if (!mmelody->cur) + return; + + if (mmelody->ticks1) { - if (mmelody->cur) - mmelody->cur = mmelody_scan (mmelody, mmelody->cur); + mmelody->ticks1--; + 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->volume = 100; mmelody->note_fraction = 1; + mmelody->note = 0; + mmelody->ticks1 = 0; + mmelody->ticks2 = 0; mmelody_speed_set (mmelody, MMELODY_SPEED_DEFAULT); - mmelody_play (mmelody, 0); + return mmelody; } diff --git a/extra/mmelody.h b/extra/mmelody.h index b00b381..50c4cad 100644 --- a/extra/mmelody.h +++ b/extra/mmelody.h @@ -7,7 +7,6 @@ #define MMELODY_H #include "system.h" -#include "ticker.h" typedef uint8_t mmelody_speed_t; typedef uint8_t mmelody_scale_t; @@ -21,7 +20,9 @@ enum {MMELODY_SPEED_DEFAULT = 200}; typedef struct { - ticker_t ticker; + uint16_t beat_duration; + uint16_t ticks1; + uint16_t ticks2; /* Pointer to current position in string. */ const char *cur; /* Pointer to start of string. */ @@ -29,6 +30,8 @@ typedef struct const char *loop_start; int8_t loop_count; uint8_t note_fraction; + uint8_t note; + /* Tempo in beats per minute. */ mmelody_speed_t speed; mmelody_volume_t volume; uint8_t octave; diff --git a/extra/tweeter.c b/extra/tweeter.c index 239306f..0e6b6b7 100644 --- a/extra/tweeter.c +++ b/extra/tweeter.c @@ -7,8 +7,6 @@ #include "tweeter.h" -#define TWEETER_HOLDOFF_TIME 50e-3 - enum {TWEETER_SCALE_SIZE = 12}; @@ -19,12 +17,6 @@ tweeter_note_set (tweeter_t tweeter, { tweeter->note_period = period; 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 octave; - if (note == 0) + if (note == 0 || velocity == 0) { - /* Play a rest. */ + /* Stop playing. */ tweeter_note_set (tweeter, 0, 0); return; } @@ -70,12 +62,6 @@ tweeter_note_play (tweeter_t tweeter, tweeter_note_t note, uint8_t velocity) bool tweeter_update (tweeter_t tweeter) { - if (tweeter->note_holdoff) - { - tweeter->note_holdoff--; - return 0; - } - if (++tweeter->note_clock >= tweeter->note_period) tweeter->note_clock = 0; diff --git a/extra/tweeter.h b/extra/tweeter.h index 990997a..e4767ba 100644 --- a/extra/tweeter.h +++ b/extra/tweeter.h @@ -54,7 +54,6 @@ typedef struct uint8_t note_clock; uint8_t note_period; uint8_t note_duty; - uint16_t note_holdoff; uint16_t poll_rate; tweeter_scale_t *scale_table; } tweeter_private_t;