Skip to content

Commit

Permalink
FIxed stereo bug, originating from Audio-loader package. In so doing,…
Browse files Browse the repository at this point in the history
… extended file type support to include flac, ogg, m4a / aac and mpga / mpeg. Now removed audio-loader and associated 89 packages, using built in AudioContext and Offline audio context to open, resample and render audio. 👍
  • Loading branch information
Mattk70 committed Jan 30, 2022
1 parent 9c9cb92 commit 750174d
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 73 deletions.
99 changes: 53 additions & 46 deletions js/ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ const {ipcRenderer} = require('electron');
const {dialog} = require('electron').remote;
const remote = require('electron').remote;
const fs = require('fs');
const load = require("audio-loader");
const remix = require('audio-buffer-remix');
const util = require('audio-buffer-utils');
const WaveSurfer = require("wavesurfer.js");
const SpectrogramPlugin = require('wavesurfer.js/dist/plugin/wavesurfer.spectrogram.min.js');
const SpecTimeline = require('wavesurfer.js/dist/plugin/wavesurfer.timeline.min.js');
Expand Down Expand Up @@ -34,56 +31,67 @@ let contentWrapperElement = $('#contentWrapper');
let controlsWrapperElement = $('#controlsWrapper');
let completeDiv = $('.complete');


async function loadAudioFile(filePath) {
// Hide load hint and show spinnner
hideAll();
disableMenuItem('analyze')
showElement('loadFileHint');
showElement('loadFileHintSpinner');
showElement('loadFileHintLog');
let start = new Date()
// load one file
console.log('loadFileHintLog', 'Loading file...');
load(filePath).then(function (buffer) {
hideElement('loadFileHint');
console.log('load gives file with duration:' + buffer.duration)
let sampleRate = buffer.sampleRate;
let timeNow = new Date() - start
console.log('loading took ' + timeNow / 1000 + ' seconds');
// Resample
start = new Date()
const offlineCtx = new OfflineAudioContext(1,
buffer.duration * 24000,
24000);

const offlineSource = offlineCtx.createBufferSource();
offlineSource.buffer = buffer;
offlineSource.connect(offlineCtx.destination);
offlineSource.start();
offlineCtx.startRendering().then((resampled) => {
// `resampled` contains an AudioBuffer resampled at 48000Hz.
// use resampled.getChannelData(x) to get an Float32Array for channel x.
timeNow = new Date() - start;
console.log('resampling took ' + timeNow / 1000 + ' seconds');
let duration = resampled.duration
if (duration < 300) {
drawSpec({
'audio': resampled,
'backend': 'WebAudio',
'alpha': 0,
'context': null,
'spectrogram': true
});
} else {
drawSpec({'audio': filePath, 'backend': 'MediaElementWebAudio', 'alpha': 1, 'spectrogram': false});
}
ipcRenderer.send('file-loaded', {message: currentFile});
fileLoaded = true;
completeDiv.hide();
if (modelReady) enableMenuItem('analyze')
hideElement('loadFileHint');
// create an audio context object and load file into it
const audioCtx = new AudioContext();
let source = audioCtx.createBufferSource();
fs.readFile(filePath, function (err, data) {
if (err) {
reject(err)
} else {
audioCtx.decodeAudioData(data.buffer).then(function (buffer) {
const myBuffer = buffer;
source.buffer = myBuffer;
const chann = buffer.getChannelData(0);
const duration = source.buffer.duration;
const sampleRate = source.buffer.sampleRate;
const offlineCtx = new OfflineAudioContext(1, 48000 * duration, 48000);
const offlineSource = offlineCtx.createBufferSource();
offlineSource.buffer = buffer;
offlineSource.connect(offlineCtx.destination);
offlineSource.start();
offlineCtx.startRendering().then(function (resampled) {
console.log('Rendering completed successfully');
// `resampled` contains an AudioBuffer resampled at 48000Hz.
// use resampled.getChannelData(x) to get an Float32Array for channel x.
const chann2 = resampled.getChannelData(0);
if (resampled.duration < 300) {
drawSpec({
'audio': resampled,
'backend': 'WebAudio',
'alpha': 0,
'context': null,
'spectrogram': true
});
} else {
drawSpec({
'audio': filePath,
'backend': 'MediaElementWebAudio',
'alpha': 1,
'spectrogram': false
});
}
})
}).catch(function (e) {
console.log("Error with decoding audio data" + e.err);
})
}

});
});
})

ipcRenderer.send('file-loaded', {message: filePath});
fileLoaded = true;
completeDiv.hide();
if (modelReady) enableMenuItem('analyze')
}

function drawSpec(args) {
Expand Down Expand Up @@ -201,7 +209,7 @@ function zoomSpecOut() {
async function showOpenDialog() {
// Show file dialog to select audio file
const fileDialog = await dialog.showOpenDialog({
filters: [{name: 'Audio Files', extensions: ['mp3', 'wav']}], // , 'ogg', 'aac', 'flac']}],
filters: [{name: 'Audio Files', extensions: ['mp3', 'wav', 'ogg', 'aac', 'flac', 'm4a', 'mpga', 'mpeg']}],
properties: ['openFile']
});
// Load audio file
Expand Down Expand Up @@ -469,7 +477,6 @@ let progressBar = $('.progress .progress-bar');
ipcRenderer.on('progress', async (event, arg) => {
progressDiv.show();
let progress = (arg.progress * 100).toFixed(1);
console.log('progress update: ' + progress);
progressBar.width(progress + '%');
progressBar.attr('aria-valuenow', progress);
progressBar.html(progress + '%');
Expand Down
56 changes: 31 additions & 25 deletions js/worker.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const {ipcRenderer} = require('electron');
const load = require("audio-loader");
const Model = require('./js/model.js');
const fs = require("fs");
const appPath = '';
//const appPath = process.resourcesPath;

Expand Down Expand Up @@ -62,28 +62,34 @@ ipcRenderer.on('analyze', async (event, arg) => {


async function loadAudioFile(filePath) {
// load one file
try {
load(filePath).then(function (buffer) {
// Resample
// if mp3
let sampleRate = model.config.sampleRate;
if (filePath.endsWith('.mp3')) sampleRate /= buffer.numberOfChannels;
const offlineCtx = new OfflineAudioContext(1,
buffer.duration * 48000,
48000);
const offlineSource = offlineCtx.createBufferSource();
offlineSource.buffer = buffer;
offlineSource.connect(offlineCtx.destination);
offlineSource.start();
offlineCtx.startRendering().then((resampled) => {
// `resampled` contains an AudioBuffer resampled at 48000Hz.
// use resampled.getChannelData(x) to get an Float32Array for channel x.
console.log("model received file of duration: " + resampled.duration)
audioBuffer = resampled.getChannelData(0);
});
})
} catch (error) {
console.log(error)
}
// create an audio context object and load file into it
const audioCtx = new AudioContext();
let source = audioCtx.createBufferSource();
fs.readFile(filePath, function (err, data) {
if (err) {
reject(err)
} else {
audioCtx.decodeAudioData(data.buffer).then(function (buffer) {
source.buffer = buffer;
const duration = source.buffer.duration;
const sampleRate = model.config.sampleRate;
const offlineCtx = new OfflineAudioContext(1, sampleRate * duration, sampleRate);
const offlineSource = offlineCtx.createBufferSource();
offlineSource.buffer = buffer;
offlineSource.connect(offlineCtx.destination);
offlineSource.start();
offlineCtx.startRendering().then(function (resampled) {
console.log('Rendering completed successfully');
// `resampled` contains an AudioBuffer resampled at 48000Hz.
// use resampled.getChannelData(x) to get an Float32Array for channel x.
audioBuffer = resampled.getChannelData(0);

})
}).catch(function (e) {
console.log("Error with decoding audio data" + e.err);
})
}

})

}
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,10 @@
},
"dependencies": {
"@tensorflow/tfjs": "3.13.0",
"audio-loader": "^1.0.3",
"bootstrap": "^4.6.1",
"colormap": "^2.3.2",
"jquery": "^3.6.0",
"seedrandom": "^3.0.5",
"wavesurfer.js": "^5.2.0"
}
}
}

0 comments on commit 750174d

Please sign in to comment.