Changed the path of octave.js to public subfolder called script
parent
bc54b1a089
commit
771a847148
|
@ -6,6 +6,5 @@ node_modules
|
|||
.output
|
||||
.env
|
||||
dist
|
||||
public
|
||||
assets
|
||||
.DS_Store
|
|
@ -0,0 +1,112 @@
|
|||
<template>
|
||||
<div>
|
||||
<button @click="startMicrophone">Start Microphone</button>
|
||||
<button @click="stopMicrophone">Stop Microphone</button>
|
||||
<div v-if="errorMessage">{{ errorMessage }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
console.log("mounted Bandprocessor");
|
||||
//this.initAudioContext();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
audioContext: null,
|
||||
microphoneStream: null,
|
||||
audioProcessorNode: null,
|
||||
errorMessage: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async initAudioContext() {
|
||||
try {
|
||||
const audioContext = new AudioContext();
|
||||
console.log("Current URL:", window.location.href);
|
||||
await audioContext.audioWorklet.addModule("/scripts/octave.js"
|
||||
|
||||
);
|
||||
// Now the 'bandpass-processor' is registered and can be used
|
||||
} catch (e) {
|
||||
console.error("Error loading audio worklet:", e);
|
||||
}
|
||||
},
|
||||
async startMicrophone() {
|
||||
console.log("Start initialization of AudioContext");
|
||||
try {
|
||||
this.initializeAudioContext();
|
||||
await this.requestMicrophoneAccess();
|
||||
await this.setupAudioProcessing();
|
||||
console.log("AudioContext sucessful initialized");
|
||||
} catch (error) {
|
||||
console.error("Error starting microphone:", error.message);
|
||||
this.errorMessage = error.message;
|
||||
}
|
||||
},
|
||||
stopMicrophone() {
|
||||
this.cleanup();
|
||||
},
|
||||
initializeAudioContext() {
|
||||
this.audioContext = new AudioContext();
|
||||
},
|
||||
async requestMicrophoneAccess() {
|
||||
try {
|
||||
this.microphoneStream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: true,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error accessing microphone:", error.message);
|
||||
this.errorMessage =
|
||||
"Microphone access denied. Please grant permission in your browser settings.";
|
||||
throw new Error("Microphone access denied.");
|
||||
}
|
||||
|
||||
if (
|
||||
!this.microphoneStream ||
|
||||
!(this.microphoneStream instanceof MediaStream)
|
||||
) {
|
||||
throw new Error("Microphone stream is not available.");
|
||||
}
|
||||
},
|
||||
async setupAudioProcessing() {
|
||||
try {
|
||||
const microphoneSource = this.audioContext.createMediaStreamSource(
|
||||
this.microphoneStream
|
||||
);
|
||||
await this.audioContext.audioWorklet.addModule("/scripts/octave.js");
|
||||
|
||||
this.audioProcessorNode = new AudioWorkletNode(this.audioContext, 'octave');
|
||||
microphoneSource.connect(this.audioProcessorNode);
|
||||
this.audioProcessorNode.connect(this.audioContext.destination);
|
||||
} catch (error) {
|
||||
console.error("Error setting up audio processing:", error.message);
|
||||
this.errorMessage =
|
||||
"Error setting up audio processing. Please check your microphone and try again.";
|
||||
throw new Error("Audio processing setup failed.");
|
||||
}
|
||||
},
|
||||
cleanup() {
|
||||
if (this.audioContext) {
|
||||
if (this.audioProcessorNode) {
|
||||
this.audioProcessorNode.disconnect();
|
||||
this.audioProcessorNode.port.postMessage({ command: "stop" });
|
||||
}
|
||||
this.audioContext.close();
|
||||
this.resetVariables();
|
||||
}
|
||||
},
|
||||
resetVariables() {
|
||||
this.audioContext = null;
|
||||
this.microphoneStream = null;
|
||||
this.audioProcessorNode = null;
|
||||
this.errorMessage = null;
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.cleanup();
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -6,6 +6,7 @@
|
|||
poster="/images/poster.png"
|
||||
>
|
||||
<div class="container-fluid overflow-auto" >
|
||||
<div class="row"> <BandProcessor /> </div>
|
||||
<div class="row ">
|
||||
<div class="col-12 col-lg-4 bg-img d-none d-lg-block" style="background-image: url('/images/login.svg');background-size: cover;height: 100vh;" >
|
||||
</div>
|
||||
|
@ -68,7 +69,7 @@
|
|||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</video-background>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -76,7 +77,9 @@
|
|||
import backgroundImagePath from '~/assets/image/login4.png';
|
||||
import {useUserStore} from '@/stores/user';
|
||||
import {mapState,mapActions} from "pinia";
|
||||
import BandProcessor from "@/components/BandProcessor";
|
||||
export default {
|
||||
|
||||
setup() {
|
||||
const { t } = useI18n()
|
||||
const localePath = useLocalePath()
|
||||
|
@ -86,6 +89,9 @@ export default {
|
|||
localePath,
|
||||
}
|
||||
},
|
||||
//Components BEGIN
|
||||
components: {BandProcessor},
|
||||
//Components END
|
||||
mounted() {
|
||||
// if (this.is_login){
|
||||
// this.$router.push('/onboarding');
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
class OctaveBandProcessor extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
super();
|
||||
// Define center frequencies for 9 octave bands
|
||||
this.centerFrequencies = [63, 125, 250, 500, 1000, 2000, 4000, 8000, 16000];
|
||||
this.filters = [];
|
||||
this.lastUpdateTimestamp = 0;
|
||||
this.updateInterval = 0.125; // Update every 0.125 seconds
|
||||
|
||||
// Create an A-weighting filter for specific frequencies
|
||||
this.createAWeightingFilter();
|
||||
|
||||
// Create bandpass filters for each center frequency
|
||||
this.centerFrequencies.forEach(frequency => {
|
||||
const filter = new BiquadFilterNode(audioContext, {
|
||||
type: 'bandpass',
|
||||
frequency: frequency,
|
||||
Q: 1.41, // Set the desired Q value
|
||||
},
|
||||
this.filters.push(filter))
|
||||
});
|
||||
|
||||
// Set up analyzers for calculating percentiles
|
||||
this.setupAnalyzers();
|
||||
|
||||
}
|
||||
|
||||
setupAnalyzers() {
|
||||
this.analyzers = [];
|
||||
this.centerFrequencies.forEach(frequency => {
|
||||
this.analyzers.push([]);
|
||||
for (let i = 0; i < 5; i++) { // Unique identifiers from 0 to 4
|
||||
const analyzer = audioContext.createAnalyser();
|
||||
analyzer.fftSize = 2048;
|
||||
|
||||
// Check if the identifier is 0 (microphone audio) before connecting to the A-weighting filter
|
||||
if (i === 0) {
|
||||
this.aWeightingFilter.connect(analyzer);
|
||||
}
|
||||
|
||||
this.analyzers[this.analyzers.length - 1].push(analyzer);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
process(inputs, outputs) {
|
||||
const numOutputChannels = outputs.length;
|
||||
for (let i = 0; i < numOutputChannels; i++) {
|
||||
const outputChannel = outputs[i][0];
|
||||
const inputChannel = inputs[i][0];
|
||||
|
||||
// Apply the filter to the input channel
|
||||
const filteredSignal = this.filters[i].process(inputChannel);
|
||||
|
||||
// Apply A-weighting only to the microphone signal (channel 0)
|
||||
if (i === 0) {
|
||||
const aWeightedSignal = this.aWeightingFilter.process(filteredSignal);
|
||||
outputChannel.set(aWeightedSignal);
|
||||
} else {
|
||||
// For other channels, pass the signal without A-weighting
|
||||
outputChannel.set(filteredSignal);
|
||||
}
|
||||
|
||||
// Check if it's time to update percentiles
|
||||
const currentTime = this.currentTime;
|
||||
if (currentTime - this.lastUpdateTimestamp >= this.updateInterval) {
|
||||
this.updatePercentiles(i);
|
||||
this.lastUpdateTimestamp = currentTime;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
calculateRMSLevel(signal, channelIndex) {
|
||||
const data = new Float32Array(signal.length);
|
||||
signal.copyFromChannel(data, 0);
|
||||
const sum = data.reduce((acc, val) => acc + val * val, 0);
|
||||
const rmsLevel = Math.sqrt(sum / data.length);
|
||||
const dBLevel = 20 * Math.log10(rmsLevel); // Convert to dB
|
||||
return dBLevel;
|
||||
}
|
||||
|
||||
updatePercentiles(channelIndex) {
|
||||
for (let i = 0; i < this.centerFrequencies.length; i++) {
|
||||
const analyzer = this.analyzers[i][channelIndex];
|
||||
const levelData = new Float32Array(analyzer.frequencyBinCount);
|
||||
analyzer.getFloatFrequencyData(levelData);
|
||||
|
||||
// Calculate percentiles for each octave band and each channel
|
||||
const percentile10 = this.calculatePercentile(levelData, 10);
|
||||
const percentile90 = this.calculatePercentile(levelData, 90);
|
||||
|
||||
const percentileDiff = percentile10 - percentile90;
|
||||
|
||||
// Store the percentile difference for each channel and each octave band
|
||||
// You can use suitable data structures to store these values for future comparisons
|
||||
}
|
||||
}
|
||||
|
||||
calculatePercentile(data, percentile) {
|
||||
const sortedData = data.slice().sort((a, b) => a - b);
|
||||
const index = Math.floor((percentile / 100) * sortedData.length);
|
||||
return sortedData[index];
|
||||
}
|
||||
|
||||
createAWeightingFilter() {
|
||||
// Use the provided A-weighting filter coefficients
|
||||
const aWeightingCoefficients = [0, -0.051, -0.142, -0.245, -0.383, -0.65, -1.293, -2.594, -6.554]; //David
|
||||
|
||||
// Create a custom IIR filter node with the A-weighting coefficients
|
||||
this.aWeightingFilter = new IIRFilterNode(audioContext, {
|
||||
feedforward: aWeightingCoefficients,
|
||||
feedback: [1],
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
combineAndCalculate() {
|
||||
let LAF10_90_total = 0; // Initialize the total LAF10%-90%
|
||||
|
||||
for (let i = 0; i < this.centerFrequencies.length; i++) {
|
||||
const micAnalyzer = this.analyzers[i][0]; // Analyzer for microphone audio (identifier 0)
|
||||
const audioFile1Analyzer = this.analyzers[i][3]; // Analyzer for audioFile1 (identifier 3)
|
||||
const audioFile2Analyzer = this.analyzers[i][4]; // Analyzer for audioFile2 (identifier 4)
|
||||
|
||||
// Calculate percentiles for the microphone audio
|
||||
const micPercentile10 = this.calculatePercentile(micAnalyzer, 10);
|
||||
const micPercentile90 = this.calculatePercentile(micAnalyzer, 90);
|
||||
|
||||
// Calculate percentiles for audioFile1
|
||||
const audioFile1Percentile10 = this.calculatePercentile(audioFile1Analyzer, 10);
|
||||
const audioFile1Percentile90 = this.calculatePercentile(audioFile1Analyzer, 90);
|
||||
|
||||
// Calculate percentiles for audioFile2
|
||||
const audioFile2Percentile10 = this.calculatePercentile(audioFile2Analyzer, 10);
|
||||
const audioFile2Percentile90 = this.calculatePercentile(audioFile2Analyzer, 90);
|
||||
|
||||
// Calculate LAF10%-90% for microphone audio, audioFile1, and audioFile2 separately
|
||||
const micLAF10_90 = micPercentile10 - micPercentile90;
|
||||
const audioFile1LAF10_90 = audioFile1Percentile10 - audioFile1Percentile90;
|
||||
const audioFile2LAF10_90 = audioFile2Percentile10 - audioFile2Percentile90;
|
||||
|
||||
// Calculate combined LAF10%-90% for microphone audio, audioFile1, and audioFile2
|
||||
const combinedLAF10_90 = micLAF10_90 + audioFile1LAF10_90 + audioFile2LAF10_90;
|
||||
|
||||
// Add the combined LAF10%-90% to the total
|
||||
LAF10_90_total += combinedLAF10_90;
|
||||
}
|
||||
|
||||
// return LAF10_90_total;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
registerProcessor('octave', OctaveBandProcessor);
|
||||
|
Loading…
Reference in New Issue