Tracker

vypracoval: Martin Řehák




Stručný popis:

     Snaha programu byla alespoň částečně napodobit 4-kanálovou FM/Wavetable syntézu, která se používá ke generování zvuku na PC (a jinde). Klasickým představitelem jsou hudební soubory .MOD, .XM, .S3M, .IT... Program na editaci a přehrávání se nazývá tracker. Každý hudební nástroj (ať už digitalizovaný sampl, nebo parametrický oscilátor) má svoji stopu (track), ve které je uložen notový zápis a všechny potřebné parametry nástroje. Signály z těchto stop se přehrávají součastně a mixují v mixeru (na zvukové kartě je obvykle HW mixer), čímž se získá výsledný polyfonní zvuk. Dříve bylo možno mixovat jen 4 kanály (např. 8bit Commodore), nyní jich lze mixovat stovky. Protože se v souboru uchovávaly pouze parametry, případně krátké samply, tak byl výsledný soubor relativně malý (od pár kB po max. asi 1MB).

Implementace:

     Můj jednoduchý tracker umožňuje přehrávat 4 kanály, z toho 2 jsou pro bicí a dva pro nezávislé melodie. Pro bicí si na začátku programu do dvou polí drum[], hihat[] předgeneruji signál bubnu a činelu (funkce gen_drum() a gen_hihat()). Buben se mi podařilo vygenerovat celkem jednoduše pomocí exponenciálně tlumené sinusovky nízké frekvence:

drum waveform

S úderem činelu jsem různě experimentoval a nejlépe se tomu podobala exponenciálně tlumená směs sinusovky vysoké frekvence a šumu. Bez šumu to znělo spíš jak úder kladiva do kovadliny.

hihat waveform

     Další dva kanály pro melodii fungují jako generátory obdélníkového signálu (díky harmonickým je zvuk 'bohatší' než u sinu a snadno se generuje) s nastavitelnou frekvencí.

melody waveform

Stopy pro jednotlivé kanály jsou uložené ve 4 polích konstant drum_track[], hihat_track[], melody_track[] a melody2_track[]. V polích pro bicí se udává amplituda, reps. dělitel, lze tedy ovlivnit pouze hlasitost. Pro hodnotu 0 nástroj nehraje vůbec. Navíc lze ještě nastavit globální amplitudu bicích pomocí proměnných gd, gh. V polích pro melodii se naopak nastavuje požadovaná frekvence a amplitudu lze měnit pouze globálně (gm1, gm2). Pro hodnotu 0 nástroj nehraje vůbec. Pro snazší zápis not jsem napřed definoval noty a jejich frekvence (v rozsahu c1-h3). Hodnoty do polí jsem přepsal z .XM souboru.
     Jádro programu tvoří softwarový mixer - funkce my_tracker() nastavená jako běžící uživatelský task s nejvyšší prioritou, kde se v hlavní smyčce do - while směšuje výstup funkcí play_drum() (DIP1), play_hihat() (DIP2), play_melody() (DIP3), play_melody2() (DIP4). Jednotlivé kanály lze navíc zapnout/vypnout DIP spínači a jejich aktivita je indikovaná odpovídajícími LED. Důležitý je globální čas t, který se inkrementuje s každým přehraným vzorkem a podle nějž se časuje přehrávání z jednotlivých funkcí. V každé play_...() funkci je třeba uchovávat informaci o čísle přehrávaného vzorku a pozici ve stopě. Každý element stopy má délku danou fs/teps, kde teps udává tempo přehrávání s počtech elementů stopy za sekundu.
     Při vzorkovací frekvenci 48kHz už program nestíhal přehrávat všechny 4 stopy a náhodně se zpomaloval. Pro 2 stopy to fungovalo. Takže 4 stopy lze přehrávat max. při fs=24kHz. Zde je výsledný hudební signál (nasamplovaný zvukovkou) tracker.mp3.



Výpis programu:

tone.c

/****************************************************************************/
/*                           Simple tracker 0.1                             */
/****************************************************************************/
/* Created: 5. 1. 2005 [TI-C54X]                                            */
/* Last modified: 7. 1. 2005 [TI-C54X]                                      */
/* Copyright (C) 2005 by Martin Rehak                                       */
/* Contact: rehakm2@feld.cvut.cz                                            */
/****************************************************************************/

// hlavicky viz TIROOT\C5400\DSK5416\INCLUDE
#include "tonecfg.h"                   // automaticky generovano z konfigurace
#include "dsk5416.h"                   // specificke I/O registry CPLD
#include "dsk5416_led.h"               // fce na ovladani LED
#include "dsk5416_dip.h"               // fce na cteni DIP prepinace
#include "dsk5416_pcm3002.h"           // fce na ovladani kodeku
#include <stdlib.h>                    // fce rand()
#include <math.h>                      // mat. fce (sinus,..)

// ovladani generatoru se deje pres globalni promene - MENU/EDIT/Variable...
#define fs 24000                       // vzorkovaci frekvence kodeku (6000, 8000, 12000, 24000, 48000)
#define teps 9                         // track element per second
int g=255;                             // zisk (amplituda vystupniho signalu) 0-255
float gd=0.7;                          // zisk pro kanal bubnu
int gh=4;                              // delitel pro kanal cinelu
int gm1=50;                            // delitel pro kanal melodie
int gm2=100;                           // delitel pro kanal melodie 2
int r=1;                               // flag pro ukonceni programu
int output;                            // vystupni zmixovany signal
long t=0;                              // globalni cas
#define drum_len (fs/teps-1)           // velikost pole drum
#define hihat_len (fs/teps-1)          // velikost pole hihat
#define melody_len (fs/teps-1)         // pocet vzorku melodie na element stopy
#define melody2_len (fs/teps-1)        // pocet vzorku melodie2 na element stopy
int drum_pos=0;                        // aktualni pozice vzorku
int hihat_pos=0;                       // aktualni pozice vzorku
int melody_pos=0;                      // aktualni pozice vzorku
int melody_s1=32000;
int melody_s2=0;
int melody2_pos=0;                     // aktualni pozice vzorku
int melody2_s1=32000;
int melody2_s2=0;
int drum[drum_len];                    // pole samplu
int hihat[hihat_len];                  // pole samplu
#define PI ((double)3.1415927)

DSK5416_PCM3002_Config setup = {       // defaultni nastaveni kodeku
  0x01FF,                              // Set-Up Reg 0 - Left channel DAC attenuation (1ff=0dB)
  0x01FF,                              // Set-Up Reg 1 - Right channel DAC attenuation
  0x0,                                 // Set-Up Reg 2 - Various ctl e.g. power-down modes
  0x0                                  // Set-Up Reg 3 - Codec data format control
};

/****************************************************************************/
#define drum_track_step (fs/teps)      // elementy tabulky po kroku 1/8s
int drum_track_pos=0;                  // cislo=delitel amplitudy, 0=vypnuto
int drum_track[]={
1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0,    // p1
1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0,
1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0,
1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0,

1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0,    // p2
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,
1,0,0,0, 1,0,0,0, 1,0,0,0, 1,0,0,0,
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,1,1,1,

1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,    // p3
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,1,
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,

1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,    // p4=p3
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,1,
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,

1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,    // p5=p3
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,1,
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,

1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,    // p6=p3
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,1,
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,

1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,    // p7=p3
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,1,
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,

1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,    // p8
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,1,
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,0,0,0,
1,0,0,0, 1,0,0,1, 1,1,0,0, 1,1,1,1,
};

#define hihat_track_step (fs/teps)     // elementy tabulky po kroku 1/8 s
int hihat_track_pos=0;
int hihat_track[]={
1,10,10,10, 1,10,10,10, 1,10,10,10, 1,10,10,10, // p1
1,10,10,10, 1,10,10,10, 1,10,10,10, 1,10,10,10,
1,10,10,10, 1,10,10,10, 1,10,10,10, 1,10,10,10,
1,10,10,10, 1,10,10,10, 1,10,10,10, 1,10,10,10,

1,10,10,10, 1,10,10,10, 1,10,10,10, 1,10,10,10, // p2
1,10,10,10, 1,10,10,2,  1,2,10,10,  1,10,10,10,
1,10,10,10, 1,10,10,10, 1,10,10,10, 1,10,10,10,
1,10,10,10, 1,10,10,2,  1,2,10,10,  1,2,2,2,

1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10, // p3
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,2,
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10,
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10,

1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10, // p4=p3
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,2,
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10,
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10,

1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10, // p5=p3
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,2,
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10,
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10,

1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10, // p6=p3
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,2,
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10,
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10,

1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10, // p7=p3
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,2,
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10,
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10,

1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10, // p8
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,2,
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,10,10,10,
1,10,10,10, 1,10,10,2, 1,2,10,10, 1,2,2,2,
};

#define c1  264                        // noticky [Hz]
#define d1  297
#define e1  330
#define f1  352
#define g1  396
#define a1  440
#define a1_ 466
#define h1  494
#define c2  523
#define c2_ 554
#define d2  587
#define d2_ 622
#define e2  659
#define f2  698
#define f2_ 740
#define g2  784
#define g2_ 831
#define a2  880
#define a2_ 932
#define h2  988
#define c3  1047
#define c3_ 1109
#define d3  1175
#define d3_ 1245
#define e3  1319
#define f3  1397
#define f3_ 1480
#define g3  1568
#define g3_ 1661
#define a3  1760
#define a3_ 1865
#define h3  1976

#define melody_track_step (fs/teps)    // elementy tabulky po kroku 1/8 s
int melody_track_pos=0;
int melody_track[]={
a1,a1,a2, a1,a1,a2, a1,a1,a2, a1,a1,a2, a1,a1,a2, // p1
a1,a1,a1,a2,
a1,a1,a2, a1,a1,a2, a1,a1,a2, a1,a1,a2,
a1,g1,g1,g2,
g1,g1,g2, g1,g1,g2, g1,g1,g2, g1,g1,g2,
g1,g1,g1,g2,
g1,g1,g2, g1,g1,g2, g1,g1,g2, g1,g1,g2, g1,

d1,d1,d2, d1,d1,d2, d1,d1,d2, d1,d1,d2, d1,d1,d2, // p2
d1,d1,d1,d2,
d1,d1,d2, d1,d1,d2, d1,d1,d2, d1,d1,d2,
d1,e1,e1,e2,
e1,e1,e2, e1,e1,e2, e1,e1,e2, e1,e1,e2,
e1,e1,e1,e2,
e1,e1,e2, e1,e1,f2, f1,f1,f2, g1,g1,g2, g1,

a1,a1,a2, a1,a1,a2, a1,a1,a2, a1,a1,a2, a1,a1,a2, // p3
a1,a1,a1,a2,
a1,a1,a2, a1,a1,a2, a1,a1,a2, a1,a1,a2,
a1,g1,g1,g2,
g1,g1,g2, g1,g1,g2, g1,g1,g2, g1,g1,g2,
g1,g1,g1,g2,
g1,g1,g2, g1,g1,g2, g1,g1,g2, g1,g1,g2, g1,

d1,d1,d2, d1,d1,d2, d1,d1,d2, d1,d1,d2, d1,d1,d2, // p4
d1,d1,d1,d2,
d1,d1,d2, d1,d1,d2, d1,d1,d2, d1,d1,d2,
d1,e1,e1,e2,
e1,e1,e2, e1,e1,e2, e1,e1,e2, e1,e1,e2,
e1,e1,e1,e2,
e1,e1,e2, e1,e1,f2, f1,f1,f2, g1,g1,g2, g1,

c1,c1,c2, c1,c1,c2, c1,c1,c2, c1,c1,c2, c1,c1,c2, // p5
c1,c1,c1,c2,
c1,c1,c2, c1,c1,c2, c1,c1,c2, c1,c1,c2,
c1,e1,e1,e2,
e1,e1,e2, e1,e1,e2, e1,e1,e2, e1,e1,e2,
e1,e1,e1,e2,
e1,e1,e2, e1,e1,e2, e1,e1,e2, e1,e1,e2, e1,

f1,f1,f2, f1,f1,f2, f1,f1,f2, f1,f1,f2, f1,f1,f2, // p6
f1,f1,f1,f2,
f1,f1,f2, f1,f1,f2, f1,f1,f2, f1,f1,f2,
f1,c1,c1,c2,
c1,c1,c2, c1,c1,c2, c1,c1,c2, c1,c1,c2,
c1,g1,g1,g2,
g1,g1,g2, g1,g1,g2, g1,g1,g2, g1,g1,g2, g1,

c1,c1,c2, c1,c1,c2, c1,c1,c2, c1,c1,c2, c1,c1,c2, // p7=p5
c1,c1,c1,c2,
c1,c1,c2, c1,c1,c2, c1,c1,c2, c1,c1,c2,
c1,e1,e1,e2,
e1,e1,e2, e1,e1,e2, e1,e1,e2, e1,e1,e2,
e1,e1,e1,e2,
e1,e1,e2, e1,e1,e2, e1,e1,e2, e1,e1,e2, e1,

a1,a1,a2, a1,a1,a2, a1,a1,a2, a1,a1,a2, a1,a1,a2, // p8=p1
a1,a1,a1,a2,
a1,a1,a2, a1,a1,a2, a1,a1,a2, a1,a1,a2,
a1,g1,g1,g2,
g1,g1,g2, g1,g1,g2, g1,g1,g2, g1,g1,g2,
g1,g1,g1,g2,
g1,g1,g2, g1,g1,g2, g1,g1,g2, g1,g1,g2, g1,
};

#define melody2_track_step (fs/teps)   // elementy tabulky po kroku 1/8 s
int melody2_track_pos=0;
int melody2_track[]={
c3,e2,a2,c3, c3,a2,e2,c3, c3,e2,a2,c3, c3,a2,e2,c3, // p1
c3,e2,a2,c3, c3,a2,e2,c3, c3,e2,a2,c3, c3,a2,e2,c3,
d3,e2,c3,d3, d3,c3,g2,d3, d3,g2,c3,d3, d3,c3,g2,d3,
d3,g2,c3,d3, d3,c3,g2,d3, d3,g2,c3,d3, d3,c3,g2,d3,

f3,a2,e3,f3, f3,e3,a2,f3, f3,a2,e3,f3, f3,e3,a2,f3, // p2
f3,a2,e3,f3, f3,e3,a2,f3, f3,a2,e3,f3, f3,e3,a2,f3,
e3,a2,d3,e3, e3,d3,a2,e3, e3,a2,d3,e3, e3,d3,a2,e3,
e3,a2,d3,e3, e3,d3,a2,e3, e3,a2,d3,e3, e3,d3,a2,e3,

c3,e2,a3,c3, c3,a3,e2,c3, c3,e2,a3,c3, c3,a3,e2,c3, // p3
c3,e2,a3,c3, c3,a3,e2,c3, c3,e2,a3,c3, c3,a3,e2,c3,
d3,e2,c3,d3, d3,c3,g2,d3, d3,g2,c3,d3, d3,c3,g2,d3,
d3,g2,c3,d3, d3,c3,g2,d3, d3,g2,c3,d3, d3,c3,g2,d3,

f3,a2,e3,f3, f3,e3,a2,f3, f3,a2,e3,f3, f3,e3,a2,f3, // p4=p1
f3,a2,e3,f3, f3,e3,a2,f3, f3,a2,e3,f3, f3,e3,a2,f3,
e3,a2,d3,e3, e3,d3,a2,e3, e3,a2,d3,e3, e3,d3,a2,e3,
e3,a2,d3,e3, e3,d3,a2,e3, e3,a2,d3,e3, e3,d3,a2,e3,

e3,g2,d2,e3, e3,d2,g2,e3, e3,g2,d2,e3, e3,d2,g2,e3, // p5
e3,g2,d2,e3, e3,d2,g2,e3, e3,g2,d2,e3, e3,d2,g2,e3,
e3,a2,d3,e3, e3,d3,a2,e3, e3,a2,d3,e3, e3,d3,a2,e3,
e3,a2,d3,e3, e3,d3,a2,e3, e3,a2,d3,e3, e3,d3,a2,e3,

c3,f2,a3,c3, c3,a3,f2,c3, c3,f2,a3,c3, c3,a3,f2,c3, // p6
c3,e2,a3,c3, c3,a3,e2,c3, c3,e2,a3,c3, c3,a3,e2,c3,
e3,g2,d2,e3, e3,d2,g2,e3, e3,g2,d2,e3, e3,d2,g2,e3,
d3,g2,c2,d3, d3,c2,g2,d3, d3,g2,c2,d3, d3,c2,g2,d3,

e3,a2,d3,e3, e3,d3,a2,e3, e3,a2,d3,e3, e3,d3,a2,e3, // p7
e3,a2,d3,e3, e3,d3,a2,e3, e3,a2,d3,e3, e3,d3,a2,e3,
e3,a2,d3,e3, e3,d3,a2,e3, e3,a2,d3,e3, e3,d3,a2,e3,
e3,a2,d3,e3, e3,d3,a2,e3, e3,a2,d3,e3, e3,d3,a2,e3,

c3,e2,a3,c3, c3,a3,e2,c3, c3,e2,a3,c3, c3,a3,e2,c3, // p8
c3,e2,a3,c3, c3,a3,e2,c3, c3,e2,a3,c3, c3,a3,e2,c3,
d3,e2,c3,d3, d3,c3,g2,d3, d3,g2,c3,d3, d3,c3,g2,d3,
d3,g2,c3,d3, d3,c3,g2,d3, d3,g2,c3,d3, d3,c3,g2,d3,
};

int track_len=sizeof(drum_track)/sizeof(float);

/****************************************************************************/
void gen_drum(int *p_array, int len)   // vygeneruj sampl bubnu
{
  int i;
  for (i=0; i<len; i++)
    p_array[i]=32760*sin(i/(fs/400.0))*exp(-i*0.00165); // w=400, delta=0.00165
}

void gen_hihat(int *p_array, int len)  // vygeneruj sampl cinelu
{
  int i;
  for (i=0; i<len; i++)                // rand() (0,32767)
    p_array[i]=32760*(sin(2*i)/4.0+(rand()/32767.0)-0.5)*exp(-i*0.00165); // w=2, delta=0.00165
}

void play_drum(float global_drum_gain) // pricti do vystupniho signalu buben
{
  if ((t%drum_track_step==0)||(drum_pos!=0))
    {
    if (drum_track[drum_track_pos]>0)
      output+=(int)(global_drum_gain*drum[drum_pos]/drum_track[drum_track_pos]);
    drum_pos++;                        // posun pozici
    if (drum_pos>=drum_len)            // pokud se prehral sampl cely
      drum_pos=0;                      // vynuluj pocitadlo
    }
  if (drum_track[drum_track_pos]>0)
    DSK5416_LED_on(0);
  else
    DSK5416_LED_off(0);
  if (t%drum_track_step==0)
    drum_track_pos++;                  // posun pozici stopy
  if (drum_track_pos>=track_len)       // konec tracku?
    r=0;                               // skonci cely program
}

void play_hihat(int global_hihat_gain) // pricti do vystupniho signalu cinel
{
  if ((t%hihat_track_step==0)||(hihat_pos!=0))
    {
    output+=(hihat[hihat_pos]/hihat_track[hihat_track_pos])/global_hihat_gain;
    hihat_pos++;                       // posun pozici
    if (hihat_pos>=hihat_len)          // pokud se prehral sampl cely
      hihat_pos=0;                     // vynuluj pocitadlo
    }
  if (hihat_track[hihat_track_pos]>0)
    DSK5416_LED_on(1);
  else
    DSK5416_LED_off(1);
  if (t%hihat_track_step==0)
    hihat_track_pos++;                 // posun pozici stopy
  if (hihat_track_pos>=track_len)      // konec tracku?
    r=0;                               // skonci cely program
}

void play_melody(int global_melody_gain) // pricti do vystupniho signalu melodii
{
  if ((t%melody_track_step==0)||(melody_pos!=0))
    {
    if (melody_track[melody_track_pos]>0)
      output+=melody_s1/global_melody_gain;
    melody_s2++;
    if (melody_s2>=fs/(melody_track[melody_track_pos]/2))
      {
      melody_s1=-melody_s1;
      melody_s2=0;
      }
    melody_pos++;                      // posun pozici
    if (melody_pos>=melody_len)        // pokud se prehral sampl cely
      melody_pos=0;                    // vynuluj pocitadlo
    }
  if (melody_track[melody_track_pos]>0)
    DSK5416_LED_on(2);
  else
    DSK5416_LED_off(2);
  if (t%melody_track_step==0)
    melody_track_pos++;                // posun pozici stopy
  if (melody_track_pos>=track_len)     // konec tracku?
    r=0;                               // skonci cely program
}

void play_melody2(int global_melody2_gain) // pricti do vystupniho signalu melodii 2
{
  if ((t%melody2_track_step==0)||(melody2_pos!=0))
    {
    if (melody2_track[melody2_track_pos]>0)
      output+=melody2_s1/global_melody2_gain;
    melody2_s2++;
    if (melody2_s2>=fs/(melody2_track[melody2_track_pos]/2))
      {
      melody2_s1=-melody2_s1;
      melody2_s2=0;
      }
    melody2_pos++;                     // posun pozici
    if (melody2_pos>=melody2_len)      // pokud se prehral sampl cely
      melody2_pos=0;                   // vynuluj pocitadlo
    }
  if (melody2_track[melody2_track_pos]>0)
    DSK5416_LED_on(3);
  else
    DSK5416_LED_off(3);
  if (t%melody2_track_step==0)
    melody2_track_pos++;               // posun pozici stopy
  if (melody2_track_pos>=track_len)    // konec tracku?
    r=0;                               // skonci cely program
}

void my_tracker(void)                  // uzivatelska uloha spustena jadrem
{
  DSK5416_PCM3002_CodecHandle hcodec;  // handler kodeku

  gen_drum(drum,sizeof(drum));
  gen_hihat(hihat,sizeof(hihat));

  hcodec=DSK5416_PCM3002_openCodec(0, &setup); // spust kodek
  DSK5416_PCM3002_setFreq(hcodec,fs);  // nastav vzorkovaci frekvenci kodeku (6000, 8000, 12000, 24000, 48000)
  DSK5416_PCM3002_outGain(hcodec,g);   // aktualizace nastaveni vystupni amplitudy

  do
    {
    if (DSK5416_DIP_get(0))
      play_drum(gd);
    if (DSK5416_DIP_get(1))
      play_hihat(gh);
    if (DSK5416_DIP_get(2))
      play_melody(gm1);
    if (DSK5416_DIP_get(3))
      play_melody2(gm2);

    while (!DSK5416_PCM3002_write16(hcodec,output)); //pravy kanal
    while (!DSK5416_PCM3002_write16(hcodec,output)); // levy kanal
    output=0;                          // vyresetuj vyst. vzorek
    t++;                               // pocitej globalni cas
    } while (r!=0);

  DSK5416_LED_off(0);
  DSK5416_LED_off(1);
  DSK5416_LED_off(2);
  DSK5416_LED_off(3);
  DSK5416_PCM3002_closeCodec(hcodec);  // uzavri kodek
}

void main()
{
  DSK5416_init();                      // inicializace knihovny pro ovladani I/O desky
  DSK5416_DIP_init();                  // inicializace DIP prepinacu
  DSK5416_LED_init();                  // inicializace LEDek
}