diff --git a/lib/core/include/av-speech-in-noise/core/Player.hpp b/lib/core/include/av-speech-in-noise/core/Player.hpp index f074f2a5..60036b27 100644 --- a/lib/core/include/av-speech-in-noise/core/Player.hpp +++ b/lib/core/include/av-speech-in-noise/core/Player.hpp @@ -48,8 +48,13 @@ struct Frequency { double Hz; }; -struct VibrotactileStimulus { +struct Vibration { Duration duration{}; +}; + +struct VibrotactileStimulus { + std::vector vibrations; + Duration gap; Delay targetStartRelativeDelay{}; Delay additionalPostFadeInDelay{}; Frequency frequency{}; diff --git a/lib/core/src/OutputFile.cpp b/lib/core/src/OutputFile.cpp index 15c1c014..7694c935 100644 --- a/lib/core/src/OutputFile.cpp +++ b/lib/core/src/OutputFile.cpp @@ -23,8 +23,8 @@ enum class OutputFileImpl::Trial { none }; -static auto operator<<(std::ostream &os, const std::vector &v) - -> std::ostream & { +static auto operator<<( + std::ostream &os, const std::vector &v) -> std::ostream & { if (!v.empty()) { auto first{true}; os << v.front(); @@ -82,8 +82,8 @@ static auto insertNewLine(std::ostream &stream) -> std::ostream & { } template -auto insertLabeledLine(std::ostream &stream, const std::string &label, T thing) - -> std::ostream & { +auto insertLabeledLine( + std::ostream &stream, const std::string &label, T thing) -> std::ostream & { return insertNewLine(insert(insert(insert(stream, label), ": "), thing)); } @@ -91,54 +91,54 @@ static auto string(const std::stringstream &stream) -> std::string { return stream.str(); } -static auto insertSubjectId(std::ostream &stream, const TestIdentity &p) - -> std::ostream & { +static auto insertSubjectId( + std::ostream &stream, const TestIdentity &p) -> std::ostream & { return insertLabeledLine(stream, "subject", p.subjectId); } -static auto insertTester(std::ostream &stream, const TestIdentity &p) - -> std::ostream & { +static auto insertTester( + std::ostream &stream, const TestIdentity &p) -> std::ostream & { return insertLabeledLine(stream, "tester", p.testerId); } -static auto insertSession(std::ostream &stream, const TestIdentity &p) - -> std::ostream & { +static auto insertSession( + std::ostream &stream, const TestIdentity &p) -> std::ostream & { return insertLabeledLine(stream, "session", p.session); } -static auto insertMethod(std::ostream &stream, const TestIdentity &p) - -> std::ostream & { +static auto insertMethod( + std::ostream &stream, const TestIdentity &p) -> std::ostream & { return insertLabeledLine(stream, "method", p.method); } -static auto insertRmeSetting(std::ostream &stream, const TestIdentity &p) - -> std::ostream & { +static auto insertRmeSetting( + std::ostream &stream, const TestIdentity &p) -> std::ostream & { return insertLabeledLine(stream, "RME setting", p.rmeSetting); } -static auto insertTransducer(std::ostream &stream, const TestIdentity &p) - -> std::ostream & { +static auto insertTransducer( + std::ostream &stream, const TestIdentity &p) -> std::ostream & { return insertLabeledLine(stream, "transducer", p.transducer); } -static auto insertMasker(std::ostream &stream, const Test &p) - -> std::ostream & { +static auto insertMasker( + std::ostream &stream, const Test &p) -> std::ostream & { return insertLabeledLine(stream, "masker", p.maskerFileUrl.path); } -static auto insertTargetPlaylist(std::ostream &stream, const Test &p) - -> std::ostream & { +static auto insertTargetPlaylist( + std::ostream &stream, const Test &p) -> std::ostream & { return insertLabeledLine(stream, "targets", p.targetsUrl.path); } -static auto insertMaskerLevel(std::ostream &stream, const Test &p) - -> std::ostream & { +static auto insertMaskerLevel( + std::ostream &stream, const Test &p) -> std::ostream & { return insertLabeledLine( stream, "masker level (dB SPL)", p.maskerLevel.dB_SPL); } -static auto insertCondition(std::ostream &stream, const Test &p) - -> std::ostream & { +static auto insertCondition( + std::ostream &stream, const Test &p) -> std::ostream & { return insertLabeledLine(stream, "condition", name(p.condition)); } @@ -155,8 +155,8 @@ static auto evaluation(const Evaluative &trial) -> std::string { static auto identity(const Test &test) -> TestIdentity { return test.identity; } -static auto operator<<(std::ostream &stream, const TestIdentity &identity) - -> std::ostream & { +static auto operator<<( + std::ostream &stream, const TestIdentity &identity) -> std::ostream & { return insertTransducer( insertRmeSetting( insertMethod( @@ -168,8 +168,8 @@ static auto operator<<(std::ostream &stream, const TestIdentity &identity) identity); } -static auto operator<<(std::ostream &stream, const AdaptiveTest &test) - -> std::ostream & { +static auto operator<<( + std::ostream &stream, const AdaptiveTest &test) -> std::ostream & { stream << identity(test); insertMasker(stream, test); insertTargetPlaylist(stream, test); @@ -194,8 +194,8 @@ static auto operator<<(std::ostream &stream, const AdaptiveTest &test) return insertNewLine(stream); } -static auto operator<<(std::ostream &stream, const FixedLevelTest &test) - -> std::ostream & { +static auto operator<<( + std::ostream &stream, const FixedLevelTest &test) -> std::ostream & { stream << identity(test); insertMasker(stream, test); insertTargetPlaylist(stream, test); @@ -264,8 +264,8 @@ static auto operator<<(std::ostream &stream, return insertNewLine(stream); } -static auto operator<<(std::ostream &stream, TargetStartTime t) - -> std::ostream & { +static auto operator<<( + std::ostream &stream, TargetStartTime t) -> std::ostream & { return insertLabeledLine(stream, "target start time (ns)", t.nanoseconds); } @@ -281,14 +281,14 @@ static auto operator<<(std::ostream &stream, return insertNewLine(stream); } -static auto operator<<(std::ostream &stream, const AdaptiveTestResult &result) - -> std::ostream & { +static auto operator<<( + std::ostream &stream, const AdaptiveTestResult &result) -> std::ostream & { return insertLabeledLine( stream, "threshold for " + result.targetsUrl.path, result.threshold); } -static auto operator<<(std::ostream &stream, const Flaggable &flaggable) - -> std::ostream & { +static auto operator<<( + std::ostream &stream, const Flaggable &flaggable) -> std::ostream & { if (flaggable.flagged) { insertCommaAndSpace(stream); insert(stream, "FLAGGED"); @@ -652,7 +652,15 @@ class KeyPressTrialFormatter : public TrialFormatter { insertCommaAndSpace(stream); insert(stream, trial_.rt.milliseconds); insertCommaAndSpace(stream); - insert(stream, trial_.vibrotactileStimulus.duration.seconds); + stream << '['; + auto first{true}; + for (const auto &v : trial_.vibrotactileStimulus.vibrations) { + if (!first) + stream << "; "; + insert(stream, v.duration.seconds); + first = false; + } + stream << ']'; insertCommaAndSpace(stream); insert(stream, trial_.vibrotactileStimulus.targetStartRelativeDelay.seconds); @@ -782,8 +790,8 @@ void OutputFileImpl::openNewFile(const TestIdentity &test) { currentTrial = Trial::none; } -auto OutputFileImpl::generateNewFilePath(const TestIdentity &test) - -> std::string { +auto OutputFileImpl::generateNewFilePath( + const TestIdentity &test) -> std::string { path.setRelativeOutputDirectory(test.relativeOutputUrl.path); return path.outputDirectory() + "/" + path.generateFileName(test) + ".txt"; } diff --git a/lib/core/src/SubmittingKeyPress.cpp b/lib/core/src/SubmittingKeyPress.cpp index 279354f6..5823b687 100644 --- a/lib/core/src/SubmittingKeyPress.cpp +++ b/lib/core/src/SubmittingKeyPress.cpp @@ -11,13 +11,14 @@ InteractorImpl::InteractorImpl(FixedLevelMethod &method, RunningATest &model, maskerPlayer{maskerPlayer}, randomizer{randomizer} {} template -auto randomSelection(Randomizer &randomizer, std::array x) - -> double { +auto randomSelection( + Randomizer &randomizer, std::array x) -> double { return x.at(randomizer.betweenInclusive(0, x.size() - 1)); } void InteractorImpl::notifyThatTrialWillBegin(int) { - const std::array delaysSeconds = {2.060, 2.110, 2.160, 2.190}; + const std::array delaysSeconds = { + 1.94, 2., 2.060, 2.110, 2.160, 2.190}; const std::array durationsSeconds = {.100, .250}; VibrotactileStimulus stimulus; @@ -25,7 +26,13 @@ void InteractorImpl::notifyThatTrialWillBegin(int) { randomSelection(randomizer, delaysSeconds); stimulus.additionalPostFadeInDelay.seconds = RunningATest::targetOnsetFringeDuration.seconds; - stimulus.duration.seconds = randomSelection(randomizer, durationsSeconds); + stimulus.vibrations.resize(2); + const auto firstDurationIndex = randomizer.betweenInclusive(0, 1); + stimulus.vibrations.at(0).duration.seconds = + durationsSeconds.at(firstDurationIndex); + stimulus.vibrations.at(1).duration.seconds = + durationsSeconds.at((firstDurationIndex + 1) % 2); + stimulus.gap.seconds = 0.1; stimulus.frequency.Hz = 250; maskerPlayer.prepareVibrotactileStimulus(stimulus); lastVibrotactileStimulus = stimulus; @@ -46,8 +53,8 @@ void InteractorImpl::notifyThatTargetWillPlayAt( 1000; } -auto InteractorImpl::submits(const std::vector &responses) - -> bool { +auto InteractorImpl::submits( + const std::vector &responses) -> bool { if (!readyForResponse) return false; auto min{responses.end()}; diff --git a/lib/player/include/av-speech-in-noise/player/MaskerPlayerImpl.hpp b/lib/player/include/av-speech-in-noise/player/MaskerPlayerImpl.hpp index d65dcd1d..13fd874b 100644 --- a/lib/player/include/av-speech-in-noise/player/MaskerPlayerImpl.hpp +++ b/lib/player/include/av-speech-in-noise/player/MaskerPlayerImpl.hpp @@ -87,16 +87,15 @@ class MaskerPlayerImpl : public MaskerPlayer, static constexpr Delay callbackDelay{1. / 30}; struct SharedState { - audio_type sourceAudio{}; + audio_type sourceAudio; std::vector samplesToWaitPerChannel; std::vector audioFrameHeadsPerChannel; + std::vector vibrotactileStimulus; double levelScalar{1}; - double vibrotactileTimeScalar{}; std::atomic fadeInCompleteSystemTime{}; std::atomic fadeInCompleteSystemTimeSampleOffset{}; gsl::index rampSamples{}; gsl::index steadyLevelSamples{}; - gsl::index vibrotactileSamples{}; gsl::index vibrotactileSamplesToWait{}; bool firstChannelOnly{}; bool secondChannelOnly{}; diff --git a/lib/player/src/MaskerPlayerImpl.cpp b/lib/player/src/MaskerPlayerImpl.cpp index e33090fb..d55ff939 100644 --- a/lib/player/src/MaskerPlayerImpl.cpp +++ b/lib/player/src/MaskerPlayerImpl.cpp @@ -19,13 +19,13 @@ static auto at(const std::vector &x, gsl::index n) -> double { return x.at(n); } -static auto at(std::vector &x, gsl::index n) - -> sample_index_type & { +static auto at( + std::vector &x, gsl::index n) -> sample_index_type & { return x.at(n); } -static auto channel(const audio_type &x, channel_index_type i) - -> const channel_type & { +static auto channel( + const audio_type &x, channel_index_type i) -> const channel_type & { return x.at(i); } @@ -46,8 +46,8 @@ static auto samples(const audio_type &x) -> sample_index_type { return samples(firstChannel(x)); } -static auto firstChannel(const std::vector &x) - -> channel_buffer_type { +static auto firstChannel( + const std::vector &x) -> channel_buffer_type { return x.front(); } @@ -55,8 +55,8 @@ static auto channels(const audio_type &x) -> channel_index_type { return x.size(); } -static auto channels(const std::vector &x) - -> channel_index_type { +static auto channels( + const std::vector &x) -> channel_index_type { return x.size(); } @@ -106,13 +106,13 @@ static void mute(channel_buffer_type x) { std::fill(x.begin(), x.end(), sample_type{0}); } -static auto framesToFill(const std::vector &audioBuffer) - -> sample_index_type { +static auto framesToFill( + const std::vector &audioBuffer) -> sample_index_type { return noChannels(audioBuffer) ? 0 : firstChannel(audioBuffer).size(); } -static auto mathModulus(sample_index_type a, sample_index_type b) - -> sample_index_type { +static auto mathModulus( + sample_index_type a, sample_index_type b) -> sample_index_type { auto result{a % b}; return result > 0 ? result : result + b; } @@ -132,8 +132,8 @@ static void scheduleCallback(Timer &timer, Delay x) { timer.scheduleCallbackAfterSeconds(x.seconds); } -static auto audioDeviceDescriptions(AudioPlayer &player) - -> std::vector { +static auto audioDeviceDescriptions( + AudioPlayer &player) -> std::vector { std::vector descriptions( gsl::narrow(player.deviceCount())); std::generate(descriptions.begin(), descriptions.end(), @@ -141,8 +141,8 @@ static auto audioDeviceDescriptions(AudioPlayer &player) return descriptions; } -static auto findDeviceIndex(AudioPlayer &player, const std::string &device) - -> int { +static auto findDeviceIndex( + AudioPlayer &player, const std::string &device) -> int { auto devices{audioDeviceDescriptions(player)}; auto found{std::find(devices.begin(), devices.end(), device)}; if (found == devices.end()) @@ -225,13 +225,25 @@ void MaskerPlayerImpl::prepareVibrotactileStimulus( "prepare vibrotactile stimulus."); const auto sampleRateHz{av_speech_in_noise::sampleRateHz(player)}; - sharedState.vibrotactileSamples = - gsl::narrow_cast(stimulus.duration.seconds * sampleRateHz); - sharedState.vibrotactileTimeScalar = stimulus.frequency.Hz / sampleRateHz; sharedState.vibrotactileSamplesToWait = gsl::narrow_cast( (stimulus.targetStartRelativeDelay.seconds + stimulus.additionalPostFadeInDelay.seconds) * sampleRateHz); + sharedState.vibrotactileStimulus.clear(); + for (auto i{0}; i < stimulus.vibrations.size(); ++i) { + if (i > 0) + for (auto j{0}; j < gsl::narrow_cast( + stimulus.gap.seconds * sampleRateHz); + ++j) + sharedState.vibrotactileStimulus.push_back(0); + for (auto j{0}; + j < gsl::narrow_cast( + stimulus.vibrations.at(i).duration.seconds * sampleRateHz); + ++j) + sharedState.vibrotactileStimulus.push_back( + gsl::narrow_cast(std::sin( + 2 * pi() * stimulus.frequency.Hz * j / sampleRateHz))); + } } void MaskerPlayerImpl::enableVibrotactileStimulus() { @@ -400,8 +412,8 @@ void MaskerPlayerImpl::fillAudioBuffer( static auto squared(double x) -> double { return x * x; } -static auto sourceFrames(MaskerPlayerImpl::SharedState &sharedState) - -> sample_index_type { +static auto sourceFrames( + MaskerPlayerImpl::SharedState &sharedState) -> sample_index_type { return samples(firstChannel(sharedState.sourceAudio)); } @@ -472,10 +484,8 @@ void MaskerPlayerImpl::AudioThreadContext::fillAudioBuffer( if (sharedState.vibrotactileEnabled && channels(audioBuffer) > 2) at(channel(audioBuffer, 2), i) = playingVibrotactile && vibrotactileCounter >= sharedState.vibrotactileSamplesToWait - ? gsl::narrow_cast( - std::sin(2 * pi() * sharedState.vibrotactileTimeScalar * - (vibrotactileCounter - - sharedState.vibrotactileSamplesToWait))) + ? sharedState.vibrotactileStimulus.at(vibrotactileCounter - + sharedState.vibrotactileSamplesToWait) : sample_type{0.}; bool stateTransition{}; if (state == State::fadingIn && @@ -491,7 +501,7 @@ void MaskerPlayerImpl::AudioThreadContext::fillAudioBuffer( } if (playingVibrotactile && vibrotactileCounter == - sharedState.vibrotactileSamples + + sharedState.vibrotactileStimulus.size() + sharedState.vibrotactileSamplesToWait) { clear(playingVibrotactile); } diff --git a/test/MaskerPlayer.cpp b/test/MaskerPlayer.cpp index b17e67a7..39dd0f2a 100644 --- a/test/MaskerPlayer.cpp +++ b/test/MaskerPlayer.cpp @@ -2,7 +2,6 @@ #include "AudioReaderStub.hpp" #include "TimerStub.hpp" -#include #include #include @@ -125,8 +124,8 @@ class AudioPlayerStub : public AudioPlayer { return nanoseconds_; } - [[nodiscard]] auto systemTimeForNanoseconds() const - -> player_system_time_type { + [[nodiscard]] auto + systemTimeForNanoseconds() const -> player_system_time_type { return systemTimeForNanoseconds_; } @@ -179,13 +178,13 @@ class MaskerPlayerListenerStub : public MaskerPlayer::Observer { void fadeOutComplete() override { fadeOutCompleted_ = true; } - [[nodiscard]] auto fadeInCompleteSystemTime() const - -> player_system_time_type { + [[nodiscard]] auto + fadeInCompleteSystemTime() const -> player_system_time_type { return fadeInCompleteSystemTime_; } - [[nodiscard]] auto fadeInCompleteSystemTimeSampleOffset() const - -> gsl::index { + [[nodiscard]] auto + fadeInCompleteSystemTimeSampleOffset() const -> gsl::index { return fadeInCompleteSystemTimeSampleOffset_; } @@ -210,16 +209,16 @@ class MaskerPlayerListenerStub : public MaskerPlayer::Observer { }; template -auto elementWiseProduct(std::vector v, const std::vector &y) - -> std::vector { +auto elementWiseProduct( + std::vector v, const std::vector &y) -> std::vector { std::transform( v.begin(), v.end(), y.begin(), v.begin(), std::multiplies()); return v; } template -auto subvector(const std::vector &v, int offset, int size) - -> std::vector { +auto subvector( + const std::vector &v, int offset, int size) -> std::vector { const auto begin = v.begin() + offset; return {begin, begin + size}; } @@ -258,8 +257,8 @@ auto mToN(int M, int N) -> std::vector { auto oneToN(int N) -> std::vector { return mToN(1, N); } -auto concatenate(std::vector first, const std::vector &second) - -> std::vector { +auto concatenate(std::vector first, + const std::vector &second) -> std::vector { first.insert(first.end(), second.begin(), second.end()); return first; } @@ -278,8 +277,8 @@ void setCurrentSystemTime(AudioPlayerStub &player, std::uintmax_t t) { player.setCurrentSystemTime(t); } -auto nanoseconds(MaskerPlayerImpl &player, player_system_time_type t = {}) - -> std::uintmax_t { +auto nanoseconds(MaskerPlayerImpl &player, + player_system_time_type t = {}) -> std::uintmax_t { return player.nanoseconds({t}); } @@ -287,14 +286,14 @@ auto currentSystemTime(MaskerPlayerImpl &player) -> PlayerTime { return player.currentSystemTime(); } -auto systemTimeForNanoseconds(AudioPlayerStub &player) - -> player_system_time_type { +auto systemTimeForNanoseconds( + AudioPlayerStub &player) -> player_system_time_type { return player.systemTimeForNanoseconds(); } auto fillAudioBuffer(AudioPlayer::Observer *observer, gsl::index channels, - gsl::index frames, player_system_time_type t = {}) - -> std::vector> { + gsl::index frames, + player_system_time_type t = {}) -> std::vector> { std::vector> audio(channels); std::vector> adapted; for (auto &channel : audio) { @@ -321,8 +320,8 @@ auto setOnPlayTask(AudioPlayerStub &audioPlayer, } auto fillAudioBufferAsync(MaskerPlayerImpl &player, - AudioPlayerStub &audioPlayer, gsl::index channels, gsl::index frames) - -> std::future>> { + AudioPlayerStub &audioPlayer, gsl::index channels, + gsl::index frames) -> std::future>> { auto future{ setOnPlayTask(audioPlayer, [=](AudioPlayer::Observer *observer) { return fillAudioBuffer(observer, channels, frames); @@ -331,15 +330,15 @@ auto fillAudioBufferAsync(MaskerPlayerImpl &player, return future; } -auto fillAudioBufferMonoAsync( - MaskerPlayerImpl &player, AudioPlayerStub &audioPlayer, gsl::index frames) - -> std::future>> { +auto fillAudioBufferMonoAsync(MaskerPlayerImpl &player, + AudioPlayerStub &audioPlayer, + gsl::index frames) -> std::future>> { return fillAudioBufferAsync(player, audioPlayer, 1, frames); } -auto fillAudioBufferStereoAsync( - MaskerPlayerImpl &player, AudioPlayerStub &audioPlayer, gsl::index frames) - -> std::future>> { +auto fillAudioBufferStereoAsync(MaskerPlayerImpl &player, + AudioPlayerStub &audioPlayer, + gsl::index frames) -> std::future>> { return fillAudioBufferAsync(player, audioPlayer, 2, frames); } @@ -618,9 +617,8 @@ MASKER_PLAYER_TEST(setChannelDelayMonoLoadNewAudio) { setSampleRateHz(audioPlayer, 3); setChannelDelaySeconds(player, 0, 1); loadMonoAudio(player, audioReader, {4, 5, 6}); - callInRealisticExecutionContext(player, audioPlayer, [&]() { - loadMonoAudio(player, audioReader, {1, 2, 3}); - }); + callInRealisticExecutionContext(player, audioPlayer, + [&]() { loadMonoAudio(player, audioReader, {1, 2, 3}); }); assertAsyncFilledMonoAudioEquals(player, audioPlayer, {0, 0, 0}); } @@ -798,9 +796,8 @@ MASKER_PLAYER_TEST(twentydBMultipliesSignalByTen) { MASKER_PLAYER_TEST(loadFileResetsSampleIndex) { loadMonoAudio(player, audioReader, {1, 2, 3}); - callInRealisticExecutionContext(player, audioPlayer, [&]() { - loadMonoAudio(player, audioReader, {4, 5, 6}); - }); + callInRealisticExecutionContext(player, audioPlayer, + [&]() { loadMonoAudio(player, audioReader, {4, 5, 6}); }); assertAsyncFilledMonoAudioEquals(player, audioPlayer, {4, 5, 6}); } @@ -980,12 +977,15 @@ MASKER_PLAYER_TEST(steadyLevelFollowingFadeIn) { MASKER_PLAYER_TEST(vibrotactile) { setRampSeconds(player, 3); setSampleRateHz(audioPlayer, 8); - setSteadyLevelSeconds(player, 1); + setSteadyLevelSeconds(player, 4); player.enableVibrotactileStimulus(); player.loadFile({}); VibrotactileStimulus stimulus; - stimulus.duration.seconds = 0.5; + stimulus.vibrations.resize(2); + stimulus.vibrations.at(0).duration.seconds = 0.5; + stimulus.vibrations.at(1).duration.seconds = 0.5; + stimulus.gap.seconds = 1; stimulus.targetStartRelativeDelay.seconds = 0.25; stimulus.frequency.Hz = 2; player.prepareVibrotactileStimulus(stimulus); @@ -994,10 +994,17 @@ MASKER_PLAYER_TEST(vibrotactile) { auto future{ setOnPlayTask(audioPlayer, [=](AudioPlayer::Observer *observer) { av_speech_in_noise::fillAudioBuffer(observer, 3, halfWindowLength); - return av_speech_in_noise::fillAudioBuffer(observer, 3, 6); + return av_speech_in_noise::fillAudioBuffer(observer, 3, 18); })}; fadeIn(player); - assertEqual(future.get().at(2), {0, 0, 0, 1, 0, -1}, 1e-15F); + assertEqual(future.get().at(2), + { + 0, 0, // target start delay + 0, 1, 0, -1, // vibration #1 + 0, 0, 0, 0, 0, 0, 0, 0, // gap + 0, 1, 0, -1 // vibration #2 + }, + 1e-15F); } MASKER_PLAYER_TEST(steadyLevelFollowingFadeInAmplified) { diff --git a/test/Model.cpp b/test/Model.cpp index c68bfdb9..6a14d622 100644 --- a/test/Model.cpp +++ b/test/Model.cpp @@ -19,8 +19,8 @@ #include namespace av_speech_in_noise { -static auto operator==(const AdaptiveTestResult &a, const AdaptiveTestResult &b) - -> bool { +static auto operator==( + const AdaptiveTestResult &a, const AdaptiveTestResult &b) -> bool { return a.targetsUrl.path == b.targetsUrl.path && a.threshold == b.threshold; } @@ -816,7 +816,7 @@ void submitValidResponse(submitting_keypress::InteractorImpl &interactor, } SUBMITTING_KEYPRESS_TEST(savesReactionTime) { - randomizer.randomInts.push(2); // 60, 110, 160, 190; 2 second delay added + randomizer.randomInts.push(4); // 1.94, 2, 2.06, 2.11, 2.16, 2.19 interactor.notifyThatTrialWillBegin({}); maskerPlayer.setNanosecondsFromPlayerTime(1e9); @@ -893,16 +893,20 @@ SUBMITTING_KEYPRESS_TEST(writesTarget) { } SUBMITTING_KEYPRESS_TEST(selectsRandomVibrotactileStimulus) { - randomizer.randomInts.push(3); // 60, 110, 160, 190; 2 second delay added + randomizer.randomInts.push(3); // 1.94, 2, 2.06, 2.11, 2.16, 2.19 randomizer.randomInts.push(1); // 100, 250 interactor.notifyThatTrialWillBegin({}); - AV_SPEECH_IN_NOISE_EXPECT_EQUAL(2.190, + AV_SPEECH_IN_NOISE_EXPECT_EQUAL(2.110, maskerPlayer.vibrotactileStimulus.targetStartRelativeDelay.seconds); AV_SPEECH_IN_NOISE_EXPECT_EQUAL( RunningATest::targetOnsetFringeDuration.seconds, maskerPlayer.vibrotactileStimulus.additionalPostFadeInDelay.seconds); AV_SPEECH_IN_NOISE_EXPECT_EQUAL( - 0.250, maskerPlayer.vibrotactileStimulus.duration.seconds); + 0.100, maskerPlayer.vibrotactileStimulus.gap.seconds); + AV_SPEECH_IN_NOISE_EXPECT_EQUAL(0.250, + maskerPlayer.vibrotactileStimulus.vibrations.at(0).duration.seconds); + AV_SPEECH_IN_NOISE_EXPECT_EQUAL(0.100, + maskerPlayer.vibrotactileStimulus.vibrations.at(1).duration.seconds); } } } diff --git a/test/OutputFile.cpp b/test/OutputFile.cpp index 431eb75d..0a5759d4 100644 --- a/test/OutputFile.cpp +++ b/test/OutputFile.cpp @@ -168,16 +168,16 @@ void assertEndsWith(WriterStub &writer, const std::string &s) { AV_SPEECH_IN_NOISE_EXPECT_TRUE(endsWith(written(writer), s)); } -auto find_nth_element(const std::string &content, gsl::index n, char what) - -> std::string::size_type { +auto find_nth_element(const std::string &content, gsl::index n, + char what) -> std::string::size_type { auto found{std::string::npos}; for (int i = 0; i < n; ++i) found = content.find(what, found + 1U); return found; } -auto upUntilFirstOfAny(const std::string &content, std::vector v) - -> std::string { +auto upUntilFirstOfAny( + const std::string &content, std::vector v) -> std::string { return content.substr(0, content.find_first_of({v.begin(), v.end()})); } @@ -226,8 +226,8 @@ void assertNthEntryOfSecondLine( auto test(WritingTest &useCase) -> Test & { return useCase.test(); } -auto at(const std::map &m, HeadingItem item) - -> gsl::index { +auto at(const std::map &m, + HeadingItem item) -> gsl::index { return m.at(item); } @@ -485,7 +485,9 @@ class WritingKeyPressTrial : public WritingTrial { trial.target = "a"; trial.key = KeyPressed::second; trial.rt.milliseconds = 3.4; - trial.vibrotactileStimulus.duration.seconds = 0.25; + trial.vibrotactileStimulus.vibrations.resize(2); + trial.vibrotactileStimulus.vibrations.at(0).duration.seconds = 0.25; + trial.vibrotactileStimulus.vibrations.at(1).duration.seconds = 0.1; trial.vibrotactileStimulus.targetStartRelativeDelay.seconds = 0.19; } @@ -501,7 +503,7 @@ class WritingKeyPressTrial : public WritingTrial { at(headingLabels_, HeadingItem::keyPressed), line); assertNthCommaDelimitedEntryOfLine( writer, "3.4", at(headingLabels_, HeadingItem::reactionTime), line); - assertNthCommaDelimitedEntryOfLine(writer, "0.25", + assertNthCommaDelimitedEntryOfLine(writer, "[0.25; 0.1]", at(headingLabels_, HeadingItem::vibrotactileDuration), line); assertNthCommaDelimitedEntryOfLine(writer, "0.19", at(headingLabels_, HeadingItem::vibrotactileDelay), line);