diff --git a/expansion/expander.js b/expansion/expander.js
deleted file mode 100644
index aa87cb0..0000000
--- a/expansion/expander.js
+++ /dev/null
@@ -1,435 +0,0 @@
-/****************************************************************************
- * expander.js
- * openacousticdevices.info
- * June 2020
- *****************************************************************************/
-
-'use strict';
-
-const fs = require('fs');
-const path = require('path');
-
-const wavHeader = require('./wavHeader.js');
-
-/* Expansion constants */
-
-const MILLISECONDS_IN_SECONDS = 1000;
-
-const NUMBER_OF_BYTES_IN_SAMPLE = 2;
-
-const EXPANSION_BUFFER_ENCODING_SIZE = 32;
-
-const EXPANSION_BUFFER_SIZE_IN_BYTES = 512;
-
-const SECONDS_IN_DAY = 24 * 60 * 60;
-
-const DATE_REGEX = /Recorded at (\d\d):(\d\d):(\d\d) (\d\d)\/(\d\d)\/(\d\d\d\d)/;
-
-/* Buffers for reading data */
-
-const headerBuffer = Buffer.alloc(wavHeader.LENGTH_OF_WAV_HEADER);
-
-const blankHeaderBuffer = Buffer.alloc(wavHeader.LENGTH_OF_WAV_HEADER);
-
-const fileBuffer = Buffer.alloc(EXPANSION_BUFFER_SIZE_IN_BYTES);
-
-const blankFileBuffer = Buffer.alloc(EXPANSION_BUFFER_SIZE_IN_BYTES);
-
-/* Decode the expansion buffer */
-
-function decodeExpansionBuffer (buffer) {
-
- var i, value, numberOfExpandedBuffers;
-
- numberOfExpandedBuffers = 0;
-
- for (i = 0; i < EXPANSION_BUFFER_ENCODING_SIZE; i += 1) {
-
- value = buffer.readInt16LE(NUMBER_OF_BYTES_IN_SAMPLE * i);
-
- if (value === 1) {
-
- numberOfExpandedBuffers += (1 << i);
-
- } else if (value !== -1) {
-
- return 0;
-
- }
-
- }
-
- for (i = EXPANSION_BUFFER_ENCODING_SIZE; i < EXPANSION_BUFFER_SIZE_IN_BYTES / NUMBER_OF_BYTES_IN_SAMPLE; i += 1) {
-
- value = buffer.readInt16LE(NUMBER_OF_BYTES_IN_SAMPLE * i);
-
- if (value !== 0) {
-
- return 0;
-
- }
-
- }
-
- return numberOfExpandedBuffers;
-
-}
-
-/* Date functions */
-
-function twoDigits (value) {
-
- var string = '00' + value;
- return string.substr(string.length - 2);
-
-}
-
-function formatFilename (timestamp) {
-
- var date = new Date(timestamp);
-
- return date.getUTCFullYear() + twoDigits(date.getUTCMonth() + 1) + twoDigits(date.getUTCDate()) + '_' + twoDigits(date.getUTCHours()) + twoDigits(date.getUTCMinutes()) + twoDigits(date.getUTCSeconds()) + '.WAV';
-
-}
-
-function formatCommentDate (timestamp) {
-
- var date = new Date(timestamp);
-
- return 'Recorded at ' + twoDigits(date.getUTCHours()) + ':' + twoDigits(date.getUTCMinutes()) + ':' + twoDigits(date.getUTCSeconds()) + ' ' + twoDigits(date.getUTCDate()) + '/' + twoDigits(date.getUTCMonth() + 1) + '/' + date.getUTCFullYear();
-
-}
-
-/* Expand a T.WAV file */
-
-function expand (inputPath, maximumFileDuration, callback) {
-
- var fi, fo, fileSize, header, headerCheck, progress, inputFileDataSize, aligned, regex, filename, timestamp, outputPath, fileIsOpen, numberOfBytes, numberOfInputBytes, numberOfBlankBytes, inputFileBytesRead, numberOfBytesWritten, numberOfDeferredBlankBytes, numberOfInputBytesAlreadyWritten, bytesToWriteInEachOutputFile;
-
- /* Check parameter */
-
- maximumFileDuration = maximumFileDuration || SECONDS_IN_DAY;
-
- if (maximumFileDuration !== Math.round(maximumFileDuration)) {
-
- return {
- success: false,
- error: 'Maximum file duration must be an integer.'
- };
-
- }
-
- if (maximumFileDuration <= 0) {
-
- return {
- success: false,
- error: 'Maximum file duration must be greater than zero.'
- };
-
- }
-
- /* Generate the output filename */
-
- if (!inputPath.includes('T.wav') && !inputPath.includes('T.WAV')) {
-
- return {
- success: false,
- error: 'File name is incorrect.'
- };
-
- }
-
- /* Open input file */
-
- try {
-
- fi = fs.openSync(inputPath, 'r');
-
- } catch (e) {
-
- return {
- success: false,
- error: 'Could not open input file.'
- };
-
- }
-
- /* Find the input file size */
-
- try {
-
- fileSize = fs.statSync(inputPath).size;
-
- } catch (e) {
-
- return {
- success: false,
- error: 'Could not read input file size.'
- };
-
- }
-
- if (fileSize === 0) {
-
- return {
- success: false,
- error: 'Input file has zero size.'
- };
-
- }
-
- if (fileSize <= wavHeader.LENGTH_OF_WAV_HEADER) {
-
- return {
- success: false,
- error: 'Input file is too small.'
- };
-
- }
-
- /* Read the header */
-
- try {
-
- fs.readSync(fi, headerBuffer, 0, wavHeader.LENGTH_OF_WAV_HEADER, null);
-
- } catch (e) {
-
- return {
- success: false,
- error: 'Could not read the input WAV header.'
- };
-
- }
-
- /* Check the header */
-
- header = wavHeader.readHeader(headerBuffer);
-
- headerCheck = wavHeader.checkHeader(header, fileSize);
-
- if (headerCheck.success === false) {
-
- return {
- success: false,
- error: headerCheck.error
- };
-
- }
-
- /* Check the header comment format */
-
- if (header.icmt.comment.search(DATE_REGEX) !== 0) {
-
- return {
- success: false,
- error: 'Comment format is incorrect.'
- };
-
- }
-
- /* Read the timestamp from the header */
-
- regex = DATE_REGEX.exec(header.icmt.comment);
-
- timestamp = Date.UTC(regex[6], regex[5] - 1, regex[4], regex[1], regex[2], regex[3]);
-
- filename = formatFilename(timestamp);
-
- outputPath = path.join(path.parse(inputPath).dir, filename);
-
- /* Read determine settings from the input file */
-
- inputFileDataSize = header.data.size;
-
- bytesToWriteInEachOutputFile = NUMBER_OF_BYTES_IN_SAMPLE * header.wavFormat.samplesPerSecond * maximumFileDuration;
-
- /* Set up to process the file */
-
- progress = 10;
-
- aligned = false;
-
- fileIsOpen = false;
-
- inputFileBytesRead = 0;
-
- numberOfBytesWritten = 0;
-
- numberOfDeferredBlankBytes = 0;
-
- /* Main loop */
-
- try {
-
- while (inputFileBytesRead < inputFileDataSize) {
-
- if (inputFileBytesRead / inputFileDataSize > progress / 100) {
-
- if (callback) callback(progress);
-
- progress += 10;
-
- }
-
- /* Determine number of bytes to read */
-
- numberOfBytes = aligned ? Math.min(inputFileDataSize - inputFileBytesRead, EXPANSION_BUFFER_SIZE_IN_BYTES) : EXPANSION_BUFFER_SIZE_IN_BYTES - wavHeader.LENGTH_OF_WAV_HEADER;
-
- aligned = true;
-
- /* Read the data from the input file */
-
- fs.readSync(fi, fileBuffer, 0, numberOfBytes, null);
-
- inputFileBytesRead += numberOfBytes;
-
- /* Check if this is a normal buffer or an encoded buffer */
-
- if (numberOfBytes === EXPANSION_BUFFER_SIZE_IN_BYTES) {
-
- numberOfBlankBytes = EXPANSION_BUFFER_SIZE_IN_BYTES * decodeExpansionBuffer(fileBuffer);
- numberOfInputBytes = numberOfBlankBytes > 0 ? 0 : EXPANSION_BUFFER_SIZE_IN_BYTES;
-
- } else {
-
- numberOfBlankBytes = 0;
- numberOfInputBytes = numberOfBytes;
-
- }
-
- /* Process these input bytes */
-
- numberOfInputBytesAlreadyWritten = 0;
-
- while (numberOfBlankBytes > 0 || numberOfInputBytes > 0) {
-
- if (numberOfBlankBytes > 0) {
-
- if (fileIsOpen) {
-
- numberOfBytes = Math.min(numberOfBlankBytes, bytesToWriteInEachOutputFile - numberOfBytesWritten);
-
- numberOfBytesWritten += numberOfBytes;
-
- numberOfBlankBytes -= numberOfBytes;
-
- while (numberOfBytes > 0) {
-
- fs.writeSync(fo, blankFileBuffer, 0, Math.min(numberOfBytes, EXPANSION_BUFFER_SIZE_IN_BYTES), null);
-
- numberOfBytes -= Math.min(numberOfBytes, EXPANSION_BUFFER_SIZE_IN_BYTES);
-
- }
-
- } else {
-
- numberOfBytes = Math.min(numberOfBlankBytes, bytesToWriteInEachOutputFile - numberOfDeferredBlankBytes);
-
- numberOfDeferredBlankBytes += numberOfBytes;
-
- numberOfBlankBytes -= numberOfBytes;
-
- }
-
- }
-
- if (numberOfInputBytes > 0) {
-
- if (fileIsOpen) {
-
- numberOfBytes = Math.min(numberOfInputBytes, bytesToWriteInEachOutputFile - numberOfBytesWritten, EXPANSION_BUFFER_SIZE_IN_BYTES - numberOfInputBytesAlreadyWritten);
-
- fs.writeSync(fo, fileBuffer, numberOfInputBytesAlreadyWritten, numberOfBytes);
-
- numberOfInputBytesAlreadyWritten += numberOfBytes;
-
- numberOfBytesWritten += numberOfBytes;
-
- numberOfInputBytes -= numberOfBytes;
-
- } else {
-
- fo = fs.openSync(outputPath, 'w');
-
- fs.writeSync(fo, blankHeaderBuffer, 0, wavHeader.LENGTH_OF_WAV_HEADER, null);
-
- fileIsOpen = true;
-
- numberOfBlankBytes += numberOfDeferredBlankBytes;
-
- numberOfDeferredBlankBytes = 0;
-
- continue;
-
- }
-
- }
-
- if (inputFileBytesRead === inputFileDataSize || numberOfBytesWritten === bytesToWriteInEachOutputFile || numberOfDeferredBlankBytes === bytesToWriteInEachOutputFile) {
-
- /* Write header and close file if it has been opened */
-
- if (fileIsOpen === true) {
-
- wavHeader.updateDataSize(header, numberOfBytesWritten);
-
- wavHeader.overwriteComment(header, formatCommentDate(timestamp));
-
- wavHeader.writeHeader(headerBuffer, header);
-
- fs.writeSync(fo, headerBuffer, 0, wavHeader.LENGTH_OF_WAV_HEADER, 0);
-
- fs.closeSync(fo);
-
- }
-
- /* Reset for next file */
-
- numberOfBytesWritten = 0;
-
- numberOfDeferredBlankBytes = 0;
-
- timestamp += maximumFileDuration * MILLISECONDS_IN_SECONDS;
-
- filename = formatFilename(timestamp);
-
- outputPath = path.join(path.parse(inputPath).dir, filename);
-
- fileIsOpen = false;
-
- }
-
- }
-
- }
-
- fs.closeSync(fi);
-
- } catch (e) {
-
- return {
- success: false,
- error: 'Error occurred while processing file. ' + e
- };
-
- }
-
- if (callback) {
-
- callback(100);
-
- }
-
- /* Return success */
-
- return {
- success: true,
- error: null
- };
-
-}
-
-/* Export expand */
-
-exports.expand = expand;
diff --git a/expansion/wavHeader.js b/expansion/wavHeader.js
deleted file mode 100644
index c3f08a4..0000000
--- a/expansion/wavHeader.js
+++ /dev/null
@@ -1,292 +0,0 @@
-/****************************************************************************
- * wavHeader.js
- * openacousticdevices.info
- * June 2020
- *****************************************************************************/
-
-'use strict';
-
-/* WAV header constants */
-
-const UINT16_LENGTH = 2;
-const UINT32_LENGTH = 4;
-const RIFF_ID_LENGTH = 4;
-
-/* WAV format constants */
-
-const PCM_FORMAT = 1;
-const NUMBER_OF_CHANNELS = 1;
-const NUMBER_OF_BITS_IN_SAMPLE = 16;
-const NUMBER_OF_BYTES_IN_SAMPLE = 2;
-
-/* WAV header base component read functions */
-
-function readString (state, length) {
-
- if (state.buffer.length - state.index < length) throw new Error('WAVE header exceeded buffer length.');
-
- var result = state.buffer.toString('utf8', state.index, state.index + length).replace(/\0/g, '');
- state.index += length;
- return result;
-
-}
-
-function readUInt32LE (state) {
-
- if (state.buffer.length - state.index < UINT32_LENGTH) throw new Error('WAVE header exceeded buffer length.');
-
- var result = state.buffer.readUInt32LE(state.index);
- state.index += UINT32_LENGTH;
- return result;
-
-}
-
-function readUInt16LE (state) {
-
- if (state.buffer.length - state.index < UINT16_LENGTH) throw new Error('WAVE header exceeded buffer length.');
-
- var result = state.buffer.readUInt16LE(state.index);
- state.index += UINT16_LENGTH;
- return result;
-
-}
-
-/* WAV header high-level component read functions */
-
-function readID (state, id) {
-
- const result = readString(state, id.length);
-
- if (result !== id) throw new Error('Could not find ' + id + ' ID.');
-
- return result;
-
-}
-
-function readChunk (state, id) {
-
- const result = {};
-
- result.id = readString(state, RIFF_ID_LENGTH);
-
- if (result.id !== id) throw new Error('Could not find ' + id.replace(' ', '') + ' chunk ID.');
-
- result.size = readUInt32LE(state);
-
- return result;
-
-}
-
-/* WAV header component write functions */
-
-function writeString (state, string, length, zeroTerminated) {
-
- const maximumWriteLength = zeroTerminated ? Math.min(string.length, length - 1) : Math.min(string.length, length);
- state.buffer.fill(0, state.index, state.index + length);
- state.buffer.write(string, state.index, maximumWriteLength, 'utf8');
- state.index += length;
-
-}
-
-function writeUInt32LE (state, value) {
-
- state.buffer.writeUInt32LE(value, state.index);
- state.index += UINT32_LENGTH;
-
-}
-
-function writeUInt16LE (state, value) {
-
- state.buffer.writeUInt16LE(value, state.index);
- state.index += UINT16_LENGTH;
-
-}
-
-function writeChunk (state, chunk) {
-
- writeString(state, chunk.id, RIFF_ID_LENGTH, false);
- writeUInt32LE(state, chunk.size);
-
-}
-
-/* WAV header read and write functions */
-
-function readHeader (buffer, fileSize) {
-
- const header = {};
-
- const state = {buffer: buffer, index: 0};
-
- try {
-
- /* Read RIFF chunk */
-
- header.riff = readChunk(state, 'RIFF');
-
- if (header.riff.size + RIFF_ID_LENGTH + UINT32_LENGTH !== fileSize) {
-
- return {
- success: false,
- error: 'RIFF chunk size does not match file size.'
- };
-
- }
-
- /* Read WAVE ID */
-
- header.format = readID(state, 'WAVE');
-
- /* Read FMT chunk */
-
- header.fmt = readChunk(state, 'fmt ');
-
- header.wavFormat = {};
- header.wavFormat.format = readUInt16LE(state);
- header.wavFormat.numberOfChannels = readUInt16LE(state);
- header.wavFormat.samplesPerSecond = readUInt32LE(state);
- header.wavFormat.bytesPerSecond = readUInt32LE(state);
- header.wavFormat.bytesPerCapture = readUInt16LE(state);
- header.wavFormat.bitsPerSample = readUInt16LE(state);
-
- if (header.wavFormat.format !== PCM_FORMAT || header.wavFormat.numberOfChannels !== NUMBER_OF_CHANNELS || header.wavFormat.bytesPerSecond !== NUMBER_OF_BYTES_IN_SAMPLE * header.wavFormat.samplesPerSecond || header.wavFormat.bytesPerCapture !== NUMBER_OF_BYTES_IN_SAMPLE || header.wavFormat.bitsPerSample !== NUMBER_OF_BITS_IN_SAMPLE) {
-
- return {
- success: false,
- error: 'Unexpected WAVE format.'
- };
-
- }
-
- /* Read LIST chunk */
-
- header.list = readChunk(state, 'LIST');
-
- /* Read INFO ID */
-
- header.info = readID(state, 'INFO');
-
- /* Read ICMT chunk */
-
- header.icmt = readChunk(state, 'ICMT');
-
- header.icmt.comment = readString(state, header.icmt.size);
-
- /* Read IART chunk */
-
- header.iart = readChunk(state, 'IART');
-
- header.iart.artist = readString(state, header.iart.size);
-
- /* Check LIST chunk size */
-
- if (header.list.size !== 3 * RIFF_ID_LENGTH + 2 * UINT32_LENGTH + header.iart.size + header.icmt.size) {
-
- return {
- success: false,
- error: 'LIST chunk size does not match total size of INFO, ICMT and IART chunks.'
- };
-
- }
-
- /* Read DATA chunk */
-
- header.data = readChunk(state, 'data');
-
- /* Set the header size and check DATA chunk size */
-
- header.size = state.index;
-
- if (header.data.size + header.size !== fileSize) {
-
- return {
- success: false,
- error: 'DATA chunk size does not match file size.'
- };
-
- }
-
- /* Success */
-
- return {
- header: header,
- success: true,
- error: null
- };
-
- } catch (e) {
-
- /* Header has exceed file buffer length */
-
- return {
- success: false,
- error: e.message
- };
-
- }
-
-}
-
-function writeHeader (buffer, header) {
-
- const state = {buffer: buffer, index: 0};
-
- writeChunk(state, header.riff);
-
- writeString(state, header.format, RIFF_ID_LENGTH, false);
-
- writeChunk(state, header.fmt);
-
- writeUInt16LE(state, header.wavFormat.format);
- writeUInt16LE(state, header.wavFormat.numberOfChannels);
- writeUInt32LE(state, header.wavFormat.samplesPerSecond);
- writeUInt32LE(state, header.wavFormat.bytesPerSecond);
- writeUInt16LE(state, header.wavFormat.bytesPerCapture);
- writeUInt16LE(state, header.wavFormat.bitsPerSample);
-
- writeChunk(state, header.list);
-
- writeString(state, header.info, RIFF_ID_LENGTH, false);
-
- writeChunk(state, header.icmt);
- writeString(state, header.icmt.comment, header.icmt.size, true);
-
- writeChunk(state, header.iart);
- writeString(state, header.iart.artist, header.iart.size, true);
-
- writeChunk(state, header.data);
-
- return buffer;
-
-}
-
-/* Functions to update header */
-
-function updateDataSize (header, size) {
-
- header.riff.size = header.size + size - UINT32_LENGTH - RIFF_ID_LENGTH;
-
- header.data.size = size;
-
-}
-
-function updateComment (header, comment) {
-
- header.icmt.comment = comment;
-
-}
-
-function overwriteComment (header, comment) {
-
- var length = Math.min(comment.length, header.icmt.size - 1);
-
- header.icmt.comment = comment.substr(0, length) + header.icmt.comment.substr(length);
-
-}
-
-/* Exports */
-
-exports.writeHeader = writeHeader;
-exports.readHeader = readHeader;
-exports.updateDataSize = updateDataSize;
-exports.updateComment = updateComment;
-exports.overwriteComment = overwriteComment;
diff --git a/main.js b/main.js
index b6a1a11..01d6fc9 100644
--- a/main.js
+++ b/main.js
@@ -27,9 +27,9 @@ require('electron-debug')({
devToolsMode: 'undocked'
});
-var mainWindow, aboutWindow, expansionWindow, splitWindow;
+var mainWindow, aboutWindow, expansionWindow, splitWindow, downsampleWindow;
-var expandProgressBar, splitProgressBar;
+var expandProgressBar, splitProgressBar, downsampleProgressBar;
function shrinkWindowHeight (windowHeight) {
@@ -60,7 +60,7 @@ function openSplitWindow () {
splitWindow = new BrowserWindow({
width: 565,
height: shrinkWindowHeight(403),
- title: 'Split AudioMoth Recordings',
+ title: 'Split AudioMoth WAV Files',
useContentSize: true,
resizable: false,
fullscreenable: false,
@@ -72,7 +72,7 @@ function openSplitWindow () {
});
splitWindow.setMenu(null);
- splitWindow.loadURL(path.join('file://', __dirname, 'expansion/split.html'));
+ splitWindow.loadURL(path.join('file://', __dirname, 'processing/split.html'));
splitWindow.webContents.on('dom-ready', function () {
@@ -117,7 +117,7 @@ function openExpansionWindow () {
expansionWindow = new BrowserWindow({
width: 565,
height: shrinkWindowHeight(575),
- title: 'Expand AudioMoth T.WAV Recordings',
+ title: 'Expand AudioMoth T.WAV Files',
useContentSize: true,
resizable: false,
fullscreenable: false,
@@ -129,7 +129,7 @@ function openExpansionWindow () {
});
expansionWindow.setMenu(null);
- expansionWindow.loadURL(path.join('file://', __dirname, 'expansion/expansion.html'));
+ expansionWindow.loadURL(path.join('file://', __dirname, 'processing/expansion.html'));
expansionWindow.webContents.on('dom-ready', function () {
@@ -161,6 +161,63 @@ function openExpansionWindow () {
}
+function openDownsamplingWindow () {
+
+ if (downsampleWindow) {
+
+ return;
+
+ }
+
+ const iconLocation = (process.platform === 'linux') ? '/build/icon.png' : '/build/icon.ico';
+
+ downsampleWindow = new BrowserWindow({
+ width: 565,
+ height: shrinkWindowHeight(380),
+ title: 'Downsample AudioMoth WAV Files',
+ useContentSize: true,
+ resizable: false,
+ fullscreenable: false,
+ icon: path.join(__dirname, iconLocation),
+ parent: mainWindow,
+ webPreferences: {
+ nodeIntegration: true
+ }
+ });
+
+ downsampleWindow.setMenu(null);
+ downsampleWindow.loadURL(path.join('file://', __dirname, 'processing/downsampling.html'));
+
+ downsampleWindow.webContents.on('dom-ready', function () {
+
+ mainWindow.webContents.send('poll-night-mode');
+
+ });
+
+ ipcMain.on('night-mode-poll-reply', (e, nightMode) => {
+
+ if (downsampleWindow) {
+
+ downsampleWindow.webContents.send('night-mode', nightMode);
+
+ }
+
+ });
+
+ downsampleWindow.on('close', function (e) {
+
+ if (downsampleProgressBar) {
+
+ e.preventDefault();
+
+ }
+
+ downsampleWindow = null;
+
+ });
+
+}
+
function openAboutWindow () {
if (aboutWindow) {
@@ -351,7 +408,7 @@ app.on('ready', function () {
}, {
type: 'separator'
}, {
- label: 'Split AudioMoth WAV Recordings',
+ label: 'Split AudioMoth WAV Files',
accelerator: 'CommandOrControl+P',
click: function () {
@@ -359,12 +416,20 @@ app.on('ready', function () {
}
}, {
- label: 'Expand AudioMoth T.WAV Recordings',
+ label: 'Expand AudioMoth T.WAV Files',
accelerator: 'CommandOrControl+E',
click: function () {
openExpansionWindow();
+ }
+ }, {
+ label: 'Downsample AudioMoth WAV Files',
+ accelerator: 'CommandOrControl+D',
+ click: function () {
+
+ openDownsamplingWindow();
+
}
}, {
type: 'separator'
@@ -715,6 +780,139 @@ ipcMain.on('poll-split-cancelled', (event) => {
});
+/* Downsampling progress bar functions */
+
+ipcMain.on('start-downsample-bar', (event, fileCount) => {
+
+ if (downsampleProgressBar) {
+
+ return;
+
+ }
+
+ let detail = 'Starting to downsample file';
+ detail += (fileCount > 1) ? 's' : '';
+ detail += '.';
+
+ downsampleProgressBar = new ProgressBar({
+ title: 'AudioMoth Configuration App',
+ text: 'Downsampling files...',
+ detail: detail,
+ closeOnComplete: false,
+ indeterminate: false,
+ browserWindow: {
+ parent: splitWindow,
+ webPreferences: {
+ nodeIntegration: true
+ },
+ closable: true,
+ modal: false
+ },
+ maxValue: fileCount * 100
+ });
+
+ downsampleProgressBar.on('aborted', () => {
+
+ if (downsampleProgressBar) {
+
+ downsampleProgressBar.close();
+ downsampleProgressBar = null;
+
+ }
+
+ });
+
+});
+
+ipcMain.on('set-downsample-bar-progress', (event, fileNum, progress, name) => {
+
+ const index = fileNum + 1;
+ const fileCount = downsampleProgressBar.getOptions().maxValue / 100;
+
+ if (downsampleProgressBar) {
+
+ downsampleProgressBar.value = (fileNum * 100) + progress;
+ downsampleProgressBar.detail = 'Downsampling ' + name + ' (' + index + ' of ' + fileCount + ').';
+
+ }
+
+});
+
+ipcMain.on('set-downsample-bar-error', (event, name) => {
+
+ if (downsampleProgressBar) {
+
+ downsampleProgressBar.detail = 'Error when downsampling ' + name + '.';
+
+ }
+
+});
+
+ipcMain.on('set-downsample-bar-completed', (event, successCount, errorCount, errorWritingLog) => {
+
+ if (downsampleProgressBar) {
+
+ let messageText;
+
+ downsampleProgressBar.setCompleted();
+
+ if (errorCount > 0) {
+
+ messageText = 'Errors occurred in ' + errorCount + ' file';
+ messageText += (errorCount === 1 ? '' : 's');
+ messageText += '.
';
+
+ if (errorWritingLog) {
+
+ messageText += 'Failed to write ERRORS.TXT to destination.';
+
+ } else {
+
+ messageText += 'See ERRORS.TXT for details.';
+
+ }
+
+ } else {
+
+ messageText = 'Successfully downsampled ' + successCount + ' file';
+ messageText += (successCount === 1 ? '' : 's');
+ messageText += '.';
+
+ }
+
+ downsampleProgressBar.detail = messageText;
+
+ setTimeout(function () {
+
+ downsampleProgressBar.close();
+ downsampleProgressBar = null;
+
+ if (downsampleWindow) {
+
+ downsampleWindow.send('downsample-summary-closed');
+
+ }
+
+ }, 5000);
+
+ }
+
+});
+
+ipcMain.on('poll-downsample-cancelled', (event) => {
+
+ if (downsampleProgressBar) {
+
+ event.returnValue = false;
+
+ } else {
+
+ event.returnValue = true;
+
+ }
+
+});
+
/* Update which amplitude threshold scale option is checked in menu */
ipcMain.on('set-amplitude-threshold-scale', (event, index) => {
diff --git a/package.json b/package.json
index 1935d57..44afacc 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "AudioMoth-Config",
- "version": "1.7.0",
+ "version": "1.8.0",
"description": "The configuration app for the AudioMoth acoustic monitoring device.",
"main": "main.js",
"author": "openacousticdevices.info",
@@ -68,7 +68,7 @@
},
"dependencies": {
"audiomoth-hid": "^2.1.0",
- "audiomoth-utils": "^1.1.0",
+ "audiomoth-utils": "^1.2.0",
"bootstrap": "4.3.1",
"bootstrap-slider": "^10.6.2",
"electron-debug": "3.0.1",
diff --git a/packetReader.js b/packetReader.js
index d657b87..d0b52d9 100644
--- a/packetReader.js
+++ b/packetReader.js
@@ -296,7 +296,7 @@ exports.read = (packet) => {
console.log('Active recording periods:', activeStartStopPeriods);
- for (let j = 0; j < activeStartStopPeriods.length; j++) {
+ for (let j = 0; j < activeStartStopPeriods; j++) {
console.log('Start: ' + formatTime(startStopPeriods[j].startMinutes) + ' - Stop: ' + formatTime(startStopPeriods[j].stopMinutes));
diff --git a/processing/downsampling.html b/processing/downsampling.html
new file mode 100644
index 0000000..29cc0d9
--- /dev/null
+++ b/processing/downsampling.html
@@ -0,0 +1,222 @@
+
+
+
+
+
+
+ Downsample AudioMoth WAV Files
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Writing WAV files to source folder.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ No AudioMoth WAV files selected.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/expansion/expansion.html b/processing/expansion.html
similarity index 95%
rename from expansion/expansion.html
rename to processing/expansion.html
index b785153..5418327 100644
--- a/expansion/expansion.html
+++ b/processing/expansion.html
@@ -4,7 +4,7 @@
-
Expand AudioMoth T.WAV Recordings
+
Expand AudioMoth T.WAV Files
@@ -48,7 +48,7 @@
@@ -126,7 +128,7 @@
@@ -284,7 +288,7 @@
- No AudioMoth T.WAV files selected.
+ No AudioMoth T.WAV files selected.
diff --git a/expansion/split.html b/processing/split.html
similarity index 96%
rename from expansion/split.html
rename to processing/split.html
index 91d2c48..c00c040 100644
--- a/expansion/split.html
+++ b/processing/split.html
@@ -4,7 +4,7 @@
- Split AudioMoth Recordings
+ Split AudioMoth WAV Files
@@ -20,7 +20,7 @@
@@ -156,7 +158,7 @@
- No AudioMoth WAV files selected.
+ No AudioMoth WAV files selected.
diff --git a/expansion/uiCommon.js b/processing/uiCommon.js
similarity index 93%
rename from expansion/uiCommon.js
rename to processing/uiCommon.js
index b6f2442..d629865 100644
--- a/expansion/uiCommon.js
+++ b/processing/uiCommon.js
@@ -219,19 +219,3 @@ prefixCheckbox.addEventListener('change', () => {
}
});
-
-/* Update label to notify user if a custom output directtory is being used */
-
-exports.updateOutputLabel = (outputDir) => {
-
- if (outputDir === '') {
-
- outputLabel.textContent = 'Writing WAV files to source folder.';
-
- } else {
-
- outputLabel.textContent = 'Writing WAV files to custom folder.';
-
- }
-
-};
diff --git a/processing/uiDownsampling.js b/processing/uiDownsampling.js
new file mode 100644
index 0000000..cd95b8e
--- /dev/null
+++ b/processing/uiDownsampling.js
@@ -0,0 +1,298 @@
+/****************************************************************************
+ * uiDownsampling.js
+ * openacousticdevices.info
+ * June 2022
+ *****************************************************************************/
+
+'use strict';
+
+/* global document */
+
+const electron = require('electron');
+const dialog = electron.remote.dialog;
+
+/* Get functions which control elements common to the expansion, split, and downsample windows */
+const ui = require('./uiCommon.js');
+const uiOutput = require('./uiOutput.js');
+
+const path = require('path');
+const fs = require('fs');
+
+const audiomothUtils = require('audiomoth-utils');
+
+var currentWindow = electron.remote.getCurrentWindow();
+
+const SAMPLE_RATES = [8000, 16000, 32000, 48000, 96000, 192000, 250000, 384000];
+
+const FILE_REGEX = /^(\d\d\d\d\d\d\d\d_)?\d\d\d\d\d\d.WAV$/;
+
+const sampleRateRadioHolder = document.getElementById('sample-rate-holder');
+const disabledSampleRateRadioHolder = document.getElementById('disabled-sample-rate-holder');
+
+const sampleRateRadios = document.getElementsByName('sample-rate-radio');
+const disabledSampleRateRadios = document.getElementsByName('disabled-sample-rate-radio');
+
+const selectionRadios = document.getElementsByName('selection-radio');
+
+const prefixCheckbox = document.getElementById('prefix-checkbox');
+const prefixInput = document.getElementById('prefix-input');
+
+const fileLabel = document.getElementById('file-label');
+const fileButton = document.getElementById('file-button');
+const downsampleButton = document.getElementById('downsample-button');
+
+var files = [];
+var downsampling = false;
+
+/* Disable UI elements in main window while progress bar is open and downsample is in progress */
+
+function disableUI () {
+
+ fileButton.disabled = true;
+ downsampleButton.disabled = true;
+ selectionRadios[0].disabled = true;
+ selectionRadios[1].disabled = true;
+
+ sampleRateRadioHolder.style.display = 'none';
+ disabledSampleRateRadioHolder.style.display = '';
+
+ uiOutput.disableOutputCheckbox();
+ uiOutput.disableOutputButton();
+
+ prefixCheckbox.disabled = true;
+ prefixInput.disabled = true;
+
+}
+
+function enableUI () {
+
+ fileButton.disabled = false;
+ downsampleButton.disabled = false;
+ selectionRadios[0].disabled = false;
+ selectionRadios[1].disabled = false;
+
+ sampleRateRadioHolder.style.display = '';
+ disabledSampleRateRadioHolder.style.display = 'none';
+
+ uiOutput.enableOutputCheckbox();
+ uiOutput.enableOutputButton();
+
+ prefixCheckbox.disabled = false;
+
+ if (prefixCheckbox.checked) {
+
+ prefixInput.disabled = false;
+
+ }
+
+ downsampling = false;
+
+}
+
+/* Split selected files */
+
+function downsampleFiles () {
+
+ if (!files) {
+
+ return;
+
+ }
+
+ let successCount = 0;
+ let errorCount = 0;
+ const errors = [];
+ const errorFiles = [];
+
+ let errorFilePath;
+
+ for (let i = 0; i < files.length; i++) {
+
+ /* If progress bar is closed, the downsample task is considered cancelled. This will contact the main thread and ask if that has happened */
+
+ const cancelled = electron.ipcRenderer.sendSync('poll-downsample-cancelled');
+
+ if (cancelled) {
+
+ console.log('Downsample cancelled.');
+ enableUI();
+ return;
+
+ }
+
+ /* Let the main thread know what value to set the progress bar to */
+
+ electron.ipcRenderer.send('set-downsample-bar-progress', i, 0, path.basename(files[i]));
+
+ const sampleRate = SAMPLE_RATES[ui.getSelectedRadioValue('sample-rate-radio')];
+
+ console.log('Downsampling:', files[i]);
+ console.log('New sample rate:', sampleRate);
+
+ console.log('-');
+
+ /* Check if the optional prefix/output directory setttings are being used. If left as null, splitter will put file(s) in the same directory as the input with no prefix */
+
+ const outputPath = uiOutput.isChecked() ? uiOutput.getOutputDir() : null;
+ const prefix = (prefixCheckbox.checked && prefixInput.value !== '') ? prefixInput.value : null;
+
+ const response = audiomothUtils.downsample(files[i], outputPath, prefix, sampleRate, (progress) => {
+
+ electron.ipcRenderer.send('set-downsample-bar-progress', i, progress, path.basename(files[i]));
+
+ });
+
+ if (response.success) {
+
+ successCount++;
+
+ } else {
+
+ /* Add error to log file */
+
+ errorCount++;
+ errors.push(response.error);
+ errorFiles.push(files[i]);
+
+ electron.ipcRenderer.send('set-downsample-bar-error', path.basename(files[i]));
+
+ if (errorCount === 1) {
+
+ const errorFileLocation = uiOutput.isChecked() ? uiOutput.getOutputDir() : path.dirname(errorFiles[0]);
+
+ errorFilePath = path.join(errorFileLocation, 'ERRORS.TXT');
+
+ }
+
+ let fileContent = '';
+
+ for (let j = 0; j < errorCount; j++) {
+
+ fileContent += path.basename(errorFiles[j]) + ' - ' + errors[j] + '\n';
+
+ }
+
+ try {
+
+ fs.writeFileSync(errorFilePath, fileContent);
+
+ console.log('Error summary written to ' + errorFilePath);
+
+ } catch (err) {
+
+ console.error(err);
+ electron.ipcRenderer.send('set-downsample-bar-completed', successCount, errorCount, true);
+ return;
+
+ }
+
+ ui.sleep(3000);
+
+ }
+
+ }
+
+ /* Notify main thread that split is complete so progress bar is closed */
+
+ electron.ipcRenderer.send('set-downsample-bar-completed', successCount, errorCount, false);
+
+}
+
+/* When the progress bar is complete and the summary window at the end has been displayed for a fixed amount of ttime, it will close and this re-enables the UI */
+
+electron.ipcRenderer.on('downsample-summary-closed', enableUI);
+
+/* Update label to reflect new file/folder selection */
+
+function updateInputDirectoryDisplay (directoryArray) {
+
+ if (directoryArray.length === 0 || !directoryArray) {
+
+ fileLabel.innerHTML = 'No AudioMoth WAV files selected.';
+ downsampleButton.disabled = true;
+
+ } else {
+
+ fileLabel.innerHTML = 'Found ';
+ fileLabel.innerHTML += directoryArray.length + ' AudioMoth WAV file';
+ fileLabel.innerHTML += (directoryArray.length === 1 ? '' : 's');
+ fileLabel.innerHTML += '.';
+ downsampleButton.disabled = false;
+
+ }
+
+}
+
+/* Reset UI back to default state, clearing the selected files */
+
+function resetUI () {
+
+ files = [];
+
+ fileLabel.innerHTML = 'No AudioMoth WAV files selected.';
+
+ downsampleButton.disabled = true;
+
+ sampleRateRadioHolder.style.display = 'none';
+ disabledSampleRateRadioHolder.style.display = '';
+
+ ui.updateButtonText();
+
+}
+
+/* Whenever the file/folder radio button changes, reset the UI */
+
+selectionRadios[0].addEventListener('change', resetUI);
+selectionRadios[1].addEventListener('change', resetUI);
+
+/* Select/process file(s) buttons */
+
+fileButton.addEventListener('click', () => {
+
+ files = ui.selectRecordings(FILE_REGEX);
+
+ updateInputDirectoryDisplay(files);
+
+ ui.updateButtonText();
+
+});
+
+downsampleButton.addEventListener('click', () => {
+
+ if (downsampling) {
+
+ return;
+
+ }
+
+ if ((!prefixCheckbox.checked || prefixInput.value === '') && (!uiOutput.isChecked() || uiOutput.getOutputDir() === '')) {
+
+ dialog.showMessageBox(currentWindow, {
+ type: 'error',
+ title: 'Cannot downsample with current settings',
+ message: 'Without a prefix or custom destination, downsampling will overwrite the original file. Set one of these values to continue.'
+ });
+
+ return;
+
+ }
+
+ downsampling = true;
+ disableUI();
+
+ electron.ipcRenderer.send('start-downsample-bar', files.length);
+ setTimeout(downsampleFiles, 2000);
+
+});
+
+for (let i = 0; i < sampleRateRadios.length; i++) {
+
+ sampleRateRadios[i].addEventListener('click', () => {
+
+ // Match hidden sample rate radios which are only displayed when UI is disabled
+
+ disabledSampleRateRadios[i].checked = true;
+
+ });
+
+}
diff --git a/expansion/uiExpansion.js b/processing/uiExpansion.js
similarity index 88%
rename from expansion/uiExpansion.js
rename to processing/uiExpansion.js
index 1251a5b..eadf316 100644
--- a/expansion/uiExpansion.js
+++ b/processing/uiExpansion.js
@@ -9,18 +9,18 @@
/* global document */
const electron = require('electron');
-const dialog = electron.remote.dialog;
-/* Get functions which control elements common to the expansion and split windows */
+/* Get functions which control elements common to the expansion, split, and downsample windows */
const ui = require('./uiCommon.js');
+const uiOutput = require('./uiOutput.js');
const path = require('path');
const fs = require('fs');
const audiomothUtils = require('audiomoth-utils');
-const MAX_LENGTHS = [5, 10, 15, 30, 60, 300, 600, 3600];
-const MAX_LENGTH_STRINGS = ['5 seconds', '10 seconds', '15 seconds', '30 seconds', '1 minute', '5 minutes', '10 minutes', '1 hour'];
+const MAX_LENGTHS = [1, 5, 10, 15, 30, 60, 300, 600, 3600];
+const MAX_LENGTH_STRINGS = ['1 second', '5 seconds', '10 seconds', '15 seconds', '30 seconds', '1 minute', '5 minutes', '10 minutes', '1 hour'];
const FILE_REGEX = /^(\d\d\d\d\d\d\d\d_)?\d\d\d\d\d\dT.WAV$/;
@@ -43,12 +43,6 @@ const overviewPanel = document.getElementById('overview-panel');
const prefixCheckbox = document.getElementById('prefix-checkbox');
const prefixInput = document.getElementById('prefix-input');
-const outputCheckbox = document.getElementById('output-checkbox');
-const outputButton = document.getElementById('output-button');
-const outputLabel = document.getElementById('output-label');
-
-var outputDir = '';
-
const fileLabel = document.getElementById('file-label');
const fileButton = document.getElementById('file-button');
const expandButton = document.getElementById('expand-button');
@@ -83,8 +77,8 @@ function disableUI () {
silentFilesCheckbox.disabled = true;
alignmentCheckbox.disabled = true;
- outputCheckbox.disabled = true;
- outputButton.disabled = true;
+ uiOutput.disableOutputCheckbox();
+ uiOutput.disableOutputButton();
prefixCheckbox.disabled = true;
prefixInput.disabled = true;
@@ -123,8 +117,8 @@ function enableUI () {
silentFilesCheckbox.disabled = !durationMaxLengthCheckbox.checked;
alignmentCheckbox.disabled = false;
- outputCheckbox.disabled = false;
- outputButton.disabled = false;
+ uiOutput.enableOutputCheckbox();
+ uiOutput.enableOutputButton();
prefixCheckbox.disabled = false;
@@ -236,7 +230,7 @@ function expandFiles () {
/* Check if the optional prefix/output directory setttings are being used. If left as null, expander will put expanded file(s) in the same directory as the input with no prefix */
- const outputPath = outputCheckbox.checked ? outputDir : null;
+ const outputPath = uiOutput.isChecked() ? uiOutput.getOutputDir() : null;
const prefix = (prefixCheckbox.checked && prefixInput.value !== '') ? prefixInput.value : null;
const response = audiomothUtils.expand(files[i], outputPath, prefix, expansionType, maxLength, generateSilentFiles, alignToSecondTransitions, (progress) => {
@@ -261,7 +255,7 @@ function expandFiles () {
if (errorCount === 1) {
- const errorFileLocation = outputCheckbox.checked ? outputDir : path.dirname(errorFiles[0]);
+ const errorFileLocation = uiOutput.isChecked() ? uiOutput.getOutputDir() : path.dirname(errorFiles[0]);
errorFilePath = path.join(errorFileLocation, 'ERRORS.TXT');
@@ -476,43 +470,6 @@ updateOverviewPanel();
updateFileMaxLengthUI('duration-max-length-ui', durationMaxLengthCheckbox);
updateFileMaxLengthUI('event-max-length-ui', eventMaxLengthCheckbox);
-/* Add listener which handles enabling/disabling custom output directory UI */
-
-outputCheckbox.addEventListener('change', () => {
-
- if (outputCheckbox.checked) {
-
- outputLabel.classList.remove('grey');
- outputButton.disabled = false;
-
- } else {
-
- outputLabel.classList.add('grey');
- outputButton.disabled = true;
- outputDir = '';
- ui.updateOutputLabel(outputDir);
-
- }
-
-});
-
-/* Select a custom output directory. If Cancel is pressed, assume no custom direcotry is wantted */
-
-outputButton.addEventListener('click', () => {
-
- const destinationName = dialog.showOpenDialogSync({
- title: 'Select Destination',
- nameFieldLabel: 'Destination',
- multiSelections: false,
- properties: ['openDirectory']
- });
-
- outputDir = (destinationName !== undefined) ? destinationName[0] : '';
-
- ui.updateOutputLabel(outputDir);
-
-});
-
/* Whenever tthe file/folder radio button changes, reset the UI */
selectionRadios[0].addEventListener('change', resetUI);
diff --git a/processing/uiOutput.js b/processing/uiOutput.js
new file mode 100644
index 0000000..0e91562
--- /dev/null
+++ b/processing/uiOutput.js
@@ -0,0 +1,107 @@
+/****************************************************************************
+ * uiOutput.js
+ * openacousticdevices.info
+ * June 2022
+ *****************************************************************************/
+
+'use strict';
+
+/* global document */
+
+const electron = require('electron');
+const dialog = electron.remote.dialog;
+
+const outputCheckbox = document.getElementById('output-checkbox');
+const outputButton = document.getElementById('output-button');
+const outputLabel = document.getElementById('output-label');
+
+var outputDir = '';
+
+/* Update label to notify user if a custom output directtory is being used */
+
+function updateOutputLabel (outputDir) {
+
+ if (outputDir === '') {
+
+ outputLabel.textContent = 'Writing WAV files to source folder.';
+
+ } else {
+
+ outputLabel.textContent = 'Writing WAV files to custom folder.';
+
+ }
+
+};
+
+/* Add listener which handles enabling/disabling custom output directory UI */
+
+outputCheckbox.addEventListener('change', () => {
+
+ if (outputCheckbox.checked) {
+
+ outputLabel.classList.remove('grey');
+ outputButton.disabled = false;
+
+ } else {
+
+ outputLabel.classList.add('grey');
+ outputButton.disabled = true;
+ outputDir = '';
+ updateOutputLabel(outputDir);
+
+ }
+
+});
+
+/* Select a custom output directory. If Cancel is pressed, assume no custom direcotry is wantted */
+
+outputButton.addEventListener('click', () => {
+
+ const destinationName = dialog.showOpenDialogSync({
+ title: 'Select Destination',
+ nameFieldLabel: 'Destination',
+ multiSelections: false,
+ properties: ['openDirectory']
+ });
+
+ outputDir = (destinationName !== undefined) ? destinationName[0] : '';
+
+ updateOutputLabel(outputDir);
+
+});
+
+exports.disableOutputCheckbox = () => {
+
+ outputCheckbox.disabled = true;
+
+};
+
+exports.disableOutputButton = () => {
+
+ outputButton.disabled = true;
+
+};
+
+exports.enableOutputCheckbox = () => {
+
+ outputCheckbox.disabled = false;
+
+};
+
+exports.enableOutputButton = () => {
+
+ outputButton.disabled = false;
+
+};
+
+exports.isChecked = () => {
+
+ return outputCheckbox.checked;
+
+};
+
+exports.getOutputDir = () => {
+
+ return outputDir;
+
+};
diff --git a/expansion/uiSplit.js b/processing/uiSplit.js
similarity index 79%
rename from expansion/uiSplit.js
rename to processing/uiSplit.js
index 06b713d..a011816 100644
--- a/expansion/uiSplit.js
+++ b/processing/uiSplit.js
@@ -11,8 +11,9 @@
const electron = require('electron');
const dialog = electron.remote.dialog;
-/* Get functions which control elements common to the expansion and split windows */
+/* Get functions which control elements common to the expansion, split, and downsample windows */
const ui = require('./uiCommon.js');
+const uiOutput = require('./uiOutput.js');
const path = require('path');
const fs = require('fs');
@@ -21,7 +22,7 @@ const audiomothUtils = require('audiomoth-utils');
var currentWindow = electron.remote.getCurrentWindow();
-const MAX_LENGTHS = [5, 10, 15, 30, 60, 300, 600, 3600];
+const MAX_LENGTHS = [1, 5, 10, 15, 30, 60, 300, 600, 3600];
const FILE_REGEX = /^(\d\d\d\d\d\d\d\d_)?\d\d\d\d\d\d.WAV$/;
@@ -32,12 +33,6 @@ const selectionRadios = document.getElementsByName('selection-radio');
const prefixCheckbox = document.getElementById('prefix-checkbox');
const prefixInput = document.getElementById('prefix-input');
-const outputCheckbox = document.getElementById('output-checkbox');
-const outputButton = document.getElementById('output-button');
-const outputLabel = document.getElementById('output-label');
-
-var outputDir = '';
-
const fileLabel = document.getElementById('file-label');
const fileButton = document.getElementById('file-button');
const splitButton = document.getElementById('split-button');
@@ -60,8 +55,8 @@ function disableUI () {
}
- outputCheckbox.disabled = true;
- outputButton.disabled = true;
+ uiOutput.disableOutputCheckbox();
+ uiOutput.disableOutputButton();
prefixCheckbox.disabled = true;
prefixInput.disabled = true;
@@ -81,8 +76,8 @@ function enableUI () {
}
- outputCheckbox.disabled = false;
- outputButton.disabled = false;
+ uiOutput.enableOutputCheckbox();
+ uiOutput.enableOutputButton();
prefixCheckbox.disabled = false;
@@ -140,7 +135,7 @@ function splitFiles () {
/* Check if the optional prefix/output directory setttings are being used. If left as null, splitter will put file(s) in the same directory as the input with no prefix */
- const outputPath = outputCheckbox.checked ? outputDir : null;
+ const outputPath = uiOutput.isChecked() ? uiOutput.getOutputDir() : null;
const prefix = (prefixCheckbox.checked && prefixInput.value !== '') ? prefixInput.value : null;
const response = audiomothUtils.split(files[i], outputPath, prefix, maxLength, (progress) => {
@@ -165,7 +160,7 @@ function splitFiles () {
if (errorCount === 1) {
- const errorFileLocation = outputCheckbox.checked ? outputDir : path.dirname(errorFiles[0]);
+ const errorFileLocation = uiOutput.isChecked() ? uiOutput.getOutputDir() : path.dirname(errorFiles[0]);
errorFilePath = path.join(errorFileLocation, 'ERRORS.TXT');
@@ -244,44 +239,7 @@ function resetUI () {
}
-/* Add listener which handles enabling/disabling custom output directory UI */
-
-outputCheckbox.addEventListener('change', () => {
-
- if (outputCheckbox.checked) {
-
- outputLabel.classList.remove('grey');
- outputButton.disabled = false;
-
- } else {
-
- outputLabel.classList.add('grey');
- outputButton.disabled = true;
- outputDir = '';
- ui.updateOutputLabel(outputDir);
-
- }
-
-});
-
-/* Select a custom output directory. If Cancel is pressed, assume no custom direcotry is wantted */
-
-outputButton.addEventListener('click', () => {
-
- const destinationName = dialog.showOpenDialogSync({
- title: 'Select Destination',
- nameFieldLabel: 'Destination',
- multiSelections: false,
- properties: ['openDirectory']
- });
-
- outputDir = (destinationName !== undefined) ? destinationName[0] : '';
-
- ui.updateOutputLabel(outputDir);
-
-});
-
-/* Whenever tthe file/folder radio button changes, reset the UI */
+/* Whenever the file/folder radio button changes, reset the UI */
selectionRadios[0].addEventListener('change', resetUI);
selectionRadios[1].addEventListener('change', resetUI);
@@ -306,7 +264,7 @@ splitButton.addEventListener('click', () => {
}
- if ((!prefixCheckbox.checked || prefixInput.value === '') && (!outputCheckbox.checked || outputDir === '')) {
+ if ((!prefixCheckbox.checked || prefixInput.value === '') && (!uiOutput.isChecked() || uiOutput.getOutputDir() === '')) {
dialog.showMessageBox(currentWindow, {
type: 'error',