ffsaf-site/src/main/webapp/public/processor-dtmf.js

85 lines
3.4 KiB
JavaScript

class ProcessorDTMF extends AudioWorkletProcessor {
constructor() {
super();
this.sampleRate = sampleRate;
this.symbolDuration = 0.03; // 50 ms par symbole
this.samplesPerSymbol = Math.floor(this.sampleRate * this.symbolDuration);
this.encodeLowPrio = [];
this.symbolSamples = [];
this.lastBlackStep = 0;
this.port.onmessage = (e) => {
if (e.data.type === 'encode') {
this.symbolSamples.push(...this.encodeSymbols(e.data.symbols));
this.symbolSamples.push(...this.encodeBlack(this.sampleRate * 0.02));
}
if (e.data.type === 'encodeLowPrio') {
this.encodeLowPrio.push(e.data.symbols);
}
};
}
dtmfFrequencies = [
[697, 770, 852, 941], // Fréquences basses
[1209, 1336, 1477, 1633] // Fréquences hautes
];
encodeSymbols(symbols) {
const samples = [];
for (const symbol of symbols) {
const lf = this.dtmfFrequencies[0][symbol % 4]; // Fréquence basse
const hf = this.dtmfFrequencies[1][Math.floor(symbol / 4)]; // Fréquence haute
// console.log(`Symbol: ${symbol}, LF: ${lf} Hz, HF: ${hf} Hz`);
for (let i = 0; i < this.samplesPerSymbol; i++) {
const t = i / this.sampleRate;
const t2 = (this.lastBlackStep + i) / this.sampleRate;
samples.push(0.5 * Math.sin(2 * Math.PI * lf * t) + 0.5 * Math.sin(2 * Math.PI * hf * t) // Signal DTMF
+ Math.sin(2 * Math.PI * 150 * t2) * (0.0625 * (Math.sin(2 * Math.PI * 0.5 * t2) + 1))); // Ajouter un signal à 150 Hz pour le "black"
}
this.lastBlackStep += this.samplesPerSymbol;
// ajouter un silence de 10 ms entre les symboles
samples.push(...this.encodeBlack(this.sampleRate * 0.01)); // Silence
}
return samples;
}
encodeBlack(size) {
const samples = [];
for (let i = 0; i < size; i++) {
const t = (this.lastBlackStep + i) / this.sampleRate;
samples.push(Math.sin(2 * Math.PI * 150 * t) * (0.0625 * (Math.sin(2 * Math.PI * 0.5 * t) + 1))); // Signal à 350 Hz pour le "black"
}
this.lastBlackStep += size;
this.lastBlackStep %= this.sampleRate * 2; // Réinitialiser tous les 2 secondes pour éviter les débordements
return samples;
}
process(inputs, outputs, parameters) {
const output = outputs[0]; // output est un tableau de canaux (ex: [Float32Array, ...])
const channelData = output[0]; // Accéder au premier canal (mono)
if (this.symbolSamples.length === 0 && this.encodeLowPrio.length > 0) {
this.symbolSamples.push(...this.encodeSymbols(this.encodeLowPrio.shift()));
this.symbolSamples.push(...this.encodeBlack(this.sampleRate * 0.02));
}
if (this.symbolSamples.length === 0) {
const samples = this.encodeBlack(channelData.length)
for (let i = 0; i < channelData.length; i++) {
channelData[i] = samples[i] || 0;
}
return true;
}
for (let i = 0; i < channelData.length; i++) {
channelData[i] = this.symbolSamples.shift() || 0; // Prendre le prochain échantillon ou 0 si vide
}
return true;
}
}
registerProcessor('dtmf-processor', ProcessorDTMF);