Я использую wavesurfer.js для создания многодорожечного плеера в Интернете и хочу экспортировать ремиксную версию комбинированных треков с панорамированием уровней и т. Д.
Сначала у меня есть массив audioFiles, и я использую его для создания массива элементов waveurfer.
for(var i=0; i<audiofiles.length; i++){
spectrum[i] = WaveSurfer.create({
});
}
Затем я создаю буфер для каждого из них из backend-а.
for(var i=0; i<audiofiles.length; i++){
var ctx = spectrum[i].backend.ac;
var length = spectrum[i].getDuration() * sample_rate * 2;
var ctx_buffer = ctx.createBuffer(2, length, ctx.sampleRate);
// pass raw pcm buffer to download function
}
И, наконец, я получил некоторую помощь с функцией загрузки здесь Загрузка аудио из Интернета, который был изменен с помощью wavesurfer.js
Моя проблема на данный момент в том, что то, что я передаю функции загрузки, похоже, имеет неправильный формат. Я новичок в работе со звуком и не уверен, что делаю.
Если я передаю переменную ctx_buffer функции в другом вопросе (и использую ее вместо переменной буфера, полученной непосредственно из файла pcm), я получу успешную загрузку, но файл пуст, хотя это правильная длина (если не указывать * 2 в приведенной выше длине, будет пустой файл, равный половине длины моего оригинала).
Здесь есть функция exportPCM () в wavesurfer.js https://wavesurfer-js.org/docs/methods.html но я тоже не знаю, как это работает.
buttons.save_all.addEventListener("click", function(){
document.getElementById("download_icon").className = "fas fa-spinner loader";
document.getElementById("download_text").innerText = "Loading...";
for (let i=0; i<audiofiles.length; i++) {
const track = spectrum[i];
const sampleRate = track.backend.ac.sampleRate;
const audioBuffer = track.backend.buffer;
const interleavedSamples = getInterleavedStereo(audioBuffer);
const file_name = `track-${i+1}.wav`; download_init(interleavedSamples.buffer, sampleRate, file_name); } console.log(blobs); }, false); function showError(e) { console.log(`ERROR: ${e}`);
}
var x = 0;
function download_init(ctx_buffer, sample_rate, file_name) {
const wavBytes = getWavBytes(ctx_buffer, {
numChannels: 2,
sampleRate: sample_rate,
isFloat: true
});
blobs[x] = URL.createObjectURL(
new Blob([wavBytes], { type: 'audio/wav' })
)
buttons.download.href = blobs[0];
buttons.download.setAttribute('download', file_name);
buttons.save_all.hidden = true;
buttons.download.hidden = false;
x++;
}
function getInterleavedStereo(audioBuffer) {
if (audioBuffer.numberOfChannels !== 2) {
throw Error('source audio is not stereo');
}
const [left, right] = [audioBuffer.getChannelData(0), audioBuffer.getChannelData(1)];
const interleaved = new Float32Array(left.length + right.length);
for (let src=0, dst=0; src < left.length; src++, dst+=2) {
interleaved[dst] = left[src];
interleaved[dst+1] = right[src];
}
return interleaved;
}
function getWavBytes(buffer, options) {
const type = options.isFloat ? Float32Array : Uint16Array;
const numFrames = buffer.byteLength / type.BYTES_PER_ELEMENT;
const headerBytes = getWavHeader(Object.assign({}, options, { numFrames }));
const wavBytes = new Uint8Array(headerBytes.length + buffer.byteLength);
wavBytes.set(headerBytes, 0);
wavBytes.set(new Uint8Array(buffer), headerBytes.length);
return wavBytes;
}
function getWavHeader(options) {
const numFrames = options.numFrames;
const numChannels = options.numChannels || 2;
const sampleRate = options.sampleRate || 44100;
const bytesPerSample = options.isFloat? 4 : 2;
const format = options.isFloat? 3 : 1;
const blockAlign = numChannels * bytesPerSample;
const byteRate = sampleRate * blockAlign;
const dataSize = numFrames * blockAlign;
const buffer = new ArrayBuffer(44);
const dv = new DataView(buffer);
let p = 0;
function writeString(s) {
for (let i=0; i<s.length; i++) {
dv.setUint8(p + i, s.charCodeAt(i));
}
p += s.length;
}
function writeUint32(d) {
dv.setUint32(p, d, true);
p += 4;
}
function writeUint16(d) {
dv.setUint16(p, d, true);
p += 2;
}
writeString('RIFF'); // ChunkID
writeUint32(dataSize + 36); // ChunkSize
writeString('WAVE'); // Format
writeString('fmt '); // Subchunk1ID
writeUint32(16); // Subchunk1Size
writeUint16(format); // AudioFormat
writeUint16(numChannels); // NumChannels
writeUint32(sampleRate); // SampleRate
writeUint32(byteRate); // ByteRate
writeUint16(blockAlign); // BlockAlign
writeUint16(bytesPerSample * 8); // BitsPerSample
writeString('data'); // Subchunk2ID
writeUint32(dataSize); // Subchunk2Size
return new Uint8Array(buffer);
}
Учитывая, что в настоящее время у вас есть массив AudioBufferобъектов, вы можете чередовать данные PCM Float32Array, содержащиеся в каждом AudioBuffer, а затем использовать этот чередующийся PCM для создания файла RIFF / Wav для загрузки. Если каждый из них AudioBufferявляется дорожкой, тогда все левый / правый каналы в массиве должны быть объединены отдельно и в конце перемежены. Вот как начать с одного AudioBufferтрека:
Преобразование AudioBuffer в ArrayBuffer / Blob для загрузки WAV
Яна Дуггар открыто говорила о своих поисках любви. Вот все, что она сказала на эту тему и о своем пятилетнем окне для замужества.
Звезда «Чужестранки» Сэм Хьюэн недавно рассказал, что он возьмет со съемочной площадки, чтобы вспомнить Джейми Фрейзера, роль, которая сделала его звездой.
«She Loves You» была написана за час, записана за день и стала песней The Beatles с одним из лучших исполнений в их карьере.
У Долли Партон и ее бабушки Бесси были особые отношения. Бабушка Партон была очень больна, но это не мешало Долли разыгрывать ее.
Вы можете подумать, что дуб или гикори — прочные породы дерева, но когда речь идет о самой твердой древесине в мире, они даже близко не стоят.
Океан полон красоты, но он также скрывает одних из самых страшных морских существ на планете. Многие из этих животных скрываются глубоко под поверхностью океана, в тёмном, полном давления мире морских глубин.
Если вы сражаетесь с враждебными мобами или готовитесь к PvP-боям, знание лучших чар для мечей в Minecraft может дать вам серьёзное преимущество. Зачарование мечей позволяет наносить больше урона, увеличивать количество выпадающих мобов и продлевать срок службы меча.
Когда говорят о социалистических странах, часто представляют себе полный государственный контроль и отсутствие частной собственности. Но на практике социалистические экономики сильно различаются.
В «Детях» появится громкая камео и несколько разрушительных новостей
Утверждается, что этот RAV4 находится в отличном состоянии и готов к игре в музыкальные стулья.
На кадрах, снятых с дрона, видно, как пожарные изо всех сил пытаются потушить пламя.
«Глаза Ваканды» напрямую связаны с MCU, а также обновления о «Людях Икс '97», «Что, если...», «Сорвиголова» и многом другом.
Ава Гарднер была замужем за Микки Руни и Фрэнком Синтрой, и встречалась с несколькими другими голливудскими звездами. Вот взгляд назад на историю знакомств Авы Гарднер.
Джон Клиз женился на Дженнифер Уэйд в 2012 году. Вот все, что нужно знать о жене Джона Клиза, Дженнифер Уэйд.
Олимпийская чемпионка Эллисон Феликс вышла замуж за своего мужа Кеннета Фергюсона в 2018 году. Вот все, что нужно знать о муже Эллисон Феликс, Кеннете Фергюсоне.
Мена Сувари замужем за своим мужем Майклом Хоупом с 2018 года. Вот все, что нужно знать о муже Мены Сувари.
Это поражает меня Внезапно, как это часто бывает, Это снова и снова на полпути <Нет, не то, что в Тихом океане, ты темно-бордовый, то, что на карнавале> Каждый громкий заголовок…..
В 2022 году, с выпуском GPT-3, навыки письма, кажется, стали менее важными. С помощью ИИ люди с плохим письмом также могут генерировать качественный персонал.
В современном быстро меняющемся и конкурентном мире карьера играет важную роль в личностном росте, финансовой стабильности и общей удовлетворенности жизнью. Однако многие люди оказываются в безжалостном цикле застоя и неудовлетворенности, постепенно угасая в своей профессиональной жизни.
На прошлой неделе я заметил пресс-релиз, разосланный через PressGazette (новостной веб-сайт британских СМИ). В статье сообщалось, что Acast, скандинавская компания по размещению и рекламе подкастов, возглавит консорциум «вероятно, самых влиятельных» издателей подкастинга.