%  Uebung 7:    Schaetzen der Dauerwerte eines Satzes mittels
%               Lautdauermodell und Synthetisieren des Signals 
%-----------------------------------------------------------------------
%  Benoetigte Files:
%    satz?.txt         Text des zu synthetisierenden Satzes
%    satz?.ethpa       Phonologische Darstellung des Satzes
%    satz?.sigele      Sigele-Datei (von SVOX) des Satzes, 
%                        aus der F0 gelesen wird 
%    ueb7_corp.wav     Diphonsammlung (Signal- und Label-Datei)
%    ueb7_corp.lab.mat
%
%  Fuer jedes mit dem Matlab-Skript `create_duration_model.m` erzeugte 
%  Lautdauermodell wird ein Signal synthetisiert. Als Vergleich wird
%  zudem mit den Lautdauerwerten aus der Sigele-Datei ein Signal erzeugt.
%
%  Das Skript synthetisiert die Signale nach folgender Vorgehensweise:
%  Fall 1: Es sind nur Funktionen zur Lautdauersteuerung mit der Bezeichnung 
%          "get_dur_rule_conditions*.m" vorhanden (Uebung 7). In diesem Fall 
%          wird fuer jede vorhandene Funktion ein Signal erzeugt, wobei fuer 
%          die Grundfrequenz die Werte aus der Sigele-Datei genommen werden. 
%          
%  Fall 2: Es sind nur nur Funktionen zur Grundfrequenzsteuerung mit der 
%          Bezeichnung "get_F0_rule_conditions*.m" vorhanden (Uebung 8).
%          In diesem Fall wird fuer jede vorhandene Funktion zur 
%          Grundfrequenzsteuerung ein Signal erzeugt, wobei fuer die 
%          Lautdauer die Werte aus der Sigele-Datei genommen werden.
% 
%  Fall 3: Es sind sowohl Funktionen zur Grundfrequenzsteuerung als auch 
%          Lautdauersteuerung vorhanden. In diesem Fall werden die 
%          zusammenpassenden Funktionen kombiniert, d.h. die gegebenen 
%          Funktionen "...frame.m", diejenigen der Studierenden und 
%          diejenigen der Musterloesung und daraus die 4 Signale erzeugt.
%          Ist eine zur Kombination benoetigte Funktion nicht vorhanden,
%          wird das entsprechende Signal nicht erzeugt. 

clear all;

%   LPC-Analyse/Synthese-Parameter
%-------------------------------------
%
SamplFreq = 8000;  % Hz
POrd = 12;         % Praediktorordnung
WinSize = 176;     % Laenge des Analysefensters
WinShift = 80;     % Verschiebung des Analysefensters

%
% Ueberpruefung der vorhandenen Funktionen und Modelle
%
% Lautdauersteuerung
if exist('get_dur_rule_conditions_frame','file') && ~exist('DurModel0.mat','file') 
  warning('Die Funktion ''get_dur_rule_conditions_frame.m'' ohne die Modellparameter ''Durmod0.mat'' gefunden!');
end
if ~exist('get_dur_rule_conditions_frame','file') && exist('DurModel0.mat','file') 
  warning('Die Modellparameter ''DurModel0.mat'' ohne die Funktion ''get_dur_rule_conditions_frame'' gefunden!');
end

if exist('get_dur_rule_conditions','file') && ~exist('DurModel1.mat','file') 
  warning('Die Funktion ''get_dur_rule_conditions'' ohne die Modellparameter ''DurModel1.mat'' gefunden!');
end
if ~exist('get_dur_rule_conditions','file') && exist('DurModel1.mat','file') 
  warning('Die Modellparameter ''DurModel1.mat'' ohne die Funktion ''get_dur_rule_conditions'' gefunden!');
end

if exist('get_dur_rule_conditions_sol','file') && ~exist('DurModel2.mat','file') 
  warning('Die Funktion ''get_dur_rule_conditions_sol'' ohne die Modellparameter ''DurModel2.mat'' gefunden!');
end
if ~exist('get_dur_rule_conditions_sol','file') && exist('DurModel2.mat','file') 
  warning('Die Modellparameter ''DurModel2.mat'' ohne die Funktion ''get_dur_rule_conditions_sol'' gefunden!');
end

% Grundfrequenzsteuerung
if exist('get_f0_rule_conditions_frame','file') && ~exist('F0Model0.mat','file') 
  warning('Die Funktion ''get_f0_rule_conditions_frame'' ohne die Modellparameter ''F0Model0.mat'' gefunden!');
end
if ~exist('get_f0_rule_conditions_frame','file') && exist('F0Model0.mat','file') 
  warning('Die Modellparameter ''F0Model0.mat'' ohne die Funktion ''get_f0_rule_conditions_frame'' gefunden!');
end

if exist('get_f0_rule_conditions','file') && ~exist('F0Model1.mat','file') 
  warning('Die Funktion ''get_f0_rule_conditions'' ohne die Modellparameter ''F0Model1.mat'' gefunden!');
end
if ~exist('get_f0_rule_conditions','file') && exist('F0Model1.mat','file') 
  warning('Die Modellparameter ''F0Model1.mat'' ohne die Funktion ''get_f0_rule_conditions'' gefunden!');
end

if exist('get_f0_rule_conditions_sol','file') && ~exist('F0Model2.mat','file') 
  warning('Die Funktion ''get_f0_rule_conditions_sol'' ohne die Modellparameter ''F0Model2.mat'' gefunden!');
end
if ~exist('get_f0_rule_conditions_sol','file') &&exist('F0Model2.mat','file') 
  warning('Die Modellparameter ''F0Model2.mat'' ohne die Funktion ''get_f0_rule_conditions_sol'' gefunden!');
end


%   Grundfrequenzmodelle laden
%--------------------------------
%
if exist('F0Model0.mat','file') 
  disp('Modell fuer mittlere Grundfrequenz laden ...');
  load('F0Model0.mat');
  F0Model0 = F0mod;
end
if exist('F0Model1.mat','file')
  disp('Grundfrequenzmodell der Studenten laden ...');
  load('F0Model1.mat');
  F0Model1 = F0mod;
end
if exist('F0Model2.mat','file')
  disp('Grundfrequenzmodell der Musterloesung laden ...');
  load('F0Model2.mat');
  F0Model2 = F0mod;
end

if exist('F0Model0', 'var') &&  exist('get_f0_rule_conditions_frame','file') || ...
    exist('F0Model1', 'var') &&  exist('get_f0_rule_conditions','file') || ...    
    exist('F0Model2', 'var') &&  exist('get_f0_rule_conditions_sol','file') 
  f0ModelExists = 1;
else
  f0ModelExists = 0;
end


%   Lautdauermodelle laden
%----------------------------
%
if exist('DurModel0.mat','file') 
  disp('Modell fuer mittlere Lautdauer laden ...');
  load('DurModel0.mat');
  Durmod0 = Durmod;
end
if exist('DurModel1.mat','file')
  disp('Lautdauermodell der Studenten laden ...');
  load('DurModel1.mat');
  Durmod1 = Durmod;
end
if exist('DurModel2.mat','file')
  disp('Lautdauermodell der Musterloesung laden ...');
  load('DurModel2.mat');
  Durmod2 = Durmod;
end

if exist('Durmod0', 'var') &&  exist('get_dur_rule_conditions_frame','file') || ...
    exist('Durmod1', 'var') &&  exist('get_dur_rule_conditions','file') || ...    
    exist('Durmod2', 'var') &&  exist('get_dur_rule_conditions_sol','file') 
  durModelExists = 1;
else 
  durModelExists = 0;
end


if ~f0ModelExists && ~durModelExists
  str = '';
  if exist('create_duration_model') 
    str = 'Bitte die Funktion ''create_duration_model'' ausfuehren!';
  end
  if exist('create_f0_model') 
    str = 'Bitte die Funktion ''create_f0_model'' ausfuehren!';
  end
  error(['*** Weder Lautdauermodell noch Grundfrequenzmodell gefunden! ' ...
         char(10) '    ' str])
end



%   Auswahl des Satzes
%----------------------------
%
snum = 0;
while (snum < 1) || (snum > 9),
  snum = input('Satznummer eingeben [1 - 9]:    >> ');
  if isempty(snum),
    snum = 0;
  end
end

ptrfln = ['satz' num2str(snum) '.ethpa'];
sigelefln = ['satz' num2str(snum) '.sigele'];



%   Einflussfaktoren aus phonologischer Beschreibung 
%   ermitteln und Synthesedaten des Satzes laden
%-----------------------------------------------------
%

if exist(ptrfln,'file') ~= 2,
  p = fullpath('ueb7_data');
  if isempty(p)
    error('ueb7_data could not be found');
  else
    ptrfln = [p '/' ptrfln];
  end
  if exist(ptrfln,'file') ~= 2,
    error(['*** file not found:  ' ptrfln])
  end
end

[syl,acc,lng,phr,bnd] = ptrread(ptrfln);

F = load_phonol_repr(syl,acc,lng,phr,bnd);
[elem_nam,optimalDuration,optimalFreq] = load_sigele_data(sigelefln);


%   Regelbedingungen setzen 
%-------------------------------------------
%
if durModelExists
  if exist('get_dur_rule_conditions_frame','file')
    if exist('Durmod0','var')
      C0 = get_dur_rule_conditions_frame(F);
    else 
      error(['*** Das Lautdauermodell zur Funktion ' ...
         '''get_dur_rule_conditions_frame'' ist nicht vorhanden. ' ...  
         'Bitte die Funktion ''create_duration_model'' ausfuehren oder ' ...
         'die Datei DurModel0.mat in das aktuelle Verzeichnis kopieren!']);
    end
  end
  if exist('get_dur_rule_conditions','file')
    if exist('Durmod1','var')
      C1 = get_dur_rule_conditions(F);
    else 
      error(['*** Das Lautdauermodell zur Funktion ' ...
         '''get_dur_rule_conditions'' ist nicht vorhanden. ' ... 
         'Bitte die Funktion ''create_duration_model'' ausfuehren oder ' ...
         'die Datei DurModel1.mat in das aktuelle Verzeichnis kopieren!']);
    end
  end
  if exist('get_dur_rule_conditions_sol','file')
    if exist('Durmod2','var')
      C2 = get_dur_rule_conditions_sol(F);
    else 
      error(['*** Das Lautdauermodell zur Funktion ' ...
         '''get_dur_rule_conditions_sol'' ist nicht vorhanden. ' ... 
         'Bitte die Funktion ''create_duration_model'' ausfuehren oder ' ...
         'die Datei DurModel2.mat in das aktuelle Verzeichnis kopieren!']);
    end
  end


  %   Schaetzen der Lautdauerwerte
  %---------------------------------
  %
  if exist('C0', 'var')      % mit Modell fuer mittlere Lautdauern
    d0 = 10.^(C0*Durmod0.q);
  end
  if exist('C1', 'var')      % mit Lautdauermodell der Studenten
    d1 = 10.^(C1*Durmod1.q);
  end
  if exist('C2', 'var')      % mit Lautdauermodell der Musterloesung
    d2 = 10.^(C2*Durmod2.q);
  end

  for ii = 1:length(F.phone_id)    % Sprechpausen auf 350 ms setzen
    if F.phone_id(ii,1) == '/'
      if exist('C0', 'var') 
        d0(ii) = 350;
      end
      if exist('C1', 'var') 
        d1(ii) = 350;
      end
      if exist('C2', 'var') 
        d2(ii) = 350;
      end
    end
  end  
end


  
%   Regelbedingungen fuer Grundfrequenzsteuerung setzen 
%-------------------------------------------
%
if f0ModelExists
  if exist('get_F0_rule_conditions_frame','file')
    if exist('F0Model0','var')
      CFreq0 = get_F0_rule_conditions_frame(F);
    end
  end
  if exist('get_F0_rule_conditions','file')
    if exist('F0Model1','var')
      CFreq1 = get_F0_rule_conditions(F);
    end
  end
  if exist('get_F0_rule_conditions_sol','file')
    if exist('F0Model2','var')
      CFreq2 = get_F0_rule_conditions_sol(F);
    end
  end



  %   Schaetzen der Grundfrequenzwerte
  %---------------------------------
  %
  if exist('CFreq0', 'var')      % mit Modell fuer mittlere Grundfrequenzen
    freq0 = CFreq0*F0Model0.q;
  end
  if exist('CFreq1', 'var')      % mit Grundfrequenzmodell der Studenten
    freq1 = CFreq1*F0Model1.q;
  end
  if exist('CFreq2', 'var')      % mit Grundfrequenzmodell der Musterloesung
    freq2 = CFreq2*F0Model2.q;
  end

end

  


%   Erzeugen der Semidiphonsequenz
%------------------------------------
%
[sd sdi] = get_semidiphones(F.phone_id,elem_nam);



%   Lautdaueruebertragung auf Semidiphone
%------------------------------------------
%
% sdd(:,1) enthaelt danach die durchschnittliche Lautdauer
% sdd(:,2) die Lautdauer nach dem Modell der Studenten
% sdd(:,3) die Lautdauer nach dem Modell der Musterloesung
if durModelExists
  if exist('d0','var')
    dlen = length(d0);
  elseif exist('d1','var')
    dlen = length(d1);
  elseif exist('d2','var')
    dlen = length(d2);
  end
  sdd = zeros(length(sdi),2);  
  for i = 1:dlen
    phi = find(sdi == i);
    l = zeros(length(phi),1);
    for j = 1:length(phi)
      sig = get_corp_elem(sd{phi(j)},0);
      l(j) = length(sig);
      clear sig
    end
    for j = 1:length(phi),
      if exist('d0','var')
        sdd(phi(j),1) = d0(i)*l(j)/sum(l);
      end
      if exist('C1','var')
        sdd(phi(j),2) = d1(i)*l(j)/sum(l);
      end
      if exist('C2','var')
        sdd(phi(j),3) = d2(i)*l(j)/sum(l);
      end
    end
  end
end


%   Grundfrequenzkontur 
%   auf Semidiphonsequenz uebertragen
%----------------------------------------------
%
 % sdF0(:,1) enthaelt danach die mittlere Grundfrequenz
 % sdF0(:,2) enthaelt danach die Grundfrequenz des Modells der Studenten
 % sdF0(:,3) enthaelt danach die Grundfrequenz des Modells der Musterloesung
 if f0ModelExists 
  % verwende optimale Dauer zum Vergleich der F0-Modelle
  t = zeros(size(optimalDuration',1),1); %% oder d0, d1 oder d2, wann vorhanden?
  f1 = t; f2 = t; f3 = t;
  j = 1;
  for i = 1:size(F.phone_id,1)
    t(i) = round(sum(optimalDuration(1:i)) - optimalDuration(i)/2)/1000;
    if phone_has_properties(F.phone_id(i), 'nucleus'), 
     f1(i) = freq0(j);
     if exist('CFreq1', 'var')     
      f2(i) = freq1(j);
     end     
     if exist('CFreq2', 'var')     
       f3(i) = freq2(j);
     end
     j = j+1;
    else
     f1(i) = 0;
     f2(i) = 0;
    end
  end
  f1 = interp1(t(f1>0),f1(f1>0),t,'linear',NaN);
  if exist('CFreq1', 'var')     
    f2 = interp1(t(f2>0),f2(f2>0),t,'linear',NaN);     
  end  
  if exist('CFreq2', 'var')     
    f3 = interp1(t(f3>0),f3(f3>0),t,'linear',NaN);
  end
  % set F0 values of first onset and last offset. 
  for i = 2:size(t,1)
    if isnan(f1(i))
     f1(i) = f1(i-1);
    end
    if exist('CFreq1', 'var') && isnan(f2(i))
     f2(i) = f2(i-1);
    end 
    if exist('CFreq2', 'var') && isnan(f3(i))    
     f3(i) = f3(i-1);
    end
  end
  for i = size(t,1)-1:-1:1
    if isnan(f1(i))
     f1(i) = f1(i+1);
    end
    if exist('CFreq1', 'var') && isnan(f2(i))
     f2(i) = f2(i+1);
    end
    if exist('CFreq2', 'var') && isnan(f3(i))    
     f3(i) = f3(i+1);
    end    
  end

  sdF0 = zeros(size(optimalDuration',1),2); 
  for i = 1:size(optimalDuration',1)
    phi = find(sdi == i);
    sdF0(phi,1) = f1(i);
    if exist('CFreq1', 'var')  
      sdF0(phi,2) = f2(i);
    end        
    if exist('CFreq2', 'var')  
     sdF0(phi,3) = f3(i);
    end    
  end
end



%   Verkettungssynthese  
%-----------------------------------------------------------------
%

if ~f0ModelExists && durModelExists 
  duration = sdd;
  freq(:,1) = optimalFreq';
  freq(:,2) = optimalFreq';
  freq(:,3) = optimalFreq';    
  dur_mod_desc = {'Synthese mit durchschnittlicher Lautdauer und optimaler Grundfrequenz', ...
                  'Synthese mit Lautdauermodell der Studenten und optimaler Grundfrequenz', ...
                  'Synthese mit Lautdauermodell der Musterloesung und optimaler Grundfrequenz', ...
                  'Synthese mit optimaler Lautdauer und optimaler Grundfrequenz'};  
end  
if f0ModelExists && ~durModelExists 
  freq = sdF0;
  duration(:,1) = optimalDuration;
  duration(:,2) = optimalDuration;
  duration(:,3) = optimalDuration;  
  dur_mod_desc = {'Synthese mit durchschnittlicher Grundfrequenz und optimaler Lautdauer', ...
                'Synthese mit Grundfrequenzmodell der Studenten und optimaler Lautdauer', ...
                'Synthese mit Grundfrequenzmodell der Musterloesung und optimaler Lautdauer', ...
                'Synthese mit optimaler Grundfrequenz und optimaler Lautdauer'};
end
if f0ModelExists && durModelExists 
  freq = sdF0;
  duration = sdd;
  dur_mod_desc = {'Synthese mit durchschnittlicher Grundfrequenz und durchschnittlicher Lautdauer', ...
              'Synthese mit Grundfrequenzmodell und Lautdauermodell der Studenten', ...
              'Synthese mit Grundfrequenzmodell und Lautdauermodell der Musterloesung', ...
              'Synthese mit optimaler Grundfrequenz und Lautdauer'};  
end


%   Semidiphonsequenz anzeigen
%-----------------------------------
%
if ~f0ModelExists && durModelExists
  for i = 1:size(sd,1)
    fprintf('%s \t%d \t%.2f\n',sd{i},sdi(i),duration(i,2));
  end
end 
if  f0ModelExists && durModelExists
  for i = 1:size(sd,1)
    fprintf('%s \t%d \t%.2f \t%.2f\n',sd{i},sdi(i),duration(i,2),freq(i,2));
  end
end


% the _frame get_..._rule_conditions should always be there...
if durModelExists && ~f0ModelExists && exist('C0','var')  || ...
    durModelExists && f0ModelExists &&   exist('C0','var') && exist('CFreq0','var') || ...
    ~durModelExists && f0ModelExists && exist('CFreq0','var')  
  disp(dur_mod_desc{1})
  syn = diphone_synthesis(elem_nam,duration(:,1),freq(:,1),SamplFreq,POrd, ...
                          WinSize,WinShift);
  signal{1} = syn./max(syn)*0.99;
end

if durModelExists && ~f0ModelExists && exist('C1','var')  || ...
    durModelExists && f0ModelExists &&   exist('C1','var') && exist('CFreq1','var') || ...
    ~durModelExists && f0ModelExists && exist('CFreq1','var')
  disp(dur_mod_desc{2})
  syn = diphone_synthesis(elem_nam,duration(:,2),freq(:,2),SamplFreq,POrd, ...
                          WinSize,WinShift);
  signal{2} = syn./max(syn)*0.99;
end

if durModelExists && ~f0ModelExists && exist('C2','var')  || ...
    durModelExists && f0ModelExists &&   exist('C2','var') && exist('CFreq2','var') || ...
    ~durModelExists && f0ModelExists && exist('CFreq2','var')
  disp(dur_mod_desc{3})
  syn = diphone_synthesis(elem_nam,duration(:,3),freq(:,3),SamplFreq,POrd, ...
                          WinSize,WinShift);
  signal{3} = syn./max(syn)*0.99;
end

% optimale Dauer und Frequenz
disp(dur_mod_desc{4})
syn = diphone_synthesis(elem_nam,optimalDuration,optimalFreq',SamplFreq,POrd,WinSize,WinShift);
signal{4} = syn./max(syn)*0.99;




%   Graphische Darstellung der Signale
%--------------------------------------------------
%

figure(1)            
numsigs = 0;
dursig = 0;
for ii = 1:length(signal) 
  numsigs = numsigs+~isempty(signal{ii});
  dursig = max(dursig,length(signal{ii}));
end
pos = get(gcf,'position');
if pos(4) == 420
  pos(1) = pos(1)-250;
  pos(2) = pos(2)-(numsigs-2)*160;
  pos(3) = pos(3)+500;
  pos(4) = 160*numsigs;
  set(gcf,'position',pos)
end
clf             
                                        % Satz im Figurentitel anzeigen
fp = fullpath('ueb7_data/','file');
fid = fopen([fp 'satz' num2str(snum) '.txt'],'r');
if fid ~= -1,
  str = fgetl(fid);
  fclose(fid);
  set(1,'name',str);
end
jj = numsigs-1;
for ii = 1:length(signal) 
  if ~isempty(signal{ii})
    axes('position',[0.03 (0.03+jj*0.245)/numsigs*4 0.95 0.175/numsigs*4])
    jj = jj-1;
    plot((1:length(signal{ii}))/SamplFreq,signal{ii})
    set(gca,'xlim',[0 dursig-1]/SamplFreq)
    title(dur_mod_desc{ii},'fontsize',12)
  end
end
drawnow;


%   Audio-Ausgabe der Signale
%--------------------------------------------------
%
numstr = ' ';
while lower(numstr) ~= 'q',
  disp(['Signale fuer Satznummer ' num2str(snum) ' abspielen:'])
  for ii = 1:length(signal)  
    if ~isempty(signal{ii})
      str = [dur_mod_desc{ii}];
      stringEnd = min(74, length(str));
      disp(['  (' num2str(ii) ') ' str(1:stringEnd)]);
    end
  end  
  disp(['  (q) beenden']);
  num = 0;
  while num == 0
    numstr = input(['          Signal auswaehlen:   >>  '],'s');
    if lower(numstr) == 'q', break; end;
    num = str2num(numstr);
    if isempty(num) | num < 1 | num > length(signal) ,
      num = 0;
    elseif isempty(signal{num})
      num = 0;
    end
  end
  if num > 0
    sound(signal{num},SamplFreq);                % Signal abspielen
  end
end




