Skip to content

Commit 6e7fbee

Browse files
Add files via upload
1 parent 5a3bcc2 commit 6e7fbee

1 file changed

Lines changed: 112 additions & 0 deletions

File tree

ExtractAllMeasurements_mqx.html

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<style>
5+
button {
6+
padding: 10px 20px;
7+
font-size: 16px;
8+
background-color: yellowgreen;
9+
color: darkred;
10+
border: thin;
11+
cursor: pointer;
12+
border-radius: 4px;
13+
}
14+
button:hover {
15+
background-color: #45a049;
16+
}
17+
</style>
18+
</head>
19+
<body>
20+
<h2>MultEQ-X measurement extractor by OCA</h2>
21+
<br>
22+
<label for="input">Select .mqx file to upload:</label>
23+
<input type="file" id="input" accept=".mqx">
24+
<br>
25+
<p style="font-size: small; color: red;">Remember to upload ACM1HB standard mic calibration file (included in the ZIP) to REW before importing measurements for more accurate responses!</p>
26+
<br>
27+
<br>
28+
<button onclick="decodeAndConvert()">
29+
Decode, convert and save<br>measurements for REW
30+
</button>
31+
<p id="message" style="display: none;">Please wait, working on the zip...</p>
32+
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.0/FileSaver.min.js"></script>
33+
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.6.0/jszip.min.js"></script>
34+
<script>
35+
async function decodeAndConvert() {
36+
const button = document.querySelector('button');
37+
button.disabled = true; // Disable the button
38+
const message = document.getElementById('message');
39+
message.style.display = 'block'; // Show the message
40+
const input = document.getElementById('input');
41+
const file = input.files[0];
42+
const text = await file.text();
43+
const jsonData = JSON.parse(text);
44+
const channelMap = {};
45+
const channelDataMap = jsonData._channelDataMap;
46+
for (const channelGuid in channelDataMap) {
47+
const metadata = channelDataMap[channelGuid].Metadata;
48+
channelMap[channelGuid] = metadata.AvrOriginatingDesignation;
49+
}
50+
const zip = new JSZip();
51+
const measurements = jsonData._measurements;
52+
const trimPositionGuids = jsonData.CalibrationSettings.TrimPositionGuids;
53+
const distancePoisitionGuid = jsonData.CalibrationSettings.DistancePoisitionGuid;
54+
measurements.forEach((measurement, index) => {
55+
const base64String = measurement.Data;
56+
const bytesArray = new Uint8Array(atob(base64String).split('').map(c => c.charCodeAt(0)));
57+
const floats = [];
58+
for (let i = 0; i < bytesArray.length; i += 4) {
59+
floats.push(readFloat(bytesArray, i));
60+
}
61+
const channelGuid = measurement.ChannelGuid;
62+
const positionGuid = measurement.PositionGuid;
63+
const avrOriginatingDesignation = channelMap[channelGuid];
64+
const positionIndex = trimPositionGuids.indexOf(positionGuid);
65+
const isDistancePosition = positionGuid === distancePoisitionGuid;
66+
let filename;
67+
if (positionIndex === -1) {
68+
const shortenedGuid = positionGuid.substring(0, 3);
69+
filename = isDistancePosition
70+
? `${avrOriginatingDesignation}_${shortenedGuid}_dp.txt`
71+
: `${avrOriginatingDesignation}_${shortenedGuid}.txt`;
72+
} else {
73+
filename = isDistancePosition
74+
? `${avrOriginatingDesignation}_${positionIndex}_dp.txt`
75+
: `${avrOriginatingDesignation}_${positionIndex}.txt`;
76+
}
77+
const txtContent = `* Impulse Response data saved by REW
78+
0 // Peak value before normalisation
79+
0 // Peak index
80+
16384 // Response length
81+
2.0833333333333333E-5 // Sample interval (seconds)
82+
0.0 // Start time (seconds)
83+
* Data start
84+
${floats.join('\n')}`;
85+
zip.file(filename, txtContent);
86+
});
87+
const zipBlob = await zip.generateAsync({ type: 'blob' });
88+
saveAs(zipBlob, 'REW_Measurements.zip');
89+
message.style.display = 'none'; // Hide the message
90+
button.disabled = false; // Enable the button
91+
}
92+
function readFloat(bytesArray, start) {
93+
const dv = new DataView(bytesArray.buffer);
94+
const intBits = dv.getUint32(start, true);
95+
const signBit = (intBits >> 31) & 0x1;
96+
const exponent = (intBits >> 23) & 0xFF;
97+
const mantissa = intBits & 0x7FFFFF;
98+
if (exponent === 0xFF) {
99+
if (mantissa === 0) {
100+
return signBit ? Number.NEGATIVE_INFINITY : Number.POSITIVE_INFINITY;
101+
} else {
102+
return NaN;
103+
}
104+
}
105+
const bias = 127;
106+
const normalizedMantissa = 1 + mantissa / Math.pow(2, 23);
107+
const value = Math.pow(-1, signBit) * normalizedMantissa * Math.pow(2, exponent - bias);
108+
return value;
109+
}
110+
</script>
111+
</body>
112+
</html>

0 commit comments

Comments
 (0)