/*
 * Diplomová práce
 *
 * magisterský navazující studijní obor Audio inženýrství
 * Ústav telekomunikací
 *
 * Název:					Sluchátka s adaptivním potlačením šumu
 *
 * Autor:					Bc. Vojtěch Panenka			ID: 174370
 * Vedoucí práce:			doc. Ing. Petr Sysel, Ph.D
 *
 * Ročník:					2019/2020
 */

/*
 * Teto kód je realizován na vývojové desce TMS320C6416T DSK od firmy Texas Instruments Incorporated.
 *
 * DSP čip na této desce, TMS320C6416T, operuje v šestnáctibitové aritmetice s pevnou řádovou čárkou (fixed-point).
 * Většina výpočetních operací v tomto kódu je tomu přizpůsobena, především využíváním tzv. intrinsic funkcí,
 * které jsou definovány a popsány v dokumentu "spru198" - TMS320C6000 Programmer’s Guide.
 *
 */

#include <std.h>

#include <log.h>
#include <sts.h>
#include <clk.h>

#include <stdlib.h>
#include <math.h>
#include <stdio.h>

#include "dsk6416.h"									// Obsluha vývojové desky TMS320C6146T DSK
#include "dsk6416_dip.h"								// Obsluha fyzických přepínačů na vývojové desce
#include "dsk6416_led.h"								// Obsluha fyzických LED diod na vývojové desce

#include "hellocfg.h"

#include "aic23.h"										// Nastavení a obsluha zvukového kodeku

#include "dsp_fir_r4.h"									// Optimalizovaná funkce pro realizaci diskrétního FIR filtru
#include "dsp_firlms2.h"								// Optimalizované funkce pro realizaci LMS bloku pro výpočet nových koeficientů

#include "noise.h"										// Uložení předem určených 132 072 (2^17 + 1000) vzorků růžového šumu do proměnné "noise"
															// a následné přesunutí této proměnné do externí paměti SDRAM na vývojové desce
															// jde o přibližně 1,3 sekundy signálu při vzorkovacím kmitočtu 96 kHz

static AIC23_ConfigTab CodecCfg = AIC23_DEFAULTCONFIG;	// Výchozí konfigurace kodeku

//#define	FLOAT2FIXED(x)	((x) >= 0 ? ((Int16)((x)*32768+0.5 )) : ((Int16)((x)*32768-0.5)))
														// Předpis pro převod hodnot z rozsahu <-1;1) do rozsahu datového typu short <-32768;32767>

# define N (96)											// Počet koeficientů adaptivního filtru (řád filtru + 1)

short outMicBuffer[N+3];								// Zásobník pro ukládání vstupních vzorků z proměnné "outMic"
//#pragma DATA_SECTION( outMicBuffer,".EXTRAM") 		// Možnost uložení proměnné do externí paměti SDRAM
short delay[32];										// Zásobník pro realizaci zpoždění až o 31 vzorků
//#pragma DATA_SECTION( delay,".EXTRAM")
short delayBuffer[N+3];									// Zásobník pro ukládání vzorků z výstupu zpožďovacího zásobníku "delay"
//#pragma DATA_SECTION( delayBuffer,".EXTRAM")
short h1[N];											// Pole koeficientů určených pro LAC1
//#pragma DATA_SECTION( h1,".EXTRAM")
short h2[N];											// Pole koeficientů určených pro LAC2
//#pragma DATA_SECTION( h2,".EXTRAM")
short mem[N];											// Krátkodobá paměť pro uložení potřebných vzorků
int nh = N;												// Počet koeficientů v "h1" a "h2"
short r1[4];											// Výstupní vzorky LAC1
short r2[4];											// Výstupní vzorky LAC2
int nr = 4;												// Počet vzorků v "r1" a "r2"
short b = 0;											// Aktuální hodnota chyby odečtu/chyby adaptace (error signal)
const short nd = 32;									// Délka zásobníku "delay"
short dlyRead = 0;										// Index pro čtení ze zásobníku "delay"
short dlyWrite = 18;									// Index pro zápis do zásobníku "delay"

short k = 0;											// Konstanta pro postupnou navigaci programem

/*
short fxfir( const short x[], short h[], int nh){
	//
	// Funkce většinově nahrazující interní funkci DSP_fir_r4, realizuje výpočet diskrétního FIR filtru
	//
	//  - x[] = pole vstupních vzorků o délce "nh", na první pozici je vždy nejnovější vzorek
	//  - h[] = pole koeficientů pro výpočet FIR filtru
	//  - nh = počet prvků v poli "h" a "x"
	//

	int i;
	int accu = 0;
	short yn = 0;

	for (i = 0; i < nh; i++){
		// accu += (h[i] * x[i]);
		accu = _sadd( accu, _smpy( h[i], x[i] ) );		
	}

	yn = _sadd( 0x00008000, accu) >> 16;

	return yn;
}

void fxlms(short h, const short x,  short  b, int nh ){
	//
	// Funkce částečně nahrazující interní funkci DSP_firlms2, realizuje výpočet a adaptaci nových koeficientů FIR filtru pro následující cyklus
	//
	//  - h[] = pole koeficientů pro výpočet FIR filtru
	//  - x[] = pole vstupních vzorků o délce "nh", na první pozici je vždy nejnovější vzorek
	//  - b = chybový signál, na jehož základě probíhá adaptace koeficientů
	//  - nh = počet prvků v poli "h" a "x"
	//

	int i;
	int accu;

	for (i = 0; i < nh; i++){
		//w[i] += b*x[i];
		accu = _sshl( h[i], 16);
		accu = _sadd( accu, _smpy(b, x[i]) );
		h[i] = _sadd( 0x00008000, accu) >> 16;
	}
}
*/

void process( void)										// Funkce process je spuštěna jako "task" (= úloha, vlákno) operačním systémem DSP/BIOS
{
	Int32 sample;										// Celý vstupní vzorek (32 bitů pro dva 16 bitové kanály)
	Int16 left, right, inMic, outMic;					// Vstupní vzorky jednotlivých kanálů
	Int16 meas = {0}, head = {0};						// Výstupní hodnoty jednotlivých kanálů
															// označení odvozeno od reálného využití pro lepší orientaci napříč programem
	Int32 accu;											// Dočasná pomocná proměnná pro výpočty s rozlišením 32 bitů

	Int32 t = 0;										// Index pro čtení z pole "noise" - cyklické přehrávání růžového šumu z externí paměti

	if( AIC23_OpenCodec( &CodecCfg) < 0)				// Čekání na spuštění zvukového kodeku
		return;

	AIC23_SetFreq( AIC23_FREQ_96KHZ);					// Nastavení vzorkovacího kmitočtu na 96 kHz
	AIC23_InGain(23);									// Nastavení vstupního zesílení kodeku na hodnotu 23 (z rozsahu 0-127)
	AIC23_OutGain(127);									// Nastavení výstupního zesílení kodeku na hodnotu 127 (z rozsahu 0-127)

	AIC23_Loopback(0);									// Možnost propojit přímo v kodeku signál ze vstupu na výstup - použití pro diagnostiku a vývoj
	AIC23_Mute(0);										// Možnost vypnout zvukový výstup přímo v kodeku - použití pro diagnostiku a vývoj


	while( 1)											// Hlavní cyklus, který realizuje čtení vstupního, výpočet a následný zápis výstupního vzorku
	{

			int i;										// Pomocná proměnná

// READ INPUT SAMPLE

			AIC23_Read( &sample);						// Čtení celého aktuálního vzorku z kodeku AIC23 a jeho uložení do proměnné "sample"
															// (32 bitů pro dva kanály po 16 bitech)

			left = _ext( sample, 0, 16);				// Izolace 16 bitů levého kanálu
			right = _ext( sample, 16, 16);				// Izolace 16 bitů pravého kanálu

// INPUT ROUTING MATRIX													// Sekce pro uložení správných vstupních vzorků do správných proměnných

			inMic = left;												// Signál z vnitřního mikrofonu je uložen do proměnné inMic
			outMic = right;												// Signál z vnějšího mikrofonu je uložen do proměnné outMic

// PROCESSING															// Sekce pro realizaci samotného výpočtu
																			// navigace v této sekci je realizována pomocí proměnné "k"
																			// jednotlivé fáze se přepínají pomocí prvního HW přepínače na vývojové desce


			if( DSK6416_DIP_get(0)){									// Čtení hodnoty prvního HW přepínače na vývojové desce
																			// tímto přepínačem je řízen přechod mezi jednotlivými fázemi programu

				if(k == 1)
					// Transition before Primary Path estimation		// Přechod předcházející aproximaci přenosu PRIMÁRNÍ zvukové cesty
					k = 2;
				if(k == 3)
					// Transition to re-adjust Primary Path estimation	// Přechod předcházející opakované aproximaci přenosu PRIMÁRNÍ zvukové cesty
					k = 2;

				switch (k){
					case 0:
						// Phase 1 - system ID - Secondary Path			// První fáze - aproximace přenosu SEKUNDÁRNÍ zvukové cesty

						head = noise[t+100] >> 1;						// Do výstupu "head" je posílán růžový šum čtený z externí paměti na vývojové desce
																			// amplituda signálu je následně snížena na polovinu pro dosažení optimálního
																			// chování při LMS adaptaci (úroveň určena experimentálně)

						delay[dlyWrite] = noise[t+100] >> 1;			// Ten stejný šumový signál je uložen na vstupní pozici do zásobníku "delay"
						accu = delay[dlyRead];

						*(short *)&delayBuffer[0] = accu;				// Hodnota šumového signálu zpožděná o 18 vzorků je následně uložena na první pozici
																			// v zásobníku "delayBuffer"

						DSP_fir_r4( delayBuffer, h1, r1, nh, nr);		// Realizace LAC1
						//r1[0] = fxfir(delayBuffer, h1, nh);				// LAC = linear adaptive combiner
																			// jde o odborné označení diskrétního FIR filtru s proměnnými koeficienty

						meas = r1[0];									// Do výstupu "meas" je posílán výstup LAC1 pro možnost měření jeho přenosu

						accu = _smpy(r1[0], -32768);					// Výstup LAC1 je následně invertován
						r1[0] = _sadd(accu, 0x00008000) >> 16;

						b = b >> 2;										// Chybový signál je před výpočtem nových koeficientů násoben konstantou 0.25

						accu = DSP_firlms2( h1, delayBuffer, b, nh);	// Funkce aktualizuje koeficienty v poli "h1" na základě algoritmu LMS
																			// její návratová hodnota není v tomto kódu využita


						accu = _sadd( inMic << 16, r1[0] << 16);		// Výpočet chybového signálu pro příští výpočet nových koeficientů LAC1
						b = _sadd(accu, 0x00008000) >> 16;

						//meas = inMic;									// Po odkomentování je do výstupu "meas" posílán signál z vnitřního mikrofonu
																			// toto je třeba udělat pro externí měření přenosu SEKUNDÁRNÍ zvukové cesty
																			// a také pro následné nastavení vhodného zesílení mikrofonního předzesilovače

						//meas = inMic;		// measure preamp + DSK TF	// Po odkomentování je do levého výstupu přímo poslán levý vstup
						//head = outMic;	// measure preamp + DSK TF	// Po odkomentování je do pravého výstupu přímo poslán pravý vstup
																			// toto je třeba udělat pro vhodné nastavení vstupních a výstupních úrovní
																			// zvukového kodeku na vývojové desce
					break;

					case 2:
						// Phase 2 - system ID - Primary Path			// Druhá fáze - aproximace přenosu PRIMÁRNÍ zvukové cesty

						head = 0;										// Do výstupu "head" není posílán žádný zvukový signál

																		// Do okolního prostředí je přehráván růžový šum z externího zdroje

						delay[dlyWrite] = outMic;						// Vstupní signál z vnějšího mikrofonu je uložen do zásobníku "delay"
						accu = delay[dlyRead];

						*(short *)&delayBuffer[0] = accu;				// Hodnota signálu z vnějšího mikrofonu zpožděná o 18 vzorků je následně
																			// uložena na první pozici v zásobníku "delayBuffer"

						DSP_fir_r4( delayBuffer, h1, r1, nh, nr);		// Realizace LAC1
						//r1[0] = fxfir(delayBuffer, h1, nh);				// LAC = linear adaptive combiner
																			// jde o odborné označení diskrétního FIR filtru s proměnnými koeficienty

						meas = r1[0];									// Do výstupu "meas" je posílán výstup LAC1 pro možnost měření jeho přenosu

						accu = _smpy(r1[0], -32768);					// Výstup LAC1 je následně invertován
						r1[0] = _sadd(accu, 0x00008000) >> 16;

						//b = b >> 1;									// Chybový signál tentokrát není násoben žádnou konstantou (nebo konstantou 1)

						accu = DSP_firlms2( h1, delayBuffer, b, nh);	// Funkce aktualizuje koeficienty v poli "h1" na základě algoritmu LMS
																			// její návratová hodnota není v tomto kódu využita


						accu = _sadd( inMic << 16, r1[0] << 16);		// Výpočet chybového signálu pro budoucí výpočet nových koeficientů LAC1
						b = _sadd(accu, 0x00008000) >> 16;

						//meas = inMic;									// Po odkomentování je do výstupu "meas" posílán vstupní signál z vnitřního mikrofonu
																			// toto je třeba udělat pro externí měření přenosu PRIMÁRNÍ zvukové cesty
																			// pozor, při tomto externím měření je třeba změnit referenční signál
																			// viz. příslušná kapitola diplomové práce
					break;
				}


			}else{

				// Phase 3 - noise canceling							// Třetí fáze - realizace samotného odečtu okolního hluku

				if(k == 0){
					// Transition after Secondary Path is estimated		// Přechodová akce po aproximaci přenosu SEKUNDÁRNÍ zvukové cesty

					for (i = N-1; i >= 0; i--){							// Při aproximaci SEKUNDÁRNÍ zvukové cesty jsou použity koeficienty v poli "h1",
						h2[i] = h1[i];										// proto je nutné je následně překopírovat do pole "h2", kde jsou uloženy
																			// a později použity k dalšímu výpočtu
						h1[i] = 0;										// Zároveň je provedeno nulování původních koeficientů v poli "h1"
					}
					*(short *)&h1[0] = 32767;							// První koeficient v poli "h1" je nastaven na výchozí hodnotu přibližně +1
																			// kvůli limitaci aritmetiky s pevnou řádovou čárkou neexistuje přímo
																			// hodnota +1 (32768), nahrazena je tedy nejbližším existujícím číslem
					k = 1;
				}

				if(k == 2){
					// Transition after Primary Path is estimated		// Přechod po aproximaci přenosu PRIMÁRNÍ zvukové cesty
					for (i = N-1; i >= 0; i--){
						mem[i] = h1[i];
					}

					k = 3;
				}

				switch (k){

					case 1:
						// Noise canceling before Primary Path is estimated
																		// Odečet okolního hluku před aproximací přenosu PRIMÁRNÍ zvukové cesty
																			// jde o náhled toho, jak by vypadal odečet bez realizace druhé fáze programu

						*(short *)&outMicBuffer[0] = outMic;			// Vstupní signál z vnějšího mikrofonu je uložen do zásobníku "outMicBuffer"

						DSP_fir_r4( outMicBuffer, h1, r1, nh, nr);		// Realizace LAC1
						//r1[0] = fxfir(outMicBuffer, h1, nh);				// LAC = linear adaptive combiner
																			// jde o odborné označení diskrétního FIR filtru s proměnnými koeficienty

						accu = _smpy(r1[0], -32768);					// Výstup LAC1 je následně invertován
						r1[0] = _sadd(accu, 0x00008000) >> 16;

						head = r1[0];									// Do výstupu "head" je posílán invertovaný signál z výstupu LAC1


						/*												// Tato část kódu je zakomentována, protože bez prvotní aproximace PRIMÁRNÍ
						DSP_fir_r4( outMicBuffer, h2, r2, nh, nr);			// zvukové cesty nedoporučuji spouštět adaptaci odečtu ve třetí fázi programu,
						//r2[0] = fxfir(outMicBuffer, h2, nh);				// přestože by tato adaptace mohla dosáhnout požadovaného výsledku.

						delay[dlyWrite] = r2[0];							// Při realizaci systému pomocí aritmetiky s pohyblivou čárkou by tato sekce
						accu = delay[dlyRead];								// měla bez poblému konvergovat k cílenému výsledku, při realizaci systému
																			// pomocí aritmetiky s pohyblivou čárkou tomu tak však není a bez jakéhokoli
						*(short *)&delayBuffer[0] = accu;					// výchozího bodu je adaptace značně nestabilní a způsobuje nepříjemné
						accu = DSP_firlms2( h1, delayBuffer, b, nh);		// zvukové artefakty.
						*/

						b = inMic;										// Chybový signál je tentokrát reprezentován akustickou sumací okolního hluku
																			// a zvuku přehrávaného z reproduktoru sluchátka. Výsledný chybový signál je
																			// zaznamenán mikrofonem uvnitř sluchátka a jeho aktuální hodnota je uložena
																			// do proměnné "b"
						meas = b;										// Do výstupu "meas" je posílán přímo chybový signál pro možnost měření přenosu
																			// okolního hluku do sluchátka
					break;

					case 3:
						// Noise canceling after both Secondary Path and Primary Path are estimated
																		// Odečet okolního hluku po aproximaci přenosu PRIMÁRNÍ i SEKUNDÁRNÍ zvukové cesty

						*(short *)&outMicBuffer[0] = outMic;			// Vstupní signál z vnějšího mikrofonu je uložen do zásobníku "outMicBuffer"

						DSP_fir_r4( outMicBuffer, h1, r1, nh, nr);		// Realizace LAC1
						//r1[0] = fxfir(outMicBuffer, h1, nh);				// LAC = linear adaptive combiner
																			// jde o odborné označení diskrétního FIR filtru s proměnnými koeficienty

						accu = _smpy(r1[0], -32768);					// Výstup LAC1 je následně invertován
						r1[0] = _sadd(accu, 0x00008000) >> 16;

						head = r1[0];									// Do výstupu "head" je posílán invertovaný signál z výstupu LAC1

						DSP_fir_r4( outMicBuffer, h2, r2, nh, nr);		// Realizace LAC2
						//r2[0] = fxfir(outMicBuffer, h2, nh);

						delay[dlyWrite] = r2[0];						// Výstupní signál z LAC2 je uložen do zásobníku "delay"
						accu = delay[dlyRead];

						*(short *)&delayBuffer[0] = accu;				// Ten samý signál zpožděný o 18 vzorků je následně zapsán na první pozici
																			// zásobníku "delayBuffer"

						b = b >> 1;										// Chybový signál je před výpočtem nových koeficientů násoben konstantou 0.5

						mem[0] = h1[0];									// První tři koeficienty z pole "h1" jsou uloženy v krátkodobé paměti "mem"
						mem[1] = h1[1];										// Ty jsou následně použity pro optimalizaci adaptace
						mem[2] = h1[2];
						//mem[3] = h1[3];

						accu = DSP_firlms2( h1, delayBuffer, b, nh);	// Funkce aktualizuje koeficienty v poli "h1" na základě algoritmu LMS
																			// její návratová hodnota není v tomto kódu využita

						h1[0] = mem[0];									// Pro zajištění větší přesnosti výsledného odečtu není několik prvních koeficientů
						h1[1] = mem[1];										// aktualizováno, protože tyto jsou nejdůležitější pro nejvyšší kmitočty, na
						h1[2] = mem[2];										// kterých nemá funkce DSP_firlms2 dostatečné hodnoty na vstupu kvůli omezenému
						//h1[3] = mem[3];													// propustnému pásmu snímacích mikrofonů.
																			// Jedná se o jakési omezení adaptace na nejvyšších kmitočtech...

						b = inMic;										// Chybový signál je tentokrát reprezentován akustickou sumací okolního hluku
																			// a zvuku přehrávaného z reproduktoru sluchátka. Výsledný chybový signál je
																			// zaznamenán mikrofonem uvnitř sluchátka a jeho aktuální hodnota je uložena
																			// do proměnné "b"

						meas = b;										// Do výstupu "meas" je posílán přímo chybový signál pro možnost měření přenosu
																			// okolního hluku do sluchátka

					break;
				}

			}

// USER INTERFACE										// Uživatelské rozhraní je v tuto chvíli reprezentováno čtyřmi HW přepínači, které jsou integrovány
															// přímo na vývojové desce. Mimo tyto přepínače jsou funkce jednotlivých fází programu
															// monitorovány pomocí výstupu "meas" s využitím externích měřících nástrojů.

			/*
			if( DSK6416_DIP_get(0)){					// Funkce prvního HW přepínače je popsána i implementována v kódu výše, zde jej uvádím
			}else{											// pouze jako formalitu pro zlepšení přehlednosti programu.
			}												// Tento přepínač je používan pro přechod mezi jednotlivými fázemi programu.
			*/

			if( !DSK6416_DIP_get(1)){					// Pomocí druhého HW přepínače je možné krátkodobě ztlumit výstup "head" do reproduktoru sluchátka.
				head = 0;									// Tato funkce umožňuje měření pasivního útlumu sluchátka bez odečtového signálu
			}

			if( !DSK6416_DIP_get(2)){					// Třetí HW přepínač umožňuje smazat koeficienty uložené v poli "h1" a nahradit je výchozími
				if(k != 3){
					for (i = N-1; i >= 0; i--){
						h1[i] = 0;						// Pokud nejsem ve třetí fázi programu, výchozí "h1" je [1,0,0,0...0]
					}
					h1[0] = 32767;
				}else{
					for (i = N-1; i >= 0; i--){
						h1[i] = mem[i];					// Pokud jsem ve třetí fázi programu, výchozí "h1" je to získané ve fázi druhé a uložené v "mem"
					}
				}
			}

			if( !DSK6416_DIP_get(3))					// Čtvrtý HW přepínač umožňuje zapínat a vypínat adaptaci koeficientů v poli "h1" pomocí manipulace
				b = _smpy( b, 32767) >> 16;					// s chybovým signálem.
			else{											// Pro upřesnění je třeba dodat, že adaptace probíhá, i pokud je chybový signál nulový, ale
				b = _smpy( b, 0) >> 16;						// hodnota koeficientů v poli "h1" se nemění. Toto chování je žádané, je vhodné program pracoval
			}												// stále stejně a rovnoměrně, ale bylo možné kontrolovat, kdy jsou a kdy nejsou koeficienty
															// aktualizovány a měněny.


// OUTPUT ROUTING MATRIX								// Sekce pro odeslání správných výstupných hodnot na správné výstupy

			left = meas;
			right = head;

// WRITE OUTPUT SAMPLE

			// "line output" obsahuje integrovaný filtr typu horní propusti, výstup má správnou polaritu
			// "headphone output" je v rámci možností lineární, výstup má však otočenou polaritu

			left = _smpy(-32768, left) >> 16;			// Jelikož volím pro výstup sluchátkový výstup, je třeba kompenzovat otočenou polaritu
			right = _smpy(-32768, right) >> 16;

			sample = _extu( right, 16, 16);				// Složení celého výstupního vzorku o délce 32 bitů ze dvou kanálů po 16 bitech
			sample = sample | _extu( left, 16, 0);

			AIC23_Write( sample);						// Zapsání celého výstupního vzorku na výstup do zvukového kodeku AIC23


// UPDATE BUFFERS										// Na závěr každého cyklu je nutné aktualizovat všechny zásobníky a další pomocné proměnné

			for (i = N+3-1; i >= 0; i--){
				*(short *)&outMicBuffer[i] = *(short *)&outMicBuffer[i-1];	// Zásobníky "outMicBuffer" a "delayBuffer" jsou kvůli vstupním podmínkám
				*(short *)&delayBuffer[i] = *(short *)&delayBuffer[i-1];		// používaných optimalizovaných funkcí realizovány jako lineární posuvné
			}																	// zásobníky, proto je třeba každý vzorek posunout o jednu pozici dále.
																				// Následující aktuální vzorek bude vložen na první pozici těchto zásobníků
																				// na začátku následujícího cyklu.

			dlyRead = (dlyRead + 1) & (nd - 1);			// Zásobník "delay" je realizován jako kruhový zásobník, na konci každého cyklu je tedy nutné
			dlyWrite = (dlyWrite + 1) & (nd - 1);			// pouze zvětšit indexy pro čtení a zápis o 1. Pro zajištění cyklického opakování těchto
															// indexů je využito faktu, že velikost zásobníku "delay" odpovídá mocnině 2 a tím pádem
															// lze cyklické opakování zajistit pomocí bitového součinu (operátor "&") s délkou zásobníku
															// sníženou o 1.

			t = (t + 1) & (131072 - 1);					// Stejným způsobem je zvyšován i index "t" pro cyklické čtení z pole "noise".

	}

	//AIC23_CloseCodec();								// Jelikož je tělo programu v rámci vývoje realizováno jako nekonečný cyklus, do tohoto bodu se
															// program nikdy nemůže dostat, kodek proto není nutné vypínat
}

Void main()												// Hlavní funkce "main()" je spuštěna ihned po inicializaci globálních proměnných
{															// po jejím vykonání přebírá řízení procesoru operační systém DSP/BIOS, který spouští jako
															// tzv. "task" (= úlohu) funkci "process" a pomocí obsluhy přerušení realizuje (mimo jiné)
															// čtení a zápis aktuálních vzorků z a do zásobníku zvukového kodeku AIC23.

	CSL_init();
	DSK6416_init();										// Inicializace samotné vývojové desky a jejích obslužných programů
	DSK6416_DIP_init();									// Inicializace obsluhy HW přepínačů na vývojové desce
	DSK6416_LED_init();									// Inicializace obsluhy LED diod na vývojové desce

	int i;												// Pomocná proměnná
	for (i = 0; i < nh+3; i++){
		*(short *)&outMicBuffer[i] = 0;					// Nastavení všech počátečních hodnot v zásobnících "outMicBuffer" a "delayBuffer" na nulu
		*(short *)&delayBuffer[i] = 0;
	}
	for (i = 0; i < nh; i++){
		*(short *)&h1[i] = 0;							// Nastavení všech koeficientů v poli "h1" a "h2" na nulu
		*(short *)&h2[i] = 0;
	}
	*(short *)&h1[0] = 32767;							// Nastavení výchozích hodnot koeficientů v poli "h1" a "h2" na [1,0,0, ... 0]
	*(short *)&h2[0] = 32767;

	for (i = 0; i < nd; i++){
		*(short *)&delay[i] = 0;						// Vymazání všech počátečních hodnot v zásobníku "delay"
	}
	for (i = 0; i < 4; i++){
		*(short *)&r1[i] = 0;							// Nastavení všech výchozích hodnot v poli "r1" a "r2" na nulu
		*(short *)&r2[i] = 0;
	}

    return;
}
