Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 1 addition & 26 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1 @@
Audapter is a software package for configurable real-time manipulation of acoustic parameters of speech that runs on general-purpose computers. It is designed for research on auditory-motor interactions in speech production, but may also be of use for certain speech signal processing applications. The current version of Audapter supports manipulation (i.e., perturbation) of the following acoustic parameters:


1) Formant frequencies (F1 and F2), in both static and time-varying ways

2) Fundamental frequency (F0, or pitch)

3) Local timing, through time-warping

4) Local intensity

5) Global time delay (delayed auditory feedback)

6) Global intensity



This repository contains the MATLAB code for Audapter.

The C++ source code for the MEX core of Audapter is open-source: https://github.com/shanqing-cai/audapter_mex

You can download a copy of Audapter manual at:
- Latest version: https://sites.bu.edu/guentherlab/files/2022/09/AudapterManual_2.1.5.pdf

The MEX files (64-bit) can be downloaded from: https://github.com/shanqing-cai/audapter_mex/tree/master/bin

This is the companion repository for Audapter, which contains the MATLAB code. For full information about Audapter, see the readme on [the blab-lab fork of the main Audapter repository](https://github.com/blab-lab/audapter_mex).
35 changes: 35 additions & 0 deletions mcode/AudapterIO.m
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,28 @@
if (isfield(p, 'fb4GainDB'))
Audapter(3, 'fb4gaindb', p.fb4GainDB, toPrompt);
end

if (isfield(p, 'fb5GainDB_speech'))
try
Audapter(3, 'fb5gaindb_speech', p.fb5GainDB_speech, toPrompt);
catch ME
audapterSetParamError(ME, 'b2.5')
if isfield(p,'fb') && p.fb == 5 % actually error out if using feedback mode 5
rethrow(ME);
end
end
end

if (isfield(p, 'fb5Gain_playback'))
try
Audapter(3, 'fb5gain_playback', p.fb5Gain_playback, toPrompt);
catch ME
audapterSetParamError(ME, 'b2.5')
if isfield(p,'fb') && p.fb == 5 % actually error out if using feedback mode 5
rethrow(ME);
end
end
end

if (isfield(p, 'rmsFF_fb'))
Audapter(3, 'rmsff_fb', p.rmsFF_fb, toPrompt);
Expand Down Expand Up @@ -415,3 +437,16 @@


end

end



function audapterSetParamError(ME, versionName)
warning(['Audapter returned an error with this message: \n"%s".\n' ...
'The error may be due to a mismatch between your version of the Audapter mex file vs Audapter MATLAB files, ' ...
'since this field was introduced in blab-lab fork Audapter version %s. ' ...
'You can check the Audapter mex file version with Audapter(''version''), and ' ...
'you can check the Audapter MATLAB files version in audapter_matlab/README.md.'], ...
ME.message, versionName);
end
2 changes: 1 addition & 1 deletion mcode/UIRecorder.m
Original file line number Diff line number Diff line change
Expand Up @@ -1071,7 +1071,7 @@ function record(handles)
error('Not exactly one wav file was found.');
end

[wx, fs] = read_audio(fullfile(handles.simDataDir, handles.phase, ...
[wx, fs] = audioread(fullfile(handles.simDataDir, handles.phase, ...
['rep', num2str(handles.repNum)], ...
dir1(1).name));
if fs ~= 48000 % Resample
Expand Down
2 changes: 1 addition & 1 deletion mcode/audapterDemo_online.m
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function audapterDemo_online(mode, varargin)
maxPBSize = Audapter('getMaxPBLen');

check_file(noiseWavFN);
[w, fs] = read_audio(noiseWavFN);
[w, fs] = audioread(noiseWavFN);

if fs ~= params.sr * params.downFact
w = resample(w, params.sr * params.downFact, fs);
Expand Down
79 changes: 75 additions & 4 deletions mcode/genRandScript.m
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,15 @@

else
trialTypes = strip_brackets(trialTypes, 'Wrong format in field TRIAL_TYPES_IN_BLOCK');
t_items = splitstring(trialTypes, ',');
t_items = strsplit(trialTypes, ',');

for i1 = 1 : numel(t_items)
if length(strfind(t_items{i1}, '-')) ~= 1
error('Wrong format in item #%d of TRIAL_TYPES_IN_BLOCK: %s', ...
i1, t_items{i1});
end

t_strs = splitstring(t_items{i1}, '-');
t_strs = strsplit(t_items{i1}, '-');
a_trialTypes{end + 1} = t_strs{2};
a_trialTypeIsPert(end + 1) = ~(isequal(lower(a_trialTypes{end}), 'ctrl') || ...
isequal(lower(a_trialTypes{end}), 'baseline'));
Expand Down Expand Up @@ -307,7 +307,7 @@
if ~isempty(strfind(t_val, '-'))
error('Unrecognized format in PITCH_SHIFT_DURS_MS')
end
t_vals = splitstring(t_val, ',');
t_vals = strsplit(t_val, ',');

if length(t_vals) == 1
a_shiftDurs_ms.(tt) = repmat(str2double(t_vals{1}), 1, a_numShifts.(tt));
Expand Down Expand Up @@ -525,6 +525,77 @@

return

function out = string2intervals(str, bCheckOrder)
%% Constants
sep = ',';

%%
out = {};

str = strrep(str, ' ', '');
if ~isequal(str(end), sep)
str = [str, sep];
end

idx = 1;
bBracket = 0;
tmpStr = [];
while idx <= length(str)
if bBracket == 0
if isequal(str(idx), '[')
bBracket = 1;
elseif isequal(str(idx), ']')
error('Unexpected right bracket');
elseif isequal(str(idx), sep)
if isempty(strfind(tmpStr, '-'))
out{end + 1} = repmat(str2double(tmpStr), 1, 2);
elseif length(strfind(tmpStr, '-') == 1)
t_vals = strsplit(tmpStr, '-');
t_array = [str2double(t_vals{1}), str2double(t_vals{2})];
if bCheckOrder
t_array = sort(t_array);
end
out{end + 1} = t_array;
end

tmpStr = [];
else
tmpStr = [tmpStr, str(idx)];
end
else
if isequal(str(idx), ']')
bBracket = 0;
if isempty(strfind(tmpStr, '-'))
out{end + 1} = repmat(str2double(tmpStr), 1, 2);
elseif length(strfind(tmpStr, '-') == 1)
t_vals = strsplit(tmpstr, '-');
t_array = [str2double(t_vals{1}), str2double(t_vals{2})];
if bCheckOrder
t_array = sort(t_array);
end
out{end + 1} = t_array;
end

tmpStr = [];
elseif isequal(str(idx), '[')
error('Unexpected left bracket');
else
tmpStr = [tmpStr, str(idx)];
end

end
idx = idx + 1;
end

%% Prune results
bPreserve = zeros(1, length(out));
for i1 = 1 : length(out)
bPreserve(i1) = ~isnan(out{i1}(1));
end

out = out(find(bPreserve));
return

function str1 = strip_brackets(str0, errMsg)
str1 = strrep(deblank(str0), ' ', '');
if length(str1) <= 3 || ...
Expand Down Expand Up @@ -589,7 +660,7 @@
% if ~isempty(strfind(t_val, '-'))
% error('Unrecognized format in PITCH_SHIFTS_CENT')
% end
t_vals = splitstring(t_val, ',');
t_vals = strsplit(t_val, ',');

if length(t_vals) == 1
a_shifts.(tt) = repmat(str2double(t_vals{1}), 1, a_numShifts.(tt));
Expand Down
8 changes: 7 additions & 1 deletion mcode/getAudapterDefaultParams.m
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,13 @@

p.fb3Gain = dBSPL2WaveAmp(-Inf);

p.fb4GainDB = 10;
% feedback mode 4 is speech-modulated noise.
p.fb4GainDB = 10; % A gain multiplier calculated as 10^(p.fb4GainDB / 20). So if p.fb4GainDB is set to 0, the gain multiplier is set to 1.

% feedback mode 5 is playback (noise) + speech-modulated playback (noise)
p.fb5GainDB_speech = 0.0; % gain multiplier (in dB) for the speech-modulated noise component. Actual scaling factor is 10^(p.fb5GainDB_speech / 20). So if p.fb5GainDB is set to 0, the gain multiplier is set to 1.
p.fb5Gain_playback = 1.0; % gain multiplier (linear scaling factor) for the constant noise component

p.rmsFF_fb = [0.8, 0.99, 0.1, 0.1];

%% Perturbation-related variables: these are for the mel (bMelShift=1) or Hz (bMelShift=0) frequency space
Expand Down
3 changes: 2 additions & 1 deletion mcode/getAudapterParamSet.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
'pertAmp2D', 'pertPhi', 'pertPhi2D', 'gain', ...
'tsgToneDur', 'tsgToneFreq', 'tsgToneAmp', 'tsgToneRamp', ...
'tsgInt', ...
'bClampFormants','clamposts', 'clampf1' 'clampf2'};
'bClampFormants','clamposts', 'clampf1' 'clampf2', ...
'fb5GainDB_speech', 'fb5Gain_playback'};

% TODO: datapb length

Expand Down
2 changes: 1 addition & 1 deletion mcode/getPitch.m
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
function f0s=getPitch(varargin)
%% Load signal and specify parameters
if (nargin==0)
[sig,sr]=read_audio('site2.wav'); % Site2: Fric.(9338:11400),Vowel:(11700:16380)
[sig,sr]=audioread('site2.wav'); % Site2: Fric.(9338:11400),Vowel:(11700:16380)
else
% fileName=varargin{1};
% load(fileName); % gives data
Expand Down
31 changes: 30 additions & 1 deletion mcode/getPitchShiftTimeStamps.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,33 @@
psCents(stret_on(i1))];
end

return
end


function [t_onset, t_offset] = get_cont_stretches(x)
t_onset = [];
t_offset = [];

stat = 0;

for i1 = 1 : numel(x)
if stat == 0
if x(i1) == 1
t_onset(end + 1) = i1;
stat = 1;
end
else
if x(i1) == 0
t_offset(end + 1) = i1 - 1;
stat = 0;
end
end
end

if length(t_onset) > length(t_offset)
t_offset(end + 1) = length(x);
end


end

2 changes: 1 addition & 1 deletion mcode/play_wav.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ function play_wav(wavFN, gain)
fs1 = 48000;
rampDur = 0.1;

[w, fs0] = read_audio(wavFN);
[w, fs0] = audioread(wavFN);
w = resample(w, fs1, fs0);

if length(w) > MAX_PB_SIZE
Expand Down
4 changes: 2 additions & 2 deletions mcode/runExperiment.m
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ function runExperiment(exptConfigFN, varargin)
expt_config.SUST_F1_SHIFTS_RATIO, expt_config.SUST_F2_SHIFTS_RATIO, ...
expt_config.SUST_SHIFT_DURS_MS, expt_config.SUST_STIM_UTTER, '');
else
info_log(sprintf('Sust phase %s will not be included due to nReps == 0', t_phase));
warning('Sust phase %s will not be included due to nReps == 0', t_phase);
idxKeep = setxor(1 : length(expt.allPhases), fsic(expt.allPhases, t_phase));
expt.allPhases = expt.allPhases(idxKeep);
expt.recPhases = expt.recPhases(idxKeep);
Expand Down Expand Up @@ -315,7 +315,7 @@ function runExperiment(exptConfigFN, varargin)
end

%% Load the multi-talker babble noise
[mbw, fs_mtb]=read_audio('mtbabble48k.wav');
[mbw, fs_mtb]=audioread('mtbabble48k.wav');

% Normalize the amplitude of the mtb noise
mbw = mbw - mean(mbw);
Expand Down
2 changes: 1 addition & 1 deletion mcode/test_audapter.m
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ function test_audapter(varargin)
% Audapter('setParam', 'bbypassfmt', 0, 1);

%% Load the multi-talker babble noise
[mbw, fs_mtb] = read_audio('mtbabble48k.wav');
[mbw, fs_mtb] = audioread('mtbabble48k.wav');

% Normalize the amplitude of the mtb noise
mbw = mbw - mean(mbw);
Expand Down
2 changes: 1 addition & 1 deletion mcode/test_fmt_shift_audapter.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
% Audapter(3, 'bpitchshift', 0, 1);

%% Load the multi-talker babble noise
[mbw, fs_mtb]=read_audio('mtbabble48k.wav');
[mbw, fs_mtb]=audioread('mtbabble48k.wav');

% Normalize the amplitude of the mtb noise
mbw = mbw - mean(mbw);
Expand Down