Если в прошлом эксперименте ты попробовал выполнить дополнительное задание и записать мелодию, то, вероятно, понял, что это не просто, учитывая, что нужно описывать и ноты и их длительности и паузы между ними. А если после написания такой мелодии потребуется изменить ее темп, то придется пересчитывать все паузы. Должен быть другой, более удобный способ записывать мелодии.
Для этого запишем мелодию, последовательность ее нот, в массив, а длительности этих нот в другой. С помощью оператора цикла будем получать эти данные и исполнять. Для записи темпа заведем отдельную переменную, которая будет учитываться в расчете длительностей.
Схему эксперимента оставим прежней, займемся программой.
Рисунок 1. Электрическая принципиальная схема эксперимента
from machine import Pin, PWM import time _init() tempo = 2 tones = { 'c': 262, 'd': 294, 'e': 330, 'f': 349, 'g': 392, 'a': 440, 'b': 494, 'C': 523 } speaker = PWM(Pin(15, Pin.OUT)) melody = 'abcdefgC' rhythm = [8, 2, 1, 8, 3, 4, 6, 8] for tone, length in zip(melody, rhythm): speaker.duty(512) speaker.freq(tones[tone]) time.sleep(tempo/length) speaker.duty(0) time.sleep(tempo/length/4)
Мелодию мы записали строкой abcdefgC
, а ритм массивом [8, 2, 1, 8, 3, 4, 6, 8]
.
С помощью цикла for
и оператора in
проходим по всем элементам мелодии. Для этого мы использовали оператор zip
. Он нужен для одновременного перебора сразу двух массивов и получения их элементов в переменные tone
и length
. Так на первой итерации в переменной tone
окажется a
, а в length
— 8
. На второй итерации b
и 2
соответственно.
Здесь внимательный читатель заметит, что melody
не является массивом, а является строкой. Почему же мы говорим о ней как о массиве и работаем как с массивом. Оказывается в Python любую строку можно представить как массив символов и обращаться к ним по индексу, что мы и делаем.
Получив ноту и ее длительность настраиваем частоту и скважность. Нота начинает звучать:
speaker.duty(512) speaker.freq(tones[tone])
Нота звучит, пока мы ждем время, равное ее длительности. В расчете учитывается темп:
time.sleep(tempo/length)
Чтобы ноты не сливались, мы делаем между ними маленькие паузы. Паузы между нотами также зависят от темпа и длительности ноты, но в 4 раза короче.
speaker.duty(0) time.sleep(tempo/length/4)