Cómo crear formas de onda de SoundCloud en tiempo real en React Native

Introducción

SoundCloud es una plataforma de transmisión de música y podcasts para escuchar millones de pistas auténticas. Tienen una interfaz realmente interactiva para reproducir / escuchar las pistas.

La característica más importante de su interfaz es mostrar el progreso de la pista en función de su forma de onda de frecuencia. Esto ayuda a los usuarios a identificar la naturaleza del mismo.

También tienen una publicación de blog que describe cómo usar la forma de onda en función de su imagen. Es difícil usar las mismas técnicas para generar la forma de onda en una aplicación React Native . Su SDK Waveform.js traduce una forma de onda en puntos flotantes para representarla en un lienzo HTML5 y actualmente ya no está operativo.

En este artículo discutiremos cómo usar la misma forma de onda para nuestras aplicaciones React Native.

¿Por qué debería utilizar las formas de onda de SoundCloud?

  • La forma de onda de SoundCloud se ve más impresionante que la antigua y aburrida forma de mostrar la barra de progreso.
  • La forma de onda precargada le dará al usuario una idea de las diferentes frecuencias presentes en la canción.
  • También es mucho más fácil mostrar el porcentaje de pista almacenada en búfer en una forma de onda en lugar de mostrarlo en una barra de progreso en blanco.

Aprendamos más sobre las formas de onda de SoundCloud

SoundCloud proporciona una waveform_urlAPI en sus pistas.

  • Cada pista tiene su propia singularidad waveform_url.
  • El waveform_urlcontiene un enlace a la imagen izada sobre la nube.

Ejemplo: //w1.sndcdn.com/PP3Eb34ToNki_m.png

A partir de ahora, todos los argumentos son estáticos, por lo que no se pueden utilizar en este estado actual. Por lo tanto, necesitamos volver a crear la forma de onda basada en ella utilizando los contenedores de React Native para tener acceso a los eventos táctiles, estilos, etc.

Empezando

Aquí hay una lista de cosas que necesitará:

  • escala d3
  • matriz d3

Primero, necesitamos el muestreo de la forma de onda. El truco consiste en reemplazar .pngcon .jsonel waveform_url. Una GETllamada nos daría un objeto de respuesta que contiene

  • ancho (ancho de la forma de onda)
  • altura (altura de la forma de onda)
  • muestras (matriz)

Para obtener más información, puede probar el siguiente enlace //w1.sndcdn.com/PP3Eb34ToNki_m.json.

Sumérgete en el código

Agregar un componente SoundCloudWave personalizado

function percentPlayed (time, totalDuration) { return Number(time) / (Number(totalDuration) / 1000)}

Sería mejor crear un componente SoundCloudWave personalizado que se pueda usar en varios lugares según sea necesario. Aquí están los requeridos props:

  • waveformUrl : el objeto URL de la forma de onda (accesible a través de la API de pistas)
  • height : altura de la forma de onda
  • width : ancho del componente de forma de onda
  • percentPlayable : la duración de la pista almacenada en búfer en segundos
  • percentPlayed : la duración de la pista reproducida en segundos
  • setTime: el controlador de devolución de llamada para cambiar el tiempo actual de la pista.

Obtener las muestras

fetch(waveformUrl.replace('png', 'json')) .then(res => res.json()) .then(json => { this.setState({ waveform: json, waveformUrl }) });

Obtenga las muestras mediante una simple GETllamada a la API y almacene el resultado en el archivo state.

Crear un componente de forma de onda

import { mean } from 'd3-array';
const ACTIVE = '#FF1844', INACTIVE = '#424056', ACTIVE_PLAYABLE = '#1b1b26'
const ACTIVE_INVERSE = '#4F1224', ACTIVE_PLAYABLE_INVERSE = '#131116', INACTIVE_INVERSE = '#1C1A27'
function getColor( bars, bar, percentPlayed, percentPlayable, inverse) { if(bar/bars.length < percentPlayed) { return inverse ? ACTIVE : ACTIVE_INVERSE } else if(bar/bars.length < percentPlayable) { return inverse ? ACTIVE_PLAYABLE : ACTIVE_PLAYABLE_INVERSE } else { return inverse ? INACTIVE : INACTIVE_INVERSE }}
const Waveform = ( { waveform, height, width, setTime, percentPlayed, percentPlayable, inverse } ) => { const scaleLinearHeight = scaleLinear().domain([0, waveform.height]).range([0, height]); const chunks = _.chunk(waveform.samples, waveform.width/((width - 60)/3)) return (  {chunks.map((chunk, i) => (  { setTime(i) }}>   ))}  ) }

El componente de forma de onda funciona de la siguiente manera:

  • Los fragmentos dividen el samplesobjeto en función de lo widthque el usuario desea representar en la pantalla.
  • Luego, los fragmentos se asignan a un Touchableevento. Los estilos como width:2y height: scaleLinearHeight(mean(chunk)). Esto genera el meandesde el d3-array.
  • The backgroundColor is being passed as a method with different parameters to the getColor method. This will then determine the color to return based on the conditions set.
  • The Touchable onPress event will call the custom handler passed into it, to set the new seek time of the track.

Now this stateless component can be rendered to your child component as:

render() { const {height, width} = this.props const { waveform } = this.state if (!waveform) return null; return (     )}

Here one of the waveform component is original and one inverted as in the SoundCloud’s player.

Conclusion

Here are the links to the react-native-soundcloud-waveform

  • Github
  • npm

I’ve also made an app in react-native — MetalCloud for Metal Music fans where you can see the above component at work.

Here are the links:

  • IOS
  • Android

Thanks for reading. If you liked this article, show your support by clapping to share with other people on Medium.

More of the cool stuff can be found on my StackOverflow and GitHub profiles.

Follow me on LinkedIn, Medium, Twitter for further update new articles.