Кабы не было зимы...

lilik
Offline
Зарегистрирован: 19.10.2017

ua6em пишет:

lilik пишет:

А кнопку надо нажать (7 пин) и держать чтобы играла мелодия. Я на уно экспериментирую.

на предыдущей работает, на этой нет, ардуино нано, компилируется и заливается без ошибок

Странно, я проверил на своей нано - работает.

Может я что потерял?, вот ещё раз код.

//instrument definitions          
#define ninstr 12           //   piano xlphn guitar cmbll bell funky vibr metal violin bass trumpt harm
unsigned int ldness[ninstr]  = {   64,   64,   64,   64,   64,   64,   64,   64,   64,   64,   64,   64}; // loudness   
unsigned int pitch0[ninstr]  = {   0,   0,   0,   12,   24,   24,    0,   12,   24,   12,   12,   0}; // pitch of key0         
unsigned int ADSR_a[ninstr]  = { 4096, 8192, 8192, 8192, 4096,  512,  512, 8192,  128,  128,  256,  4096}; // attack parameter  
unsigned int ADSR_d[ninstr]  = {    256,   256,   512,   16,    8,   16,   16,    8,   16,   16,   64,   128}; // decay parameter   
unsigned int ADSR_s[ninstr]  = {    0,    0,    0,    0,    0,    0,    0,    0,  240,  240,  192,  0}; // sustain parameter 
unsigned int ADSR_r[ninstr]  = {   64,  128,   32,   32,   16,   32,   32,   32,   32,   32,   64,   4096}; // release parameter 
unsigned int FM_inc[ninstr]  = {  256,  512,  768,  400,  200,   96,  528,  244,  256,  128,   64,  64}; // FM frequency wrt pitch
unsigned int FM_a1[ninstr]  =  {  128,  512,  512, 1024,  512,    0, 1024, 2048,  256,  256,  384,  256}; // FM amplitude start
unsigned int FM_a2[ninstr]  =  {   64,    0,  128,  128,  128,  512,  768,  512,  128,  128,  256,  128}; // FM amplitude end
unsigned int FM_dec[ninstr]  = {   64,  128,  128,  128,   32,  128,  128,  128,  128,  128,   64,   128}; // FM decay

//define the pitch2key mapping
#define NOTE_C4   0
#define NOTE_CS4  1
#define NOTE_D4   2
#define NOTE_DS4  3
#define NOTE_E4   4
#define NOTE_F4   5
#define NOTE_FS4  6
#define NOTE_G4   7
#define NOTE_GS4  8
#define NOTE_A4   9
#define NOTE_AS4 10
#define NOTE_B4  11
#define NOTE_C5  12
#define NOTE_CS5 13
#define NOTE_D5  14
#define NOTE_DS5 15
#define NOTE_E5  16
#define NOTE_F5  17
#define NOTE_FS5  18
#define NOTE_G5   19
#define NOTE_GS5  20
#define NOTE_A5   21
#define NOTE_AS5 22
#define NOTE_B5  23
#define NOTE_C6  24
#define NOTE_CS6 25
#define NOTE_D6  26
#define NOTE_DS6 27
#define NOTE_E6  28
#define NOTE_F6  29
#define NOTE_FS6  30
#define NOTE_G6   31
#define NOTE_GS6  32
#define NOTE_A6   33
#define NOTE_AS6 34
#define NOTE_B6  35

#define PAUZA  50

#define nokey 255
#define instrkey 254



//set up array with sine values in signed 8-bit numbers 
const float pi = 3.14159265;
char sine[256];
void setsine() {
  for (int i = 0; i < 256; ++i) {
    sine[i] = (sin(2 * 3.14159265 * (i + 0.5) / 256)) * 128;
  }
}

//setup frequencies/phase increments, starting at C3=0 to B6. (A4 is defined as 440Hz)
unsigned int tone_inc[48];
void settones() {
  for (byte i=0; i<48; i++){
    tone_inc[i]= 440.0 * pow(2.0, ( (i-21) / 12.0)) * 65536.0 / (16000000.0/512) + 0.5;
  }
}

byte instr=11;//счётчик инструмента включённого
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
long Y=0;//переменная хранения моментов времени
int k=0;// счётчик прогресса исполнения мелодии
int i=0;//
const int notes_times[]PROGMEM = {
  // кабы не было зимы
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_FS5,200,
  NOTE_A5,400, NOTE_G5,400, NOTE_E5,800,PAUZA,50,
  NOTE_D5,400, NOTE_D5,400, NOTE_D6,600, NOTE_C6,200, NOTE_C6,400,NOTE_B5,400,PAUZA,800, 
  NOTE_D6,400,NOTE_C6,400, NOTE_A5,400,NOTE_FS5,400, NOTE_C6,400,NOTE_B5,400,NOTE_B5,800,
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_A5,200,NOTE_A5,400, NOTE_G5,400, PAUZA,800,
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_FS5,200,
  NOTE_A5,400, NOTE_G5,400, NOTE_E5,800,PAUZA,50,
  NOTE_D5,400, NOTE_D5,400, NOTE_D6,600, NOTE_C6,200, NOTE_C6,400,NOTE_B5,400,PAUZA,400,
  NOTE_E6,800,NOTE_C6,400, NOTE_A5,400, NOTE_FS5,400, NOTE_C6,400,NOTE_B5,400,NOTE_B5,800,PAUZA,50,
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_A5,200,NOTE_A5,400, NOTE_G5,400, PAUZA,400,
  NOTE_E6,800,NOTE_C6,400, NOTE_A5,400, NOTE_FS5,400, NOTE_C6,400,NOTE_B5,400,NOTE_B5,800,PAUZA,50,
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_DS5,200,NOTE_FS5,400, NOTE_E5,400,PAUZA,5000 
  };
float temp=0.9;//задаём темп исполнения мелодии
int dlina= sizeof(notes_times)/sizeof(notes_times[0]);//определяем длину массива
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

void setup() {

  //disable all inerrupts to avoid glitches отключите все прерывания, чтобы избежать сбоев
 // noInterrupts();

  //setup the array with sine values настройте массив со значениями синуса
  setsine();

  //setup array with tone frequency phase increments установочная матрица с приращениями фазы тональной частоты
  settones();

  //Set a fast PWM signal on TIMER1A, 9-bit resolution, 31250Hz
  pinMode(9, OUTPUT);// вывод для динамика
  TCCR1A = 0B10000010; //9-bit fast PWM
  TCCR1B = 0B00001001;
/////////////////////////////////////////////////////////////////////////////////
 pinMode(7, INPUT);//кнопку подключить
 digitalWrite(7, HIGH);// включить подтягивающий резистор к ней
/////////////////////////////////////////////////////////////////////////////////
  
}


//initialize the main parameters of the pulse length setting инициализируйте основные параметры настройки длительности импульса
#define nch 4 //number of channels that can produce sound simultaneously количество каналов, которые могут воспроизводить звук одновременно
unsigned int phase[nch]  = {0,0,0,0};
int          inc[nch]    = {0,0,0,0};
byte         amp[nch]    = {0,0,0,0};
unsigned int FMphase[nch]= {0,0,0,0};
unsigned int FMinc[nch]  = {0,0,0,0};
unsigned int FMamp[nch]  = {0,0,0,0};

// main function (forced inline) to update the pulse length основная функция (принудительная встроенная) для обновления длительности импульса
inline void setPWM() __attribute__((always_inline));
inline void setPWM() {

  //wait for the timer to complete loop подождите, пока таймер завершит цикл
  while ((TIFR1 & 0B00000001) == 0);

  //Clear(!) the overflow bit by writing a 1 to it
  TIFR1 |= 0B00000001;

  //increment the phases of the FM
  FMphase[0] += FMinc[0];
  FMphase[1] += FMinc[1];
  FMphase[2] += FMinc[2];
  FMphase[3] += FMinc[3];

  //increment the phases of the note
  phase[0] += inc[0];
  phase[1] += inc[1];
  phase[2] += inc[2];
  phase[3] += inc[3];

  //calculate the output value and set pulse width for timer2
  int val = sine[(phase[0]+sine[FMphase[0]>>8]*FMamp[0]) >> 8] * amp[0];
  val += sine[(phase[1]+sine[FMphase[1]>>8]*FMamp[1]) >> 8] * amp[1];
  val += sine[(phase[2]+sine[FMphase[2]>>8]*FMamp[2]) >> 8] * amp[2];
  val += sine[(phase[3]+sine[FMphase[3]>>8]*FMamp[3]) >> 8] * amp[3];

  //set the pulse length
  OCR1A = val/128 + 256;
}

//properties of each note played  свойства каждой сыгранной ноты
byte         iADSR[nch]     = {0, 0, 0, 0}; 
unsigned int envADSR[nch]   = {0, 0, 0, 0}; 
unsigned int ADSRa[nch]     = {0, 0, 0, 0};
unsigned int ADSRd[nch]     = {0, 0, 0, 0};
unsigned int ADSRs[nch]     = {0, 0, 0, 0};
unsigned int ADSRr[nch]     = {0, 0, 0, 0};
byte         amp_base[nch]  = {0, 0, 0, 0};
unsigned int inc_base[nch]  = {0, 0, 0, 0};
unsigned int FMa0[nch]      = {0, 0, 0, 0};
int          FMda[nch]      = {0, 0, 0, 0};
unsigned int FMinc_base[nch]= {0, 0, 0, 0};
unsigned int FMdec[nch]     = {0, 0, 0, 0};
unsigned int FMexp[nch]     = {0, 0, 0, 0};
unsigned int FMval[nch]     = {0, 0, 0, 0};
byte         keych[nch]     = {0, 0, 0, 0}; 
unsigned int tch[nch]       = {0, 0, 0, 0}; 
byte keypressed;
byte keyreleased;

/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
// main loop. Duration of loop is determined by number of setPWM calls
// Each setPWMcall corresponds to 512 cylcles=32mus
// Tloop= 32mus * #setPWM. #setPWM=15 gives Tloop=0.48ms
void loop() {
  keypressed = nokey;
  keyreleased = nokey;
 if(digitalRead (7)==LOW){//если нажали кнопку то...
 for(int i=0;i< dlina;i=i+2){//...сыграть мелодию...
 if(k==i&&millis()-Y>10){Y=millis();k++;if(pgm_read_word(&notes_times[i])!=PAUZA){keypressed = pgm_read_word(&notes_times[i]);}}
 if(k==i+1&&millis()-Y>pgm_read_word(&notes_times[i+1])*temp){Y=millis();k++;if(pgm_read_word(&notes_times[i])!=PAUZA){keyreleased = pgm_read_word(&notes_times[i]);}}
 setPWM();//#0
}
if(k==dlina){k=0;}//... и повторить её снова при долгом удержании кнопки
}else {k=0;}//при повторном нажатии кнопки начать исполнение сначала
 osnova();// вынес в отдельную функцию часть исходника автора
 }
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
void osnova(){
  setPWM(); //#1
//find the best channel to start a new note  найдите лучший канал, чтобы начать новую заметку 
  byte nextch = 255;
  //first check if the key is still being played  сначала проверьте, воспроизводится ли еще клавиша 
  if (iADSR[0] > 0 and keypressed == keych[0])nextch = 0;
  if (iADSR[1] > 0 and keypressed == keych[1])nextch = 1;
  if (iADSR[2] > 0 and keypressed == keych[2])nextch = 2;
  if (iADSR[3] > 0 and keypressed == keych[3])nextch = 3;
  //then check for an empty channel затем проверьте, нет ли пустого канала 
  if (nextch == 255) {
    if (iADSR[0] == 0)nextch = 0;
    if (iADSR[1] == 0)nextch = 1;
    if (iADSR[2] == 0)nextch = 2;
    if (iADSR[3] == 0)nextch = 3;
  }
  //otherwise use the channel with the longest playing note   в противном случае используйте канал с самой длинной воспроизводимой нотой
  if (nextch == 255) {
    nextch = 0;
    if (tch[0] > tch[nextch])nextch = 0;
    if (tch[1] > tch[nextch])nextch = 1;
    if (tch[2] > tch[nextch])nextch = 2;
    if (tch[3] > tch[nextch])nextch = 3;
  }

  setPWM(); //#3

  //initiate new note if needed  при необходимости инициируйте новую заметку
  if (keypressed != nokey) {
    phase[nextch]=0;
    amp_base[nextch] = ldness[instr];
    inc_base[nextch] = tone_inc[pitch0[instr]+keypressed];
    ADSRa[nextch]=ADSR_a[instr];
    ADSRd[nextch]=ADSR_d[instr];
    ADSRs[nextch]=ADSR_s[instr]<<8;
    ADSRr[nextch]=ADSR_r[instr];
    iADSR[nextch] = 1;
    FMphase[nextch]=0;
    FMinc_base[nextch] = ((long)inc_base[nextch]*FM_inc[instr])/256;
    FMa0[nextch] = FM_a2[instr];
    FMda[nextch] = FM_a1[instr]-FM_a2[instr];
    FMexp[nextch]=0xFFFF;
    FMdec[nextch]=FM_dec[instr];
    keych[nextch] = keypressed;
    tch[nextch] = 0;
  }

  setPWM(); //#4

  //stop a note if the button is released остановите заметку, если кнопка отпущена
  if (keyreleased != nokey) {
    if (keych[0] == keyreleased)iADSR[0] = 4;
    if (keych[1] == keyreleased)iADSR[1] = 4;
    if (keych[2] == keyreleased)iADSR[2] = 4;
    if (keych[3] == keyreleased)iADSR[3] = 4;
  }
  
  setPWM(); //#5

  //update FM decay exponential обновление FM-спад экспоненциальный
  FMexp[0]-=(long)FMexp[0]*FMdec[0]>>16;
  FMexp[1]-=(long)FMexp[1]*FMdec[1]>>16;
  FMexp[2]-=(long)FMexp[2]*FMdec[2]>>16;
  FMexp[3]-=(long)FMexp[3]*FMdec[3]>>16;
  
  setPWM(); //#6
  
  //adjust the ADSR envelopes отрегулируйте конверты ADSR
  for (byte ich = 0; ich < nch; ich++) {
    if (iADSR[ich] == 4) {
      if (envADSR[ich] <= ADSRr[ich]) {
        envADSR[ich] = 0;
        iADSR[ich] = 0;
      }
      else envADSR[ich] -= ADSRr[ich];
    }
    if (iADSR[ich] == 2) {
      if (envADSR[ich] <= (ADSRs[ich] + ADSRd[ich])) {
        envADSR[ich] = ADSRs[ich];
        iADSR[ich] = 3;
      }
      else envADSR[ich] -= ADSRd[ich];
    }
    if (iADSR[ich] == 1) {
      if ((0xFFFF - envADSR[ich]) <= ADSRa[ich]) {
        envADSR[ich] = 0xFFFF;
        iADSR[ich] = 2;
      }
      else envADSR[ich] += ADSRa[ich];
    }
    tch[ich]++;
    setPWM(); //#7-10
  }

  //update the tone for channel 0  обновите звуковой сигнал для канала 0
  amp[0] = (amp_base[0] * (envADSR[0] >> 8)) >> 8;
  inc[0] = inc_base[0];
  FMamp[0] = FMa0[0] + ((long)FMda[0] * FMexp[0]>>16);
  FMinc[0] = FMinc_base[0];
  setPWM(); //#11

  //update the tone for channel 1
  amp[1] = (amp_base[1] * (envADSR[1] >> 8)) >> 8;
  inc[1] = inc_base[1];
  FMamp[1] = FMa0[1] + ((long)FMda[1] * FMexp[1]>>16);
  FMinc[1] = FMinc_base[1];
  setPWM(); //#12

  //update the tone for channel 2
  amp[2] = (amp_base[2] * (envADSR[2] >> 8)) >> 8;
  inc[2] = inc_base[2];
  FMamp[2] = FMa0[2] + ((long)FMda[2] * FMexp[2]>>16);
  FMinc[2] = FMinc_base[2];
  setPWM(); //#13

  //update the tone for channel 3
  amp[3] = (amp_base[3] * (envADSR[3] >> 8)) >> 8;
  inc[3] = inc_base[3];
  FMamp[3] = FMa0[3] + ((long)FMda[3] * FMexp[3]>>16);
  FMinc[3] = FMinc_base[3];
  setPWM(); //#14

  //update counters  счетчики обновлений
  tch[0]++;
  tch[1]++;
  tch[2]++;
  tch[3]++;

  setPWM(); //#15
 
}
///////////////////////////////////////////////////////

Этот вариант инструмента с очень низким звучанием. Можно на пианино проверить, тогда надо заменить в строке byte instr=11;//счётчик инструмента включённого  11 на 0.  

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

на 2 заработало )))
Мне тестировщиком работать надо, если что-то может пойти не так оно у меня обязательно пойдёт не так )))

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

ua6em пишет:

andriano пишет:

float везде одинаковая и везде 24 двоичных разряда (один из которых не нуждается в хранении).

не скажите, в MYSQL не так:
TINYINT      0 - 255
SMALLINT   0 - 65535
MEDIUMINT 0 - 16777215
INT            0 - 4294967295
BIGINT      (8 байт)
FLOAT       ;-)))
 

Так что там с FLOAT?

Кстати, то, что в Си называется float, это число, удовлетворяющее стандарту IEEE 754. В других языках программирования может называться по-другому: single, real и т.п. Но всегда представляет собой 4-байтовое число, в котором 1 бит (старший) отводится под знак, 8 - под порядок и 23 - под мантиссу, причем старший бит мантиссы опускается.

Другими словами, называться может по-разному, но формат (и, соответственно, - точность) всегда один и тот же.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

lilik пишет:

А кнопку надо нажать (7 пин) и держать чтобы играла мелодия. Я на уно экспериментирую.

Я, чтобы не нажимать кнопку (точнее говоря, вообще не подсоединять ее), заменил в if() LOW на HIGH. Но звук не впечатлил.

lilik
Offline
Зарегистрирован: 19.10.2017

По сравнению с tone(); звук гораздо интереснее. Теперь можно не только пищать и зудеть, но и струнить, колоколить, дудеть (последнее правда у автора не получается). Но есть настройки голоса инструмента :

//instrument definitions  instr = 0     1     2       3    4     5    6    7      8     9    10     11
#define ninstr 12           //   piano xlphn guitar cmbll bell funky vibr metal violin bass trumpt harm
unsigned int ldness[ninstr]  = {   64,   64,   64,   64,   64,   64,   64,   64,   64,   64,   64,   64}; // loudness   
unsigned int pitch0[ninstr]  = {   0,   0,   0,   12,   24,   24,    0,   12,   24,   12,   12,   0}; // pitch of key0         
unsigned int ADSR_a[ninstr]  = { 4096, 8192, 8192, 8192, 4096,  512,  512, 8192,  256,  128,  1024,  4096}; // attack parameter  
unsigned int ADSR_d[ninstr]  = {    256,   256,   512,   16,    8,   16,   16,    8,   16,   16,   64,   128}; // decay parameter   
unsigned int ADSR_s[ninstr]  = {    0,    0,    0,    0,    0,    0,    0,    0,  32,  128,  32,  0}; // sustain parameter 
unsigned int ADSR_r[ninstr]  = {   64,  128,   32,   32,   16,   32,   32,   32,   32,   32,   256,   4096}; // release parameter 
unsigned int FM_inc[ninstr]  = {  256,  512,  768,  400,  200,   96,  528,  244,  256,  128,   64,  64}; // FM frequency wrt pitch
unsigned int FM_a1[ninstr]  =  {  128,  512,  512, 1024,  512,    0, 1024, 2048,  256,  256,  512,  256}; // FM amplitude start
unsigned int FM_a2[ninstr]  =  {   64,    0,  128,  128,  128,  512,  768,  512,  128,  128,  64,  128}; // FM amplitude end
unsigned int FM_dec[ninstr]  = {   64,  128,  128,  128,   32,  128,  128,  128,  128,  128,   64,   128}; // FM decay

и он их в количественно-качественных характеристиках описывает. Мелодии на 0,1,11 инструментах-голосах звучат своеобразно (на остальных не очень гармонично, на моё мнение). Конечно после моего "распрета" прерываний в исходнике, может звучание ухудшилось.

lilik
Offline
Зарегистрирован: 19.10.2017

Ну и автор скетч построил так, что блокирующий код не работает (это плохо :-). Можно, наверное, было попробовать реализовать несколько голосов как простенькую добавочную библиотеку к имеющейся tone. Тогда динамик 0,1-0,5 Вт, платка-усилитель и можно дальше экспериментировать.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

andriano пишет:

Так что там с FLOAT?

знак, 1 - 3, и 38 нулей после запятой (приблизительно)

lilik
Offline
Зарегистрирован: 19.10.2017

andriano пишет:

Но звук не впечатлил.

https://disk.yandex.ru/d/ZtqnZplfekynbw

https://disk.yandex.ru/d/T77wCY24ZQSdFw

https://disk.yandex.ru/d/7QTGTSkVWxYgzQ

Вот на всякий случай для сравнения, у меня. Играет "прямо в ссылке".

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

lilik пишет:

andriano пишет:

Но звук не впечатлил.

https://disk.yandex.ru/d/ZtqnZplfekynbw

https://disk.yandex.ru/d/T77wCY24ZQSdFw

https://disk.yandex.ru/d/7QTGTSkVWxYgzQ

Вот на всякий случай для сравнения, у меня. Играет "прямо в ссылке".

Вы всерьез полагаете, что я буду заморачиваться, чтобы прорваться через все препятствия на пути к Вашим файлам?

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

Upper
Offline
Зарегистрирован: 23.06.2020

lilik пишет:

Вот на всякий случай для сравнения, у меня. Играет "прямо в ссылке".

Спасибо. Подключать динамик было затруднительно, а послушать хотелось. У меня проигралось прямо по ссылке без проблем.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

А у меня по ссылке сначала требуют подтвердить, что я не робот, а потом еще нужно что-то куда-то вводить.

lilik
Offline
Зарегистрирован: 19.10.2017

andriano пишет:

 а потом еще нужно что-то куда-то вводить.

:-)

А как быть и что делать?

Напомнило общагу, в местах где сидели с газеткой в руках, умники вырывали фразочки и клеили на кафель "самописные апфоризмы". Теперь интернеть рулит.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Не хочу пробовать ни в первый, ни еще раз.

Если уж размещаете что-то на стороннем ресурсе, позаботьтесь о том, чтобы этим было удобно пользоваться.

lilik
Offline
Зарегистрирован: 19.10.2017
//instrument definitions  instr = 0     1     2       3    4     5    6    7      8     9    10     11
#define ninstr 12           //   piano xlphn guitar cmbll bell funky vibr dudka violin bass trumpt harm
unsigned int ldness[ninstr]  = {   64,   64,   64,   64,   64,   64,   64,   128,   64,   64,   64,   64}; // loudness   
unsigned int pitch0[ninstr]  = {   0,   12,   12,   0,   24,   24,    0,   12,   24,   12,   12,   0}; // pitch of key0         
unsigned int ADSR_a[ninstr]  = { 4096, 8192, 8192, 8192, 4096,  512,  512, 2000,  256,  128,  1024,  4096}; // attack parameter  
unsigned int ADSR_d[ninstr]  = {    256,   256,   1024,   16,    8,   16,   16,    2000,   16,   16,   64,   128}; // decay parameter   
unsigned int ADSR_s[ninstr]  = {    0,    0,    15,    0,    0,    0,    0,    4,  32,  128,  32,  0}; // sustain parameter 
unsigned int ADSR_r[ninstr]  = {   64,  128,   32,   32,   16,   32,   32,   512,   32,   32,   256,   4096}; // release parameter 
unsigned int FM_inc[ninstr]  = {  256,  512,  750,  400,  200,   96,  528,  512,  256,  128,   64,  64}; // FM frequency wrt pitch
unsigned int FM_a1[ninstr]  =  {  128,  512,  512, 1024,  512,    0, 1024, 64,  256,  256,  512,  256}; // FM amplitude start
unsigned int FM_a2[ninstr]  =  {   64,    0,  128,  128,  128,  512,  768,  512,  128,  128,  64,  128}; // FM amplitude end
unsigned int FM_dec[ninstr]  = {   64,  128,  128,  128,   32,  128,  128,  128,  128,  128,   64,   128}; // FM decay

//define the pitch2key mapping
#define NOTE_C4   0
#define NOTE_CS4  1
#define NOTE_D4   2
#define NOTE_DS4  3
#define NOTE_E4   4
#define NOTE_F4   5
#define NOTE_FS4  6
#define NOTE_G4   7
#define NOTE_GS4  8
#define NOTE_A4   9
#define NOTE_AS4 10
#define NOTE_B4  11
#define NOTE_C5  12
#define NOTE_CS5 13
#define NOTE_D5  14
#define NOTE_DS5 15
#define NOTE_E5  16
#define NOTE_F5  17
#define NOTE_FS5  18
#define NOTE_G5   19
#define NOTE_GS5  20
#define NOTE_A5   21
#define NOTE_AS5 22
#define NOTE_B5  23
#define NOTE_C6  24
#define NOTE_CS6 25
#define NOTE_D6  26
#define NOTE_DS6 27
#define NOTE_E6  28
#define NOTE_F6  29
#define NOTE_FS6  30
#define NOTE_G6   31
#define NOTE_GS6  32
#define NOTE_A6   33
#define NOTE_AS6 34
#define NOTE_B6  35

#define PAUZA  50

#define nokey 255
#define instrkey 254



//set up array with sine values in signed 8-bit numbers 
const float pi = 3.14159265;
char sine[256];
void setsine() {
  for (int i = 0; i < 256; ++i) {
    sine[i] = (sin(2 * 3.14159265 * (i + 0.5) / 256)) * 128;
  }
}

//setup frequencies/phase increments, starting at C3=0 to B6. (A4 is defined as 440Hz)
unsigned int tone_inc[48];
void settones() {
  for (byte i=0; i<48; i++){
    tone_inc[i]= 440.0 * pow(2.0, ( (i-21) / 12.0)) * 65536.0 / (16000000.0/512) + 0.5;
  }
}

byte instr=11;//счётчик инструмента включённого
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
long Y=0;//переменная хранения моментов времени
int k=0;// счётчик прогресса исполнения мелодии
int i=0;//
int FLAG=0;//

const int notes_times_A[]PROGMEM = {
  // кабы не было зимы
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_FS5,200,
  NOTE_A5,400, NOTE_G5,400, NOTE_E5,800,PAUZA,50,
  NOTE_D5,400, NOTE_D5,400, NOTE_D6,600, NOTE_C6,200, NOTE_C6,400,NOTE_B5,400,PAUZA,800, 
  NOTE_D6,400,NOTE_C6,400, NOTE_A5,400,NOTE_FS5,400, NOTE_C6,400,NOTE_B5,400,NOTE_B5,800,
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_A5,200,NOTE_A5,400, NOTE_G5,400, PAUZA,800,
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_FS5,200,
  NOTE_A5,400, NOTE_G5,400, NOTE_E5,800,PAUZA,50,
  NOTE_D5,400, NOTE_D5,400, NOTE_D6,600, NOTE_C6,200, NOTE_C6,400,NOTE_B5,400,PAUZA,400,
  NOTE_E6,800,NOTE_C6,400, NOTE_A5,400, NOTE_FS5,400, NOTE_C6,400,NOTE_B5,400,NOTE_B5,800,PAUZA,50,
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_A5,200,NOTE_A5,400, NOTE_G5,400, PAUZA,400,
  NOTE_E6,800,NOTE_C6,400, NOTE_A5,400, NOTE_FS5,400, NOTE_C6,400,NOTE_B5,400,NOTE_B5,800,PAUZA,50,
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_DS5,200,NOTE_FS5,400, NOTE_E5,400,PAUZA,5000 
  };
  const int notes_times_B[]PROGMEM = {
  // Колокольчики-"джингл белз"
  NOTE_C4,800, NOTE_A4,800, NOTE_G4,800, NOTE_F4,800, NOTE_C4,1600,PAUZA,800, NOTE_C4,400,NOTE_C4,400,
  NOTE_C4,800, NOTE_A4,800, NOTE_G4,800, NOTE_F4,800, NOTE_D4,2400,PAUZA,800,
  NOTE_D4,800, NOTE_AS4,800, NOTE_A4,800, NOTE_G4,800, NOTE_E4,2400,PAUZA,800,
  NOTE_C5,800, NOTE_C5,800, NOTE_AS4,800, NOTE_G4,800, NOTE_A4,2400,PAUZA,800,
  NOTE_C4,800, NOTE_A4,800, NOTE_G4,800, NOTE_F4,800, NOTE_C4,2400,PAUZA,800,
  NOTE_C4,800, NOTE_A4,800, NOTE_G4,800, NOTE_F4,800, NOTE_D4,1600,PAUZA,800,NOTE_D4,800,
  NOTE_D4,800, NOTE_AS4,800, NOTE_A4,800, NOTE_G4,800,NOTE_C5,800,NOTE_C5,800,NOTE_C5,800,NOTE_C5,800, PAUZA,50,
  NOTE_D5,800, NOTE_C5,800, NOTE_AS4,800, NOTE_G4,800, NOTE_F4,2400,PAUZA,800,PAUZA,50,
  NOTE_A4,800, NOTE_A4,800, NOTE_A4,1600, PAUZA,50,
  NOTE_A4,800, NOTE_A4,800, NOTE_A4,1600, PAUZA,50,
  NOTE_A4,800, NOTE_C5,800, NOTE_F4,800, NOTE_G4,800,NOTE_A4,2400,PAUZA,800,PAUZA,50,
  NOTE_AS4,800, NOTE_AS4,800, NOTE_AS4,800, NOTE_AS4,800,PAUZA,50,
  NOTE_AS4,800,NOTE_A4,800,NOTE_A4,800,NOTE_A4,400, NOTE_A4,400,PAUZA,50,
  NOTE_A4,800, NOTE_G4,800, NOTE_G4,800, NOTE_A4,800,PAUZA,50,
  NOTE_G4,1600, NOTE_C5,1600, PAUZA,50,
  NOTE_A4,800, NOTE_A4,800, NOTE_A4,1600, PAUZA,50,
  NOTE_A4,800, NOTE_A4,800, NOTE_A4,1600, PAUZA,50,
  NOTE_A4,800, NOTE_C5,800, NOTE_F4,800, NOTE_G4,800,NOTE_A4,2400,PAUZA,800,PAUZA,50,
  NOTE_AS4,800, NOTE_AS4,800, NOTE_AS4,800, NOTE_AS4,800,PAUZA,50,
  NOTE_AS4,800,NOTE_A4,800,NOTE_A4,800,NOTE_A4,400, NOTE_A4,400,PAUZA,50,
  NOTE_C5,800, NOTE_C5,800, NOTE_AS4,800, NOTE_G4,800, NOTE_F4,2400,PAUZA,800,PAUZA,50,
 PAUZA,5000 
  };
  const int notes_times_C[]PROGMEM = {
  // вальс - "мой ласковый и нежный зверь"
  NOTE_C5,1200, NOTE_E5,1200, NOTE_A5,1200, NOTE_C6,800, NOTE_B5,400,PAUZA,50, 
  NOTE_E5,1200, NOTE_C6,800, NOTE_B5, 400, NOTE_C6,800, NOTE_B5, 400,NOTE_C6,800, NOTE_B5, 400,PAUZA,50,
  NOTE_C5,1200, NOTE_E5,1200, NOTE_A5,1200, NOTE_B5,400, NOTE_D6,600,NOTE_C6,400,
  NOTE_F5,1200, NOTE_D6,800, NOTE_C6, 400, NOTE_D6,800, NOTE_C6, 400,NOTE_D6,800, NOTE_C6,400,PAUZA,50,
  NOTE_D5,1200, NOTE_F5,1200, NOTE_A5,1200, NOTE_D6,400, NOTE_E6,600,NOTE_D6,200,PAUZA,50,
  NOTE_F6,2000, NOTE_E6,400, NOTE_AS5,2400, PAUZA,50,
  NOTE_A5,400, NOTE_D6,600, NOTE_CS6,200, NOTE_CS6,1200, NOTE_A5,400,NOTE_F6,600,NOTE_E6,200,NOTE_E6,1200,PAUZA,50,
  NOTE_CS6,400, NOTE_AS6,400, NOTE_A5, 400, NOTE_AS5,400, NOTE_A5, 400,NOTE_AS5,400, NOTE_AS5, 1200,NOTE_A5, 1200,PAUZA,50,
  NOTE_F5,1200, NOTE_F5,1200, NOTE_F5,1200, NOTE_F5,400, NOTE_G5,600,NOTE_A5,200,PAUZA,50, 
  NOTE_AS5,2000, NOTE_D5,400, NOTE_CS5,2400, PAUZA,50,
  NOTE_E5,1200, NOTE_E5,1200, NOTE_E5,1200, NOTE_E5,400, NOTE_G5,600,NOTE_F5,200,PAUZA,50,
  NOTE_F5,2000, NOTE_A5,400, PAUZA,50,NOTE_A4,1200,PAUZA,50, NOTE_A4,400, NOTE_AS4,400, NOTE_C5, 400,PAUZA,50,
  NOTE_D5,1200, NOTE_D5,1200, NOTE_D5, 400, NOTE_E5,400, NOTE_F5, 400,NOTE_G5,400, NOTE_A5, 400,NOTE_AS5, 400,PAUZA,50,
  NOTE_D6,1200, NOTE_E6,800, NOTE_F6,400, NOTE_AS6,2400,PAUZA,50,
  NOTE_AS5,400, NOTE_A5,600, NOTE_G5,200, NOTE_G5,400, NOTE_A5,400,NOTE_AS5,400,NOTE_D6,1200,NOTE_AS5,400,NOTE_F6,600,NOTE_E6,200,PAUZA,50, 
  NOTE_E6,1200,PAUZA,5000 
  };
  const int notes_times_D[]PROGMEM = {
  //в лесу родилась ёлочка
  NOTE_C4,400, NOTE_A4,400, NOTE_A4,400, NOTE_G4,400,
  NOTE_A4,400, NOTE_F4,400, NOTE_C4,400, NOTE_C4,400,
  NOTE_C4,400, NOTE_A4,400, NOTE_A4,400, NOTE_AS4,400,
  NOTE_G4,400, NOTE_C5,1000,PAUZA, 500, NOTE_C5,400, NOTE_D4,400,
  NOTE_D4,400, NOTE_AS4,400,NOTE_AS4,400,NOTE_A4,400,
  NOTE_G4,400, NOTE_F4,400, NOTE_C4,400, NOTE_A4,400,
  NOTE_A4,400, NOTE_G4,400, NOTE_A4,400, NOTE_F4,5000,
  //маленькой ёлочке холодно зимой
  NOTE_G4,600, NOTE_E4,400, NOTE_E4,400, NOTE_G4,600,
  NOTE_E4,400, NOTE_E4,400, NOTE_G4,400, NOTE_F4,400,
  NOTE_E4,400, NOTE_D4,400, NOTE_C4,1000,PAUZA,750,NOTE_A4,600,
  NOTE_C5,400, NOTE_A4,400, NOTE_G4,600, NOTE_E4,400,
  NOTE_E4,400, NOTE_G4,400, NOTE_F4,400, NOTE_E4,400,
  NOTE_D4,400, NOTE_C4,1000,PAUZA,750, NOTE_A4,600,
  NOTE_C5,400, NOTE_A4,400, NOTE_G4,600, NOTE_E4,400,
  NOTE_E4,400, NOTE_G4,400, NOTE_F4,400, NOTE_E4,400,
  NOTE_D4,400, NOTE_C4,5000
  };
  const int notes_times_E[]PROGMEM = {
  ////рождество-"кристмас"
  NOTE_D4,800, NOTE_G4,800, NOTE_G4,400, NOTE_A4,400, NOTE_G4,400, NOTE_FS4,400, NOTE_E4,800, NOTE_E4, 800, NOTE_E4,800,PAUZA,50,
  NOTE_A4,800, NOTE_A4,400, NOTE_B4,400, NOTE_A4,400, NOTE_G4,400,NOTE_FS4,800,NOTE_D4,800,NOTE_D4,800,PAUZA,50, 
  NOTE_B4,800, NOTE_B4,400, NOTE_C5,400, NOTE_B4,400, NOTE_A4,400, NOTE_G4,800, NOTE_E4,800,PAUZA,50,
  NOTE_D4, 400, NOTE_D4,400,
  NOTE_E4,800, NOTE_A4,800, NOTE_FS4,800,PAUZA,50,
  NOTE_G4,1600,PAUZA,1500, NOTE_D4,800, NOTE_G4,800, NOTE_G4, 800, NOTE_G4,800,PAUZA,50,
  NOTE_FS4,1600,PAUZA,50, NOTE_FS4,800,PAUZA,50, 
  NOTE_G4,800, NOTE_FS4, 800, NOTE_E4,800,PAUZA,50,
  NOTE_D4,1600,PAUZA,50, NOTE_A4,800,
  NOTE_B4,800, NOTE_A4, 800, NOTE_G4,800,PAUZA,50,
  NOTE_D5,800, NOTE_D4, 800,NOTE_D4,400, NOTE_D4,400,PAUZA,50,
  NOTE_E4,800, NOTE_A4,800, NOTE_FS4,800,PAUZA,50,
  NOTE_G4,2400,PAUZA,5000  
  };
float temp=0.9;//задаём темп исполнения мелодии
int dlina_A= sizeof(notes_times_A)/sizeof(notes_times_A[0]);//определяем длину массива
int dlina_B= sizeof(notes_times_B)/sizeof(notes_times_B[0]);//определяем длину массива
int dlina_C= sizeof(notes_times_C)/sizeof(notes_times_C[0]);//определяем длину массива
int dlina_D= sizeof(notes_times_D)/sizeof(notes_times_D[0]);//определяем длину массива
int dlina_E= sizeof(notes_times_E)/sizeof(notes_times_E[0]);//определяем длину массива
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

void setup() {

  //disable all inerrupts to avoid glitches отключите все прерывания, чтобы избежать сбоев
 // noInterrupts();

  //setup the array with sine values настройте массив со значениями синуса
  setsine();

  //setup array with tone frequency phase increments установочная матрица с приращениями фазы тональной частоты
  settones();

  //Set a fast PWM signal on TIMER1A, 9-bit resolution, 31250Hz
  pinMode(9, OUTPUT);// вывод для динамика
  TCCR1A = 0B10000010; //9-bit fast PWM
  TCCR1B = 0B00001001;
/////////////////////////////////////////////////////////////////////////////////
 pinMode(7, INPUT);//кнопку подключить
 digitalWrite(7, HIGH);// включить подтягивающий резистор к ней
/////////////////////////////////////////////////////////////////////////////////
  
}


//initialize the main parameters of the pulse length setting инициализируйте основные параметры настройки длительности импульса
#define nch 4 //number of channels that can produce sound simultaneously количество каналов, которые могут воспроизводить звук одновременно
unsigned int phase[nch]  = {0,0,0,0};
int          inc[nch]    = {0,0,0,0};
byte         amp[nch]    = {0,0,0,0};
unsigned int FMphase[nch]= {0,0,0,0};
unsigned int FMinc[nch]  = {0,0,0,0};
unsigned int FMamp[nch]  = {0,0,0,0};

// main function (forced inline) to update the pulse length основная функция (принудительная встроенная) для обновления длительности импульса
inline void setPWM() __attribute__((always_inline));
inline void setPWM() {

  //wait for the timer to complete loop подождите, пока таймер завершит цикл
  while ((TIFR1 & 0B00000001) == 0);

  //Clear(!) the overflow bit by writing a 1 to it
  TIFR1 |= 0B00000001;

  //increment the phases of the FM
  FMphase[0] += FMinc[0];
  FMphase[1] += FMinc[1];
  FMphase[2] += FMinc[2];
  FMphase[3] += FMinc[3];

  //increment the phases of the note
  phase[0] += inc[0];
  phase[1] += inc[1];
  phase[2] += inc[2];
  phase[3] += inc[3];

  //calculate the output value and set pulse width for timer2
  int val = sine[(phase[0]+sine[FMphase[0]>>8]*FMamp[0]) >> 8] * amp[0];
  val += sine[(phase[1]+sine[FMphase[1]>>8]*FMamp[1]) >> 8] * amp[1];
  val += sine[(phase[2]+sine[FMphase[2]>>8]*FMamp[2]) >> 8] * amp[2];
  val += sine[(phase[3]+sine[FMphase[3]>>8]*FMamp[3]) >> 8] * amp[3];

  //set the pulse length
  OCR1A = val/128 + 256;
}

//properties of each note played  свойства каждой сыгранной ноты
byte         iADSR[nch]     = {0, 0, 0, 0}; 
unsigned int envADSR[nch]   = {0, 0, 0, 0}; 
unsigned int ADSRa[nch]     = {0, 0, 0, 0};
unsigned int ADSRd[nch]     = {0, 0, 0, 0};
unsigned int ADSRs[nch]     = {0, 0, 0, 0};
unsigned int ADSRr[nch]     = {0, 0, 0, 0};
byte         amp_base[nch]  = {0, 0, 0, 0};
unsigned int inc_base[nch]  = {0, 0, 0, 0};
unsigned int FMa0[nch]      = {0, 0, 0, 0};
int          FMda[nch]      = {0, 0, 0, 0};
unsigned int FMinc_base[nch]= {0, 0, 0, 0};
unsigned int FMdec[nch]     = {0, 0, 0, 0};
unsigned int FMexp[nch]     = {0, 0, 0, 0};
unsigned int FMval[nch]     = {0, 0, 0, 0};
byte         keych[nch]     = {0, 0, 0, 0}; 
unsigned int tch[nch]       = {0, 0, 0, 0}; 
byte keypressed;
byte keyreleased;

/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
//
//
//

void loop() {
  keypressed = nokey;
  keyreleased = nokey;
  ///////////////////////////////////////////////////
  if(digitalRead (7)==LOW){//если нажали кнопку то меняем мелодию
  FLAG++;k=0;if(FLAG>4){FLAG=0;}delay(200);
  }
  //////////////////////////////////////////////////
 if(FLAG==0){//
 temp=0.9;instr=11;
 for(int i=0;i< dlina_A;i=i+2){//...сыграть мелодию...
 if(k==i&&millis()-Y>10){Y=millis();k++;if(pgm_read_word(&notes_times_A[i])!=PAUZA){keypressed = pgm_read_word(&notes_times_A[i]);}}
 if(k==i+1&&millis()-Y>pgm_read_word(&notes_times_A[i+1])*temp){Y=millis();k++;if(pgm_read_word(&notes_times_A[i])!=PAUZA){keyreleased = pgm_read_word(&notes_times_A[i]);}}
 setPWM();//#0
}
if(k==dlina_A){k=0;}//... и повторить её снова 
}
////////////////////////////////////////////////////
if(FLAG==1){//
 temp=0.4;instr=1;
 for(int i=0;i< dlina_B;i=i+2){//...сыграть мелодию...
 if(k==i&&millis()-Y>10){Y=millis();k++;if(pgm_read_word(&notes_times_B[i])!=PAUZA){keypressed = pgm_read_word(&notes_times_B[i]);}}
 if(k==i+1&&millis()-Y>pgm_read_word(&notes_times_B[i+1])*temp){Y=millis();k++;if(pgm_read_word(&notes_times_B[i])!=PAUZA){keyreleased = pgm_read_word(&notes_times_B[i]);}}
 setPWM();//#0
}
if(k==dlina_B){k=0;}//... и повторить её снова 
}
////////////////////////////////////////////////////
if(FLAG==2){//
 temp=0.7;instr=0;
 for(int i=0;i< dlina_C;i=i+2){//...сыграть мелодию...
 if(k==i&&millis()-Y>10){Y=millis();k++;if(pgm_read_word(&notes_times_C[i])!=PAUZA){keypressed = pgm_read_word(&notes_times_C[i]);}}
 if(k==i+1&&millis()-Y>pgm_read_word(&notes_times_C[i+1])*temp){Y=millis();k++;if(pgm_read_word(&notes_times_C[i])!=PAUZA){keyreleased = pgm_read_word(&notes_times_C[i]);}}
 setPWM();//#0
}
if(k==dlina_C){k=0;}//... и повторить её снова 
}
////////////////////////////////////////////////////
if(FLAG==3){//
 temp=0.7;instr=2;
 for(int i=0;i< dlina_D;i=i+2){//...сыграть мелодию...
 if(k==i&&millis()-Y>10){Y=millis();k++;if(pgm_read_word(&notes_times_D[i])!=PAUZA){keypressed = pgm_read_word(&notes_times_D[i]);}}
 if(k==i+1&&millis()-Y>pgm_read_word(&notes_times_D[i+1])*temp){Y=millis();k++;if(pgm_read_word(&notes_times_D[i])!=PAUZA){keyreleased = pgm_read_word(&notes_times_D[i]);}}
 setPWM();//#0
}
if(k==dlina_D){k=0;}//... и повторить её снова 
}
////////////////////////////////////////////////////
if(FLAG==4){//
 temp=0.6;instr=7;
 for(int i=0;i< dlina_E;i=i+2){//...сыграть мелодию...
 if(k==i&&millis()-Y>10){Y=millis();k++;if(pgm_read_word(&notes_times_E[i])!=PAUZA){keypressed = pgm_read_word(&notes_times_E[i]);}}
 if(k==i+1&&millis()-Y>pgm_read_word(&notes_times_E[i+1])*temp){Y=millis();k++;if(pgm_read_word(&notes_times_E[i])!=PAUZA){keyreleased = pgm_read_word(&notes_times_E[i]);}}
 setPWM();//#0
}
if(k==dlina_E){k=0;}//... и повторить её снова 
}
////////////////////////////////////////////////////
 osnova();// вынес в отдельную функцию часть исходника автора
 }
/////////////////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
//
//
//
//
//

/////////////////////////////////////////////////////////////////////////////////////////////
void osnova(){
  setPWM(); //#1
//find the best channel to start a new note  найдите лучший канал, чтобы начать новую заметку 
  byte nextch = 255;
  //first check if the key is still being played  сначала проверьте, воспроизводится ли еще клавиша 
  if (iADSR[0] > 0 and keypressed == keych[0])nextch = 0;
  if (iADSR[1] > 0 and keypressed == keych[1])nextch = 1;
  if (iADSR[2] > 0 and keypressed == keych[2])nextch = 2;
  if (iADSR[3] > 0 and keypressed == keych[3])nextch = 3;
  //then check for an empty channel затем проверьте, нет ли пустого канала 
  if (nextch == 255) {
    if (iADSR[0] == 0)nextch = 0;
    if (iADSR[1] == 0)nextch = 1;
    if (iADSR[2] == 0)nextch = 2;
    if (iADSR[3] == 0)nextch = 3;
  }
  //otherwise use the channel with the longest playing note   в противном случае используйте канал с самой длинной воспроизводимой нотой
  if (nextch == 255) {
    nextch = 0;
    if (tch[0] > tch[nextch])nextch = 0;
    if (tch[1] > tch[nextch])nextch = 1;
    if (tch[2] > tch[nextch])nextch = 2;
    if (tch[3] > tch[nextch])nextch = 3;
  }

  setPWM(); //#3

  //initiate new note if needed  при необходимости инициируйте новую заметку
  if (keypressed != nokey) {
    phase[nextch]=0;
    amp_base[nextch] = ldness[instr];
    inc_base[nextch] = tone_inc[pitch0[instr]+keypressed];
    ADSRa[nextch]=ADSR_a[instr];
    ADSRd[nextch]=ADSR_d[instr];
    ADSRs[nextch]=ADSR_s[instr]<<8;
    ADSRr[nextch]=ADSR_r[instr];
    iADSR[nextch] = 1;
    FMphase[nextch]=0;
    FMinc_base[nextch] = ((long)inc_base[nextch]*FM_inc[instr])/256;
    FMa0[nextch] = FM_a2[instr];
    FMda[nextch] = FM_a1[instr]-FM_a2[instr];
    FMexp[nextch]=0xFFFF;
    FMdec[nextch]=FM_dec[instr];
    keych[nextch] = keypressed;
    tch[nextch] = 0;
  }

  setPWM(); //#4

  //stop a note if the button is released остановите заметку, если кнопка отпущена
  if (keyreleased != nokey) {
    if (keych[0] == keyreleased)iADSR[0] = 4;
    if (keych[1] == keyreleased)iADSR[1] = 4;
    if (keych[2] == keyreleased)iADSR[2] = 4;
    if (keych[3] == keyreleased)iADSR[3] = 4;
  }
  
  setPWM(); //#5

  //update FM decay exponential обновление FM-спад экспоненциальный
  FMexp[0]-=(long)FMexp[0]*FMdec[0]>>16;
  FMexp[1]-=(long)FMexp[1]*FMdec[1]>>16;
  FMexp[2]-=(long)FMexp[2]*FMdec[2]>>16;
  FMexp[3]-=(long)FMexp[3]*FMdec[3]>>16;
  
  setPWM(); //#6
  
  //adjust the ADSR envelopes отрегулируйте конверты ADSR
  for (byte ich = 0; ich < nch; ich++) {
    if (iADSR[ich] == 4) {
      if (envADSR[ich] <= ADSRr[ich]) {
        envADSR[ich] = 0;
        iADSR[ich] = 0;
      }
      else envADSR[ich] -= ADSRr[ich];
    }
    if (iADSR[ich] == 2) {
      if (envADSR[ich] <= (ADSRs[ich] + ADSRd[ich])) {
        envADSR[ich] = ADSRs[ich];
        iADSR[ich] = 3;
      }
      else envADSR[ich] -= ADSRd[ich];
    }
    if (iADSR[ich] == 1) {
      if ((0xFFFF - envADSR[ich]) <= ADSRa[ich]) {
        envADSR[ich] = 0xFFFF;
        iADSR[ich] = 2;
      }
      else envADSR[ich] += ADSRa[ich];
    }
    tch[ich]++;
    setPWM(); //#7-10
  }

  //update the tone for channel 0  обновите звуковой сигнал для канала 0
  amp[0] = (amp_base[0] * (envADSR[0] >> 8)) >> 8;
  inc[0] = inc_base[0];
  FMamp[0] = FMa0[0] + ((long)FMda[0] * FMexp[0]>>16);
  FMinc[0] = FMinc_base[0];
  setPWM(); //#11

  //update the tone for channel 1
  amp[1] = (amp_base[1] * (envADSR[1] >> 8)) >> 8;
  inc[1] = inc_base[1];
  FMamp[1] = FMa0[1] + ((long)FMda[1] * FMexp[1]>>16);
  FMinc[1] = FMinc_base[1];
  setPWM(); //#12

  //update the tone for channel 2
  amp[2] = (amp_base[2] * (envADSR[2] >> 8)) >> 8;
  inc[2] = inc_base[2];
  FMamp[2] = FMa0[2] + ((long)FMda[2] * FMexp[2]>>16);
  FMinc[2] = FMinc_base[2];
  setPWM(); //#13

  //update the tone for channel 3
  amp[3] = (amp_base[3] * (envADSR[3] >> 8)) >> 8;
  inc[3] = inc_base[3];
  FMamp[3] = FMa0[3] + ((long)FMda[3] * FMexp[3]>>16);
  FMinc[3] = FMinc_base[3];
  setPWM(); //#14

  //update counters  счетчики обновлений
  tch[0]++;
  tch[1]++;
  tch[2]++;
  tch[3]++;

  setPWM(); //#15
 
}
///////////////////////////////////////////////////////

Вот вариант, кнопка переключает мелодии. Можно по желанию добавить кнопки выбора инструмента (дудку сделал, котика - нет) и темпа-ритма исполнения.

lilik
Offline
Зарегистрирован: 19.10.2017
[code]



//instrument definitions  instr = 0       1      2       3      4         
#define ninstr 5           //   пианино кселоф.гитара флейта басс стр. 
unsigned int ldness[ninstr]  = {   64,    64,    64,     128,  64    }; // loudness   
unsigned int pitch0[ninstr]  = {   0,    12,     12,    12,    0     }; // pitch of key0         
unsigned int ADSR_a[ninstr]  = { 4096,  8192,  8192,   2000,   4096  }; // attack parameter  
unsigned int ADSR_d[ninstr]  = {  256,   256,   1024,   2000,  128   }; // decay parameter   
unsigned int ADSR_s[ninstr]  = {    0,     0,     15,    4,     0    }; // sustain parameter 
unsigned int ADSR_r[ninstr]  = {   64,   128,    32,    512,   4096   }; // release parameter 
unsigned int FM_inc[ninstr]  = {  256,   512,    750,  512,    64    }; // FM frequency wrt pitch
unsigned int FM_a1[ninstr]  =  {  128,   512,    512,  64,      256  }; // FM amplitude start
unsigned int FM_a2[ninstr]  =  {   64,    0,    128,   512,    128    }; // FM amplitude end
unsigned int FM_dec[ninstr]  = {   64,   128,    128,  128,    128    }; // FM decay

//define the pitch2key mapping
#define NOTE_C4   0
#define NOTE_CS4  1
#define NOTE_D4   2
#define NOTE_DS4  3
#define NOTE_E4   4
#define NOTE_F4   5
#define NOTE_FS4  6
#define NOTE_G4   7
#define NOTE_GS4  8
#define NOTE_A4   9
#define NOTE_AS4 10
#define NOTE_B4  11
#define NOTE_C5  12
#define NOTE_CS5 13
#define NOTE_D5  14
#define NOTE_DS5 15
#define NOTE_E5  16
#define NOTE_F5  17
#define NOTE_FS5  18
#define NOTE_G5   19
#define NOTE_GS5  20
#define NOTE_A5   21
#define NOTE_AS5 22
#define NOTE_B5  23
#define NOTE_C6  24
#define NOTE_CS6 25
#define NOTE_D6  26
#define NOTE_DS6 27
#define NOTE_E6  28
#define NOTE_F6  29
#define NOTE_FS6  30
#define NOTE_G6   31
#define NOTE_GS6  32
#define NOTE_A6   33
#define NOTE_AS6 34
#define NOTE_B6  35


#define PAUZA  50

#define nokey 255
#define instrkey 254



//set up array with sine values in signed 8-bit numbers 
const float pi = 3.14159265;
char sine[256];
void setsine() {
  for (int i = 0; i < 256; ++i) {
    sine[i] = (sin(2 * 3.14159265 * (i + 0.5) / 256)) * 128;
  }
}

//setup frequencies/phase increments, starting at C3=0 to B6. (A4 is defined as 440Hz)
unsigned int tone_inc[48];
void settones() {
  for (byte i=0; i<48; i++){
    tone_inc[i]= 440.0 * pow(2.0, ( (i-21) / 12.0)) * 65536.0 / (16000000.0/512) + 0.5;
  }
}

byte instr=0;//счётчик инструмента включённого
/////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
long Y=0;//переменная хранения моментов времени
int k=0;// счётчик прогресса исполнения мелодии
int i=0;//
int FLAG=0;//

const int notes_times_A[]PROGMEM = {
  // кабы не было зимы
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_FS5,200,
  NOTE_A5,400, NOTE_G5,400, NOTE_E5,800,PAUZA,50,
  NOTE_D5,400, NOTE_D5,400, NOTE_D6,600, NOTE_C6,200, NOTE_C6,400,NOTE_B5,400,PAUZA,800, 
  NOTE_D6,400,NOTE_C6,400, NOTE_A5,400,NOTE_FS5,400, NOTE_C6,400,NOTE_B5,400,NOTE_B5,800,
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_A5,200,NOTE_A5,400, NOTE_G5,400, PAUZA,800,
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_FS5,200,
  NOTE_A5,400, NOTE_G5,400, NOTE_E5,800,PAUZA,50,
  NOTE_D5,400, NOTE_D5,400, NOTE_D6,600, NOTE_C6,200, NOTE_C6,400,NOTE_B5,400,PAUZA,400,
  NOTE_E6,800,NOTE_C6,400, NOTE_A5,400, NOTE_FS5,400, NOTE_C6,400,NOTE_B5,400,NOTE_B5,800,PAUZA,50,
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_A5,200,NOTE_A5,400, NOTE_G5,400, PAUZA,400,
  NOTE_E6,800,NOTE_C6,400, NOTE_A5,400, NOTE_FS5,400, NOTE_C6,400,NOTE_B5,400,NOTE_B5,800,PAUZA,50,
  NOTE_B4,400, NOTE_B4,400, NOTE_B5,600, NOTE_DS5,200,NOTE_FS5,400, NOTE_E5,400,PAUZA,5000 
  };
  const int notes_times_B[]PROGMEM = {
  // Колокольчики-"джингл белз"
  NOTE_C4,800, NOTE_A4,800, NOTE_G4,800, NOTE_F4,800, NOTE_C4,1600,PAUZA,800, NOTE_C4,400,NOTE_C4,400,
  NOTE_C4,800, NOTE_A4,800, NOTE_G4,800, NOTE_F4,800, NOTE_D4,2400,PAUZA,800,
  NOTE_D4,800, NOTE_AS4,800, NOTE_A4,800, NOTE_G4,800, NOTE_E4,2400,PAUZA,800,
  NOTE_C5,800, NOTE_C5,800, NOTE_AS4,800, NOTE_G4,800, NOTE_A4,2400,PAUZA,800,
  NOTE_C4,800, NOTE_A4,800, NOTE_G4,800, NOTE_F4,800, NOTE_C4,2400,PAUZA,800,
  NOTE_C4,800, NOTE_A4,800, NOTE_G4,800, NOTE_F4,800, NOTE_D4,1600,PAUZA,800,NOTE_D4,800,
  NOTE_D4,800, NOTE_AS4,800, NOTE_A4,800, NOTE_G4,800,NOTE_C5,800,NOTE_C5,800,NOTE_C5,800,NOTE_C5,800, PAUZA,50,
  NOTE_D5,800, NOTE_C5,800, NOTE_AS4,800, NOTE_G4,800, NOTE_F4,2400,PAUZA,800,PAUZA,50,
  NOTE_A4,800, NOTE_A4,800, NOTE_A4,1600, PAUZA,50,
  NOTE_A4,800, NOTE_A4,800, NOTE_A4,1600, PAUZA,50,
  NOTE_A4,800, NOTE_C5,800, NOTE_F4,800, NOTE_G4,800,NOTE_A4,2400,PAUZA,800,PAUZA,50,
  NOTE_AS4,800, NOTE_AS4,800, NOTE_AS4,800, NOTE_AS4,800,PAUZA,50,
  NOTE_AS4,800,NOTE_A4,800,NOTE_A4,800,NOTE_A4,400, NOTE_A4,400,PAUZA,50,
  NOTE_A4,800, NOTE_G4,800, NOTE_G4,800, NOTE_A4,800,PAUZA,50,
  NOTE_G4,1600, NOTE_C5,1600, PAUZA,50,
  NOTE_A4,800, NOTE_A4,800, NOTE_A4,1600, PAUZA,50,
  NOTE_A4,800, NOTE_A4,800, NOTE_A4,1600, PAUZA,50,
  NOTE_A4,800, NOTE_C5,800, NOTE_F4,800, NOTE_G4,800,NOTE_A4,2400,PAUZA,800,PAUZA,50,
  NOTE_AS4,800, NOTE_AS4,800, NOTE_AS4,800, NOTE_AS4,800,PAUZA,50,
  NOTE_AS4,800,NOTE_A4,800,NOTE_A4,800,NOTE_A4,400, NOTE_A4,400,PAUZA,50,
  NOTE_C5,800, NOTE_C5,800, NOTE_AS4,800, NOTE_G4,800, NOTE_F4,2400,PAUZA,800,PAUZA,50,
 PAUZA,5000 
  };
  const int notes_times_C[]PROGMEM = {
  // вальс - "мой ласковый и нежный зверь"
  NOTE_C5,1200, NOTE_E5,1200, NOTE_A5,1200, NOTE_C6,800, NOTE_B5,400,PAUZA,50, 
  NOTE_E5,1200, NOTE_C6,800, NOTE_B5, 400, NOTE_C6,800, NOTE_B5, 400,NOTE_C6,800, NOTE_B5, 400,PAUZA,50,
  NOTE_C5,1200, NOTE_E5,1200, NOTE_A5,1200, NOTE_B5,400, NOTE_D6,600,NOTE_C6,400,
  NOTE_F5,1200, NOTE_D6,800, NOTE_C6, 400, NOTE_D6,800, NOTE_C6, 400,NOTE_D6,800, NOTE_C6,400,PAUZA,50,
  NOTE_D5,1200, NOTE_F5,1200, NOTE_A5,1200, NOTE_D6,400, NOTE_E6,600,NOTE_D6,200,PAUZA,50,
  NOTE_F6,2000, NOTE_E6,400, NOTE_AS5,2400, PAUZA,50,
  NOTE_A5,400, NOTE_D6,600, NOTE_CS6,200, NOTE_CS6,1200, NOTE_A5,400,NOTE_F6,600,NOTE_E6,200,NOTE_E6,1200,PAUZA,50,
  NOTE_CS6,400, NOTE_AS6,400, NOTE_A5, 400, NOTE_AS5,400, NOTE_A5, 400,NOTE_AS5,400, NOTE_AS5, 1200,NOTE_A5, 1200,PAUZA,50,
  NOTE_F5,1200, NOTE_F5,1200, NOTE_F5,1200, NOTE_F5,400, NOTE_G5,600,NOTE_A5,200,PAUZA,50, 
  NOTE_AS5,2000, NOTE_D5,400, NOTE_CS5,2400, PAUZA,50,
  NOTE_E5,1200, NOTE_E5,1200, NOTE_E5,1200, NOTE_E5,400, NOTE_G5,600,NOTE_F5,200,PAUZA,50,
  NOTE_F5,2000, NOTE_A5,400, PAUZA,50,NOTE_A4,1200,PAUZA,50, NOTE_A4,400, NOTE_AS4,400, NOTE_C5, 400,PAUZA,50,
  NOTE_D5,1200, NOTE_D5,1200, NOTE_D5, 400, NOTE_E5,400, NOTE_F5, 400,NOTE_G5,400, NOTE_A5, 400,NOTE_AS5, 400,PAUZA,50,
  NOTE_D6,1200, NOTE_E6,800, NOTE_F6,400, NOTE_AS6,2400,PAUZA,50,
  NOTE_AS5,400, NOTE_A5,600, NOTE_G5,200, NOTE_G5,400, NOTE_A5,400,NOTE_AS5,400,NOTE_D6,1200,NOTE_AS5,400,NOTE_F6,600,NOTE_E6,200,PAUZA,50, 
  NOTE_E6,1200,PAUZA,5000 
  };
  const int notes_times_D[]PROGMEM = {
  //в лесу родилась ёлочка
  NOTE_C4,400, NOTE_A4,400, NOTE_A4,400, NOTE_G4,400,
  NOTE_A4,400, NOTE_F4,400, NOTE_C4,400, NOTE_C4,400,
  NOTE_C4,400, NOTE_A4,400, NOTE_A4,400, NOTE_AS4,400,
  NOTE_G4,400, NOTE_C5,1000,PAUZA, 500, NOTE_C5,400, NOTE_D4,400,
  NOTE_D4,400, NOTE_AS4,400,NOTE_AS4,400,NOTE_A4,400,
  NOTE_G4,400, NOTE_F4,400, NOTE_C4,400, NOTE_A4,400,
  NOTE_A4,400, NOTE_G4,400, NOTE_A4,400, NOTE_F4,5000
  };
  const int notes_times_E[]PROGMEM = {
  //рождество-"кристмас"
  NOTE_D4,800, NOTE_G4,800, NOTE_G4,400, NOTE_A4,400, NOTE_G4,400, NOTE_FS4,400, NOTE_E4,800, NOTE_E4, 800, NOTE_E4,800,PAUZA,50,
  NOTE_A4,800, NOTE_A4,400, NOTE_B4,400, NOTE_A4,400, NOTE_G4,400,NOTE_FS4,800,NOTE_D4,800,NOTE_D4,800,PAUZA,50, 
  NOTE_B4,800, NOTE_B4,400, NOTE_C5,400, NOTE_B4,400, NOTE_A4,400, NOTE_G4,800, NOTE_E4,800,PAUZA,50,
  NOTE_D4, 400, NOTE_D4,400,
  NOTE_E4,800, NOTE_A4,800, NOTE_FS4,800,PAUZA,50,
  NOTE_G4,1600,PAUZA,1500, NOTE_D4,800, NOTE_G4,800, NOTE_G4, 800, NOTE_G4,800,PAUZA,50,
  NOTE_FS4,1600,PAUZA,50, NOTE_FS4,800,PAUZA,50, 
  NOTE_G4,800, NOTE_FS4, 800, NOTE_E4,800,PAUZA,50,
  NOTE_D4,1600,PAUZA,50, NOTE_A4,800,
  NOTE_B4,800, NOTE_A4, 800, NOTE_G4,800,PAUZA,50,
  NOTE_D5,800, NOTE_D4, 800,NOTE_D4,400, NOTE_D4,400,PAUZA,50,
  NOTE_E4,800, NOTE_A4,800, NOTE_FS4,800,PAUZA,50,
  NOTE_G4,2400,PAUZA,5000  
  };
   const int notes_times_F[]PROGMEM = {
  //маленькой ёлочке холодно зимой
  NOTE_G4,600, NOTE_E4,400, NOTE_E4,400, NOTE_G4,600,
  NOTE_E4,400, NOTE_E4,400, NOTE_G4,400, NOTE_F4,400,
  NOTE_E4,400, NOTE_D4,400, NOTE_C4,1000,PAUZA,750,NOTE_A4,600,
  NOTE_C5,400, NOTE_A4,400, NOTE_G4,600, NOTE_E4,400,
  NOTE_E4,400, NOTE_G4,400, NOTE_F4,400, NOTE_E4,400,
  NOTE_D4,400, NOTE_C4,1000,PAUZA,750, NOTE_A4,600,
  NOTE_C5,400, NOTE_A4,400, NOTE_G4,600, NOTE_E4,400,
  NOTE_E4,400, NOTE_G4,400, NOTE_F4,400, NOTE_E4,400,
  NOTE_D4,400, NOTE_C4,5000
  };
float temp=0.9;//задаём темп исполнения мелодии

int dlina_A= sizeof(notes_times_A)/sizeof(notes_times_A[0]);//определяем длину массива
int dlina_B= sizeof(notes_times_B)/sizeof(notes_times_B[0]);//определяем длину массива
int dlina_C= sizeof(notes_times_C)/sizeof(notes_times_C[0]);//определяем длину массива
int dlina_D= sizeof(notes_times_D)/sizeof(notes_times_D[0]);//определяем длину массива
int dlina_E= sizeof(notes_times_E)/sizeof(notes_times_E[0]);//определяем длину массива
int dlina_F= sizeof(notes_times_F)/sizeof(notes_times_F[0]);//определяем длину массива
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////

void setup() {
 Serial.begin(19200);  //
  
  //disable all inerrupts to avoid glitches отключите все прерывания, чтобы избежать сбоев
 // noInterrupts();

  //setup the array with sine values настройте массив со значениями синуса
  setsine();

  //setup array with tone frequency phase increments установочная матрица с приращениями фазы тональной частоты
  settones();

  //Set a fast PWM signal on TIMER1A, 9-bit resolution, 31250Hz
  pinMode(9, OUTPUT);// вывод для динамика
  TCCR1A = 0B10000010; //9-bit fast PWM
  TCCR1B = 0B00001001;
/////////////////////////////////////////////////////////////////////////////////
 pinMode(7, INPUT);//кнопку подключить (смена мелодий)
 digitalWrite(7, HIGH);// включить подтягивающий резистор к ней
////////////////////////////////////////////////////////////////////////////////
  
}


//initialize the main parameters of the pulse length setting инициализируйте основные параметры настройки длительности импульса
#define nch 4 //number of channels that can produce sound simultaneously количество каналов, которые могут воспроизводить звук одновременно
unsigned int phase[nch]  = {0,0,0,0};
int          inc[nch]    = {0,0,0,0};
byte         amp[nch]    = {0,0,0,0};
unsigned int FMphase[nch]= {0,0,0,0};
unsigned int FMinc[nch]  = {0,0,0,0};
unsigned int FMamp[nch]  = {0,0,0,0};

// main function (forced inline) to update the pulse length основная функция (принудительная встроенная) для обновления длительности импульса
inline void setPWM() __attribute__((always_inline));
inline void setPWM() {

  //wait for the timer to complete loop подождите, пока таймер завершит цикл
  while ((TIFR1 & 0B00000001) == 0);

  //Clear(!) the overflow bit by writing a 1 to it
  TIFR1 |= 0B00000001;

  //increment the phases of the FM
  FMphase[0] += FMinc[0];
  FMphase[1] += FMinc[1];
  FMphase[2] += FMinc[2];
  FMphase[3] += FMinc[3];

  //increment the phases of the note
  phase[0] += inc[0];
  phase[1] += inc[1];
  phase[2] += inc[2];
  phase[3] += inc[3];

  //calculate the output value and set pulse width for timer2
  int val = sine[(phase[0]+sine[FMphase[0]>>8]*FMamp[0]) >> 8] * amp[0];
  val += sine[(phase[1]+sine[FMphase[1]>>8]*FMamp[1]) >> 8] * amp[1];
  val += sine[(phase[2]+sine[FMphase[2]>>8]*FMamp[2]) >> 8] * amp[2];
  val += sine[(phase[3]+sine[FMphase[3]>>8]*FMamp[3]) >> 8] * amp[3];

  //set the pulse length
  OCR1A = val/128 + 256;
}

//properties of each note played  свойства каждой сыгранной ноты
byte         iADSR[nch]     = {0, 0, 0, 0}; 
unsigned int envADSR[nch]   = {0, 0, 0, 0}; 
unsigned int ADSRa[nch]     = {0, 0, 0, 0};
unsigned int ADSRd[nch]     = {0, 0, 0, 0};
unsigned int ADSRs[nch]     = {0, 0, 0, 0};
unsigned int ADSRr[nch]     = {0, 0, 0, 0};
byte         amp_base[nch]  = {0, 0, 0, 0};
unsigned int inc_base[nch]  = {0, 0, 0, 0};
unsigned int FMa0[nch]      = {0, 0, 0, 0};
int          FMda[nch]      = {0, 0, 0, 0};
unsigned int FMinc_base[nch]= {0, 0, 0, 0};
unsigned int FMdec[nch]     = {0, 0, 0, 0};
unsigned int FMexp[nch]     = {0, 0, 0, 0};
unsigned int FMval[nch]     = {0, 0, 0, 0};
byte         keych[nch]     = {0, 0, 0, 0}; 
unsigned int tch[nch]       = {0, 0, 0, 0}; 
byte keypressed;
byte keyreleased;

/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
//
//
//
void loop() {
  keypressed = nokey;
  keyreleased = nokey;
  ///////////////////////////////////////////////////
  if(digitalRead (7)==LOW){//если нажали кнопку то меняем мелодию
  FLAG++;k=0;if(FLAG>5){FLAG=0;}instr++;if(instr==ninstr){instr=0;}delay(200);
  }
 //////////////////////////////////////////////////
 if(FLAG==0){//
 temp=0.9;
 for(int i=0;i<dlina_A;i=i+2){//...сыграть мелодию...
 if(k==i&&millis()-Y>10){Y=millis();k++;if(pgm_read_word(&notes_times_A[i])!=PAUZA){keypressed = pgm_read_word(&notes_times_A[i]);Serial.println("1\n");} }
 if(k==i+1&&millis()-Y>pgm_read_word(&notes_times_A[i+1])*temp){Y=millis();k++;if(pgm_read_word(&notes_times_A[i])!=PAUZA){keyreleased = pgm_read_word(&notes_times_A[i]);}}
 setPWM();//#0
}
if(k==dlina_A){k=0;FLAG=1;instr++;if(instr==ninstr){instr=0;}}//... и повторить её снова 
}
////////////////////////////////////////////////////
if(FLAG==1){//
 temp=0.4;
 for(int i=0;i< dlina_B;i=i+2){//...сыграть мелодию...
 if(k==i&&millis()-Y>10){Y=millis();k++;if(pgm_read_word(&notes_times_B[i])!=PAUZA){keypressed = pgm_read_word(&notes_times_B[i]);Serial.println("1\n");}}
 if(k==i+1&&millis()-Y>pgm_read_word(&notes_times_B[i+1])*temp){Y=millis();k++;if(pgm_read_word(&notes_times_B[i])!=PAUZA){keyreleased = pgm_read_word(&notes_times_B[i]);}}
 setPWM();//#0
}
if(k==dlina_B){k=0;FLAG=2;instr++;if(instr==ninstr){instr=0;}}//... и повторить её снова 
}
////////////////////////////////////////////////////
if(FLAG==2){//
 temp=0.7;
 for(int i=0;i< dlina_C;i=i+2){//...сыграть мелодию...
 if(k==i&&millis()-Y>10){Y=millis();k++;if(pgm_read_word(&notes_times_C[i])!=PAUZA){keypressed = pgm_read_word(&notes_times_C[i]);Serial.println("1\n");}}
 if(k==i+1&&millis()-Y>pgm_read_word(&notes_times_C[i+1])*temp){Y=millis();k++;if(pgm_read_word(&notes_times_C[i])!=PAUZA){keyreleased = pgm_read_word(&notes_times_C[i]);}}
 setPWM();//#0
}
if(k==dlina_C){k=0;FLAG=3;instr++;if(instr==ninstr){instr=0;}}//... и повторить её снова 
}
////////////////////////////////////////////////////
if(FLAG==3){//
 temp=0.7;
 for(int i=0;i< dlina_D;i=i+2){//...сыграть мелодию...
 if(k==i&&millis()-Y>10){Y=millis();k++;if(pgm_read_word(&notes_times_D[i])!=PAUZA){keypressed = pgm_read_word(&notes_times_D[i]);Serial.println("1\n");}}
 if(k==i+1&&millis()-Y>pgm_read_word(&notes_times_D[i+1])*temp){Y=millis();k++;if(pgm_read_word(&notes_times_D[i])!=PAUZA){keyreleased = pgm_read_word(&notes_times_D[i]);}}
 setPWM();//#0
}
if(k==dlina_D){k=0;FLAG=4;instr++;if(instr==ninstr){instr=0;}}//... и повторить её снова 
}
////////////////////////////////////////////////////
if(FLAG==4){//
 temp=0.6;
 for(int i=0;i< dlina_E;i=i+2){//...сыграть мелодию...
 if(k==i&&millis()-Y>10){Y=millis();k++;if(pgm_read_word(&notes_times_E[i])!=PAUZA){keypressed = pgm_read_word(&notes_times_E[i]);}Serial.println("1\n");}
 if(k==i+1&&millis()-Y>pgm_read_word(&notes_times_E[i+1])*temp){Y=millis();k++;if(pgm_read_word(&notes_times_E[i])!=PAUZA){keyreleased = pgm_read_word(&notes_times_E[i]);}}
 setPWM();//#0
}
if(k==dlina_E){k=0;FLAG=5;instr++;if(instr==ninstr){instr=0;}}//... и повторить её снова 
}
////////////////////////////////////////////////////
if(FLAG==5){//
 temp=0.6;
 for(int i=0;i< dlina_F;i=i+2){//...сыграть мелодию...
 if(k==i&&millis()-Y>10){Y=millis();k++;if(pgm_read_word(&notes_times_F[i])!=PAUZA){keypressed = pgm_read_word(&notes_times_F[i]);}Serial.println("1\n");}
 if(k==i+1&&millis()-Y>pgm_read_word(&notes_times_F[i+1])*temp){Y=millis();k++;if(pgm_read_word(&notes_times_F[i])!=PAUZA){keyreleased = pgm_read_word(&notes_times_F[i]);}}
 setPWM();//#0
}
if(k==dlina_F){k=0;FLAG=0;instr++;if(instr==ninstr){instr=0;}}//... и повторить её снова 
}
////////////////////////////////////////////////////
 osnova();// вынес в отдельную функцию часть исходника автора
 }
/////////////////////////////////////////////////////////////////////////////////////////////
//
//
//
//
//
//
//
//
//
//
//
//

/////////////////////////////////////////////////////////////////////////////////////////////
void osnova(){
  setPWM(); //#1
//find the best channel to start a new note  найдите лучший канал, чтобы начать новую заметку 
  byte nextch = 255;
  //first check if the key is still being played  сначала проверьте, воспроизводится ли еще клавиша 
  if (iADSR[0] > 0 and keypressed == keych[0])nextch = 0;
  if (iADSR[1] > 0 and keypressed == keych[1])nextch = 1;
  if (iADSR[2] > 0 and keypressed == keych[2])nextch = 2;
  if (iADSR[3] > 0 and keypressed == keych[3])nextch = 3;
  //then check for an empty channel затем проверьте, нет ли пустого канала 
  if (nextch == 255) {
    if (iADSR[0] == 0)nextch = 0;
    if (iADSR[1] == 0)nextch = 1;
    if (iADSR[2] == 0)nextch = 2;
    if (iADSR[3] == 0)nextch = 3;
  }
  //otherwise use the channel with the longest playing note   в противном случае используйте канал с самой длинной воспроизводимой нотой
  if (nextch == 255) {
    nextch = 0;
    if (tch[0] > tch[nextch])nextch = 0;
    if (tch[1] > tch[nextch])nextch = 1;
    if (tch[2] > tch[nextch])nextch = 2;
    if (tch[3] > tch[nextch])nextch = 3;
  }

  setPWM(); //#3

  //initiate new note if needed  при необходимости инициируйте новую заметку
  if (keypressed != nokey) {
    phase[nextch]=0;
    amp_base[nextch] = ldness[instr];
    inc_base[nextch] = tone_inc[pitch0[instr]+keypressed];
    ADSRa[nextch]=ADSR_a[instr];
    ADSRd[nextch]=ADSR_d[instr];
    ADSRs[nextch]=ADSR_s[instr]<<8;
    ADSRr[nextch]=ADSR_r[instr];
    iADSR[nextch] = 1;
    FMphase[nextch]=0;
    FMinc_base[nextch] = ((long)inc_base[nextch]*FM_inc[instr])/256;
    FMa0[nextch] = FM_a2[instr];
    FMda[nextch] = FM_a1[instr]-FM_a2[instr];
    FMexp[nextch]=0xFFFF;
    FMdec[nextch]=FM_dec[instr];
    keych[nextch] = keypressed;
    tch[nextch] = 0;
  }

  setPWM(); //#4

  //stop a note if the button is released остановите заметку, если кнопка отпущена
  if (keyreleased != nokey) {
    if (keych[0] == keyreleased)iADSR[0] = 4;
    if (keych[1] == keyreleased)iADSR[1] = 4;
    if (keych[2] == keyreleased)iADSR[2] = 4;
    if (keych[3] == keyreleased)iADSR[3] = 4;
  }
  
  setPWM(); //#5

  //update FM decay exponential обновление FM-спад экспоненциальный
  FMexp[0]-=(long)FMexp[0]*FMdec[0]>>16;
  FMexp[1]-=(long)FMexp[1]*FMdec[1]>>16;
  FMexp[2]-=(long)FMexp[2]*FMdec[2]>>16;
  FMexp[3]-=(long)FMexp[3]*FMdec[3]>>16;
  
  setPWM(); //#6
  
  //adjust the ADSR envelopes отрегулируйте конверты ADSR
  for (byte ich = 0; ich < nch; ich++) {
    if (iADSR[ich] == 4) {
      if (envADSR[ich] <= ADSRr[ich]) {
        envADSR[ich] = 0;
        iADSR[ich] = 0;
      }
      else envADSR[ich] -= ADSRr[ich];
    }
    if (iADSR[ich] == 2) {
      if (envADSR[ich] <= (ADSRs[ich] + ADSRd[ich])) {
        envADSR[ich] = ADSRs[ich];
        iADSR[ich] = 3;
      }
      else envADSR[ich] -= ADSRd[ich];
    }
    if (iADSR[ich] == 1) {
      if ((0xFFFF - envADSR[ich]) <= ADSRa[ich]) {
        envADSR[ich] = 0xFFFF;
        iADSR[ich] = 2;
      }
      else envADSR[ich] += ADSRa[ich];
    }
    tch[ich]++;
    setPWM(); //#7-10
  }

  //update the tone for channel 0  обновите звуковой сигнал для канала 0
  amp[0] = (amp_base[0] * (envADSR[0] >> 8)) >> 8;
  inc[0] = inc_base[0];
  FMamp[0] = FMa0[0] + ((long)FMda[0] * FMexp[0]>>16);
  FMinc[0] = FMinc_base[0];
  setPWM(); //#11

  //update the tone for channel 1
  amp[1] = (amp_base[1] * (envADSR[1] >> 8)) >> 8;
  inc[1] = inc_base[1];
  FMamp[1] = FMa0[1] + ((long)FMda[1] * FMexp[1]>>16);
  FMinc[1] = FMinc_base[1];
  setPWM(); //#12

  //update the tone for channel 2
  amp[2] = (amp_base[2] * (envADSR[2] >> 8)) >> 8;
  inc[2] = inc_base[2];
  FMamp[2] = FMa0[2] + ((long)FMda[2] * FMexp[2]>>16);
  FMinc[2] = FMinc_base[2];
  setPWM(); //#13

  //update the tone for channel 3
  amp[3] = (amp_base[3] * (envADSR[3] >> 8)) >> 8;
  inc[3] = inc_base[3];
  FMamp[3] = FMa0[3] + ((long)FMda[3] * FMexp[3]>>16);
  FMinc[3] = FMinc_base[3];
  setPWM(); //#14

  //update counters  счетчики обновлений
  tch[0]++;
  tch[1]++;
  tch[2]++;
  tch[3]++;

  setPWM(); //#15
 
}
///////////////////////////////////////////////////////
[/code]

Придумал куда практически этот синтез-проигрыватель мелодий можно пристроить. К новогодней гирлянде :-)

Просто посылаем через блютуз-модуль "1" на каждой ноте. В итоге колонки с синтезатором в одном углу, ёлка с гирляндой в другом. Свет и звук синхронны. 

Кстати нашёл пример "библиотечного" варианта синтеза звуков.

 http://digitrode.ru/computing-devices/mcu_cpu/2517-sintezator-zvukovyh-signalov-na-arduino-svoimi-rukami.html

lilik
Offline
Зарегистрирован: 19.10.2017

Мелодий взял 6, а инструментов 5. После исполнения мелодии набавляю по кругу номер мелодии и инструмента - получается своеобразное чередование 30 исполнений.

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

А подобие терменвокса слабо на ардуине забубенить? 

lilik
Offline
Зарегистрирован: 19.10.2017

У него голос своеобразный для синтеза. Найти бы простое описание как формируют голоса инструментов настройками.

Rumata
Rumata аватар
Offline
Зарегистрирован: 29.03.2019

lilik пишет:

 Найти бы простое описание как формируют голоса инструментов настройками.

Ну как 100 лет назад могли формировать голоса... Никак

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

lilik пишет:

У него голос своеобразный для синтеза. Найти бы простое описание как формируют голоса инструментов настройками.

Даю самое простое описание (проще вряд ли возможно): 

на слух.

 

PS. Кстати, если речь идет о волновой форме терменвокса, то, если мне не изменяет память, там одностороннее ограничение синусоиды.

lilik
Offline
Зарегистрирован: 19.10.2017

А внешне? Вот диаграммы моих псевдоинструментов. Зависимость от времени чего? Теперь можно сопоставить числовые коэффициенты из массивов базового скетча с внешним видом и попытаться связать "хрен с носом" :-) 

lilik
Offline
Зарегистрирован: 19.10.2017

БАС СТРУНА и КСИЛОФОН.