Intereting Posts
Как непрерывно запускать эффект тени через тексты в виде андроидного текста? Родовой сбой в /system/lib/libart.so Заменить селекторные изображения программно Как программно прокручивать ScrollView до нижнего уровня Не удалось найти класс XXX, ссылающийся на метод XXX. <YYY> Android – поставщик файлов – отказ в разрешении Скрыть полосу прокрутки по горизонталиScrollView Android: основной проигрыватель с закрытыми субтитрами Отображение изображений из определенной папки на SD-карте с использованием gridview Где разместить BroadcastReceiver в Android MVP? Что такое префикс «андроид:» в модуле android framework-res Пользовательский ListView для Android не может нажимать на элементы Пользовательский EditText не работает после установки его типа ввода через setInputType () Иногда listView.getChildAt (int index) возвращает NULL (Android) Как использовать холст андроида, чтобы нарисовать прямоугольник с только тупиковыми и вертикальными углами вокруг?

Переписывание Java-кода в JS – создание звука из байтов?

Я пытаюсь переписать некоторый (очень простой) код Android, который я нашел написанным на Java, в статическое приложение HTML5 (мне не нужен сервер, чтобы что-то делать, я хотел бы сохранить его таким образом). У меня есть обширный опыт в области веб-разработки, но базовое понимание Java и даже меньше знаний в области разработки Android.

Единственная функция приложения – взять некоторые цифры и преобразовать их в звуковой чирп из байтов. У меня нет абсолютно никакой проблемы перевода математической логики в JS. Там, где у меня возникают проблемы, возникает вопрос, когда на самом деле получается звук. Это соответствующие части исходного кода:

import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTrack; // later in the code: AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, minBufferSize, AudioTrack.MODE_STATIC); // some math, and then: track.write(sound, 0, sound.length); // sound is an array of bytes 

Как это сделать в JS? Я могу использовать dataURI для создания звука из байтов , но позволяет ли я управлять другой информацией здесь (например, частотой дискретизации и т. Д.)? Другими словами: что является самым простым и точным способом сделать это в JS?

Обновить

Я пытаюсь воспроизвести то, что я нашел в этом ответе . Это важная часть моего кода:

 window.onload = init; var context; // Audio context var buf; // Audio buffer function init() { if (!window.AudioContext) { if (!window.webkitAudioContext) { alert("Your browser does not support any AudioContext and cannot play back this audio."); return; } window.AudioContext = window.webkitAudioContext; } context = new AudioContext(); } function playByteArray( bytes ) { var buffer = new Uint8Array( bytes.length ); buffer.set( new Uint8Array(bytes), 0 ); context.decodeAudioData(buffer.buffer, play); } function play( audioBuffer ) { var source = context.createBufferSource(); source.buffer = audioBuffer; source.connect( context.destination ); source.start(0); } 

Однако, когда я запускаю это, я получаю эту ошибку:

 Uncaught (in promise) DOMException: Unable to decode audio data 

Который я нахожу довольно экстраординарным, так как это такая общая ошибка, что ему удается красиво сказать, что я точно приседаю о том, что не так. Еще более удивительно, когда я отлаживал это шаг за шагом, хотя цепочка ошибок запускается (предположительно) с помощью строки context.decodeAudioData(buffer.buffer, play); Он фактически пробегает еще несколько строк в файле jQuery ( 3.2.1, несжатый ), проходя через строки 5208, 5195, 5191, 5219, 5223 и, наконец, 5015 перед ошибкой. Я не знаю, почему jQuery имеет к этому какое-то отношение, и ошибка не дает мне понять, что попробовать. Есть идеи?

Solutions Collecting From Web of "Переписывание Java-кода в JS – создание звука из байтов?"

Если bytes являются ArrayBuffer нет необходимости создавать Uint8Array . Вы можете передать bytes ArrayBuffer как параметр в AudioContext.decodeAudioData() который возвращает Promise , цепочку .then() в .decodeAudioData() , вызов с функцией play качестве параметра.

В javascript в stacksnippets элемент <input type="file"> используется для приема загрузки аудиофайла, FileReader.prototype.readAsArrayBuffer() создает ArrayBuffer из объекта File , который передается в playByteArray .

 window.onload = init; var context; // Audio context var buf; // Audio buffer var reader = new FileReader(); // to create `ArrayBuffer` from `File` function init() { if (!window.AudioContext) { if (!window.webkitAudioContext) { alert("Your browser does not support any AudioContext and cannot play back this audio."); return; } window.AudioContext = window.webkitAudioContext; } context = new AudioContext(); } function handleFile(file) { console.log(file); reader.onload = function() { console.log(reader.result instanceof ArrayBuffer); playByteArray(reader.result); // pass `ArrayBuffer` to `playByteArray` } reader.readAsArrayBuffer(file); }; function playByteArray(bytes) { context.decodeAudioData(bytes) .then(play) .catch(function(err) { console.error(err); }); } function play(audioBuffer) { var source = context.createBufferSource(); source.buffer = audioBuffer; source.connect(context.destination); source.start(0); } 
 <input type="file" accepts="audio/*" onchange="handleFile(this.files[0])" /> 

Я решил это сам. Я больше читал в документах MDN, объясняющих AudioBuffer, и реализовал две важные вещи:

  1. Мне не нужно было decodeAudioData (поскольку я сам создаю данные, нет ничего, чтобы расшифровать). Я на самом деле взял этот бит из ответа, который я воспроизводил, и это ретроспектива, это было совершенно бесполезно.
  2. Поскольку я работаю с 16-битным PCM-стерео, это означает, что мне нужно использовать Float32Array (2 канала, каждый 16 бит).

Конечно, у меня все еще была проблема с некоторыми моими вычислениями, которые приводили к искаженному звуку, но что касается создания самого звука, я в конечном итоге сделал это очень простое решение:

 function playBytes(bytes) { var floats = new Float32Array(bytes.length); bytes.forEach(function( sample, i ) { floats[i] = sample / 32767; }); var buffer = context.createBuffer(1, floats.length, 48000), source = context.createBufferSource(); buffer.getChannelData(0).set(floats); source.buffer = buffer; source.connect(context.destination); source.start(0); } 

Возможно, я оптимизирую его немного дальше – часть 32767 должна произойти до этого, в той части, где я вычисляю данные, например. Кроме того, я создаю Float32Array с двумя каналами, а затем выводя один из них, потому что мне действительно не нужны оба. Я не мог понять, есть ли способ создать одноканальный моно файл с Int16Array, или если это даже необходимо \ лучше.

Во всяком случае, это по существу это. Это действительно просто базовое решение, с минимальным пониманием в моей части того, как правильно обрабатывать мои данные. Надеюсь, это поможет кому угодно.