mirror of
https://github.com/esphome/esphome.git
synced 2026-05-21 17:39:00 +08:00
[rtttl] allow any control parameters order and default value fallback (#14438)
Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
This commit is contained in:
@@ -294,57 +294,59 @@ void Rtttl::play(std::string rtttl) {
|
||||
}
|
||||
ESP_LOGD(TAG, "Playing song %.*s", (int) this->position_, this->rtttl_.c_str());
|
||||
|
||||
// Get default duration
|
||||
this->position_ = this->rtttl_.find("d=", this->position_);
|
||||
if (this->position_ == std::string::npos) {
|
||||
ESP_LOGE(TAG, "Missing 'd='");
|
||||
return;
|
||||
}
|
||||
this->position_ += 2;
|
||||
num = this->get_integer_();
|
||||
if (num == 1 || num == 2 || num == 4 || num == 8 || num == 16 || num == 32) {
|
||||
this->default_note_denominator_ = num;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid default duration: %d", num);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get default octave
|
||||
this->position_ = this->rtttl_.find("o=", this->position_);
|
||||
if (this->position_ == std::string::npos) {
|
||||
ESP_LOGE(TAG, "Missing 'o=");
|
||||
return;
|
||||
}
|
||||
this->position_ += 2;
|
||||
num = this->get_integer_();
|
||||
if (num >= MIN_OCTAVE && num <= MAX_OCTAVE) {
|
||||
this->default_octave_ = num;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid default octave: %d", num);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get BPM
|
||||
this->position_ = this->rtttl_.find("b=", this->position_);
|
||||
if (this->position_ == std::string::npos) {
|
||||
ESP_LOGE(TAG, "Missing b=");
|
||||
return;
|
||||
}
|
||||
this->position_ += 2;
|
||||
num = this->get_integer_();
|
||||
if (num >= 4) { // Below 4 is not realistic and would cause a integer overflow
|
||||
bpm = num;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid BPM: %d", num);
|
||||
return;
|
||||
}
|
||||
|
||||
this->position_ = this->rtttl_.find(':', this->position_);
|
||||
if (this->position_ == std::string::npos) {
|
||||
size_t name_end_position = this->position_;
|
||||
size_t control_end = this->rtttl_.find(':', name_end_position + 1);
|
||||
if (control_end == std::string::npos) {
|
||||
ESP_LOGE(TAG, "Missing second ':'");
|
||||
return;
|
||||
}
|
||||
this->position_++;
|
||||
|
||||
// Get default duration
|
||||
size_t pos = this->rtttl_.find("d=", name_end_position);
|
||||
if (pos == std::string::npos || pos >= control_end) {
|
||||
ESP_LOGW(TAG, "Missing 'd='; use default duration %d", this->default_note_denominator_);
|
||||
} else {
|
||||
this->position_ = pos + 2;
|
||||
num = this->get_integer_();
|
||||
if (num == 1 || num == 2 || num == 4 || num == 8 || num == 16 || num == 32) {
|
||||
this->default_note_denominator_ = num;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid default duration: %d", num);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get default octave
|
||||
pos = this->rtttl_.find("o=", name_end_position);
|
||||
if (pos == std::string::npos || pos >= control_end) {
|
||||
ESP_LOGW(TAG, "Missing 'o='; use default octave %d", this->default_octave_);
|
||||
} else {
|
||||
this->position_ = pos + 2;
|
||||
num = this->get_integer_();
|
||||
if (num >= MIN_OCTAVE && num <= MAX_OCTAVE) {
|
||||
this->default_octave_ = num;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid default octave: %d", num);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Get BPM
|
||||
pos = this->rtttl_.find("b=", name_end_position);
|
||||
if (pos == std::string::npos || pos >= control_end) {
|
||||
ESP_LOGW(TAG, "Missing 'b='; use default BPM %d", bpm);
|
||||
} else {
|
||||
this->position_ = pos + 2;
|
||||
num = this->get_integer_();
|
||||
if (num >= 4) { // Below 4 is not realistic and would cause a integer overflow
|
||||
bpm = num;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Invalid BPM: %d", num);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this->position_ = control_end + 1;
|
||||
|
||||
// BPM usually expresses the number of quarter notes per minute
|
||||
this->wholenote_duration_ = 60 * 1000L * 4 / bpm; // This is the time for whole note (in milliseconds)
|
||||
|
||||
@@ -3,6 +3,22 @@ esphome:
|
||||
then:
|
||||
- rtttl.play: 'siren:d=8,o=5,b=100:d,e,d,e,d,e,d,e'
|
||||
- rtttl.stop
|
||||
# Test all note features: all notes, denominators (1,2,4,8,16,32), sharp (#), octaves (4-7), dotted (.), note gap (c5,c5), pause (p)
|
||||
- rtttl.play: 'special:d=4,o=5,b=120:1c4,2d#5,4e6.,8f#7,16g4,32a5,8a#5,4b6,8h5,c5,c5,8p,2c4'
|
||||
# Different orders of control parameters
|
||||
- rtttl.play: 'test_odb:o=5,d=8,b=100:c'
|
||||
- rtttl.play: 'test_bod:b=100,o=5,d=8:c'
|
||||
- rtttl.play: 'test_bdo:b=100,d=8,o=5:c'
|
||||
- rtttl.play: 'test_obd:o=5,b=100,d=8:c'
|
||||
- rtttl.play: 'test_dbo:d=8,b=100,o=5:c'
|
||||
# Missing parameters (use defaults)
|
||||
- rtttl.play: 'test_no_d:o=5,b=100:c'
|
||||
- rtttl.play: 'test_no_o:d=8,b=100:c'
|
||||
- rtttl.play: 'test_no_b:d=8,o=5:c'
|
||||
- rtttl.play: 'test_only_d:d=8:c'
|
||||
- rtttl.play: 'test_only_o:o=5:c'
|
||||
- rtttl.play: 'test_only_b:b=100:c'
|
||||
- rtttl.play: 'test_empty::c'
|
||||
|
||||
output:
|
||||
- platform: ${output_platform}
|
||||
|
||||
Reference in New Issue
Block a user