function sola( filePath, fileName )
%--------------------------------------------------------------------------
% Synchronous OverLap Add
%
% adapted from:
% TimeScaleSOLA.m   [DAFXbook, 2nd ed., chapter 6]
%
% Cooper Baker - 2014
%--------------------------------------------------------------------------

close all;

% Settings
%--------------------------------------------------------------------------
grainSize      = 1024;                  % 2048 - default
hopSize        = 256;                   % 256  - default
stretchFactor  = 2;                     % >= 0.25 and <= 2
tag            = 'sola';

% Initializations
%--------------------------------------------------------------------------
if any( exist( 'fileName' ) ~= 1 )
    [ fileName, filePath ] = uigetfile( '*.wav', 'Audio File' );
end

overlap        = ( hopSize * stretchFactor ) / 2;
[ input, sr ]  = audioread( [ filePath, fileName ] );
inputTranspose = input';
grainIndex     = 1;
grainMax	   = ceil( length( inputTranspose ) / hopSize );
hopSizeStretch = round(hopSize*stretchFactor);
inputTranspose( grainMax * hopSize + grainSize ) = 0;
output         =  inputTranspose( 1 : grainSize );

% create progress bar dialog box
bar = waitbar( 0, '0%', 'Name', sprintf( '%s: processing %s...', mfilename, fileName ) );

% Processing Loop
%--------------------------------------------------------------------------
while grainIndex < grainMax

    % copy the input grain
    grain = inputTranspose( grainIndex * hopSize + 1 : grainSize + grainIndex * hopSize );

    % perform cross correlation
    crossCorrelation = xcorr( grain ( 1 : overlap ), output( 1, grainIndex * hopSizeStretch : grainIndex * hopSizeStretch + ( overlap - 1 ) ) );

    % find maximum in cross correlate
    [ xmax( 1, grainIndex ), index( 1, grainIndex ) ] = max( crossCorrelation );

    % generate fadeOut ramp
    fadeOut = 1 : ( -1 / ( length( output ) - ( grainIndex * hopSizeStretch - ( overlap - 1 ) + index( 1, grainIndex ) - 1 ) ) ) : 0;

    % generate fadeIn ramp
    fadeIn  = 0 : (  1 / ( length( output ) - ( grainIndex * hopSizeStretch - ( overlap - 1 ) + index( 1, grainIndex ) - 1 ) ) ) : 1;

    % fade out tail portion of previous grain
    tail = output( 1, ( grainIndex * hopSizeStretch - ( overlap - 1 ) ) + index( 1, grainIndex ) - 1 : length( output) ) .* fadeOut;

    % fade in head portion of current grain
    head = grain( 1 : length( fadeIn ) ) .* fadeIn;

    % mix head and tail into crossfade
    crossfade = tail + head;

    % concatenate result to end of output buffer
    output = [ output( 1, 1 : grainIndex * hopSizeStretch - overlap + index( 1, grainIndex ) - 1 ), crossfade, grain( length( fadeIn ) + 1 : grainSize ) ];

    % increment the grain index
    grainIndex = grainIndex + 1;

    % update the progress bar
    progress = ( grainIndex / grainMax );
    waitbar( progress, bar, sprintf( '%2.3f%%', progress * 100 ) )
end

% close progress bar dialog box
close( bar );

% Output
%--------------------------------------------------------------------------

% crop output buffer
output = output( 1 : length( output ) );

% normalize audio
normCoeff = 1 / max( abs( output ) );
output = output * normCoeff;

% make comments for file
commentString = sprintf( 'WinSize: %.0f,\nOverlap: %.0f,\nStretch: %.2f,\nWindow: %s', grainSize, overlap, stretchFactor, 'Hann' );

% write audio file to disk
[ a, fileName, b ] = fileparts( fileName );
outFile = sprintf( '%s.%s.wav', fileName, tag );
audiowrite( outFile, output, sr, 'BitsPerSample', 32, 'Artist', 'NormCoeff', 'Title', num2str( normCoeff ), 'Comment', commentString );

% plot output
timevector = linspace( 0, length( output )/sr, length( output ) );
plot( timevector, output );

% EOF
