6 #include <satcat5/codec_rtttl.h>
17 constexpr u32 bpm2msec(
unsigned bpm) {
18 return u32(60000 / bpm);
24 if (ch ==
'c' || ch ==
'C') result = 0;
25 if (ch ==
'd' || ch ==
'D') result = 2;
26 if (ch ==
'e' || ch ==
'E') result = 4;
27 if (ch ==
'f' || ch ==
'F') result = 5;
28 if (ch ==
'g' || ch ==
'G') result = 7;
29 if (ch ==
'a' || ch ==
'A') result = 9;
30 if (ch ==
'b' || ch ==
'B') result = 11;
31 if (ch ==
'h' || ch ==
'H') result = 11;
32 if (ch ==
'p' || ch ==
'P') result = -1;
38 inline u32 note2freq(
unsigned octave,
int note) {
40 static const unsigned TABLE[] = {
41 1071618, 1135340, 1202851, 1274376, 1350154, 1430439,
42 1515497, 1605613, 1701088, 1802240, 1909407, 2022946};
43 if (note < 0 || note > 11)
return 0;
44 return TABLE[note] << octave;
48 bool RtttlDecoder::play(
const char* src) {
68 if (src->
read_u8() ==
':')
break;
78 u32 accum = 0, index = 0;
83 if (ch ==
',' || ch ==
':') {
86 if (varname ==
'o')
m_octave = accum;
92 }
else if (ch ==
' ' || ch ==
'\t') {
94 }
else if (++index == 1) {
97 }
else if (
'0' <= ch && ch <=
'9') {
99 accum = 10*accum + u32(ch -
'0');
105 while (read_note(src)) {}
115 while (read_note(src)) {++count;}
119 bool RtttlDecoder::read_note(
Readable* src) {
138 char ch = char(src->
read_u8());
141 }
else if (
'0' <= ch && ch <=
'9') {
143 accum = 10*accum + unsigned(ch -
'0');
144 }
else if (ch ==
'#') {
147 }
else if (ch ==
'.') {
150 }
else if (char2note(ch).has_value()) {
152 note = char2note(ch).value();
153 if (accum) duration = accum;
159 u32 octave = accum ? accum :
m_octave;
161 u64 freq = note2freq(octave, note);
165 static constexpr u64 HALF_LSB = (1ull << 31);
166 u32 rate = u32((
m_scale * freq + HALF_LSB) >> 32);
168 m_spkr->write_u16(msec - gap);
180 static inline const char* beep_code(s8 val) {
182 if (val >= satcat5::log::CRITICAL)
183 return "sos:d=16,o=6,b=100:f,f,f,p,8f,8f,8f,p,f,f,f";
184 else if (val >= satcat5::log::ERROR)
185 return "err:d=32,o=6,b=100:f,d,e,d";
186 else if (val >= satcat5::log::WARNING)
187 return "wrn:d=32,o=6,b=100:f,d,c";
188 else if (val >= satcat5::log::INFO)
189 return "inf:d=32,o=6,b=100:e,f";
195 : m_codec(codec), m_cooldown(500) {}
202 const char* beep = beep_code(priority);
Ephemeral Readable interface for a simple array.
unsigned get_read_ready() const override
How many bytes can be read without blocking?
Abstract API for reading byte-streams and packets.
u8 read_u8()
One of many functions for reading integer/floating point values, see details.
bool copy_and_finalize(satcat5::io::Writeable *dst, satcat5::io::CopyMode mode=CopyMode::PACKET)
Copy data to a Writeable object, then finalize.
virtual void set_callback(satcat5::io::EventListener *callback)
Update registered callback for data_rcvd() events.
virtual unsigned get_read_ready() const =0
How many bytes can be read without blocking?
Ring Tone Text Transfer Language (RTTTL) interpreter.
u32 m_octave
Default octave.
u32 m_whole_note
Duration of whole note.
bool play(const char *src)
Decode and play the specified song (string input).
satcat5::io::PacketBuffer m_queue
Playback queue.
u32 m_duration
Default note duration.
satcat5::io::Writeable *const m_spkr
Output device.
const u64 m_scale
Frequency conversion.
void data_rcvd(satcat5::io::Readable *src) override
The data_rcvd() callback is polled whenever data is available.
virtual unsigned get_write_space() const =0
How many bytes can be written without blocking?
virtual bool write_finalize()
Mark end of frame and release temporary working data.
Respond to log messages by playing a few musical notes.
void log_event(s8 priority, unsigned nbytes, const char *msg) override
Callback for each formatted Log message.
unsigned timer_remaining() const
Accessor for time to next event, if one is set.
void timer_once(unsigned msec)
Configure a one-time notification after X milliseconds.
"Readable" I/O interface core definitions
"Writeable" I/O interface core definitions
An optional field that may be filled or empty.
Miscellaneous mathematical utility functions.