From 66f2441fb5248643c784a09c4fe0955aa0d7317e Mon Sep 17 00:00:00 2001 From: Chris Naber <50926971+cwnaber@users.noreply.github.com> Date: Thu, 7 May 2026 18:13:21 -0500 Subject: [PATCH 1/7] feedback mode 5 settings --- mcode/AudapterIO.m | 8 ++++++++ mcode/getAudapterDefaultParams.m | 3 +++ mcode/getAudapterParamSet.m | 3 ++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/mcode/AudapterIO.m b/mcode/AudapterIO.m index 21a9d81..46c8e49 100644 --- a/mcode/AudapterIO.m +++ b/mcode/AudapterIO.m @@ -163,6 +163,14 @@ if (isfield(p, 'fb4GainDB')) Audapter(3, 'fb4gaindb', p.fb4GainDB, toPrompt); end + + if (isfield(p, 'fb5Gain_speechDB')) + Audapter(3, 'fb5gain_speechdb', p.fb5Gain_speechDB, toPrompt); + end + + if (isfield(p, 'fb5Gain_noise')) + Audapter(3, 'fb5gain_noise', p.fb5Gain_noise, toPrompt); + end if (isfield(p, 'rmsFF_fb')) Audapter(3, 'rmsff_fb', p.rmsFF_fb, toPrompt); diff --git a/mcode/getAudapterDefaultParams.m b/mcode/getAudapterDefaultParams.m index faddbcc..56e0750 100644 --- a/mcode/getAudapterDefaultParams.m +++ b/mcode/getAudapterDefaultParams.m @@ -129,6 +129,9 @@ p.fb4GainDB = 10; p.rmsFF_fb = [0.8, 0.99, 0.1, 0.1]; +p.fb5Gain_speechDB = 10; +p.fb5Gain_noise = 1.0; + %% Perturbation-related variables: these are for the mel (bMelShift=1) or Hz (bMelShift=0) frequency space p.F2Min=0; p.F2Max=5000; diff --git a/mcode/getAudapterParamSet.m b/mcode/getAudapterParamSet.m index 69a4e0d..629e9ae 100644 --- a/mcode/getAudapterParamSet.m +++ b/mcode/getAudapterParamSet.m @@ -22,7 +22,8 @@ 'pertAmp2D', 'pertPhi', 'pertPhi2D', 'gain', ... 'tsgToneDur', 'tsgToneFreq', 'tsgToneAmp', 'tsgToneRamp', ... 'tsgInt', ... - 'bClampFormants','clamposts', 'clampf1' 'clampf2'}; + 'bClampFormants','clamposts', 'clampf1' 'clampf2', ... + 'fb5Gain_speechDB', 'fb5Gain_noise'}; % TODO: datapb length From fc9f5cb719968685cf07a381485fb5a754c1a7bf Mon Sep 17 00:00:00 2001 From: Chris Naber <50926971+cwnaber@users.noreply.github.com> Date: Fri, 8 May 2026 14:39:47 -0500 Subject: [PATCH 2/7] use more intuitive variables --- mcode/AudapterIO.m | 8 ++++---- mcode/getAudapterDefaultParams.m | 11 +++++++---- mcode/getAudapterParamSet.m | 2 +- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/mcode/AudapterIO.m b/mcode/AudapterIO.m index 46c8e49..56ef3a9 100644 --- a/mcode/AudapterIO.m +++ b/mcode/AudapterIO.m @@ -164,12 +164,12 @@ Audapter(3, 'fb4gaindb', p.fb4GainDB, toPrompt); end - if (isfield(p, 'fb5Gain_speechDB')) - Audapter(3, 'fb5gain_speechdb', p.fb5Gain_speechDB, toPrompt); + if (isfield(p, 'fb5gain_speech')) + Audapter(3, 'fb5gain_speech', p.fb5gain_speech, toPrompt); end - if (isfield(p, 'fb5Gain_noise')) - Audapter(3, 'fb5gain_noise', p.fb5Gain_noise, toPrompt); + if (isfield(p, 'fb5gain_noise')) + Audapter(3, 'fb5gain_noise', p.fb5gain_noise, toPrompt); end if (isfield(p, 'rmsFF_fb')) diff --git a/mcode/getAudapterDefaultParams.m b/mcode/getAudapterDefaultParams.m index 56e0750..d2f67b0 100644 --- a/mcode/getAudapterDefaultParams.m +++ b/mcode/getAudapterDefaultParams.m @@ -126,11 +126,14 @@ p.fb3Gain = dBSPL2WaveAmp(-Inf); -p.fb4GainDB = 10; -p.rmsFF_fb = [0.8, 0.99, 0.1, 0.1]; +% 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 noise + speech-modulated noise +p.fb5gain_speech = 1.0; % gain multiplier for the speech-modulated noise component +p.fb5gain_noise = 1.0; % gain multiplier for the constant noise component -p.fb5Gain_speechDB = 10; -p.fb5Gain_noise = 1.0; +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 p.F2Min=0; diff --git a/mcode/getAudapterParamSet.m b/mcode/getAudapterParamSet.m index 629e9ae..0e15733 100644 --- a/mcode/getAudapterParamSet.m +++ b/mcode/getAudapterParamSet.m @@ -23,7 +23,7 @@ 'tsgToneDur', 'tsgToneFreq', 'tsgToneAmp', 'tsgToneRamp', ... 'tsgInt', ... 'bClampFormants','clamposts', 'clampf1' 'clampf2', ... - 'fb5Gain_speechDB', 'fb5Gain_noise'}; + 'fb5gain_speech', 'fb5gain_noise'}; % TODO: datapb length From e5ea93866042996a4d1897a586a431cf33c0fdba Mon Sep 17 00:00:00 2001 From: Chris Naber <50926971+cwnaber@users.noreply.github.com> Date: Thu, 11 Jun 2026 15:22:46 -0500 Subject: [PATCH 3/7] Update variable names --- mcode/AudapterIO.m | 8 ++++---- mcode/getAudapterDefaultParams.m | 6 +++--- mcode/getAudapterParamSet.m | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mcode/AudapterIO.m b/mcode/AudapterIO.m index 56ef3a9..46abae8 100644 --- a/mcode/AudapterIO.m +++ b/mcode/AudapterIO.m @@ -164,12 +164,12 @@ Audapter(3, 'fb4gaindb', p.fb4GainDB, toPrompt); end - if (isfield(p, 'fb5gain_speech')) - Audapter(3, 'fb5gain_speech', p.fb5gain_speech, toPrompt); + if (isfield(p, 'fb5GainDB_speech')) + Audapter(3, 'fb5gaindb_speech', p.fb5GainDB_speech, toPrompt); end - if (isfield(p, 'fb5gain_noise')) - Audapter(3, 'fb5gain_noise', p.fb5gain_noise, toPrompt); + if (isfield(p, 'fb5Gain_playback')) + Audapter(3, 'fb5gain_playback', p.fb5Gain_playback, toPrompt); end if (isfield(p, 'rmsFF_fb')) diff --git a/mcode/getAudapterDefaultParams.m b/mcode/getAudapterDefaultParams.m index d2f67b0..f31a13c 100644 --- a/mcode/getAudapterDefaultParams.m +++ b/mcode/getAudapterDefaultParams.m @@ -129,9 +129,9 @@ % 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 noise + speech-modulated noise -p.fb5gain_speech = 1.0; % gain multiplier for the speech-modulated noise component -p.fb5gain_noise = 1.0; % gain multiplier for the constant noise component +% 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.fb4GainDB 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]; diff --git a/mcode/getAudapterParamSet.m b/mcode/getAudapterParamSet.m index 0e15733..8c8efac 100644 --- a/mcode/getAudapterParamSet.m +++ b/mcode/getAudapterParamSet.m @@ -23,7 +23,7 @@ 'tsgToneDur', 'tsgToneFreq', 'tsgToneAmp', 'tsgToneRamp', ... 'tsgInt', ... 'bClampFormants','clamposts', 'clampf1' 'clampf2', ... - 'fb5gain_speech', 'fb5gain_noise'}; + 'fb5GainDB_speech', 'fb5Gain_playback'}; % TODO: datapb length From 9a27ce683b0907245cfb5038f88cbaf43aca52b0 Mon Sep 17 00:00:00 2001 From: Chris Naber <50926971+cwnaber@users.noreply.github.com> Date: Fri, 12 Jun 2026 10:27:56 -0500 Subject: [PATCH 4/7] Fix typo in comment --- mcode/getAudapterDefaultParams.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mcode/getAudapterDefaultParams.m b/mcode/getAudapterDefaultParams.m index f31a13c..76e49fb 100644 --- a/mcode/getAudapterDefaultParams.m +++ b/mcode/getAudapterDefaultParams.m @@ -130,7 +130,7 @@ 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.fb4GainDB is set to 0, the gain multiplier is set to 1. +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]; From bfcef4828205cbfad962fe277bb7392b2d322960 Mon Sep 17 00:00:00 2001 From: Chris Naber <50926971+cwnaber@users.noreply.github.com> Date: Thu, 25 Jun 2026 13:32:47 -0500 Subject: [PATCH 5/7] Help user if mismatch between version of mex and matlab files --- mcode/AudapterIO.m | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/mcode/AudapterIO.m b/mcode/AudapterIO.m index 46abae8..9e2d04c 100644 --- a/mcode/AudapterIO.m +++ b/mcode/AudapterIO.m @@ -165,11 +165,25 @@ end if (isfield(p, 'fb5GainDB_speech')) - Audapter(3, 'fb5gaindb_speech', p.fb5GainDB_speech, toPrompt); + 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')) - Audapter(3, 'fb5gain_playback', p.fb5Gain_playback, toPrompt); + 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')) @@ -423,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 From 4adfaad800f7373ccbcbb47ea91c9b70ada0a684 Mon Sep 17 00:00:00 2001 From: Chris Naber <50926971+cwnaber@users.noreply.github.com> Date: Thu, 25 Jun 2026 16:20:05 -0500 Subject: [PATCH 6/7] Update README.md --- README.md | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/README.md b/README.md index da9b555..6675547 100644 --- a/README.md +++ b/README.md @@ -1,25 +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: http://sites.bu.edu/guentherlab/files/2016/11/AudapterManual.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). From 4083f870e79849afb22e742a59e84bcdf681d371 Mon Sep 17 00:00:00 2001 From: Chris Naber <50926971+cwnaber@users.noreply.github.com> Date: Fri, 26 Jun 2026 11:31:31 -0500 Subject: [PATCH 7/7] Commonmcode merge (#6) * Update README.md * Updates for merging commonmcode code into free-speech --------- Co-authored-by: Shanqing Cai --- mcode/UIRecorder.m | 2 +- mcode/audapterDemo_online.m | 2 +- mcode/genRandScript.m | 79 +++++++++++++++++++++++++++++++-- mcode/getPitch.m | 2 +- mcode/getPitchShiftTimeStamps.m | 31 ++++++++++++- mcode/play_wav.m | 2 +- mcode/runExperiment.m | 4 +- mcode/test_audapter.m | 2 +- mcode/test_fmt_shift_audapter.m | 2 +- 9 files changed, 113 insertions(+), 13 deletions(-) diff --git a/mcode/UIRecorder.m b/mcode/UIRecorder.m index fda54d9..1a5fe66 100644 --- a/mcode/UIRecorder.m +++ b/mcode/UIRecorder.m @@ -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 diff --git a/mcode/audapterDemo_online.m b/mcode/audapterDemo_online.m index b42b635..0a9fcca 100644 --- a/mcode/audapterDemo_online.m +++ b/mcode/audapterDemo_online.m @@ -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); diff --git a/mcode/genRandScript.m b/mcode/genRandScript.m index cbef99e..05bffbc 100644 --- a/mcode/genRandScript.m +++ b/mcode/genRandScript.m @@ -56,7 +56,7 @@ 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 @@ -64,7 +64,7 @@ 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')); @@ -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)); @@ -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 || ... @@ -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)); diff --git a/mcode/getPitch.m b/mcode/getPitch.m index 82664b9..a8712ee 100644 --- a/mcode/getPitch.m +++ b/mcode/getPitch.m @@ -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 diff --git a/mcode/getPitchShiftTimeStamps.m b/mcode/getPitchShiftTimeStamps.m index 86487b7..fc18d5d 100644 --- a/mcode/getPitchShiftTimeStamps.m +++ b/mcode/getPitchShiftTimeStamps.m @@ -32,4 +32,33 @@ psCents(stret_on(i1))]; end -return \ No newline at end of file +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 + diff --git a/mcode/play_wav.m b/mcode/play_wav.m index 2f60be3..a4bb204 100644 --- a/mcode/play_wav.m +++ b/mcode/play_wav.m @@ -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 diff --git a/mcode/runExperiment.m b/mcode/runExperiment.m index 2bf90f5..bc89a9d 100644 --- a/mcode/runExperiment.m +++ b/mcode/runExperiment.m @@ -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); @@ -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); diff --git a/mcode/test_audapter.m b/mcode/test_audapter.m index 916e1cb..18e0d0b 100644 --- a/mcode/test_audapter.m +++ b/mcode/test_audapter.m @@ -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); diff --git a/mcode/test_fmt_shift_audapter.m b/mcode/test_fmt_shift_audapter.m index c151ae3..671cdc4 100644 --- a/mcode/test_fmt_shift_audapter.m +++ b/mcode/test_fmt_shift_audapter.m @@ -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);