Задача
Javascript-созданный WAV-файл некорректной длины и беззвучный.Веб-аудио API - созданный JAVA файл неверной длины и беззвучный
Детали
Я использую JavaScript Web Audio API для создания веб-приложение, которое может принимать несколько звуковых файлов, захватить случайный кусок каждого из них, а затем «смешивать» их вместе в пробоотборник (серийно , т. е. file1 + file2 + ... + fileN), вроде рода mashup. Звуки могут быть успешно загружены в мой пользовательский объект SoundPlayer, и они могут быть воспроизведены. Однако, когда вы идете, чтобы их смешивать вместе, полученный WAV-файл имеет неправильную длину и полностью отключается.
Интерфейс позволяет до 10 звуков загружаться и воспроизводиться на их собственном томе. Вы нажимаете кнопку, чтобы сделать сэмплером WAV их вместе, и он динамически создает ссылку для ее загрузки. У меня также есть способ увидеть шестнадцатеричный дамп результирующего файла, и он показывает кучу 00s и даже некоторые NaN в нижней части, поэтому, очевидно, мой алгоритм испорчен, но я просто не могу понять, как это сделать.
Когда вы нажимаете «Сделать пробник!» Кнопка, она выполняет следующую функцию (с массивом пользовательских объектов SoundPlayer, которые содержат аудио буферов, в качестве аргумента):
function createSampler(sndArr) {
var numberOfChannels = _getSoundChannelsMin(sndArr);
var sndLengthSum = (function() {
var lng = 0;
for (var i = 0; i < sndArr.length; i++) {
lng += sndArr[i].audioBuffer.length;
}
return lng;
})();
var samplerBuffer = getAudioContext().createBuffer(
numberOfChannels,
sndLengthSum,
sndArr[0].audioBuffer.sampleRate
);
for (var i = 0; i < numberOfChannels; i++) {
var channel = samplerBuffer.getChannelData(i);
channel.set(sndArr[0].audioBuffer.getChannelData(i), 0);
for (var j = 1; j < sndArr.length; j++) {
channel.set(sndArr[j].audioBuffer.getChannelData(i), sndArr[j-1].audioBuffer.length);
}
}
// encode our newly made audio blob into a wav file
var dataView = _encodeWavFile(samplerBuffer, samplerBuffer.sampleRate);
var audioBlob = new Blob([dataView], { type : 'audio/wav' });
// post new wav file to download link
_enableDownload(audioBlob);
}
Количество каналов (. моно/стерео/и т.д.) приобретается с помощью этой функции :
function _getSoundChannelsMin(sndArr) {
var sndChannelsArr = [];
sndArr.forEach(function(snd) {
sndChannelsArr.push(snd.audioBuffer.numberOfChannels);
});
return Math.min.apply(Math, sndChannelsArr);
}
WAV кодируется с помощью этой функции:
function _encodeWavFile(samples, sampleRate) {
var buffer = new ArrayBuffer(44 + samples.length * 2);
var view = new DataView(buffer);
// RIFF identifier
_writeString(view, 0, 'RIFF');
// file length
view.setUint32(4, 36 + samples.length * 2, true);
// RIFF type
_writeString(view, 8, 'WAVE');
// format chunk identifier
_writeString(view, 12, 'fmt ');
// format chunk length
view.setUint32(16, 16, true);
// sample format (raw)
view.setUint16(20, 1, true);
// stereo (2 channels)
view.setUint16(22, 2, true);
// sample rate
view.setUint32(24, sampleRate, true);
// byte rate (sample rate * block align)
view.setUint32(28, sampleRate * 4, true);
// block align (channels * bytes/sample)
view.setUint16(32, 4, true);
// bits/sample
view.setUint16(34, 16, true);
// data chunk identifier
_writeString(view, 36, 'data');
// data chunk length
view.setUint32(40, samples.length * 2, true);
// write the PCM samples
_writePCMSamples(view, 44, samples);
return view;
}
Строки в файле WAV обрабатываются с этим:
function _writeString(view, offset, string) {
for (var i = 0; i < string.length; i++){
view.setUint8(offset + i, string.charCodeAt(i));
}
}
образцы PCM передаются с этим:
function _writePCMSamples(output, offset, input) {
for (var i = 0; i < input.length; i++, offset+=2){
var s = Math.max(-1, Math.min(1, input[i]));
output.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);
}
}
Наконец, файл WAV превращается в связь с этим:
function _enableDownload(blob, givenFilename) {
var url = (window.URL || window.webkitURL).createObjectURL(blob);
var link = document.getElementById("linkDownloadSampler");
var d = new Date();
var defaultFilename = "sampler" + d.curDateTime() + ".wav";
link.style.display = "inline";
link.href = url;
link.download = givenFilename || defaultFilename;
}
Вот отрывок из шестнадцатеричного дампа я получаю:
52 49 46 46 FFFD FFFD 02 00 57 41 56 45 66 6D 74 20 RIFF....WAVEfmt
10 00 00 00 01 00 02 00 FFFD FFFD 00 00 00 FFFD 02 00 ................
04 00 10 00 64 61 74 61 FFFD FFFD 02 00 00 00 00 00 ....data........
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Если кто-нибудь может помочь мне увидеть ошибку в моих путях, я был бы признателен. Извините за длинный пост, но я хотел опубликовать все соответствующие данные и код вперед.
Спасибо!
Я обновил свой код и удалил прокомментированные '_writePCMSamples', поскольку я забыл, что добавил это позже. Кроме того, я уже обновляю 'offset' в функции' _writePCMSamples': это после 'i ++'. Несмотря на это, я попытался удалить это и добавить вашу идею, но я получаю тот же результат. – mjchadwick