Article original : How to make realtime SoundCloud Waveforms in React Native
Par Pritish Vaidya
Introduction
SoundCloud est une plateforme de streaming de musique et de podcasts pour écouter des millions de pistes authentiques. Ils ont une interface vraiment interactive pour jouer/écouter les pistes.
La fonctionnalité la plus importante de leur interface est d'afficher la progression de la piste basée sur sa forme d'onde de fréquence. Cela aide les utilisateurs à identifier la nature de celle-ci.
Ils ont également un article de blog qui décrit comment utiliser la forme d'onde basée sur son image. Il est difficile d'utiliser les mêmes techniques pour générer la forme d'onde dans une application React Native. Leur SDK Waveform.js traduit une forme d'onde en points flottants à rendre sur une toile HTML5 et n'est actuellement plus opérationnel.
Dans cet article, nous discuterons de la manière d'utiliser la même forme d'onde pour nos applications React Native.
Pourquoi devrais-je utiliser les formes d'onde de SoundCloud ?
_Crédits image — [KnowYourMeme](https://knowyourmeme.com/photos/1269398-arthurs-headphones" rel="noopener" target="blank" title=")
- La forme d'onde de SoundCloud est plus impressionnante que l'ancienne manière ennuyeuse d'afficher la barre de progression.
- La forme d'onde préchargée donnera à l'utilisateur une idée des différentes fréquences présentes dans la chanson.
- Il est également beaucoup plus facile d'afficher le pourcentage de piste mis en mémoire tampon sur une forme d'onde plutôt que de l'afficher sur une barre de progression vide.
En savoir plus sur les formes d'onde de SoundCloud
_Crédits image — [Backstage Blog par les développeurs de SoundCloud](http://img.svbtle.com/inline_leemartin_24131769094098_raw.png" rel="noopener" target="blank" title=")
SoundCloud fournit une waveform_url dans son API de pistes.
- Chaque piste a sa propre
waveform_urlunique. - La
waveform_urlcontient un lien vers l'image hébergée dans le cloud.
Exemple — https://w1.sndcdn.com/PP3Eb34ToNki_m.png
_Crédits image — [Forme d'onde de SoundCloud pour la piste « Megadeth — Sweating Bullets » par mauriciohaensch](https://w1.sndcdn.com/PP3Eb34ToNki_m.png" rel="noopener" target="blank" title=")
Pour l'instant, tous les arguments sont statiques, donc ils sont inutilisables dans cet état actuel. Par conséquent, nous devons recréer la forme d'onde basée sur celle-ci en utilisant les conteneurs de React Native afin d'avoir accès aux événements tactiles, styles, etc.
Prise en main
_Crédits image — [ImgFlip](https://imgflip.com/memegenerator/4081988/What-if-i-told-you" rel="noopener" target="blank" title=")
Voici une liste de ce dont vous aurez besoin :
Tout d'abord, nous avons besoin de l'échantillonnage de la forme d'onde. L'astuce consiste à remplacer .png par .json pour la waveform_url. Un appel GET à celle-ci nous donnerait un objet de réponse qui contient
- width (Largeur de la forme d'onde)
- height (Hauteur de la forme d'onde)
- samples (Tableau)
Pour plus d'informations, vous pouvez essayer le lien suivant https://w1.sndcdn.com/PP3Eb34ToNki_m.json.
Plongez dans le code
_Crédits image — [Unsplash](https://images.unsplash.com/photo-1466477234737-8a3b3faed8c3?ixlib=rb-0.3.5&s=919a7e046d85dc25ac72f4c3070228b6&auto=format&fit=crop&w=800&q=60" rel="noopener" target="blank" title=")
Ajouter un composant SoundCloudWave personnalisé
function percentPlayed (time, totalDuration) {
return Number(time) / (Number(totalDuration) / 1000)
}
<SoundCloudWave
waveformUrl={waveform_url}
height={50}
width={width}
percentPlayable={percentPlayed(bufferedTime, totalDuration)}
percentPlayed={percentPlayed(currentTime, totalDuration)}
setTime={this.setTime}
/>
Il serait préférable de créer un composant personnalisé SoundCloudWave qui peut être utilisé à plusieurs endroits selon les besoins. Voici les props requis :
- waveformUrl — L'objet URL de la forme d'onde (accessible via l'API des pistes)
- height — Hauteur de la forme d'onde
- width — Largeur du composant de la forme d'onde
- percentPlayable — La durée de la piste mise en mémoire tampon en secondes
- percentPlayed — La durée de la piste jouée en secondes
- setTime — Le gestionnaire de rappel pour changer l'heure actuelle de la piste.
Obtenir les échantillons
fetch(waveformUrl.replace('png', 'json'))
.then(res => res.json())
.then(json => {
this.setState({
waveform: json,
waveformUrl
})
});
Obtenez les échantillons en utilisant un simple appel d'API GET et stockez le résultat dans le state.
Créer un composant Waveform
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 (
<View style={[{
height,
width,
justifyContent: 'center',
flexDirection: 'row',
},
inverse && {
transform: [
{ rotateX: '180deg' },
{ rotateY: '0deg'},
]
}
]}>
{chunks.map((chunk, i) => (
<TouchableOpacity key={i} onPress={() => {
setTime(i)
}}>
<View style={{
backgroundColor: getColor
(
chunks,
i,
percentPlayed,
percentPlayable,
inverse
),
width: 2,
marginRight: 1,
height: scaleLinearHeight(mean(chunk))
}}
/>
</TouchableOpacity>
))}
</View>
)
}
Le composant Waveform fonctionne comme suit :
- Les Chunks divisent l'objet
samplesen fonction de lawidthque l'utilisateur souhaite rendre à l'écran. - Les Chunks sont ensuite mappés dans un événement
Touchable. Les styles sontwidth:2etheight: scaleLinearHeight(mean(chunk)). Cela génère lamoyenneà partir ded3-array. - La
backgroundColorest passée en tant que méthode avec différents paramètres à la méthodegetColor. Cela déterminera ensuite la couleur à retourner en fonction des conditions définies. - L'événement
Touchable onPressappellera le gestionnaire personnalisé passé dans celui-ci, pour définir le nouveau temps de recherche de la piste.
Ce composant sans état peut maintenant être rendu dans votre composant enfant comme suit :
render() {
const {height, width} = this.props
const { waveform } = this.state
if (!waveform) return null;
return (
<View style={{flex: 1, justifyContent: 'center'}}>
<Waveform
waveform={waveform}
height={height}
width={width}
setTime={this.setTime}
percentPlayed={this.props.percent}
percentPlayable={this.props.percentPlayable}
inverse
/>
<Waveform
waveform={waveform}
height={height}
width={width}
setTime={this.setTime}
percentPlayed={this.props.percent}
percentPlayable={this.props.percentPlayable}
inverse={false}
/>
</View>
)
}
Ici, l'un des composants de forme d'onde est original et l'autre est inversé comme dans le lecteur de SoundCloud.
Conclusion
Voici les liens vers react-native-soundcloud-waveform
J'ai également créé une application en react-native — MetalCloud pour les fans de musique Metal où vous pouvez voir le composant ci-dessus en action.
Voici les liens :
Merci d'avoir lu. Si vous avez aimé cet article, montrez votre soutien en applaudissant pour partager avec d'autres personnes sur Medium.
D'autres choses intéressantes peuvent être trouvées sur mes profils StackOverflow et GitHub.
Suivez-moi sur LinkedIn, Medium, Twitter pour des mises à jour sur les nouveaux articles.