%% Augment Audio Dataset
% The audioDataAugmenter supports multiple workflows for augmenting your datastore, including:
% Offline augmentation
% Augmentation using tall arrays
% Augmentation using transform datastores
% In each workflow, begin by creating an audio datastore to point to your audio data. In this example, you create an audio datastore that points to audio samples included with Audio Toolbox™. Count the number of files in the dataset.

folder = fullfile(matlabroot,"toolbox","audio","samples");
ADS = audioDatastore(folder)
numFilesInDataset = numel(ADS.Files)

%
% Create an audioDataAugmenter that applies random sequential augmentations. Set NumAugmentations to 2.

aug = audioDataAugmenter('NumAugmentations',2)

%
%% Offline Augmentation
% To augment the audio dataset, create two augmentations of each file and then write the augmentations as WAV files.

while hasdata(ADS)
    [audioIn,info] = read(ADS);
    
    data = augment(aug,audioIn,info.SampleRate);
    
    [~,fn] = fileparts(info.FileName);
    for i = 1:size(data,1)
        augmentedAudio = data.Audio{i};
        
        % If augmentation caused an audio signal to have values outside of -1 and 1, 
        % normalize the audio signal to avoid clipping when writing.
        if max(abs(augmentedAudio),[],'all')>1
            augmentedAudio = augmentedAudio/max(abs(augmentedAudio),[],'all');
        end
        
        audiowrite(sprintf('%s_aug%d.wav',fn,i),augmentedAudio,info.SampleRate)
    end
end

%
% Create an audioDatastore that points to the augmented dataset and confirm that the number of files in the dataset is double the original number of files.

augmentedADS = audioDatastore(pwd)
numFilesInAugmentedDataset = numel(augmentedADS.Files)

%
%% Augment Using Tall Arrays
% When augmenting a dataset using tall arrays, the input data to the augmenter should be sampled at a consistent rate. Subset the original audio dataset to only include files with a sample rate of 44.1 kHz. Most datasets are already cleaned to have a consistent sample rate.

keepFile = cellfun(@(x)contains(x,'44p1'),ADS.Files);
ads44p1 = subset(ADS,keepFile);
fs = 44.1e3;

% Convert the audio datastore to a tall array. tall arrays are evaluated only when you request them explicitly using gather. MATLAB® automatically optimizes the queued calculations by minimizing the number of passes through the data. If you have the Parallel Computing Toolbox™, you can spread the calculations across multiple machines. The audio data is represented as an M-by-1 tall cell array, where M is the number of files in the audio datastore.

adsTall = tall(ads44p1)

% Define a cellfun function so that augmentation is applied to each cell of the tall array. Call gather to evaluate the tall array.

augTall = cellfun(@(x)augment(aug,x,fs),adsTall,"UniformOutput",false);
augmentedDataset = gather(augTall)

% The augmented dataset is returned as a numFiles-by-1 cell array, where numFiles is the number of files in the datastore. Each element of the cell array is a numAugmentationsPerFile-by-2 table, where numAugmentationsPerFile is the number of augmentations returned per file.

numFiles = numel(augmentedDataset)
numAugmentationsPerFile = size(augmentedDataset{1},1)

%
%% Augment Using Transform Datastore
% You can perform online data augmentation while you train your machine learning application using a transform datastore. Call transform to create a new datastore that applies data augmentation while reading.

transformADS = transform(ADS,@(x,info)augment(aug,x,info),'IncludeInfo',true)

% Call read to return the augmented first file from the transform datastore.

augmentedRead = read(transformADS)

% Copyright 2019 The MathWorks, Inc.