Commit d2140f76 authored by Robbie Meyers's avatar Robbie Meyers
Browse files

Revert "Revert "Merge branch 'master' into 'develop'""

This reverts commit 95d281f2.
parent 95d281f2
Pipeline #350465343 passed with stage
in 44 seconds
Changelog
==========
v4.1.1
------
Features
- Update Bekesy MLD schema to support cutoff frequencies.
- Update tone generation schema to support binaural exams.
- Support binaural results in audiometry tables.
- Dichotic Digits response area.
- Frequency Pattern response area.
- Accelerated threshold exam type.
Bug Fixes
- Resolve issue with PlaySound exam when user attempts to proceed before audio
is done playing.
- Allow media to play when protocol and calibration headset fields do not match.
v4.1.0
------
......
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<widget android-versionCode="266" id="com.creare.skhr.tabsint" version="4.1.0" xmlns="http://www.w3.org/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cdv="http://cordova.apache.org/ns/1.0" xmlns:gap="http://phonegap.com/ns/1.0">
<widget android-versionCode="267" id="com.creare.skhr.tabsint" version="4.1.1" xmlns="http://www.w3.org/ns/widgets" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cdv="http://cordova.apache.org/ns/1.0" xmlns:gap="http://phonegap.com/ns/1.0">
<name>TabSINT</name>
<description>TabSINT</description>
<author email="tabsint@creare.com" href="http://www.creare.com">&#xD;&#xD;&#xD;&#xD;&#xD;&#xD;&#xD;&#xD;&#xD;&#xD;
......@@ -19,9 +19,9 @@
<preference name="android-minSdkVersion" value="22"/>
<preference name="android-targetSdkVersion" value="29"/>
<preference name="deployment-target" value="8.0"/>
<preference name="AndroidXEnabled" value="true" />
<preference name="AndroidXEnabled" value="true"/>
<edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application">
<application android:requestLegacyExternalStorage="true" />
<application android:requestLegacyExternalStorage="true"/>
</edit-config>
<allow-navigation href="*"/>
<allow-intent href="*"/>
......
{
"name": "tabsint",
"version": "4.1.0",
"version": "4.1.1",
"repository": {
"type": "git",
"url": "git+https://gitlab.com/creare-com/tabsint.git"
......@@ -213,4 +213,4 @@
"cordova-plugin-webserver": {}
}
}
}
\ No newline at end of file
}
......@@ -15,12 +15,15 @@
"enum":[0, 180],
"description": "Phase of the masking material delivered to the right channel (used only if MaskerEar = 2). If 0, deliver the exact same noise to both channels. If 180, invert it at the right ear."
},
"BandpassOctaveWidth": {
"LowCutoff" : {
"type": "number",
"description": "Width of noise. This is the denominator, e.g., 8 results in 1/8th octave noise. If 0, don't apply filtering.",
"default": 1,
"maximum": 24,
"minimum": 0
"description": "Low cutoff frequency to filter the masker noise.",
"default": 500
},
"HighCutoff" : {
"type": "number",
"description": "High cutoff frequency to filter the masker noise.",
"default": 2000
},
"TargetEar": {
"type": "number",
......
......@@ -22,6 +22,7 @@
<strong translate>Ear:</strong>
<span ng-if="!chaExams.examProperties.OutputChannel || chaExams.examProperties.OutputChannel === 'HPL0'" translate>LEFT</span>
<span ng-if="chaExams.examProperties.OutputChannel === 'HPR0'" translate>RIGHT</span>
<span ng-if="chaExams.examProperties.OutputChannel === 'HPL0 HPR0' || chaExams.examProperties.OutputChannel === ['HPL0', 'HPR0']" translate>BOTH</span>
</div>
</div>
</div>
......
......@@ -4,8 +4,8 @@
<uib-tabset active="'horizontal'">
<uib-tab heading="Default" index="'horizontal'" active="horizontal_wise">
<br />
<table class="table-audiometry table-striped table-layout-fixed" ng-repeat="channel in outputChannels" ng-init="side = ['HPL0', 'HPL1', 'LINEL0 NONE'].includes(channel) ? 'Left': 'Right' ">
<caption ng-class="{'caption-left':side === 'Left', 'caption-right':side === 'Right'}">
<table class="table-audiometry table-striped table-layout-fixed" ng-repeat="channel in outputChannels" ng-init="side = ['HPL0', 'HPL1', 'LINEL0 NONE'].includes(channel) ? 'Left': ['HPR0', 'HPR1', 'NONE LINEL0'].includes(channel) ? 'Right': 'Binaural' ">
<caption ng-class="{'caption-left':side === 'Left', 'caption-right':side === 'Right', 'caption-binaural': channel === 'HPL0 HPR0'}">
<span>{{side}}</span>
</caption>
<tbody>
......@@ -28,7 +28,7 @@
</tr>
<tr
ng-if="resultsList[0].examType != 'BHAFT'">
<th scope="row"><span ng-if="resultsList[0].examType == 'MaskedThreshold' || resultsList[0].page.responseArea.masking ">{{'Masked'|translate}} </span>{{(resultsList[0].examProperties && resultsList[0].examProperties.Screener) || (resultsList[0].page.responseArea.examProperties && resultsList[0].page.responseArea.examProperties.Screener) ? 'Screening Level' : 'Threshold'}}<br />({{resultsList[0].examType == 'MaskedThreshold' ? 'dB HL' : resultsList[0].examProperties.LevelUnits}})</th>
<th scope="row"><span ng-if="resultsList[0].examType == 'MaskedThreshold' || resultsList[0].page.responseArea.masking ">{{'Masked'|translate}} </span>{{(resultsList[0].examProperties && resultsList[0].examProperties.Screener) || (resultsList[0].page.responseArea.examProperties && resultsList[0].page.responseArea.examProperties.Screener) ? 'Screening Level' : 'Threshold'}}<br />({{resultsList[0].examType == 'MaskedThreshold' ? 'dB HL' : resultsList[0].examProperties.LevelUnits || resultsList[0].Units}})</th>
<td ng-repeat="result in resultsList | reverse | filterBy: ['examProperties.OutputChannel']: channel | unique: 'presentationId' | orderBy: 'examProperties.F'">
<span ng-if="!result.examProperties.Screener">{{getThresholdText(result)}}</span>
<span ng-if="result.examProperties.Screener" ng-style="{'color':result.ResultType == 'Fail' ? 'red': 'black'}">{{formatScreenerResult(result.ResultType)}}</span>
......@@ -66,9 +66,9 @@
<uib-tab heading="Full Results" index="'vertical'" active="vertical_tab">
<br />
<table class="table-audiometry table-striped table-rotate">
<tbody ng-repeat="channel in outputChannels" ng-init="side = ['HPL0', 'HPL1', 'LINEL0 NONE'].includes(channel) ? 'Left': 'Right' ">
<tbody ng-repeat="channel in outputChannels" ng-init="side = ['HPL0', 'HPL1', 'LINEL0 NONE'].includes(channel) ? 'Left': ['HPR0', 'HPR1', 'NONE LINEL0'].includes(channel) ? 'Right': 'Binaural' ">
<tr
ng-if="resultsList[0].examType != 'BHAFT' && side == 'Left'">
ng-if="resultsList[0].examType != 'BHAFT' && (side == 'Left' || channel === 'HPL0 HPR0')">
<th scope="row">Frequency<br />(kHz)</th>
<td ng-repeat="result in resultsList | filterBy: ['examProperties.OutputChannel']: channel">
{{result.examProperties.F / 1000}}</td>
......@@ -85,16 +85,16 @@
{{result.ThresholdLevel | round}}</td>
</tr>
<tr ng-if="resultsList[0].examType != 'BHAFT'">
<th scope="row" ng-class="{'caption-left':side === 'Left', 'caption-right':side === 'Right'}">
<th scope="row" ng-class="{'caption-left':side === 'Left', 'caption-right':side === 'Right', 'caption-binaural': channel === 'HPL0 HPR0'}">
{{side}}
<br />
{{resultsList[0].examType == 'MaskedThreshold' || resultsList[0].page.responseArea.masking ? 'Masked' : ''}} {{(resultsList[0].examProperties && resultsList[0].examProperties.Screener) || (resultsList[0].page.responseArea.examProperties && resultsList[0].page.responseArea.examProperties.Screener)? 'Screening Level' : 'Threshold'}}
<br />
(
{{resultsList[0].examProperties.LevelUnits}} {{resultsList[0].examType == 'MaskedThreshold' || resultsList[0].page.responseArea.masking ? '&nbsp;|&nbsp;dB EM' : ''}}
{{resultsList[0].examProperties.LevelUnits || resultsList[0].Units}} {{resultsList[0].examType == 'MaskedThreshold' || resultsList[0].page.responseArea.masking ? '&nbsp;|&nbsp;dB EM' : ''}}
)
</th>
<td ng-class="{'caption-left':side === 'Left', 'caption-right':side === 'Right'}" ng-if="resultsList[0].examType != 'BHAFT'"
<td ng-class="{'caption-left':side === 'Left', 'caption-right':side === 'Right', 'caption-binaural': channel === 'HPL0 HPR0'}" ng-if="resultsList[0].examType != 'BHAFT'"
ng-repeat="result in resultsList | filterBy: ['examProperties.OutputChannel']: channel">
<span ng-if="!result.examProperties.Screener">{{getThresholdText(result)}}</span>
<span ng-if="result.examProperties.Screener" ng-style="{'color':result.ResultType == 'Fail' ? 'red': 'black'}">{{formatScreenerResult(result.ResultType)}}</span>
......@@ -104,7 +104,7 @@
</td>
</tr>
<tr ng-if="showSLMNoise && !['BHAFT'].includes(resultsList[0].examType)">
<th ng-class="{'caption-left':side === 'Left', 'caption-right':side === 'Right'}" scope="row">
<th ng-class="{'caption-left':side === 'Left', 'caption-right':side === 'Right', 'caption-binaural': channel === 'HPL0 HPR0'}" scope="row">
<span>SLM</span>
<span>L<sub>Fc</sub></span>
<span>(dB SPL)</span>
......@@ -114,7 +114,7 @@
</td>
</tr>
<tr ng-if="showSLMNoise">
<th ng-class="{'caption-left':side === 'Left', 'caption-right':side === 'Right'}" scope="row">
<th ng-class="{'caption-left':side === 'Left', 'caption-right':side === 'Right', 'caption-binaural': channel === 'HPL0 HPR0'}" scope="row">
<span>SLM</span>
<span>LA<sub>eq</sub></span>
<span>(dB SPL)</span>
......@@ -124,7 +124,7 @@
</td>
</tr>
<tr ng-if="showSvantek && !['BHAFT'].includes(resultsList[0].examType)">
<th ng-class="{'caption-left':side === 'Left', 'caption-right':side === 'Right'}" scope="row">
<th ng-class="{'caption-left':side === 'Left', 'caption-right':side === 'Right', 'caption-binaural': channel === 'HPL0 HPR0'}" scope="row">
<span>Dosimeter</span>
<span>L<sub>Fc</sub></span>
<span>(dB SPL)</span>
......@@ -134,7 +134,7 @@
</td>
</tr>
<tr ng-if="showSvantek">
<th ng-class="{'caption-left':side === 'Left', 'caption-right':side === 'Right'}" scope="row">
<th ng-class="{'caption-left':side === 'Left', 'caption-right':side === 'Right', 'caption-binaural': channel === 'HPL0 HPR0'}" scope="row">
<span>Dosimeter</span>
<span>LA<sub>eq</sub></span>
<span>(dB SPL)</span>
......
......@@ -97,7 +97,7 @@ angular
$scope.digitsDisabled = true;
$scope.readyToProcess = false;
$scope.feedback = angular.isDefined(page.dm.responseArea.feedback) ? page.dm.responseArea.feedback : true;
let presDigits = page.result.PresentedDigits;
let presDigits = _.cloneDeep(page.result.PresentedDigits);
let presentationScore = 0;
_.forEach($scope.response, function(digit, index) {
if (presDigits.includes(digit)) {
......
......@@ -89,7 +89,9 @@ angular
// disable response
$scope.buttonsDisabled = true;
// End of exam
delete page.result.presentationCount; // presentationCount irrelevent above NumberOfPresentations
page.result = $.extend({}, page.result, resultFromCha, {
response: "Exam Results",
chaInfo: chaExams.getChaInfo()
});
// Ready to submit
......
......@@ -106,11 +106,13 @@ describe("Response Areas", function() {
choice1 = { id: "choice1" };
choice2 = { id: "choice2" };
result = {};
scope1 = { choice: choice1, result: result };
scope2 = { choice: choice2, result: result };
beforeEach(
angular.mock.inject(function($controller) {
angular.mock.inject(function($controller, $rootScope) {
scope1 = $rootScope.$new();
Object.assign(scope1, { choice: choice1, result: result });
scope2 = $rootScope.$new();
Object.assign(scope2, { choice: choice2, result: result });
ctrl1 = $controller("BasicChoiceController", {
$scope: scope1
});
......
......@@ -525,24 +525,27 @@ angular
* @return {promise} - promise to queue a PlaySound exam
*/
api.playSound = function(chaWavFiles) {
var playsoundInterval;
function checkPlaysoundIsDone() {
let deferredExam = $q.defer();
$timeout(function() {
let playsoundResults = setInterval(function() {
return cha.requestResults().then(
function(results) {
if (results.State === 3) {
clearInterval(playsoundResults);
deferredExam.resolve();
}
},
function(err) {
clearInterval(playsoundResults);
deferredExam.reject(err);
}
);
}, 500);
}, 500);
cha
.requestStatus()
.then(function(status) {
if (status.State === 2) {
// still running
} else if (status.State !== 1) {
return $q.reject({ code: 66, msg: "Cha is in an unknown state" });
} else if (status.State === 1) {
// done
clearInterval(playsoundInterval);
$q.resolve();
return $q.promise;
}
})
.catch(function(err) {
clearInterval(playsoundInterval);
cha.errorHandler.main(err);
});
}
if (chaWavFiles && chaWavFiles.length > 0) {
......@@ -638,8 +641,11 @@ angular
return cha.queueExam("PlaySound", pse);
})
.then(checkPlaysoundIsDone) // we request results right away to make sure there is not an error with the playing of the wav file, and make sure wave file is done playing
.then(function() {
playsoundInterval = setInterval(checkPlaysoundIsDone, 500);
}) // we request results right away to make sure there is not an error with the playing of the wav file, and make sure wave file is done playing
.catch(function(e) {
clearInterval(playsoundInterval);
logger.error("CHA - playWavs failed with error: " + JSON.stringify(e));
});
}
......
......@@ -30,21 +30,6 @@ angular
weighting,
calFactor;
if (disk.protocolHeadset != wavfile.cal.headset ||
// backwards compatibility if protocols/calibrations still refer to WAHTS as Creare Headset
(['WAHTS', 'Creare Headset'].includes(disk.protocolHeadset) && ['WAHTS', 'Creare Headset'].includes(wavfile.cal.headset))) {
notifications.alert(
gettextCatalog.getString(
`Playback Error: Attempted to play wavfile calibrated for ${wavfile.cal.headset} on ${disk.protocolHeadset}`
)
);
logger.error(
`Playback Error: Attempted to play wavfile calibrated for ${wavfile.cal.headset} on ${disk.protocolHeadset}`
);
throw `Playback Error: Attempted to play wavfile calibrated for ${wavfile.cal.headset} on ${
disk.protocolHeadset
}`;
}
// TODO: included for backwards compatibility. remove in future version
// Can this actually be removed now?
if (typeof wavfile.targetSPL === "string") {
......
......@@ -605,7 +605,6 @@ angular
// initialize error container
loading.p.errors = [];
var cCommon, msg;
disk.protocolHeadset = loading.p.headset;
// check for encryption requirements
if (disk.requireEncryptedResults && !loading.p.publicKey) {
......@@ -1049,7 +1048,6 @@ angular
if (c && c[wavfile.path]) {
wavfile.cal = c[wavfile.path];
wavfile.cal.tablet = c.tablet;
wavfile.cal.headset = c.headset;
} else {
p._missingWavCalList.push(wavfile.path);
}
......
......@@ -837,8 +837,15 @@ table.table-audiometry > tbody th {
background-color: #d9534f;
color: white;
}
.table-audiometry caption.caption-binaural,
.table-audiometry th.caption-binaural {
background-color: #a6a6a6;
color: white;
}
.table-audiometry th.caption-left,
.table-audiometry th.caption-right {
.table-audiometry th.caption-right,
.table-audiometry th.caption-binaural,
{
white-space: nowrap;
}
.table-audiometry.table-audiometry-vertical tr th {
......
......@@ -29,7 +29,7 @@ msgstr ""
msgid "(kHz)"
msgstr ""
#: src/scripts/services/protocol/protocol.js:645
#: src/scripts/services/protocol/protocol.js:644
msgid ", but current Tabsint version is"
msgstr ""
......@@ -51,8 +51,8 @@ msgstr ""
#: src/scripts/routes/admin/config/config.html:324
msgid ""
"<div class=\"col-xs-12\">\r\n"
" TabSINT is developed by <a href=\"https://www.creare.com/\">Creare</a> and available open source on <a href=\"https://gitlab.com/creare-com/tabsint\">gitlab.com/creare-com/tabsint</a>\r\n"
"<div class=\"col-xs-12\">\n"
" TabSINT is developed by <a href=\"https://www.creare.com/\">Creare</a> and available open source on <a href=\"https://gitlab.com/creare-com/tabsint\">gitlab.com/creare-com/tabsint</a>\n"
" </div>"
msgstr ""
......@@ -60,6 +60,10 @@ msgstr ""
msgid "<input class=\"form-control pin-entry\" type=\"number\" ng-model=\"pin\" pattern=\"[0-9]*\" placeholder=\"PIN\" autofocus=\"true\" enter-close>"
msgstr ""
#: src/scripts/components/response-areas/frequency-pattern/frequency-pattern.html:15
msgid "<span class=\"glyphicon glyphicon-arrow-left\"></span> Delete"
msgstr ""
#: src/scripts/components/cha-admin/cha-admin.js:88
msgid "<strong>OPTIONAL:</strong> Type in the repository tag for the version of the repository you would like to download. Leave blank to download the latest tag/commit from the repository."
msgstr ""
......@@ -202,6 +206,10 @@ msgstr ""
msgid "BC Right"
msgstr ""
#: src/scripts/components/response-areas/audiometry/audiometry-properties/audiometry-properties.html:25
msgid "BOTH"
msgstr ""
#: src/scripts/routes/exam/exam.html:114
#: src/scripts/routes/exam/exam.html:78
msgid "Back"
......@@ -235,7 +243,7 @@ msgstr ""
msgid "By default, TabSINT will track changes to protocol files based on the <b>tags</b> to a repository.<br /><br />Uncheck this box if you would only like to download changes that are associated with repository <b>commits</b>."
msgstr ""
#: src/scripts/services/cordova/media/media.js:93
#: src/scripts/services/cordova/media/media.js:80
msgid "CAUTION: Wavfile requested at a volume > 1.0. Playing at 1.0, which does NOT meet spec. Requested volume:"
msgstr ""
......@@ -299,7 +307,7 @@ msgstr ""
msgid "Cordova Version"
msgstr ""
#: src/scripts/services/cordova/media/media.js:171
#: src/scripts/services/cordova/media/media.js:158
msgid "Cordova plugin \"Media\" is unavailable"
msgstr ""
......@@ -825,7 +833,7 @@ msgstr ""
msgid "No app by that name can be found on this device. Please alert administrator."
msgstr ""
#: src/scripts/services/cordova/media/media.js:349
#: src/scripts/services/cordova/media/media.js:336
msgid "No calibrated sound available for this headset."
msgstr ""
......@@ -845,7 +853,7 @@ msgstr ""
msgid "No protocol has been loaded. Please scan your QR Code or navigate to the Admin View and load a protocol."
msgstr ""
#: src/scripts/services/protocol/protocol.js:614
#: src/scripts/services/protocol/protocol.js:613
msgid "No public encryption key is defined in the protocol. Results will not be recorded from this protocol while the \"Require Encryption\" setting is enabled."
msgstr ""
......@@ -929,19 +937,15 @@ msgstr ""
msgid "Pause Exam"
msgstr ""
#: src/scripts/services/cordova/media/media.js:35
msgid "Playback Error: Attempted to play wavfile calibrated for on"
msgstr ""
#: src/scripts/services/cordova/media/media.js:78
#: src/scripts/services/cordova/media/media.js:65
msgid "Playback Error: Invalid \"WRT-reference\" playback request."
msgstr ""
#: src/scripts/services/cordova/media/media.js:68
#: src/scripts/services/cordova/media/media.js:55
msgid "Playback Error: Invalid \"as-recorded\" playback request."
msgstr ""
#: src/scripts/services/cordova/media/media.js:87
#: src/scripts/services/cordova/media/media.js:74
msgid "Playback Error: Invalid arguments on playback."
msgstr ""
......@@ -1034,7 +1038,7 @@ msgstr ""
msgid "Protocol has calibrated audio files and requires a headset. Please choose a headset from below"
msgstr ""
#: src/scripts/services/protocol/protocol.js:643
#: src/scripts/services/protocol/protocol.js:642
msgid "Protocol requires tabsint version"
msgstr ""
......@@ -1047,7 +1051,7 @@ msgstr ""
msgid "Protocols help"
msgstr ""
#: src/scripts/services/protocol/protocol.js:613
#: src/scripts/services/protocol/protocol.js:612
msgid "Public Key"
msgstr ""
......@@ -1375,7 +1379,7 @@ msgstr ""
msgid "Successfully exported results in directory:"
msgstr ""
#: src/scripts/services/protocol/protocol.js:974
#: src/scripts/services/protocol/protocol.js:973
msgid "Successfully loaded protocol:"
msgstr ""
......@@ -1407,7 +1411,7 @@ msgstr ""
msgid "TabSINT Server"
msgstr ""
#: src/scripts/services/protocol/protocol.js:649
#: src/scripts/services/protocol/protocol.js:648
msgid "TabSINT Version"
msgstr ""
......@@ -1667,7 +1671,7 @@ msgstr ""
msgid "The password used to access the TabSINT server"
msgstr ""
#: src/scripts/services/protocol/protocol.js:963
#: src/scripts/services/protocol/protocol.js:962
msgid "The protocol contains the following errors and may not function properly."
msgstr ""
......@@ -1756,7 +1760,7 @@ msgstr ""
msgid "This media repository \""
msgstr ""
#: src/scripts/services/cordova/media/media.js:97
#: src/scripts/services/cordova/media/media.js:84
msgid "This message only appears in admin mode."
msgstr ""
......@@ -1788,7 +1792,7 @@ msgstr ""
msgid "This protocol is currently being calibrated. Please wait a few minutes and try updating the site again."
msgstr ""
#: src/scripts/services/protocol/protocol.js:976
#: src/scripts/services/protocol/protocol.js:975
msgid "This protocol requires headset:"
msgstr ""
......@@ -1953,7 +1957,7 @@ msgstr ""
msgid "View Releases"
msgstr ""
#: src/scripts/services/cordova/media/media.js:108
#: src/scripts/services/cordova/media/media.js:95
msgid "Volume out of range:"
msgstr ""
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment