Floppy & HDD Music

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

Собственно, см. видео https://youtu.be/oq2bXXktJQs

Подробности чуть позже.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не понял, звук что-ли сами дисководы издают? Или звук от звуковой карты а на дисководах просто "цветомузыка" сделана?

toxikaciya
Offline
Зарегистрирован: 11.04.2016

Судя по звукам, шумит механика. По крайней мере, местами. Вот еще.

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

Нет, Женя, вместо динамиков используются именно дисководы. А вместо звуковой платы - Ардуино, настроенный на частоту прерываний 40 кГц.

Видео промежуточных этапов:

https://www.youtube.com/watch?v=VqNxzM-S5dk&lc=z12kslihsyapfhpxs04cjp5hv...

https://www.youtube.com/watch?v=k1sQ6k0-MXY

Проект представляет, по сути, музыкальную шкатулку, собранную на базе Ardiono Pro Mini, трех Floppy дисководов и двух накопителей на жестких дисках.
Все это располагается в корпусе теперь уже наверное винтажного ПК цвета слоновой кости. Блок питания - оттуда же: стандартный компьютерный.

Каждый floppy может воспроизводить один голос, а HDD - 2. Итого 7 голосов.

Не обошлось и без некоторой "фейковатости": один НЖМД расположен в корпусе от старого пишущего CDD. Индикаторы, задающие режимы работы, заменены индикаторами включения соответствующих голосов. Второй НЖМД находится в стандартном Mobile Rack'е, но индикаторам присвоемы другие функции - как у первомго НЖМД.

FDD взяты без переделки, но используются только три сигнала: "выбор устройства", "направление" и "шаг". Собственно, шаговый двигатель с головкой и излучают звук. В процесе экспериментов выяснилось, что наиболее грмкий и отчетливый звук (понятное дело, разработчики, наоборот, стремятся сделать свои устройства как можно тише) достигается, если разрешить дисководу перемещаться только в пределах двух (а не 40-80) дорожек. Правда, появляется призвук октавой ниже, но для данного проекта это, возможно, даже плюс.

А вот HDD подверглись серьезной переделке:
- удалена плата контроллера,
- удалены блины и мотор,
- удалены некоторые конструктивные элементы, препятствующие свободному перемещению коромысла.

В И-нете аналогичные проекты попадаются не так уж редко, но, почему-то, везде рекомендуется подпаивать подводящие провода непосредственно к контактам катушки коромысла, хотя коромысло уже соединено с неподвижной колодкой гибким шлейфом, который заодно служит упругим элементом, позиционирующим головку примерно в середину диапазона свободного хода. Я подсоединялся к неподвижному концу шлейфа, в одном случае даже удалось использовать съемный контакт, выпаянный из платы контроллера.

Звук в HDD излучает коромысло, катушка которого имеет сопротивление порядка 7-9 Ом, т.е. такое же, как у стандартного динамика. Поэтому и сигнал на нее подавался со стандартного УМЗЧ, собранного на TDA2004, схема которого была слегка доработана, исходя из особенностей применения.

В качестве радиатора УМЗЧ использовался массивный корпус HDD. Естественно, с использованием теплопроводящей пасты. Усилитель питался от 12В, а индикаторы - от 5В, т.к. активному режиму соответствует низкий уровень (это стандартно для цифровой электроники и для FDD в частности, поэтому было решено не отказываться от этого стандарта и при переделке HDD). Такой подход требует подачи на устройство напряжения 5В, чего можно было бы избежать, если бы активный сигнал был высоким. Но т.к. питание все равно осуществлялось через стандартный molex, было решено оставить, как есть.
Для управления переделанным HDD используется 4 контакта: "звук 1-го канала", "выбор 1-го канала", "звук 2-го канала" и "выбор 2-го канала". "Звук" подается на входы усилителя, а катушка коромысла подключена по "мостовой" схеме. "Выбор" используется исключительно для зажигания светодиодов.

Исходники:

Основная программа:

#include <TimerOne.h>
#include "Arhat_digOut.c" 
#include "voice_0.c"
#include "voice_1.c"
#include "voice_2.c"
#include "voice_3.c"
#include "voice_4.c"
#include "voice_5.c"
#include "voice_6.c"

// change interrupt period to 25us (40kHz) insteadо 40us (25kHz)
// minimum frequence for 3.5" floppy is 440-520 Hz

          // channel 0, vely low notes: 5.25 floppy - up to  ()
#define pin_sound_0   8 //2 // sound pin, for floppy - step
#define pin_dir_0     9 //3   // step direction pin, for floppy only
#define pin_active_0 10 //4 // for LED & activate floppy drive

         // channel 1, low notes: 3.5 floppy - up to C1-F1 (261-347 Hz)
#define pin_sound_1   5 // sound pin, for floppy - step
#define pin_dir_1     6   // step direction pin, for floppy only
#define pin_active_1  7 // for LED & activate floppy drive

         // channel 2, low notes: 3.5 floppy: up to C1-F1 (261-347 Hz)
#define pin_sound_2   2 //8 // sound pin, for floppy - step
#define pin_dir_2     3 //9   // step direction pin, for floppy only
#define pin_active_2  4 //10 // for LED & activate floppy drive

        // channel 3, high notes: 1-st HDD 1-st channel - not limited
#define pin_sound_3  11 // sound pin, for HDD - sound amplifier
#define pin_active_3 12 // for LED only

        // channel 4, high notes: 1-st HDD 2-nd channel - not limited
#define pin_sound_4  13 // sound pin, for HDD - sound amplifier
#define pin_active_4 14 // for LED only

        // channel 5, high notes: 2-nd HDD 1-st channel - not limited
#define pin_sound_5  15 // sound pin, for HDD - sound amplifier
#define pin_active_5 16 // for LED only

        // channel 6, high notes: 2-nd HDD 2-nd channel - not limited
#define pin_sound_6  17 // sound pin, for HDD - sound amplifier
#define pin_active_6 18 // for LED only

#define pin_button_0 19 // for button input
 
#define RESOLUTION 25 //Microsecond resolution for notes (interrupt frequency 40 kHz)
#define FREQUENCE 1000/RESOLUTION // interrupt frequence in kHz

byte MAX_POSITION_0 = 2; //74;  // max head position: double number of track without 2, for 5.25 - 40 tracks
byte MAX_POSITION_1 = 2; //154; // max head position: double number of track without 2, for 3.5 - 80 tracks
byte MAX_POSITION_2 = 2; //154; // max head position: double number of track without 2, for 3.5 - 80 tracks
  
byte currentPosition[] = {0, 0, 0}; // head position (track number)

char currentStateAdd_0 = 1; // addition for currentPosition -1 or +1 (track)
char currentStateAdd_1 = 1;
char currentStateAdd_2 = 1;
  
byte currentStateStep[]       = {0,0,0,0,0,0,0};  // positive or negative half period
unsigned int currentPeriodA[] = {0,0,0,0,0,0,0};      // positive half period   0 = off.
unsigned int currentPeriodB[] = {0,0,0,0,0,0,0};      // negative half period   0 = off.

unsigned int currentTick_0 = 1; // sound half-perion counter (from currentPeriod*[] to 0)
unsigned int currentTick_1 = 1;
unsigned int currentTick_2 = 1;
unsigned int currentTick_3 = 1;
unsigned int currentTick_4 = 1;
unsigned int currentTick_5 = 1;
unsigned int currentTick_6 = 1;

unsigned long startTime;

void setup(){
  Serial.begin(115200);
  
  for(byte i = 2; i <= 18; i++)
    pinMode(i, OUTPUT); // 0-1 - Serial, 2-10 - floppy control, 11-18 - HDD control, 19(,A6,A7) - buttons
  pinMode(A5, INPUT_PULLUP);

  resetAll();
  
  Timer1.initialize(RESOLUTION); // Set up a timer at the defined resolution
  Timer1.attachInterrupt(tick); // Attach the tick function

  resetAll();
  delay(2000);
  startTime = millis();
}

void loop(){
  unsigned long currTime = millis() - startTime;
  static unsigned int index[7] = {0,0,0,0,0,0,0}; // array index of the note of each channels
  static byte melodyOver[7] = {0,0,0,0,0,0,0};
  if(!melodyOver[0]) {
    if(pgm_read_word(&bach_ch_0[index[0] << 1]) <= currTime/tick_0) { // even values in arrays are start time 
      unsigned int pp = pgm_read_word(&bach_ch_0[(index[0] << 1) + 1]); // and odd are note period. 0 - pause, 65535 - end
      if(pp == 65535){
        pp = 0;
        melodyOver[0] = 1;
      }
      currentPeriodA[0] = pp/2;
      currentPeriodB[0] = pp - pp/2;
      currentTick_0 = currentPeriodA[0];
      if(pp != 0) {
        digitalWrite(pin_active_0, LOW);
      } else { 
        digitalWrite(pin_active_0, HIGH);
        digitalWrite(pin_sound_0, LOW);
      }
      index[0]++;
    }
  }
  if(!melodyOver[1]) {
    if(pgm_read_word(&bach_ch_1[index[1] << 1]) <= currTime/tick_1) {
      unsigned int pp = pgm_read_word(&bach_ch_1[(index[1] << 1) + 1]);
      if(pp == 65535){
        pp = 0;
        melodyOver[1] = 1;
      }
      currentPeriodA[1] = pp/2;
      currentPeriodB[1] = pp - pp/2;
      currentTick_1 = currentPeriodA[1];
      if(pp != 0) {
        digitalWrite(pin_active_1, LOW);
      } else { 
        digitalWrite(pin_active_1, HIGH);
        digitalWrite(pin_sound_1, LOW);
      }
      index[1]++;
    }
  }
  if(!melodyOver[2]) {
    if(pgm_read_word(&bach_ch_2[index[2] << 1]) <= currTime/tick_2) {
      unsigned int pp = pgm_read_word(&bach_ch_2[(index[2] << 1) + 1]);
      if(pp == 65535){
        pp = 0;
        melodyOver[2] = 1;
      }
      currentPeriodA[2] = pp/2;
      currentPeriodB[2] = pp - pp/2;
      currentTick_2 = currentPeriodA[2];
      if(pp != 0) {
        digitalWrite(pin_active_2, LOW);
      } else { 
        digitalWrite(pin_active_2, HIGH);
        digitalWrite(pin_sound_2, LOW);
      }
      index[2]++;
    }
  }
  
  if(!melodyOver[3]) {
    if(pgm_read_word(&bach_ch_3[index[3] << 1]) <= currTime/tick_3) {
      unsigned int pp = pgm_read_word(&bach_ch_3[(index[3] << 1) + 1]);
      if(pp == 65535){
        pp = 0;
        melodyOver[3] = 1;
      }
      currentPeriodA[3] = pp/2;
      currentPeriodB[3] = pp - pp/2;
      currentTick_3 = currentPeriodA[3];
      if(pp != 0) {
        digitalWrite(pin_active_3, LOW);
      } else { 
        digitalWrite(pin_active_3, HIGH);
        digitalWrite(pin_sound_3, LOW);
      }
      index[3]++;
    }
  }
  if(!melodyOver[4]) {
    if(pgm_read_word(&bach_ch_4[index[4] << 1]) <= currTime/tick_4) {
      unsigned int pp = pgm_read_word(&bach_ch_4[(index[4] << 1) + 1]);
      if(pp == 65535){
        pp = 0;
        melodyOver[4] = 1;
      }
      currentPeriodA[4] = pp/2;
      currentPeriodB[4] = pp - pp/2;
      currentTick_4 = currentPeriodA[4];
      if(pp != 0) {
        digitalWrite(pin_active_4, LOW);
      } else { 
        digitalWrite(pin_active_4, HIGH);
        digitalWrite(pin_sound_4, LOW);
      }
      index[4]++;
    }
  }
  if(!melodyOver[5]) {
    if(pgm_read_word(&bach_ch_5[index[5] << 1]) <= currTime/tick_5) {
      unsigned int pp = pgm_read_word(&bach_ch_5[(index[5] << 1) + 1]);
      if(pp == 65535){
        pp = 0;
        melodyOver[5] = 1;
      }
      currentPeriodA[5] = pp/2;
      currentPeriodB[5] = pp - pp/2;
      currentTick_5 = currentPeriodA[5];
      if(pp != 0) {
        digitalWrite(pin_active_5, LOW);
      } else { 
        digitalWrite(pin_active_5, HIGH);
        digitalWrite(pin_sound_5, LOW);
      }
      index[5]++;
    }
  }
  if(!melodyOver[6]) {
    if(pgm_read_word(&bach_ch_6[index[6] << 1]) <= currTime/tick_6) {
      unsigned int pp = pgm_read_word(&bach_ch_6[(index[6] << 1) + 1]);
      if(pp == 65535){
        pp = 0;
        melodyOver[6] = 1;
      }
      currentPeriodA[6] = pp/2;
      currentPeriodB[6] = pp - pp/2;
      currentTick_6 = currentPeriodA[6];
      if(pp != 0) {
        digitalWrite(pin_active_6, LOW);
      } else { 
        digitalWrite(pin_active_6, HIGH);
        digitalWrite(pin_sound_6, LOW);
      }
      index[6]++;
    }
  }
}

/* Called by the timer inturrupt at the specified resolution. */
void tick()  // elapsed time ~12us (~50%)
{
//  If there is a period set for control pin 2, count the number of
//  ticks that pass, and toggle the pin if the current period is reached.
/////////////////////////////////////////////////////////////////////////////
    if (currentPeriodA[0]){ // if the note is on
      currentTick_0--;      // decrease tick counter
      if (currentTick_0 <= 0){ // half-period has been finished
        if (currentPosition[0] >= MAX_POSITION_0) {  // Switch head directions if end has been reached
          currentStateAdd_0 = -1;
          pinOutHigh(pin_dir_0);
        } else if (currentPosition[0] <= 0) {
          currentStateAdd_0 = 1;
          pinOutLow(pin_dir_0);
        }
        currentPosition[0] += currentStateAdd_0;    //Update currentPosition
        if(currentStateStep[0]) {
          pinOutHigh(pin_sound_0);  //Pulse the control pin
          currentStateStep[0] = LOW;
          currentTick_0 = currentPeriodA[0];
        } else {
          pinOutLow(pin_sound_0);  //Pulse the control pin
          currentStateStep[0] = HIGH;
          currentTick_0 = currentPeriodB[0];
        }
      }
    }

    if (currentPeriodA[1]){
      currentTick_1--;
      if (currentTick_1 <= 0){
        if (currentPosition[1] >= MAX_POSITION_1) {
          currentStateAdd_1 = -1;
          pinOutHigh(pin_dir_1);
        } else if (currentPosition[1] <= 0) {
          currentStateAdd_1 = 1;
          pinOutLow(pin_dir_1);
        }
        currentPosition[1] += currentStateAdd_1;    //Update currentPosition
        if(currentStateStep[1]) {
          pinOutHigh(pin_sound_1);
          currentStateStep[1] = LOW;
          currentTick_1 = currentPeriodA[1];
        } else {
          pinOutLow(pin_sound_1);  //Pulse the control pin
          currentStateStep[1] = HIGH;
          currentTick_1 = currentPeriodB[1];
        }
      }
    }

    if (currentPeriodA[2]){
      currentTick_2--;
      if (currentTick_2 <= 0){
        if (currentPosition[2] >= MAX_POSITION_2) {
          currentStateAdd_2 = -1;
          pinOutHigh(pin_dir_2);
        } else if (currentPosition[2] <= 0) {
          currentStateAdd_2 = 1;
          pinOutLow(pin_dir_2);
        }
        currentPosition[2] += currentStateAdd_2;    //Update currentPosition
        if(currentStateStep[2]) {
          pinOutHigh(pin_sound_2);  //Pulse the control pin
          currentStateStep[2] = LOW;
          currentTick_2 = currentPeriodA[2];
        } else {
          pinOutLow(pin_sound_2);  //Pulse the control pin
          currentStateStep[2] = HIGH;
          currentTick_2 = currentPeriodB[2];
        }
      }
    }

    if (currentPeriodA[3]){
      currentTick_3--;
      if (currentTick_3 <= 0){
        if(currentStateStep[3]) {
          pinOutHigh(pin_sound_3);  //Pulse the control pin
          currentStateStep[3] = LOW;
          currentTick_3 = currentPeriodA[3];
        } else {
          pinOutLow(pin_sound_3);  //Pulse the control pin
          currentStateStep[3] = HIGH;
          currentTick_3 = currentPeriodB[3];
        }
      }
    }

    if (currentPeriodA[4]){
      currentTick_4--;
      if (currentTick_4 <= 0){
        if(currentStateStep[4]) {
          pinOutHigh(pin_sound_4);  //Pulse the control pin
          currentStateStep[4] = LOW;
          currentTick_4 = currentPeriodA[4];
        } else {
          pinOutLow(pin_sound_4);  //Pulse the control pin
          currentStateStep[4] = HIGH;
          currentTick_4 = currentPeriodB[4];
        }
      }
    }

    if (currentPeriodA[5]){
      currentTick_5--;
      if (currentTick_5 <= 0){
        if(currentStateStep[5]) {
          pinOutHigh(pin_sound_5);  //Pulse the control pin
          currentStateStep[5] = LOW;
          currentTick_5 = currentPeriodA[5];
        } else {
          pinOutLow(pin_sound_5);  //Pulse the control pin
          currentStateStep[5] = HIGH;
          currentTick_5 = currentPeriodB[5];
        }
      }
    }

    if (currentPeriodA[6]){
      currentTick_6--;
      if (currentTick_6 <= 0){
        if(currentStateStep[6]) {
          pinOutHigh(pin_sound_6);  //Pulse the control pin
          currentStateStep[6] = LOW;
          currentTick_6 = currentPeriodA[6];
        } else {
          pinOutLow(pin_sound_6);  //Pulse the control pin
          currentStateStep[6] = HIGH;
          currentTick_6 = currentPeriodB[6];
        }
      }
    }
}

//Resets all the pins
void resetAll(){
  
  pinOutHigh(pin_dir_0); // reverse direction
  pinOutHigh(pin_dir_1);
  pinOutHigh(pin_dir_2);
  pinOutLow(pin_active_0); // drive enable
  pinOutLow(pin_active_1);
  pinOutLow(pin_active_2);

  // New all-at-once reset
  for (byte s=0;s<80;s++){ // For max drive's position
    pinOutHigh(pin_sound_0);
    pinOutHigh(pin_sound_1);
    pinOutHigh(pin_sound_2);
    delay(3);
    pinOutLow(pin_sound_0);
    pinOutLow(pin_sound_1);
    pinOutLow(pin_sound_2);
    delay(3);
  }
  
  currentPosition[0] = 0; // We're reset.
  currentPosition[1] = 0; // We're reset.
  currentPosition[2] = 0; // We're reset.

  pinOutLow(pin_dir_0); // forward direction
  pinOutLow(pin_dir_1);
  pinOutLow(pin_dir_2);
  pinOutHigh(pin_active_0); // drive disable
  pinOutHigh(pin_active_1);
  pinOutHigh(pin_active_2);
  pinOutHigh(pin_active_3);
  pinOutHigh(pin_active_4);
  pinOutHigh(pin_active_5);
  pinOutHigh(pin_active_6);

// 2 steps forward
  for (byte s=0;s<2;s++){ // For max drive's position
    pinOutHigh(pin_sound_0);
    pinOutHigh(pin_sound_1);
    pinOutHigh(pin_sound_2);
    delay(3);
    pinOutLow(pin_sound_0);
    pinOutLow(pin_sound_1);
    pinOutLow(pin_sound_2);
    delay(3);
  }
}
 

Файл с описанием команд быстрого вывода в порт  (спасибо Arhat)

#include <avr/pgmspace.h>

#define OREG0    PORTD 
#define OREG1    PORTD 
#define OREG2    PORTD 
#define OREG3    PORTD 
#define OREG4    PORTD 
#define OREG5    PORTD 
#define OREG6    PORTD 
#define OREG7    PORTD 
#define OREG8    PORTB 
#define OREG9    PORTB 
#define OREG10   PORTB 
#define OREG11   PORTB 
#define OREG12   PORTB 
#define OREG13   PORTB 
#define OREG14    PORTC //  PORTB 
#define OREG15    PORTC //  PORTB 
#define OREG16    PORTC 
#define OREG17    PORTC 
#define OREG18    PORTC 
#define OREG19    PORTC 
//#define OREG20    PORTC 
//#define OREG21    PORTC 
//#define OREG22    PORTC 

#define SET_MASK_0              (uint8_t)1
#define SET_MASK_1              (uint8_t)2
#define SET_MASK_2              (uint8_t)4
#define SET_MASK_3              (uint8_t)8
#define SET_MASK_4              (uint8_t)16
#define SET_MASK_5              (uint8_t)32
#define SET_MASK_6              (uint8_t)64
#define SET_MASK_7              (uint8_t)128

#define CLR_MASK_0              (uint8_t)254
#define CLR_MASK_1              (uint8_t)253
#define CLR_MASK_2              (uint8_t)251
#define CLR_MASK_3              (uint8_t)247
#define CLR_MASK_4              (uint8_t)239
#define CLR_MASK_5              (uint8_t)223
#define CLR_MASK_6              (uint8_t)191
#define CLR_MASK_7              (uint8_t)127 

#define BSET0    SET_MASK_0 
#define BCLR0    CLR_MASK_0 

#define BSET1    SET_MASK_1 
#define BCLR1    CLR_MASK_1 

#define BSET2    SET_MASK_2 
#define BCLR2    CLR_MASK_2 

#define BSET3    SET_MASK_3 
#define BCLR3    CLR_MASK_3 

#define BSET4    SET_MASK_4 
#define BCLR4    CLR_MASK_4 

#define BSET5    SET_MASK_5 
#define BCLR5    CLR_MASK_5 

#define BSET6    SET_MASK_6 
#define BCLR6    CLR_MASK_6 

#define BSET7    SET_MASK_7
#define BCLR7    CLR_MASK_7 

#define BSET8    SET_MASK_0  
#define BCLR8    CLR_MASK_0 

#define BSET9    SET_MASK_1 
#define BCLR9    CLR_MASK_1 

#define BSET10    SET_MASK_2 
#define BCLR10    CLR_MASK_2 

#define BSET11    SET_MASK_3 
#define BCLR11    CLR_MASK_3 

#define BSET12    SET_MASK_4 
#define BCLR12    CLR_MASK_4 

#define BSET13    SET_MASK_5 
#define BCLR13    CLR_MASK_5 

#define BSET14    SET_MASK_0 //    SET_MASK_6 
#define BCLR14    CLR_MASK_0 //    CLR_MASK_6

#define BSET15    SET_MASK_1 //    SET_MASK_7 
#define BCLR15    CLR_MASK_1 //    CLR_MASK_7 

#define BSET16    SET_MASK_2 //    SET_MASK_6 
#define BCLR16    CLR_MASK_2 //    CLR_MASK_6 

#define BSET17    SET_MASK_3 //    SET_MASK_0 
#define BCLR17    CLR_MASK_3 //    CLR_MASK_0 

#define BSET18    SET_MASK_4 //    SET_MASK_1 
#define BCLR18    CLR_MASK_4 //    CLR_MASK_1 

#define BSET19    SET_MASK_5 //    SET_MASK_2 
#define BCLR19    CLR_MASK_5 //    CLR_MASK_2 

//#define BSET20    SET_MASK_3 
//#define BCLR20    CLR_MASK_3 

//#define BSET21    SET_MASK_4
//#define BCLR21    CLR_MASK_4 

//#define BSET22    SET_MASK_5  
//#define BCLR22    CLR_MASK_5 

#define pinOutReg(p)    (OREG##p)
#define pinSetMask(p)   (BSET##p)
#define pinClearMask(p) (BCLR##p)
#define pinOutHigh(p) (pinOutReg(p) |= pinSetMask(p)) // out 1 (HIGH) to pin. Установка на выводе лог.1:
#define pinOutLow(p)  (pinOutReg(p) &= pinClearMask(p)) // out 0 (LOW) to pin. Установка на выводе лог.0:
#define pinOut(p,v)   ((v)? pinOutHigh(p) : pinOutLow(p)) // @see digitalWrite().

Файлы с данными
 

#include <avr/pgmspace.h>

#define tick_0 2
#define NumNotes_0 2

// Sound Sample Rate: 40000 Hz

const unsigned int bach_ch_0[] PROGMEM = {
  8640,  545,
 14385, 65535
};
#include <avr/pgmspace.h>

#define tick_1 2
#define NumNotes_1 54

// Sound Sample Rate: 40000 Hz

const unsigned int bach_ch_1[] PROGMEM = {
    10,   91,
    40,    0,
    55,  102,
    85,    0,
   105,   91,
   960,    0,
   970,  102,
  1000,    0,
  1025,  115,
  1055,    0,
  1070,  121,
  1100,    0,
  1105,  136,
  1140,    0,
  1160,  144,
  1675,    0,
  1715,  136,
  2015,    0,
  2895,  182,
  2920,    0,
  2935,  204,
  2970,    0,
  2985,  182,
  3780,    0,
  3860,  243,
  4015,    0,
  4040,  229,
  4200,    0,
  4220,  289,
  4375,    0,
  4390,  272,
  4760,    0,
  5775,  364,
  5810,    0,
  5820,  408,
  5855,    0,
  5870,  364,
  6715,    0,
  6740,  408,
  6765,    0,
  6785,  458,
  6805,    0,
  6820,  485,
  6850,    0,
  6870,  545,
  6895,    0,
  6910,  577,
  7440,    0,
  7465,  545,
  7775,    0,
  9135,  289,
 12465,    0,
 12480,  272,
 14385, 65535
};
#include <avr/pgmspace.h>

#define tick_2 2
#define NumNotes_2 52

// Sound Sample Rate: 40000 Hz

const unsigned int bach_ch_2[] PROGMEM = {
    10,   45,
    50,    0,
    65,   51,
    95,    0,
   105,   45,
   955,    0,
   980,   51,
  1010,    0,
  1020,   57,
  1055,    0,
  1070,   61,
  1100,    0,
  1105,   68,
  1145,    0,
  1150,   72,
  1680,    0,
  1705,   68,
  2015,    0,
  2900,   91,
  2930,    0,
  2935,  102,
  2975,    0,
  2980,   91,
  3785,    0,
  3860,  121,
  4020,    0,
  4035,  115,
  4205,    0,
  4210,  144,
  4385,    0,
  4400,  136,
  4755,    0,
  5775,  182,
  5810,    0,
  5815,  204,
  5865,    0,
  5870,  182,
  6715,    0,
  6740,  204,
  6780,    0,
  6775,  229,
  6820,    0,
  6830,  243,
  6860,    0,
  6875,  272,
  6905,    0,
  6910,  289,
  7440,    0,
  7465,  272,
  7770,    0,
  9600,  243,
 12465, 65535
};
#include <avr/pgmspace.h>

#define tick_3 2
#define NumNotes_3 7

// Sound Sample Rate: 40000 Hz

const unsigned int bach_ch_3[] PROGMEM = {
 10095,  204,
 12405,    0,
 12480,  204,
 12945,    0,
 12975,  243,
 13440,  216,
 14385, 65535
};
#include <avr/pgmspace.h>

#define tick_4 2
#define NumNotes_4 4

// Sound Sample Rate: 40000 Hz

const unsigned int bach_ch_4[] PROGMEM = {
 10560,  172,
 12465,    0,
 12480,  182,
 14385, 65535
};


#include <avr/pgmspace.h>

#define tick_5 2
#define NumNotes_5 54

// Sound Sample Rate: 40000 Hz

const unsigned int bach_ch_5[] PROGMEM = {
     0,   91,
    30,    0,
    45,  102,
    75,    0,
    90,   91,
   945,    0,
   960,  102,
   990,    0,
  1005,  115,
  1035,    0,
  1050,  121,
  1080,    0,
  1095,  136,
  1125,    0,
  1140,  144,
  1665,    0,
  1695,  136,
  1995,    0,
  2880,  182,
  2910,    0,
  2925,  204,
  2955,    0,
  2970,  182,
  3765,    0,
  3840,  243,
  4005,    0,
  4020,  229,
  4185,    0,
  4200,  289,
  4365,    0,
  4380,  272,
  4740,    0,
  5760,  364,
  5790,    0,
  5805,  408,
  5835,    0,
  5850,  364,
  6705,    0,
  6720,  408,
  6750,    0,
  6765,  458,
  6795,    0,
  6810,  485,
  6840,    0,
  6855,  545,
  6885,    0,
  6900,  577,
  7425,    0,
  7455,  545,
  7755,    0,
 11055,  144,
 12465,    0,
 12480,  136,
 14385, 65535
};
#include <avr/pgmspace.h>

#define tick_6 2
#define NumNotes_6 52

// Sound Sample Rate: 40000 Hz

const unsigned int bach_ch_6[] PROGMEM = {
     0,   45,
    30,    0,
    45,   51,
    85,    0,
    90,   45,
   945,    0,
   960,   51,
  1000,    0,
  1005,   57,
  1045,    0,
  1050,   61,
  1090,    0,
  1095,   68,
  1135,    0,
  1140,   72,
  1665,    0,
  1695,   68,
  1995,    0,
  2880,   91,
  2910,    0,
  2925,  102,
  2965,    0,
  2970,   91,
  3765,    0,
  3840,  121,
  4005,    0,
  4020,  115,
  4185,    0,
  4200,  144,
  4365,    0,
  4380,  136,
  4740,    0,
  5760,  182,
  5790,    0,
  5805,  204,
  5845,    0,
  5850,  182,
  6705,    0,
  6720,  204,
  6760,    0,
  6765,  229,
  6805,    0,
  6810,  243,
  6850,    0,
  6855,  272,
  6895,    0,
  6900,  289,
  7425,    0,
  7455,  272,
  7755,    0,
 11520,  121,
 12480, 65535
};

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ахренеть!

Снимаю шляпу!

karl2233
karl2233 аватар
Offline
Зарегистрирован: 05.07.2015

крутотень! а Ду Хаст можно так сделать?

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

В принципе можно сделать что угодно - 7 голосов достаточно для вменяемой аранжировки любого произведения. В частности, в том фрагменте, что на видео, у Баха звучит максимум 9 нот, так что кое-где пришлось подсократить октаву.

С другой стороны, звук принципиально без динамики. Так что впечатление от результата может быть делеким от желаемого. Наиболее адекватно звучат органные партии.

karl2233
karl2233 аватар
Offline
Зарегистрирован: 05.07.2015

понял, спасибо за ответ.

примерно так и подумал (про органные партии).