hvianna / audioMotion-analyzer

High-resolution real-time graphic audio spectrum analyzer JavaScript module with no dependencies.
https://audioMotion.dev
GNU Affero General Public License v3.0
609 stars 61 forks source link

Support for https://github.com/eshaz/icecast-metadata-js #11

Closed lexterror closed 3 years ago

lexterror commented 3 years ago

Hi, I wanted to know if could support the following program:

https://github.com/eshaz/icecast-metadata-js

Im trying to combine them, but Im having some issues.

Thank you!

hvianna commented 3 years ago

Hello! Just use Icecast-Metadata's player.audioElement as the audioMotion source, like so:

const player = new IcecastMetadataPlayer(
    "https://streamingv2.shoutcast.com/HAWK-Radio-Hilbert-College?icy=http",
    { onMetadata }
);

const audioMotion = new AudioMotionAnalyzer( document.getElementById('analyzer'), {
    source: player.audioElement
});

Live demo: https://codesandbox.io/s/o94y5

lexterror commented 3 years ago

Hi, it works on "codesandbox" but Im having trouble running it on my server. Could you please provide a zip with the files if you can? Or maybe have it on Codepen?

lexterror commented 3 years ago

I think it has to do with:

import AudioMotionAnalyzer from "audiomotion-analyzer"; import IcecastMetadataPlayer from "icecast-metadata-player";

hvianna commented 3 years ago

I could not get the Icecast Metadata Player running on CodePen. The import is not working as it was supposed to.

In my local server I used it as a standalone script.

lexterror commented 3 years ago

This is what I have so far. it plays the stream but doesnt show the visualizer.

https://pastiebin.com/604ab0271b0df

lexterror commented 3 years ago

Your visualizer disappears when I change this line:

source: player.audioElement

Please let me know if I can fix this

hvianna commented 3 years ago

The code below is working fine in my local server. Just put icecast-metadata-player-1.1.0.min.js and audioMotion-analyzer.js in the same folder.

<!DOCTYPE html>
<html>
<body>
  <div id="analyzer" style="height: 400px"></div>
  <button id="play"> Play </button>
  <button id="stop"> Stop </button>
  <p> Now Playing: <span id="metadata"></span> </p>

  <script src="icecast-metadata-player-1.1.0.min.js"></script>
  <script type="module">
    import AudioMotionAnalyzer from './audioMotion-analyzer.js';

    const onMetadata = (metadata) => {
      document.getElementById("metadata").innerHTML = metadata.StreamTitle;
    };
    const player = new IcecastMetadataPlayer(
        "https://streamingv2.shoutcast.com/HAWK-Radio-Hilbert-College?icy=http",
        { onMetadata }
    );

    document.getElementById('play').addEventListener( 'click', () => player.play() );
    document.getElementById('stop').addEventListener( 'click', () => player.stop() );

    const audioMotion = new AudioMotionAnalyzer( document.getElementById('analyzer'), {
      source: player.audioElement
    });
  </script>
</body>
</html>
lexterror commented 3 years ago

It finally works! Thank you for your time. I was only missing a coma. Thank you!

lexterror commented 3 years ago

Hi, I was wondering if you could tell me how to call "audioMotion = new AudioMotionAnalyzer" a second time without creating a new instance?

Im trying to change stations. But because of the "module" I'm having difficulties.

hvianna commented 3 years ago

You don't call the constructor unless you want to create a new instance.

If you need to access the audioMotion object in another script block, declare it as a global variable outside the module.

  <script>
    // THE VARIABLE BELOW IS GLOBAL
    let audioMotion;
  </script>

  <script type="module">
    import AudioMotionAnalyzer from './audioMotion-analyzer.js';

    .
    .

    // REMOVED `const` BELOW SO IT NOW USES THE GLOBAL VARIABLE
    audioMotion = new AudioMotionAnalyzer( document.getElementById('analyzer'), {
      source: player.audioElement
    });
  </script>

You can then use audioMotion elsewhere to change settings.

This is a good article about variable scope in JavaScript -> https://www.freecodecamp.org/news/an-introduction-to-scope-in-javascript-cbd957022652/

lexterror commented 3 years ago

How can I call audioMotion without starting a new instance? i'm trying to update the source(url) for "IcecastMetadataPlayer" Im trying to change the url onclick. When I click the url changes but the visualizer stops. I want audioMotion to update itself not to start a new instance.

hvianna commented 3 years ago

So I suppose you're using multiple instances of the Icecast player, one for each station. If that's the case, after you create all player instances, connect them all to audioMotion, by calling audioMotion.connectInput()

const player1 = new IcecastMetadataPlayer("https://example.com/stream_1");
const player2 = new IcecastMetadataPlayer("https://example.com/stream_2");
const player3 = new IcecastMetadataPlayer("https://example.com/stream_3");

// no need to set the `source` in the call below
const audioMotion = new AudioMotionAnalyzer( document.getElementById('analyzer') );

// set all sources here
audioMotion.connectInput( player1.audioElement );
audioMotion.connectInput( player2.audioElement );
audioMotion.connectInput( player3.audioElement );

This way audioMotion will display the audio of all player instances, and you don't need to call audioMotion again when changing stations.