Это старая версия документа!


Эксперимент 23. Темп, длительность и паузы

Если в прошлом эксперименте ты попробовал выполнить дополнительное задание и записать мелодию, то, вероятно, понял, что это не просто, учитывая, что нужно описывать и ноты и их длительности и паузы между ними. А если после написания такой мелодии потребуется изменить ее темп, то придется пересчитывать все паузы. Должен быть другой, более удобный способ записывать мелодии.

Для этого запишем мелодию, последовательность ее нот, в массив, а длительности этих нот в другой. С помощью оператора цикла будем получать эти данные и исполнять. Для записи темпа заведем отдельную переменную, которая будет учитываться в расчете длительностей.

Схема эксперимента

Схему эксперимента оставим прежней, займемся программой.

Рисунок 1. Электрическая принципиальная схема эксперимента

Рисунок 2. Монтажная схема эксперимента

Программный код эксперимента

Exp23.ino
  1. #define SPEAKER_PIN 15
  2.  
  3. int tones[8] = {262, 294, 330, 349, 392, 440, 494, 523};
  4.  
  5. enum Note {c, d, e, f, g, a, b, C};
  6.  
  7. struct Sound {
  8. int note;
  9. int length;
  10. };
  11.  
  12. const int tempo = 2000;
  13.  
  14. Sound melody[8] = {{a, 8}, {b, 2}, {c, 1}, {d, 8}, {e, 3}, {f, 4}, {g, 6}, {C, 8}};
  15.  
  16. void setup() {
  17. pinMode(SPEAKER_PIN, OUTPUT);
  18. analogWriteRange(1024);;
  19. }
  20.  
  21. void loop() {
  22. for (int i = 0; i < 8; i++){
  23. analogWrite(SPEAKER_PIN, 512);
  24. analogWriteFreq(tones[melody[i].note]);
  25. delay(tempo / melody[i].length);
  26. analogWrite(SPEAKER_PIN, 0);
  27. delay(tempo / melody[i].length / 4);
  28. }
  29. }

Для того, чтобы записать ноту и ее длительность в одну переменную воспользуемся типом ««struct»», который представляет набор переменных разного типа, объединённых одним именем, в нашем случае — ««Sound»» Количество переменных внутри ««struct»» в принципе не ограничено нам будет достаточно двух «note» и «length»:

  1. struct Sound {
  2. int note;
  3. int length;
  4. };

Мелодию мы записали строкой abcdefgC, а ритм массивом [8, 2, 1, 8, 3, 4, 6, 8]. С помощью цикла for и оператора in проходим по всем элементам мелодии. Для этого мы использовали оператор zip. Он нужен для одновременного перебора сразу двух массивов и получения их элементов в переменные tone и length. Так на первой итерации в переменной tone окажется a, а в length8. На второй итерации b и 2 соответственно.

Здесь внимательный читатель заметит, что melody не является массивом, а является строкой. Почему же мы говорим о ней как о массиве и работаем как с массивом. Оказывается в Python любую строку можно представить как массив символов и обращаться к ним по индексу, что мы и делаем.

Получив ноту и ее длительность настраиваем частоту и скважность. Нота начинает звучать:

  1. speaker.duty(512)
  2. speaker.freq(tones[tone])

Нота звучит, пока мы ждем время, равное ее длительности. В расчете учитывается темп:

  1. time.sleep(tempo/length)

Чтобы ноты не сливались, мы делаем между ними маленькие паузы. Паузы между нотами также зависят от темпа и длительности ноты, но в 4 раза короче.

  1. speaker.duty(0)
  2. time.sleep(tempo/length/4)

Дополнительное задание

  • Измени темп мелодии и длительности отдельных нот.