9static const char *
const TAG =
"rtttl";
11static const uint32_t DOUBLE_NOTE_GAP_MS = 10;
14static const uint16_t NOTES[] = {0, 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494,
15 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, 1047,
16 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976, 2093, 2217,
17 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951};
19static const uint16_t I2S_SPEED = 1000;
22static const double HALF_PI = 1.5707963267948966192313216916398;
25 static const double PI_ON_180 = 4.0 * atan(1.0) / 180.0;
26 return degrees * PI_ON_180;
30 ESP_LOGCONFIG(TAG,
"Rtttl:");
31 ESP_LOGCONFIG(TAG,
" Gain: %f",
gain_);
36 int pos = this->
rtttl_.find(
':');
37 auto name = this->
rtttl_.substr(0, pos);
38 ESP_LOGW(TAG,
"RTTTL Component is already playing: %s", name.c_str());
42 this->
rtttl_ = std::move(rtttl);
56 ESP_LOGE(TAG,
"Missing ':' when looking for name.");
61 ESP_LOGD(TAG,
"Playing song %s", name.c_str());
65 if (this->
position_ == std::string::npos) {
66 ESP_LOGE(TAG,
"Missing 'd='");
76 if (this->
position_ == std::string::npos) {
77 ESP_LOGE(TAG,
"Missing 'o=");
82 if (num >= 3 && num <= 7)
87 if (this->
position_ == std::string::npos) {
88 ESP_LOGE(TAG,
"Missing b=");
97 if (this->
position_ == std::string::npos) {
98 ESP_LOGE(TAG,
"Missing second ':'");
118 if (this->
output_ !=
nullptr) {
126 if (this->
output_ !=
nullptr) {
193 int send = this->
speaker_->
play((uint8_t *) (&sample),
x * 2);
212 while (this->
rtttl_[this->position_] ==
',' || this->
rtttl_[this->position_] ==
' ')
219 this->note_duration_ = this->
wholenote_ / num;
221 this->note_duration_ =
227 switch (this->
rtttl_[this->position_]) {
257 if (this->
rtttl_[this->position_] ==
'#') {
263 if (this->
rtttl_[this->position_] ==
'.') {
264 this->note_duration_ += this->note_duration_ / 2;
273 if (scale < 4 || scale > 7) {
274 ESP_LOGE(TAG,
"Octave out of valid range. Should be between 4 and 7. (Octave: %d)", scale);
278 bool need_note_gap =
false;
282 auto note_index = (scale - 4) * 12 + note;
283 if (note_index < 0 || note_index >= (
int)
sizeof(NOTES)) {
284 ESP_LOGE(TAG,
"Note out of valid range (note: %d, scale: %d, index: %d, max: %d)", note, scale, note_index,
285 (
int)
sizeof(NOTES));
289 auto freq = NOTES[note_index];
295 ESP_LOGVV(TAG,
"playing note: %d for %dms", note, this->note_duration_);
297 ESP_LOGVV(TAG,
"waiting: %dms", this->note_duration_);
302 if (this->
output_ !=
nullptr) {
305 delay(DOUBLE_NOTE_GAP_MS);
306 this->note_duration_ -= DOUBLE_NOTE_GAP_MS;
335 ESP_LOGVV(TAG,
"- Calc play time: wish: %d gets: %d (div: %d spw: %d)", samples_wish, this->
samples_count_,
347 if (this->
output_ !=
nullptr) {
367 ESP_LOGD(TAG,
"Playback finished");
370static const LogString *state_to_string(
State state) {
373 return LOG_STR(
"STATE_STOPPED");
375 return LOG_STR(
"STATE_STARTING");
377 return LOG_STR(
"STATE_RUNNING");
379 return LOG_STR(
"STATE_STOPPING");
381 return LOG_STR(
"STATE_INIT");
383 return LOG_STR(
"UNKNOWN");
390 ESP_LOGD(TAG,
"State changed from %s to %s", LOG_STR_ARG(state_to_string(old_state)),
391 LOG_STR_ARG(state_to_string(
state)));