Skip to content

Commit

Permalink
New custom colormaps, more work on deteched buffers
Browse files Browse the repository at this point in the history
UI:
Added 3-tone custom colormap feature
Allowed setting of window function
Changed the daefault window function to Hann

Worker:
Added file parameter to setupCtx, to aid debugging
processPredictQueue no longer async
- Emit a warning if no header found in a file during prediction
- call updatefilesbeingprocessed when concatenatedbuffer has no length when null chunk received
- DO NOT call STREAM.end()

In fetchAudioBuffer, don't look for headers each chunk. It should always be at the beginning

*Set timeout in fluent-ffmpeg to 2000, increased backlog limit to 200*

Bump version.
  • Loading branch information
Mattk70 committed Apr 20, 2024
1 parent 24044bf commit 8d8b6fd
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 71 deletions.
14 changes: 12 additions & 2 deletions Help/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@
</td>
</tr>
<tr>
<td colspan="2" class="text-center text-bg-light"><h6>Audio Export</h6></td>
<td colspan="2" class="text-center text-bg-light"><h5>Audio Export</h5></td>
</tr>
<tr>
<td><b>Format and Bitrate</b></td>
Expand Down Expand Up @@ -192,7 +192,17 @@
</tr>
<tr>
<td><b>Colourmap</b></td>
<td>Choose the colour theme for the spectrogram display</td>
<td>Choose a colour theme for the spectrogram display, or create your own. If you select 'custom', you will have the option to set the colours for peak, mid and quiet sounds according
to personal preference. You can also adjust the mid-point position: with a value of 0 or 1, the Spectrogram will be two-tone. Values in between will blend the three colours.
If you set the Mid colour the same as one of the others, you will be able to adjust the contrast in the spectrogram using Mid Position adjustments.
<p>In combination with audio filter adjustments, a custom colormap allows you to enhance the contrast / visibility of calls using the colours of your choice.</p>
</td>
</tr>
<tr>
<td><b>Window Function</b></td>
<td>A variety of windowing functinos are available for the spectrogram display. Each has slightly different characteristics, so changing the window function may also enhance the
appearance of the calls in the display.
</td>
</tr>
<tr>
<th>Timeline</th>
Expand Down
48 changes: 36 additions & 12 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -368,30 +368,54 @@ <h6 class="fs-6">Audio Export:</h6>
<div class="pe-3 input-group rounded p-2 mb-1">
<label for="colourmap" class="input-group-text col-5">Colourmap:</label>
<select class="form-select mb-0" id="colourmap">
<option value="custom">Custom</option>
<option value="greys">Greyscale</option>
<option value="bone">Bone</option>
<option value="turbidity">Turbidity</option>
<option value="chlorophyll">Chlorophyll</option>
<option value="viridis">Viridis</option>
<option value="cdom">CDom</option>
<option value="temperature">Temperature</option>
<!-- <option value="density">Density</option>-->
<!-- <option value="oxygen">Oxygen</option>-->
<!-- <option value="copper">Copper</option>-->
<!-- <option value="earth">Earth</option>-->
<option value="salinity">Salinity</option>
<option value="inferno">Inferno</option>
<option value="magma">Magma</option>
<option value="plasma">Plasma</option>
<option value="hot">Hot</option>
<!-- <option value="cubehelix">CubeHelix</option>-->
<!-- <option value="phase">Phase</option>-->
<!-- <option value="YlOrRd">Yellow/red</option>-->
<!-- <option value="picnic">Picnic</option>-->
<!-- <option value="electric">Electric</option>-->
<!-- <option value="bluered">BlueRed</option>-->
<option value="blackbody">Blackbody</option>
<!-- <option value="rainbow">Rainbow</option>-->
<!-- <option value="rainbow-soft">Rainbow</option>-->
</select>
</div>
<fieldset class="border border-secondary rounded m-2 mb-0 p-2 w-100 d-none" id="colormap-fieldset">
<div class="mt-2">
<input class="form-input pointer" type="color" id="loud-color" value="#cc00ff">
<label class="form-label pointer" for="loud-color">Peak colour</label><br>
<input class="form-input pointer" type="color" id="mid-color" value="#000000">
<label class="form-label pointer" for="mid-color">Mid colour</label><br>
<input class="form-input pointer" type="color" id="quiet-color" value="#000000">
<label class="form-label pointer" for="quiet-color">Quiet colour</label>
</div>
<label for="color-threshold-slider" class="form-label">
Mid Position:
</label>
<div class="input-group">
<input type="range" class="form-control-range w-75" min="0" max="1" step="0.01" id="color-threshold-slider">
<div class="input-group-append">
<span class="input-group-text" id="color-threshold">0.5</span>
</div>
</div>
</fieldset>
<div class="pe-3 input-group rounded p-2 mb-1">
<label for="window-function" class="input-group-text col-5">Window function:</label>
<select class="form-select mb-0" id="window-function">
<option value="bartlett">Bartlett</option>
<option value="bartlettHann">BartlettHann</option>
<option value="blackman">Blackman</option>
<option value="cosine">Cosine</option>
<option value="gauss">Gauss</option>
<option value="hamming">Hamming</option>
<option value="hann">Hann</option>
<option value="lanczoz">Lanczoz</option>
<option value="rectangular">Rectangular</option>
<option value="triangular">Triangular</option>
</select>
</div>
<div class="pe-3 input-group rounded p-2 mb-1">
Expand Down
106 changes: 88 additions & 18 deletions js/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,28 @@ const SunCalc = window.module.SunCalc;
const uuidv4 = window.module.uuidv4;
const os = window.module.os;

function hexToRgb(hex) {
// Remove the '#' character if present
hex = hex.replace(/^#/, '');

// Parse the hex string into individual RGB components
var r = parseInt(hex.substring(0, 2), 16);
var g = parseInt(hex.substring(2, 4), 16);
var b = parseInt(hex.substring(4, 6), 16);

// Return the RGB components as an array
return [r, g, b];
}
function createColormap(){
const map = config.colormap === 'custom' ? [
{index: 0, rgb: hexToRgb(config.customColormap.quiet)},
{index: config.customColormap.threshold, rgb: hexToRgb(config.customColormap.mid)},
{index: 1, rgb: hexToRgb(config.customColormap.loud)}
] : config.colormap;
return colormap({ colormap: map, nshades:256, format: 'float' });
}


let worker;

/// Set up communication channel between UI and worker window
Expand Down Expand Up @@ -332,7 +354,7 @@ const initWavesurfer = ({
waveColor: 'rgba(109,41,164,0)',
progressColor: 'rgba(109,41,16,0)',
// but keep the playhead
cursorColor: '#fff',
cursorColor: config.colormap === 'custom' ? config.customColormap.loud : '#fff',
cursorWidth: 2,
skipLength: 0.1,
partialRender: true,
Expand Down Expand Up @@ -1210,15 +1232,17 @@ const footerHeight = document.getElementById('footer').offsetHeight;
const navHeight = document.getElementById('navPadding').offsetHeight;
function adjustSpecDims(redraw, fftSamples) {
//Contentwrapper starts below navbar (66px) and ends above footer (30px). Hence - 96
DOM.contentWrapperElement.style.height = (bodyElement.clientHeight - footerHeight - navHeight) + 'px';
const contentHeight = DOM.contentWrapperElement.offsetHeight;
const contentWrapper = document.getElementById('contentWrapper');
contentWrapper.style.height = (bodyElement.clientHeight - footerHeight - navHeight) + 'px';
const contentHeight = contentWrapper.offsetHeight;
// + 2 for padding
const formOffset = document.getElementById('exploreWrapper').offsetHeight;
let specOffset;
if (!DOM.spectrogramWrapper.classList.contains('d-none')) {
const spectrogramWrapper = document.getElementById('spectrogramWrapper')
if (!spectrogramWrapper.classList.contains('d-none')) {
// Expand up to 512px unless fullscreen
const controlsHeight = document.getElementById('controlsWrapper').offsetHeight;
const timelineHeight = document.getElementById('timeline').offsetHeight;
const timelineHeight = 22 ; //document.getElementById('timeline').offsetHeight; // This is unset when there is no wavesurfer, so hard-coding
const specHeight = config.fullscreen ? contentHeight - timelineHeight - formOffset - controlsHeight : Math.min(contentHeight * 0.4, 512);
if (currentFile) {
// give the wrapper space for the transport controls and element padding/margins
Expand All @@ -1239,12 +1263,13 @@ function adjustSpecDims(redraw, fftSamples) {
document.querySelector('.spec-labels').style.width = '55px';
}
if (wavesurfer && redraw) {
specOffset = DOM.spectrogramWrapper.offsetHeight;
specOffset = spectrogramWrapper.offsetHeight;
}
} else {
specOffset = 0
}
DOM.resultTableElement.style.height = (contentHeight - specOffset - formOffset) + 'px';
const resultTableElement = document.getElementById('resultTableContainer');
resultTableElement.style.height = (contentHeight - specOffset - formOffset) + 'px';
}


Expand Down Expand Up @@ -1444,6 +1469,7 @@ window.onload = async () => {
lastUpdateCheck: 0,
UUID: uuidv4(),
colormap: 'inferno',
customColormap: {'loud': "#00f5d8", 'mid': "#000000", 'quiet': "#000000", 'threshold': 0.5, 'windowFn': 'hann'},
timeOfDay: true,
list: 'birds',
customListFile: {birdnet: '', chirpity: ''},
Expand Down Expand Up @@ -1539,8 +1565,15 @@ window.onload = async () => {
DOM.timelineSetting.value = config.timeOfDay ? 'timeOfDay' : 'timecode';
// Spectrogram colour
DOM.colourmap.value = config.colormap;
// Nocmig mode state
console.log('nocmig mode is ' + config.detect.nocmig);
// Window function & colormap
document.getElementById('window-function').value = config.customColormap.windowFn;
config.colormap === 'custom' && document.getElementById('colormap-fieldset').classList.remove('d-none');
document.getElementById('color-threshold').textContent = config.customColormap.threshold;
document.getElementById('loud-color').value = config.customColormap.loud;
document.getElementById('mid-color').value = config.customColormap.mid;
document.getElementById('quiet-color').value = config.customColormap.quiet;
document.getElementById('color-threshold-slider').value = config.customColormap.threshold;

// Audio preferences:
DOM.gain.value = config.audio.gain;
DOM.gainAdjustment.textContent = config.audio.gain + 'dB';
Expand Down Expand Up @@ -2275,23 +2308,23 @@ function onChartData(args) {
height = fftSamples / 2
}
if (wavesurfer.spectrogram) wavesurfer.destroyPlugin('spectrogram');
// set colormap
const colors = createColormap() ;
wavesurfer.addPlugin(WaveSurfer.spectrogram.create({
//deferInit: false,
wavesurfer: wavesurfer,
container: "#spectrogram",
scrollParent: false,
fillParent: true,
windowFunc: 'hamming',
windowFunc: config.customColormap.windowFn,
frequencyMin: 0,
frequencyMax: 11_950,
normalize: false,
hideScrollbar: true,
labels: true,
height: height,
fftSamples: fftSamples,
colorMap: colormap({
colormap: config.colormap, nshades: 256, format: 'float'
}),
colorMap: colors
})).initPlugin('spectrogram')
updateElementCache();
}
Expand Down Expand Up @@ -2597,7 +2630,7 @@ function onChartData(args) {
},
Minus: function (e) {
if (e.shiftKey) {
if (wavesurfer.spectrogram.fftSamples <= 2048) {
if (wavesurfer.spectrogram.fftSamples <= 4096) {
wavesurfer.spectrogram.fftSamples *= 2;
const position = clamp(wavesurfer.getCurrentTime() / windowLength, 0, 1);
postBufferUpdate({ begin: bufferBegin, position: position, region: getRegion(), goToRegion: false })
Expand All @@ -2609,7 +2642,7 @@ function onChartData(args) {
},
NumpadSubtract: function (e) {
if (e.shiftKey) {
if (wavesurfer.spectrogram.fftSamples <= 2048) {
if (wavesurfer.spectrogram.fftSamples <= 4096) {
wavesurfer.spectrogram.fftSamples *= 2;
const position = clamp(wavesurfer.getCurrentTime() / windowLength, 0, 1);
postBufferUpdate({ begin: bufferBegin, position: position, region: getRegion(), goToRegion: false })
Expand Down Expand Up @@ -4042,6 +4075,12 @@ function onChartData(args) {
SNRSlider.addEventListener('input', () => {
SNRThreshold.textContent = SNRSlider.value;
});

const colorMapThreshhold = document.getElementById('color-threshold');
const colorMapSlider = document.getElementById('color-threshold-slider');
colorMapSlider.addEventListener('input', () => {
colorMapThreshhold.textContent = colorMapSlider.value;
});

const handleHPchange = () => {
config.filters.highPassFrequency = HPSlider.valueAsNumber;
Expand Down Expand Up @@ -4360,11 +4399,42 @@ DOM.gain.addEventListener('input', () => {
}
case 'colourmap': {
config.colormap = element.value;
const colorMapFieldset = document.getElementById('colormap-fieldset')
if (config.colormap === 'custom'){
colorMapFieldset.classList.remove('d-none')
} else {
colorMapFieldset.classList.add('d-none')
}
if (wavesurfer && currentFile) {

// refresh caches
updateElementCache()
const fftSamples = wavesurfer.spectrogram.fftSamples;
wavesurfer.destroy();
wavesurfer = undefined;
adjustSpecDims(true, fftSamples)
}
break;
}
case 'window-function':
case 'loud-color':
case 'mid-color':
case 'quiet-color':
case 'color-threshold-slider': {
const windowFn = document.getElementById('window-function').value;
const loud = document.getElementById('loud-color').value;
const mid = document.getElementById('mid-color').value;
const quiet = document.getElementById('quiet-color').value;
const threshold = document.getElementById('color-threshold-slider').valueAsNumber;
document.getElementById('color-threshold').textContent = threshold;
config.customColormap = {'loud': loud, 'mid': mid, 'quiet': quiet, 'threshold': threshold, 'windowFn': windowFn};
if (wavesurfer && currentFile) {
initSpectrogram();
// refresh caches
updateElementCache()
adjustSpecDims(true)
const fftSamples = wavesurfer.spectrogram.fftSamples;
wavesurfer.destroy();
wavesurfer = undefined;
adjustSpecDims(true, fftSamples)
}
break;
}
Expand Down Expand Up @@ -5201,7 +5271,7 @@ function showCompareSpec() {
//deferInit: false,
wavesurfer: ws,
container: "#" + specContainer,
windowFunc: 'hamming',
windowFunc: 'hann',
frequencyMin: 0,
frequencyMax: 11_950,
hideScrollbar: false,
Expand Down
Loading

0 comments on commit 8d8b6fd

Please sign in to comment.