%==========================================================================
%   Nápověda Vám pomůže v případě, pokud nevíte, jak postupovat při 
%   vkládání vodoznaku.
%==========================================================================
%   Program run_enc slouží pro nevnímatelné vložení vodoznaku do audia 
%   typu "*.wav" v CD kvalitě. 
%   -----------------------------------------------------------------------
%   Program Vás nejprve vyzve pomocí dialogového okna k načtení audio 
%   souboru typu *.wav. Do Command Window se načtou základní informace
%   o audiu a zobrazí se dialogové okno pro vložení vodoznaku.
%   Do prvního řádku zadáváte vodoznak délky 1-8 Byte. Vodoznak se zadává 
%   ve znacích bez diakritiky(Doporučeno: A-Z, a-z, 0-9); (Př: "A" = 1Byte). 
%   Implicitně je zvoleno "FFFFFFFF". Do druhého řádku zadáváte koeficient 
%   intenzity vodoznaku (alfa). Implicitně je nastavena hodnota 0. Hodnota 
%   0 znamená dostatečnou míru nevnímatelnosti vloženého vodoznaku. Tím, že 
%   zvyšujeme parametr alfa k hodnotě 1, může dojít ke slyšitelnému zkreslení 
%   původního audio signálu. Naopak se ale zvýší robustnost vloženého vodoznaku.
%   Po úspěšném vložení vodoznaku můžete uložit vodoznačené audio opět typu 
%   *.wav pomocí dialogového okna na libovolné místo na Vašem disku. 
%   Implicitní název audia tvoří název orig. audia doplněné o "_waterm" 
%   značící vodoznačené audio. Název souboru můžete ale zvolit libovolný.
%   Do Command Window se následně zobrazí doba potřebná pro vložení
%   vodoznaku a dotaz na přehrání vodoznačeného audia.
%==========================================================================
%   Pro spuštění programu zadejte do Command Window: run wat_enc
%==========================================================================


clear all
close all
clc
warning off all
disp('==============================================================');
disp('||  Pro načtení audio souboru zmačkněte libovolnou klávesu  ||');
disp('==============================================================');
pause;
clc

[filename,pathname] = uigetfile( ...
{'*.wav', 'Zvukové soubory (*.wav)';
'*.wav', 'Wave (*.wav)';...
'*.*', 'Vsechny soubory (*.*)'},...
'Vyber originální audio soubor');
if isequal(filename,0)
   disp('Uživatel zvolil Storno')
   return
else
   [x,fvz,nbits]=wavread(fullfile(pathname,filename));
   while fvz~=44100
   if fvz~=44100
       clear all
       button=questdlg({'Vámi zvolený audio soubor není v CD kvalitě';' ';'Potvrďte tlačítko ANO pro nové vložení'},'Pokračovat v ...','ANO','ANO');
         [filename,pathname] = uigetfile( ...
         {'*.wav', 'Zvukové soubory (*.wav)';
        '*.wav', 'Wave (*.wav)';...
        '*.*', 'Vsechny soubory (*.*)'},...
        'Vyber originální audio soubor');
        [x,fvz,nbits]=wavread(fullfile(pathname,filename));
        if isequal(filename,0)
          disp('Uživatel zvolil Storno')
          return
        end
   end
   end
   [versn,name,ext] = fileparts(filename);
   disp(['Uživatel vybral audio soubor: ',name,ext])
   

[Nl,channels] = size( x);
if channels==1
    kanal='mono';
else
    kanal='stereo';
end

t_hh=fix((Nl/fvz)/3600);
t_h=(Nl/fvz)/3600;
t_m=fix((t_h-fix(t_h))*60);
t_mm=(t_h-fix(t_h))*60;
t_s=(t_mm-fix(t_mm))*60;

disp('---------------------------------------------');
disp(['Celková délka audia: ', num2str(t_hh, '%02.0f'),':', num2str(t_m, '%02.0f'),':',num2str( t_s, '%06.3f'), ' s']);
disp(['       Počet kanalů: ' ,num2str( channels),' (',kanal,')']);
disp(['Vzorkovací kmitočet: ' ,num2str( fvz), ' Hz',' (CD kvalita)']);
disp(['     Bitová hloubka: ', num2str( nbits), ' bitů',' (CD kvalita)']);
disp('---------------------------------------------');


options.Resize='on';
options.WindowStyle='normal';
options.Interpreter='tex';

prompt={'Vložte vodoznak (max. 8 Byte) :',...
        'Zadejte koeficient intenzity vodoznaku \alpha (0 \leq \alpha \leq 1) :'};
nazev='Vkládání vodoznaku';
numlines=1;
defaultanswer={'FFFFFFFF','0.0'};
answer=inputdlg(prompt,nazev,numlines,defaultanswer,options);
if isempty(answer)
   return
end
vznak =(answer{1});
alfa = str2num(answer{2});
alfa1 = num2str(alfa,3);


while ((length(vznak) > 8) | (length(vznak) == 0) | (alfa < 0) | (alfa > 1))
if ((length(vznak) > 8) | (length(vznak) == 0)) & ((alfa < 0) | (alfa > 1));
button=questdlg({'Vodoznak a koeficient alfa není v povoleném rozsahu';' ';'Potvrďte tlačítko ANO pro nové vložení'},'Pokračovat v ...','ANO','ANO');
   if strcmp(button,'ANO'); 
        options.Resize='on';
        options.WindowStyle='normal';
        options.Interpreter='tex';
        prompt={'Vložte vodoznak (max. 8 Byte) :',...
                'Zadejte koeficient intenzity vodoznaku \alpha (0 \leq \alpha \leq 1) :'};
        nazev='Vkládání vodoznaku';
        numlines=1;
        defaultanswer={'FFFFFFFF','0.0'};
        answer=inputdlg(prompt,nazev,numlines,defaultanswer,options);
        vznak =(answer{1});
        alfa = str2num(answer{2});
        alfa1 = num2str(alfa,3);
                    
    end
  
elseif length(vznak) > 8;
   button=questdlg({'Překročil jste maximální velikost vodoznaku';' ';['Vámi zvolená velikost vodoznaku je: ',num2str(length(vznak)),' Byte'];' ';...
      'Přejete si vodoznak zkrátit na jeho maximální velikost?'},'Pokračovat v ...','ANO','NE','ANO');
    if strcmp(button,'ANO');
            vznak = vznak(1:8);
    else strcmp(button,'NE');
            options.Resize='on';
            options.WindowStyle='normal';
            options.Interpreter='tex';
            prompt={'Vložte vodoznak (max. 8 Byte) :',...
                    'Zadejte koeficient intenzity vodoznaku \alpha (0 \leq \alpha \leq 1) :'};
            nazev='Vkládání vodoznaku';
            numlines=1;
            defaultanswer={'FFFFFFFF',alfa1};
            answer=inputdlg(prompt,nazev,numlines,defaultanswer,options);
            vznak =(answer{1});
            alfa = str2num(answer{2});
            alfa1 = num2str(alfa,3);
    end


elseif length(vznak) == 0;
   button=questdlg({'Nevložil jste žádný vodoznak';' ';'Potvrďte tlačítko ANO pro vložení vodoznaku'},'Pokračovat v ...','ANO','ANO');
    if strcmp(button,'ANO');
            options.Resize='on';
            options.WindowStyle='normal';
            options.Interpreter='tex';
            prompt={'Vložte vodoznak (max. 8 Byte) :',...
                    'Zadejte koeficient intenzity vodoznaku \alpha (0 \leq \alpha \leq 1) :'};
            nazev='Vkládání vodoznaku';
            numlines=1;
            defaultanswer={'FFFFFFFF',alfa1};
            answer=inputdlg(prompt,nazev,numlines,defaultanswer,options);
            vznak =(answer{1});
            alfa = str2num(answer{2});
            alfa1 = num2str(alfa,3);
    end


else ((alfa) < 0) | ((alfa) > 1);
     button=questdlg({'Koeficient alfa není v povoleném rozsahu';' ';'Potvrďte tlačítko ANO pro vložení koeficientu'},'Pokračovat v ...','ANO','ANO');
   if strcmp(button,'ANO'); 
            options.Resize='on';
            options.WindowStyle='normal';
            options.Interpreter='tex';
            prompt={'Vložte vodoznak (max. 8 Byte) :',...
                    'Zadejte koeficient intenzity vodoznaku \alpha (0 \leq \alpha \leq 1) :'};
            nazev='Vkládání vodoznaku';
            numlines=1;
            defaultanswer={vznak,'0.0'};
            answer=inputdlg(prompt,nazev,numlines,defaultanswer,options);
            vznak =(answer{1});
            alfa = str2num(answer{2});
            alfa1 = num2str(alfa,3);
    end
end 

end

pause (0.01)   
clc
disp(' ')
disp('Proces vkládání vodoznaku')
disp('Čekejte prosím...')
tic;   

%funkce pro segmentaci vstupního audio signálu
wind = 2048;
prekryv = 50;
[Y,R,S]=segmentace(x,wind,prekryv);

%rozklad vstupních S segmentů pomoci DWPT a uložení jednotlivých
%koeficientů do matice cfs
for i=1:S
    T=wpdec(Y(:,i),8,'db8');
    T=wpjoin(T,[5;6;10;18;20;36;37;39;40;66;68;69;70;71;72;128;130;132;135;136]);
    cfs(:,i)=read(T,'allcfs');
end

%do vektoru sAll se uloží velikost koncových uzlů rozkladového stromu
sAll=read(T,'sizes',[255;256;128;259;260;130;263;264;132;66;...
        135;136;68;69;70;71;72;36;18;39;40;20;10;5;6]);


sAll1(1,2:26)=sAll(:,1)';
sAll1(1)=0;

% výpočet energie E
E=zeros(26,S);
for i=1:S
    for j=2:length(sAll1)
        d=1:(j-1);
        E(j,i)=sum(cfs((sum(sAll1(j-d))+1):sAll1(j)+sum(sAll1(j-d)),i).^2);
    end
end
E=E(2:26,:);
% zavolání funkce pro stanovení tonálních a netonálních komponent v audiu
% Výstupem je koeficient tonality "a"
[a]=tonality(S,sAll1,cfs);
% Přepočet energie podle tonality 
SE=E.*(10.^(a*0.1));

%Zavolání funkce pro načtení hodnot pro zobrazení absolutního prahu slyšení
[Bandrate Athres] = ATH;

%normalizace energie a funkce rozprostření
barks=-8:0.05:+8;
for h=1:S
    SE(:,h)=SE(:,h)/max(SE(:,h));
    for i=1:25
      bark=i-8.5:0.05:i+7.5;
      SE(i,h)=90.3+10*log10(SE(i,h));
      SPF(:,i+((h-1)*25))=SE(i,h)+15.81+7.5*(barks+0.474)-17.5*(sqrt(1+(barks+0.474).^2));
      gmp(i+((h-1)*25),((i-1)*20)+1:321+((i-1)*20))=SPF(:,i+((h-1)*25));
    end
end


%výpočet celkového maskovacího prahu cmp
%šířka pásma L1 pro jednotlivé kritické pásma
L1=[86 86 172 86 86 171 86 86 172 344 174 170 343 344 344 343 344 688 1387 925 938 1875 1774 5514 5512];
L=log10(L1);
for i=1:S
    cmp1(i,:)=(max(gmp(((i-1)*25)+1:25+((i-1)*25),161:end-150))); 
    for l=1:25
        while l <= 25
        cmp2(i,l)=cmp1(i,20*(l-1)+1);
        l=l+1;
        end
        cmp(i,:)=max(cmp2(i,:)./L,Athres);
    end
end

for i=1:S
    Thh(i,:)=10.^((cmp(i,:)-90.3)/10);
end
Thh=Thh';
for ff=1:S
    Th(:,ff)=[repmat(Thh(1,ff),sAll(1,1),1); repmat(Thh(2,ff),sAll(2,1),1); repmat(Thh(3,ff),sAll(3,1),1); repmat(Thh(4,ff),sAll(4,1),1);...
        repmat(Thh(5,ff),sAll(5,1),1); repmat(Thh(6,ff),sAll(6,1),1); repmat(Thh(7,ff),sAll(7,1),1); repmat(Thh(8,ff),sAll(8,1),1); ...
        repmat(Thh(9,ff),sAll(9,1),1); repmat(Thh(10,ff),sAll(10,1),1); repmat(Thh(11,ff),sAll(11,1),1); repmat(Thh(12,ff),sAll(12,1),1); ...
        repmat(Thh(13,ff),sAll(13,1),1); repmat(Thh(14,ff),sAll(14,1),1); repmat(Thh(15,ff),sAll(15,1),1); repmat(Thh(16,ff),sAll(16,1),1); ...
        repmat(Thh(17,ff),sAll(17,1),1); repmat(Thh(18,ff),sAll(18,1),1); repmat(Thh(19,ff),sAll(19,1),1); repmat(Thh(20,ff),sAll(20,1),1); ...
        repmat(Thh(21,ff),sAll(21,1),1); repmat(Thh(22,ff),sAll(22,1),1); repmat(Thh(23,ff),sAll(23,1),1); repmat(Thh(24,ff),sAll(24,1),1); ...
        repmat(Thh(25,ff),sAll(25,1),1)];
end

%%%% Generace VODOZNAKU %%%%
%Převod vodoznaku na bipolární posloupnost
binseq=dec2bin(vznak,8);
for r = 1:length(vznak)
    for s = 1:length(binseq)
        bipseq(s+(r-1)*8)=2*(str2num(binseq(r,s)))-1;
    end
end
%PN sekvence SYNCHRONIZACE
pn_s=zeros(1,2560);
pn_s=rand(1,2560);
for i=1:2560;
    if (pn_s(i)>=0.5);
        pn_s(i)=-1;
    else
        pn_s(i)=1;
    end;
end;

%Opakování bitů vodoznaku N krát a zápis do prokládací matice
N=5;
M=length(bipseq);
radky_i=M;    
sloupce_i=N;
waterm=zeros(radky_i,sloupce_i);
 
for g=1:M
   bipseqN(1,(g-1)*N+1:g*N)=bipseq(g);
end

for ii=1:radky_i
    waterm(ii,1:sloupce_i)=bipseqN(sloupce_i*(ii-1)+1:sloupce_i*ii);
end
watermm=zeros(1,radky_i*sloupce_i); 
for ii=1:sloupce_i
    watermm(radky_i*(ii-1)+1:radky_i*ii)=waterm(1:radky_i,ii); 
end


%PN sekvence ROZPROSTRENI
pn_r=zeros(1,length(bipseqN));
pn_r=rand(1,length(bipseqN));
for i=1:N*length(bipseq);
    if (pn_r(i)>=0.5);
        pn_r(i)=-1;
    else
        pn_r(i)=1;
    end;
end;
%Rozpostření vodoznaku a jeho zopakování pro vícenásobné vložení
watermark = pn_r.*watermm;
watermark=[pn_s watermark]';
[mm,nn]=size(cfs);
opak=ceil((mm*nn)/length(watermark));
watermarkW=repmat(watermark,opak,1);


%%%%%%VKLÁDÁNÍ VODOZNAKU%%%%%%%%%%
www=0;
ww=1;
for jj=1:nn
    for ii=1:mm
        if alfa==0
            if cfs(ii,jj)^2 <= Th(ii,jj)
                    while www<ww
                        cfs1(ii,jj)=sqrt(Th(ii,jj))*watermarkW(ww,1)*0.1;
                        www=www+1;
                    end
                    ww=ww+1;
             else
                cfs1(ii,jj)=cfs(ii,jj);
            end
        else
            while www<ww
                if cfs(ii,jj)^2 <= Th(ii,jj)
                    cfs1(ii,jj)=sqrt(Th(ii,jj))*watermarkW(ww,1)*0.1;
                else
                    cfs1(ii,jj)=cfs(ii,jj)+alfa*watermarkW(ww,1)*0.01;
                end
                www=www+1;
            end
            ww=ww+1;
        end
    end
end

    

for i=1:S
T = write(T,'cfs',255,cfs1(1:sAll(1,1),i),...
    'cfs',256,cfs1(sAll(1,1)+1:sum(sAll(1:2,1)),i),...
    'cfs',128,cfs1(sum(sAll(1:2,1))+1:sum(sAll(1:3,1)),i),...
    'cfs',259,cfs1(sum(sAll(1:3,1))+1:sum(sAll(1:4,1)),i),...
    'cfs',260,cfs1(sum(sAll(1:4,1))+1:sum(sAll(1:5,1)),i),...
    'cfs',130,cfs1(sum(sAll(1:5,1))+1:sum(sAll(1:6,1)),i),...
    'cfs',263,cfs1(sum(sAll(1:6,1))+1:sum(sAll(1:7,1)),i),...
    'cfs',264,cfs1(sum(sAll(1:7,1))+1:sum(sAll(1:8,1)),i),...
    'cfs',132,cfs1(sum(sAll(1:8,1))+1:sum(sAll(1:9,1)),i),...
    'cfs',66,cfs1(sum(sAll(1:9,1))+1:sum(sAll(1:10,1)),i),...
    'cfs',135,cfs1(sum(sAll(1:10,1))+1:sum(sAll(1:11,1)),i),...
    'cfs',136,cfs1(sum(sAll(1:11,1))+1:sum(sAll(1:12,1)),i),...
    'cfs',68,cfs1(sum(sAll(1:12,1))+1:sum(sAll(1:13,1)),i),...
    'cfs',69,cfs1(sum(sAll(1:13,1))+1:sum(sAll(1:14,1)),i),...
    'cfs',70,cfs1(sum(sAll(1:14,1))+1:sum(sAll(1:15,1)),i),...
    'cfs',71,cfs1(sum(sAll(1:15,1))+1:sum(sAll(1:16,1)),i),...
    'cfs',72,cfs1(sum(sAll(1:16,1))+1:sum(sAll(1:17,1)),i),...
    'cfs',36,cfs1(sum(sAll(1:17,1))+1:sum(sAll(1:18,1)),i),...
    'cfs',18,cfs1(sum(sAll(1:18,1))+1:sum(sAll(1:19,1)),i),...
    'cfs',39,cfs1(sum(sAll(1:19,1))+1:sum(sAll(1:20,1)),i),...
    'cfs',40,cfs1(sum(sAll(1:20,1))+1:sum(sAll(1:21,1)),i),...
    'cfs',20,cfs1(sum(sAll(1:21,1))+1:sum(sAll(1:22,1)),i),...
    'cfs',10,cfs1(sum(sAll(1:22,1))+1:sum(sAll(1:23,1)),i),...
    'cfs',5,cfs1(sum(sAll(1:23,1))+1:sum(sAll(1:24,1)),i),...
    'cfs',6,cfs1(sum(sAll(1:24,1))+1:sum(sAll(1:25,1)),i));
X(:,i) = wprec(T);
end
YY=zeros((S-1)*1024+2048,1);
for i=1:S-1
Y1((1024*(i-1)+1):1024*i,1)=X(1025:end,i+1);
end
YY=[X(:,1);Y1(:)];

YYY=YY(1:length(x),1);

t_w = toc;

t_hhw=fix((t_w)/3600);
t_hw=(t_w)/3600;
t_mw=fix((t_hw-fix(t_hw))*60);
t_mmw=(t_hw-fix(t_hw))*60;
t_sw=(t_mmw-fix(t_mmw))*60;

clc
disp(' ')
disp(['Vodoznak "',vznak,'" byl úspěšně vložen do audia'])
disp(' ')
disp(['Doba potřebná pro vložení vodoznaku: ', num2str(t_hhw, '%02.0f'),':', num2str(t_mw, '%02.0f'),':',num2str( t_sw, '%06.3f'), ' s']);



[save_file,save_path] = uiputfile('*.wav','Ulož vodoznačené audio',[name,'_waterm']);
savefile = [ save_path,save_file];
if filename ~= 0
wavwrite(YYY,fvz,savefile)
end
[Wpathstr,Wname,Wext,Wversn] = fileparts(savefile);

play=input('\nPřehrát vodoznačené audio? Y/[N]: ', 's');
if play=='Y',
    soundsc(YYY,fvz);
end

dlmwrite(['PNS_',[Wname],'.mat'],pn_s)
dlmwrite(['PNR_',[Wname],'.mat'],pn_r)
dlmwrite(['cfs_',[Wname],'.mat'],cfs)
dlmwrite(['alfa_',[Wname],'.mat'],alfa)
dlmwrite(['bipseq_',[Wname],'.mat'],bipseq)
dlmwrite(['Th_',[Wname],'.mat'],Th)

end