Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

392
Views
reescribiendo código Java a JS - ¿creando un audio a partir de bytes?

Estoy tratando de reescribir un código de Android (muy simple) que encontré escrito en Java en una aplicación HTML5 estática (no necesito un servidor para hacer nada, me gustaría mantenerlo así). Tengo una amplia experiencia en desarrollo web, pero conocimientos básicos de Java e incluso menos conocimiento en desarrollo de Android.

La única función de la aplicación es tomar algunos números y convertirlos en un chirrido de audio de bytes. No tengo ningún problema en traducir la lógica matemática a JS. Donde tengo problemas es cuando se trata de producir el sonido. Estas son las partes relevantes del código original:

 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

¿Cómo hago esto en JS? Puedo usar un dataURI para producir el sonido de los bytes , pero ¿eso me permite controlar la otra información aquí (es decir, frecuencia de muestreo, etc.)? En otras palabras: ¿Cuál es la forma más simple y precisa de hacer esto en JS?

actualizar

He estado tratando de replicar lo que encontré en esta respuesta . Esta es la parte relevante de mi código:

 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); }

Sin embargo, cuando ejecuto esto me sale este error:

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

Lo cual me parece bastante extraordinario, ya que es un error tan general que logra decirme maravillosamente exactamente lo que está mal. Aún más sorprendente, cuando depuré esto paso a paso, aunque la cadena de errores comienza (como era de esperar) con la línea context.decodeAudioData(buffer.buffer, play); en realidad se encuentra con algunas líneas más dentro del archivo jQuery ( 3.2.1, sin comprimir ), pasando por las líneas 5208, 5195, 5191, 5219, 5223 y, por último, 5015 antes de fallar. No tengo idea de por qué jQuery tiene algo que ver con eso, y el error no me da idea de qué probar. ¿Algunas ideas?

about 4 years ago · Santiago Trujillo
2 answers
Answer question

0

Si bytes es un ArrayBuffer , no es necesario crear un Uint8Array . Puede pasar bytes de ArrayBuffer como parámetro a AudioContext.decodeAudioData() que devuelve una Promise , encadenar .then() a .decodeAudioData() , llamar con la función de play como parámetro.

En javascript en stacksnippets, el elemento <input type="file"> se usa para aceptar la carga del archivo de audio, FileReader.prototype.readAsArrayBuffer() crea ArrayBuffer a partir del objeto File , que se pasa a 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])" />

about 4 years ago · Santiago Trujillo Report

0

Lo resolví yo mismo. Leí más en los documentos de MDN que explican AudioBuffer y me di cuenta de dos cosas importantes:

  1. No necesitaba decodificar AudioData (ya que estoy creando los datos yo mismo, no hay nada que decodificar). De hecho, tomé ese fragmento de la respuesta que estaba replicando y, en retrospectiva, fue completamente innecesario.
  2. Como estoy trabajando con un estéreo PCM de 16 bits, eso significaba que necesitaba usar el Float32Array (2 canales, cada uno de 16 bits).

De acuerdo, todavía tenía un problema con algunos de mis cálculos que resultaron en un sonido distorsionado, pero en cuanto a producir el sonido en sí, terminé haciendo esta solución realmente simple:

 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); }

Probablemente pueda optimizarlo un poco más: la parte 32767 debería ocurrir antes de esto, en la parte donde estoy calculando los datos, por ejemplo. Además, estoy creando un Float32Array con dos canales, luego emito uno de ellos porque realmente no necesito ambos. No pude averiguar si hay una manera de crear un archivo mono de canal con Int16Array, o si eso es necesario\mejor.

De todos modos, eso es esencialmente todo. Realmente es solo la solución más básica, con una comprensión mínima de mi parte sobre cómo manejar mis datos correctamente. Espero que esto ayude a alguien por ahí.

about 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!