From 2a24a7c048dacc72940d08c15a831dd7752979c0 Mon Sep 17 00:00:00 2001 From: RedGuy Date: Tue, 20 Jun 2023 19:33:39 +0300 Subject: [PATCH] skatulka --- skatulka/QB.h | 261 ++++++++++++++++++++++++++++++++++++++++++ skatulka/skatulka.ino | 67 +++++++++++ 2 files changed, 328 insertions(+) create mode 100644 skatulka/QB.h create mode 100644 skatulka/skatulka.ino diff --git a/skatulka/QB.h b/skatulka/QB.h new file mode 100644 index 0000000..4ab63e3 --- /dev/null +++ b/skatulka/QB.h @@ -0,0 +1,261 @@ +int freq[7][12] = { + {65, 69, 73, 78, 82, 87, 92, 98, 104, 110, 117, 123}, //0 = Большая октава + {131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247}, //1 = Малая октава + {262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494}, //2 = 1-я октава + {523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988}, //3 = 2-я октава + {1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976}, //4 = 3-я октава + {2093, 2218, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951}, //5 = 4-я октава + {4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902}, //6 = 5-я октава +}; +int extractNumber(int& myNumber, char Muz[], int& curPosition) +{ + int digitsNumber=0; + int curDigit=0; + myNumber=0; + do + { + if ((Muz[curPosition]> 47) && (Muz[curPosition]<58)) // Коды ASCII цифр '0' == 48 , "9' == 57 + { + curDigit=Muz[curPosition]-48; + digitsNumber++; + myNumber=myNumber*10+curDigit; + } + else + { + return digitsNumber; + } + curPosition++; + }while(Muz[curPosition]!= '\0'); + return digitsNumber; +} + +int pointsCount(char Muz[], int& curPosition) +{ + int pointsNumber=0; + do + { + if (Muz[curPosition]== '.') + { + pointsNumber++; + } + else + { + return pointsNumber; + } + curPosition++; + }while(Muz[curPosition]!= '\0'); + return pointsNumber; +} + +void Qb_PLAY(char Muz[]) +{ + static int generalOktava; + int oktava; + static int tempo=120; // Задание темпа или четвертных нот, которые исполняются в минуту. n от 32 до 255. По умолчанию 120 + int Nota=0; + int curPosition, curNota4; + unsigned long currentNotaPauseDuration; + unsigned long currentNotaDuration; + unsigned long pauseDuration; + int takt=240000/tempo; + bool isNota; + bool isPause; + int pointsNum=0; + float generalNotaMultipl=0.875; + static float NotaLong; + float curMultipl; + float tempFlo; + float curPause; + unsigned long tempLong; + int i=0; + do + { + isNota=false; + isPause=false; + oktava=generalOktava; + switch(Muz[i]){ + case '\0':{ + return; + } + break; + case 'C':{ + Nota=0; + isNota=true; + } + break; + case 'D':{ + Nota=2; + isNota=true; + } + break; + case 'E':{ + Nota=4; + isNota=true; + } + break; + case 'F':{ + Nota=5; + isNota=true; + } + break; + case 'G':{ + Nota=7; + isNota=true; + } + break; + case 'A':{ + Nota=9; + isNota=true; + } + break; + case 'B':{ + Nota=11; + isNota=true; + } + break; + case 'N':{// Nнота Играет определенную ноту (0 - 84) в диапазоне семи октав (0 - пауза). + curPosition=i+1; + if (extractNumber(curNota4, Muz, curPosition)){ + i=curPosition-1; + if (curNota4){ + curNota4--; + oktava=curNota4 / 12; + Nota=curNota4 % 12; + isNota=true; + } + else{ + isPause=true; + } + } + } + break; + case 'O':{ //Oоктава Задает текущую октаву (0 - 6). + curPosition=i+1; + if (extractNumber(oktava, Muz, curPosition)){ + i=curPosition-1; + generalOktava=oktava; + } + } + break; + case '>':{ + generalOktava++; + } + break; + case '<':{ + generalOktava--; + } + break; + case 'M':{ + switch(Muz[i+1]){ + case 'N':{ //MN Нормаль. Каждая нота звучит 7/8 времени, заданного в команде L + generalNotaMultipl=0.875; // =7/8 + i++; + } + break; + case 'L':{ //ML Легато. Каждая нота звучит полный интервал времени, заданного в команде L + generalNotaMultipl=1.0; + i++; + } + break; + case 'S':{ //MS Стаккато. Каждая нота звучит 3/4 времени, заданного в команде L + generalNotaMultipl=0.75; // =3/4 + i++; + } + break; + case 'F':{ //MF Режим непосредственного исполнения. Т.е. на время проигрывания ноты программа приостанавливается. Используется по умолчанию + i++; //Сдвигаем точку чтения и ничего не делаем. + } + break; + + case 'B':{ //MB проигрывние в буффер + i++; //Сдвигаем точку чтения и ничего не делаем. + } + break; + } + } + break; + case 'L':{ //Lразмер Задает длительность каждой ноты (1 - 64). L1 - целая нота, L2 - 1/2 ноты и т.д. + curPosition=i+1; + if (extractNumber(curNota4, Muz, curPosition)){ + i=curPosition-1; + tempFlo=float(curNota4); + NotaLong=1/tempFlo; + } + } + break; + case 'T':{ //Tтемп Задает темп исполнения в четвертях в минуту (32-255).По умолчанию 120 + curPosition=i+1; + if (extractNumber(tempo, Muz, curPosition)){ + i=curPosition-1; + takt=240000/tempo; // миллисекунд на 1 целую ноту. 240000= 60 сек * 1000 мсек/сек *4 четвертей в ноте + } + } + break; + case 'P':{ //Pпауза Задает паузу (1 - 64). P1 - пауза в целую ноту, P2 - пауза в 1/2 ноты и т.д. + curPosition=i+1; + if (extractNumber(curNota4, Muz, curPosition)){ + tempFlo=float(curNota4); + curPause=1/tempFlo; + i=curPosition-1; + isPause=true; + } + } + break; + case ' ':{ //Есть в некоторых текстах. Вероятно это пауза длительностью в текущую ноту + curPause= NotaLong; + isPause=true; + } + break; + } + if (isNota){ + switch(Muz[i+1]){ + case '#':{ // диез + Nota++; + i++; + } + break; + case '+':{ // диез + Nota++; + i++; + } + break; + case '-':{ // бемоль + Nota--; + i++; + } + break; + } + curPosition=i+1; + if (extractNumber(curNota4, Muz, curPosition)){ + currentNotaDuration=takt/curNota4; + i=curPosition-1; + } + } + if (oktava<0) oktava=0; + if (oktava>6) oktava=6; + if (isNota || isPause){ + curPosition=i+1; + pointsNum=pointsCount(Muz, curPosition); + if (pointsNum) i=curPosition-1; + curMultipl=1.0; + for (int j=1; j<=pointsNum; j++) { + curMultipl= curMultipl * 1.5; + } + currentNotaPauseDuration=(takt*NotaLong); + } + if (isNota){ + curMultipl=curMultipl*generalNotaMultipl; + currentNotaDuration= (currentNotaPauseDuration*curMultipl); + if (Nota<0) Nota=0; + if (Nota>11) Nota=11; + tempLong= freq[oktava][Nota]; + tone(2,tempLong,currentNotaDuration); + delay(currentNotaPauseDuration); + } + if (isPause){ + pauseDuration=takt*curPause*curMultipl; + delay(pauseDuration); + } + i++; + } while (Muz[i]!= '\0'); +} diff --git a/skatulka/skatulka.ino b/skatulka/skatulka.ino new file mode 100644 index 0000000..617d1ec --- /dev/null +++ b/skatulka/skatulka.ino @@ -0,0 +1,67 @@ +#define SizeRegisterModules 20 +#include "QB.h" + +int IDarg = 0; +String ParsedCommand[SizeRegisterModules]; + +void ShowError(String errorMessage) { + Serial.println("Error: \n " + errorMessage); +} + +void ShowMessage(String type, String Message) { + Serial.println("[" + type + "] " + Message); +} + +char getCharCommand() { + if (Serial.available() > 0) { + char cmdraw = Serial.read(); + if (cmdraw > 0) return cmdraw; + } + return '?'; +} +void song() { +Qb_PLAY ("MNT120L16O4E.D+.E.D+.E.D.C.C.E.A.B.E.G+.B.>C.O2E.A."); +Qb_PLAY (">E.>E.D+.E.D+.E.D.C.C.E.A.B.D.>C.D.C.C.E.A.B.E.G+.B.>C.O2E.A.>E.>E.D+.E."); +Qb_PLAY ("D+.E.D.C.C.E.A.B.D.>C.B.>C.D.E.O2G.>C.G."); +Qb_PLAY (">F.E.D.O2G.B.>F.>E.D.C.O2E.A.>G.>D.C.E.P64E.>E.E.P64E.>E.<"); +Qb_PLAY ("D+.E.D+.E.D+.E.D+.E.D+.E.D+.E.D.C.C.E.A.B.E.G+.B."); +Qb_PLAY (">C.O2E.A.>E.>E.D+.E.D+.E.D.C.C.E.A.B.D.>C.B.>C.D.E.O2G.>C.G.>F.E.D.O2G.B.>F.>E.D.C.O2E.A.>E.>D.C."); +Qb_PLAY ("E.>E.E.P64E.>E.D.C.C.E."); +Qb_PLAY ("A.B.E.G+.B.>C.O2E.A.>E.>E.D+.E.D+.E.D.C.C.E.A.B."); +} + +void loop() { + char CharCommand = getCharCommand(); + if (CharCommand != ';' && CharCommand != '?') { + Serial.print(CharCommand); + if (CharCommand == ' ') { + IDarg++; + } else { + ParsedCommand[IDarg] += CharCommand; + } + } else if (CharCommand == ';') { + Serial.println(" "); + mainL(ParsedCommand); + IDarg = 0; + for (int i = 0; i <= 20; i++) { + ParsedCommand[i] = ""; + } + Serial.print(">"); + } +}