9
votes

Comment puis-je générer des données aléatoires simulant un signal audio?

Je travaille sur un logo animé qui sera révélé par un analyseur de spectre allant de zéro à onze. Je cherche quelque chose qui fonctionnera sur une large variété de navigateurs afin de le câbler jusqu'à un HTML5-AUDIO ELEMENT n'est probablement pas une option que les seules bibliothèques que j'ai trouvées pouvant effectuer ce travail sur uniquement les dernières versions WebKit et Firefox. Jusqu'à présent, je joue avec juste générer une valeur aléatoire à un intervalle. Voici un exemple de l'endroit où je suis toujours bloqué (à l'aide de la fonction Animate de JQuery ()):

<div id='Logo'>
    <div id='channelA' class='channel'></div>
    <div id='channelB' class='channel'></div>
    <div id='channelC' class='channel'></div>
    <div id='channelD' class='channel'></div>
    <div id='channelE' class='channel'></div>
    <div id='channelF' class='channel'></div>
    <div id='channelG' class='channel'></div>
</div>
<script>
  setInterval(function () {
    $('.channel').each(function () {
        $(this).animate({
            height: (Math.round(Math.random() * 185)) + 'px'
        });
    });
  }, 100);
</script>
<style>
#Logo {
    width: 245px;
    height: 245px;
    background: red;
}
div.channel {
    float: left;
    z-index: 9;
    background: white;
}
#channelA {
    width: 35px;
    height: 45px;
}
#channelB {
    width: 35px;
    height: 85px;
}
#channelC {
    width: 35px;
    height: 85px;
}
#channelD {
    width: 35px;
    height: 50px;
}
#channelE {
    width: 35px;
    height: 150px;
}
#channelF {
    width: 35px;
    height: 30px;
}
#channelG {
    width: 35px;
    height: 85px;
}
</style>


6 commentaires

Je ne sais pas ce qu'est un signal audio est censé "se sentir", mais je suis sûr que ce n'est pas la même chose que le bruit aléatoire. Peut-être devriez-vous définir la valeur de chaque barre, indiquant une valeur aléatoire dans plus ou moins deux de la valeur de la barre précédente?


Peut-être que j'ai besoin de combiner quelques signaux, bruit aléatoire pour "flotter" et une courbe pour l'effet "Tourner".


Je travaille sur la mise en œuvre d'une courbe de Bézier. Voici mes progrès jusqu'à présent: Jsfiddle.net/w9qaf/5


Vous voulez probablement une forme similaire à y = 1 / (1 + x ^ 2) .


@JasonsPerske Avez-vous envisagé d'utiliser des données à partir d'un fichier audio audio-logiciel réel? Cette question est intéressante, mais à des fins pratiques, c'est probablement ce que je ferais.


@Benjamingruenbaum j'aime cette approche


4 Réponses :


3
votes

Je pense que je suis plus proche (mais j'ai beaucoup fait si je pensais que la réponse à ma propre question était la meilleure approche, je suis toujours ouvert à de meilleures réponses, ou à des commentaires (ha) sur des problèmes. avec cette approche). Voici le code (compliqué) que j'ai mis en œuvre jusqu'à présent ( Demo ).

Utilisation d'un La version nettoyée du HTML et CSS Voici le JavaScript: P>

var amp = 0,
    flutter_range = 10,
    channels = $('.channel'),
    turnItUp = setInterval(function () {
        amp += 0.01;
    }, 50),
    flutter = setInterval(function () {
        var levels = bezier([[0.3], [0.95], [1], [0]]),
            channel;
        for(channel = 0; channel < channels.length; channel++) {
            $(channels[channel]).animate({
                height: 245-(Math.round(((Math.random() * (flutter_range*2))-flutter_range)+(levels(channel/channels.length)*amp)*245))+'px'
            }, 50);
        }
    }, 100),
    //from: https://gist.github.com/atomizer/1049745
    bezier = function (pts) {
        return function (t) {
            for (var a = pts; a.length > 1; a = b) // do..while loop in disguise
                for (var i = 0, b = [], j; i < a.length - 1; i++) // cycle over control points
                    for (b[i] = [], j = 0; j < a[i].length; j++) // cycle over dimensions
                        b[i][j] = a[i][j] * (1 - t) + a[i + 1][j] * t; // interpolation
            return a[0];
        }
    };

setTimeout(function () {
    window.clearInterval(turnItUp);
}, 5000);


1 commentaires

Voici la même approche, mais avec des CSS supplémentaires pour le rendre meilleur: Jsfiddle.net/w9qaf / 8 / Embedded / Résultat



2
votes

Je pense que la meilleure façon de rendre l'animation est réelle consiste à utiliser des données réelles et à calculer les valeurs réelles pour les barres. Faire l'animation sur les données réelles rendra les barres monter et descendre de manière réaliste, il peut être difficile d'imiter ce comportement sans faire le traitement.

Quelles sont les barres d'égaliseur vous dire est quelle est l'amplitude des différentes gammes de fréquences. Vous pouvez calculer ces barres à partir d'un fichier audio réel à l'aide d'une fonction appelée FFT (Fast Fourier Transform).

Il existe des implémentations de FFT pour presque toutes les langues, même pour JavaScript. L'algorithme fonctionnera comme suit:

  • Décidez d'un taux de trame à rafraîchir.
  • Chargez 1 / FPS d'une deuxième valeur d'échantillons de votre fichier audio dans un tampon de mémoire (non compressé, s'il s'agit de .mp3 le convertit en premier)
  • Envoyez le tampon à la fonction FFT. Vous obtiendrez un autre tampon avec un tableau de valeurs en retour.
  • Décidez le nombre de barres que vous souhaitez montrer et trouver une partie du tampon FFT qui possède de nombreux échantillons avec des données intéressantes. Vous pouvez également condenser la matrice FFT de sortie en la moyenne de plusieurs valeurs consécutives.
  • Chaque valeur dans le tableau (ou groupe moyen) vous donne la hauteur d'une barre.
  • qui vous donnera une image de votre animation. Prenez le prochain 1 / FPS d'une seconde de l'audio et répétez l'ensemble du processus pour obtenir le cadre suivant.

    Le FFT est assez intensif CPU afin que vous souhaitiez calculer les barres pour suffisamment de cadres, puis utilisez les valeurs calculées de votre script.

    Si vous voulez qu'un exemple vous achète, consultez cette démo: Fast Fourier transforme avec Audiolib.js .

    Cette démo génère une forme d'onde synthétique, la joue sur votre navigateur (non nécessaire pour vous) et dessine un égaliseur en temps réel dans un objet en toile. L'exemple sur cette page ne fonctionne pas pour moi pour une raison quelconque pour une raison quelconque, j'ai donc téléchargé le GIST code source et l'a installé sur mon ordinateur pour le faire fonctionner.


1 commentaires

Je vais profiter de creuser à ces liens :)



1
votes

J'ai fait un peu de jouant avec des volumes, des retards et des courbes. Voici mon jsfiddle y prends . Vient assez proche de cela, je pense :-) Mais définitivement améliorable (il y a un léger problème avec le canal le plus à droite).

[EDIT:] OK, je me suis amélioré un peu plus. Voici une autre jsfiddle P>

Comme vous pouvez le constater, vous n'avez pas nécessairement besoin d'une courbe de Bézier Mise en œuvre pour obtenir le travail de courbe. P>

$('.channel').each(function () {
    animate($(this));
});

var beat = 200;
var volume = 1;
setInterval(function() {
    beat = 60 + Math.random()*100;
    volume = Math.min(1,Math.max(0.1,volume + Math.random()-0.5));
}, 200);

function animate($channel) {
    var curving = Math.max(1, 30*Math.abs($channel.prevAll().length - 3));

    curving = curving + 100*volume;

    var height = Math.max(1,Math.min(curving, 240) + (Math.random()*50-25));

    $channel.animate({
        height: Math.round(height) + 'px',
    }, {
        duration: beat,
        complete: function() { animate($channel); }
    });
}


0 commentaires

8
votes

La clé pour faire un spectre d'aspect réaliste (données virtuelles ou non) est d'avoir un mécanisme de repli pour la barre de bande.

Une bande n'est définie que si la nouvelle valeur est supérieure à celle du courant. Sinon, la valeur actuelle est diminuée par une valeur (linéaire ou logarithmique). La vitesse de la tombe influence également la perception.

Comme les données d'un analyseur de spectre ne représentent pas la forme wave mais la transformation FFT (Fast-Fourier Transformer), ou Valeur de chaque bande de fréquences, elle peut fonctionner correctement avec des données aléatoires. Vous n'allez pas obtenir l'empreinte "rythmique" comme pour la musique, mais en raison de la relevée, il ressemblera toujours à un certain degré (comme si quelqu'un voulait écouter le bruit qui est :-)).

Un exemple suit -

instantané

Démo Ici :
http://jsfiddle.net/abdiassoftware/vxxwt/

HTML initial , un simple div: xxx

inital CSS: xxx

et l'appel principal pour créer un spectre virtuel de ce : xxx

Code complet: xxx

Le code n'est pas optimisé, il est donc un peu affamé sur la CPU. C'est principalement la façon dont HTML est généré pour les bandes. Je préfère le faire sur un élément en toile qui fonctionnerait beaucoup plus efficace, mais comme une multitude de support de navigateur est nécessaire, je l'ai laissé avec ceci: -)

mise à jour: < / p>

Optimisé la hauteur de réglage de la boucle et le haut sur un élément mis en cache. Il a également une méthode setvolume () qui peut être utilisé pour définir le "volume" global à partir d'une boucle, etc.

Mise à jour de l'exemple (linge en haut) avec une fondue et nouveau code.

mise à jour 2:

a ajouté plus de réalisme dans la fréquence inférieure et en simulant un BPM en fonction de l'horloge interne. Je fais maintenant l'heure affecte les trois premières bandes (si le nombre de bandes permettent): xxx

C'est peut-être subtile, mais juste pour ajouter un peu plus de réalisme.

Version de style ici avec fonctionnalité de sourdine:
http://jsfiddle.net/abdiassoftware/hvkpn/

version de style


7 commentaires

Cette solution regarde assez réaliste - très impressionnant!


Pourquoi ne pas simplement régler le haut et la hauteur de chaque itération au lieu de reconstruire HTML à chaque fois?


@JasonsonPerske parce que je l'ai fait au milieu de la nuit :) Mais oui, ça fait mal mes yeux un peu aussi et je pensais à le modifier à faire exactement cela.


Ceci est mon choix # 1 pour la bonne façon d'y aller. Le fait que ce soit du bruit aléatoire est si intéressant pour moi. Je joue avec quelques timings, et je pourrais essayer de le mélanger avec la fonction d'intervalle "Turnitup ()" de ma réponse pour obtenir l'effet de la variation du volume. Est-ce le tout en rapport avec ce que vous faites avec le logiciel Abdias?


@JasonsonPerske Je peux ajouter une fonction simple SetVolume pouvant être contrôlée de manière globale. À propos de: Pas actuellement, mais beaucoup dans le passé (assembleur 68K 68k / amiga / amiga, etc.).


Vous avez totalement gagné la prime. Si c'est le genre de travail que vous aimez vous faire, vous devez mettre à jour vos informations de contact sur votre profil. Le lien du site va à une page de placement équipé. :)


@JasonsPerske merci Jason. Je mettrai à jour mes données de contact (je n'ai pas eu le temps de préparer ma page Web :-)). Le «perfectionniste» en moi a continué un peu avec ce projet. Je penserai que j'ai besoin d'arrêter là-bas ou d'autre que cela finira par devenir un analyseur de spectre à imprimable 3D. Ou quelque chose: D