Несогласованные аудиоданные PCM, полученные из одного и того же видео с помощью AudioWorkletNode.Javascript

Форум по Javascript
Ответить Пред. темаСлед. тема
Anonymous
 Несогласованные аудиоданные PCM, полученные из одного и того же видео с помощью AudioWorkletNode.

Сообщение Anonymous »

Я пытаюсь записать аудиоданные из видео YouTube с помощью API веб-аудио. Моя цель — сохранить необработанный звук в формате PCM во время воспроизведения видео. Однако я заметил несоответствия в записанных аудиоданных при разных прогонах одного и того же видео. Хотя большая часть аудиоданных остается единообразной, некоторые разделы (например, начало, середина или конец) демонстрируют различия, даже если в воспроизведении видео не вносятся никакие изменения.
Интересно, когда эти аудиофайлы воспроизводятся, ощутимой разницы в ощущениях от прослушивания нет. Однако двоичные данные захваченного аудио различаются в зависимости от запуска, и это вызывает проблемы в моем случае использования, где согласованность необработанных данных имеет решающее значение.
Что я делаю:
Я использую AudioContext, AudioWorkletNode и MediaStreamDestination для захвата звука.
Среда
Браузер: Chrome
Аудио API: веб-аудио API
Формат PCM: Float32, моноканал
Я разработал расширение для браузера с простыми кнопками запуска и остановки записи. Кроме того, запись автоматически останавливается после завершения воспроизведения видео.
content.js

Код: Выделить всё

let audioContext;
let audioWorkletNode;
let audioChunks = [];
let isRecording = false;

chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {

if (message.type === 'start-recording') {
startRecording();
}
if (message.type === 'stop-recording') {
stopRecording();
console.log('Recording stopped.');
}
});

async function startRecording() {
try {
// Select the video element
const videoElement = document.querySelector('video');
audioChunks = [];
monitorVideo(videoElement);
if (!videoElement) {
throw new Error('No video element found!');
}

// Capture the audio stream
const stream = videoElement.captureStream();
if (!stream) {
throw new Error('Failed to capture audio stream!');
}

// Initialize AudioContext
audioContext = new AudioContext();

// Add an AudioWorkletProcessor for audio processing
await audioContext.audioWorklet.addModule(chrome.runtime.getURL('processor.js'));

// Create an AudioWorkletNode
audioWorkletNode = new AudioWorkletNode(audioContext, 'audio-processor');

// Connect the audio stream to the AudioContext
const source = audioContext.createMediaStreamSource(stream);
source.connect(audioWorkletNode).connect(audioContext.destination);

// Collect audio chunks from AudioWorkletProcessor
audioWorkletNode.port.onmessage = (event) => {
if (event.data.type === 'chunk') {
audioChunks.push(event.data.chunk);
}
};

// Start the AudioContext
await audioContext.resume();
isRecording = true;

console.log('Recording started...');
} catch (error) {
console.error('Failed to start recording:', error);
}

function stopRecording() {
if (!isRecording) {
console.warn('No recording in progress.');
return;
}
isRecording = false;

// Stop the audio context
if (audioWorkletNode) {
audioWorkletNode.disconnect();
audioContext.close();
}

if (audioChunks.length > 0) {
savePCMFile(audioChunks);
console.log('Recording stopped and saved');
}

console.log('Recording stopped and file saved.');
}

// Function to save PCM data as a binary file
function savePCMFile(pcmBuffer) {
// Flatten the chunks into one Float32Array
const totalLength = pcmBuffer.reduce((sum, chunk) => sum + chunk.length, 0);
const combinedArray = new Float32Array(totalLength);

let offset = 0;
for (const chunk of pcmBuffer) {
combinedArray.set(chunk, offset);
offset += chunk.length;
}

// Create a Blob from the combined Float32Array
const blob = new Blob([combinedArray.buffer], { type: 'application/octet-stream' });
const url = URL.createObjectURL(blob);

// Trigger download
const a = document.createElement('a');
a.href = url;
a.download = 'audio.pcm';
a.click();
}``
audio-processor.js

Код: Выделить всё

class AudioProcessor extends AudioWorkletProcessor {
constructor() {
super();
this.audioChunks = \[\];
}

process(inputs, outputs, parameters) {
const input = inputs[0]; // Get the first channel's input
if (input && input.length > 0) {
const channelData = input[0]; // First channel's audio data
this.port.postMessage({
type: 'chunk',
chunk: channelData.slice(0), // Copy the audio data
});
}

// Return true to keep processing
return true;
}

}

registerProcessor('audio-processor', AudioProcessor);
За пределами шестнадцатеричного сравнения

Подробнее здесь: https://stackoverflow.com/questions/793 ... orkletnode
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Javascript»