Is there a way get something like decibel levels from an audio file and transform that information into a json array?

前端 未结 2 1825
深忆病人
深忆病人 2020-12-09 00:31

So that I can use the information to coordinate a page animation like making elements brighter as the decibel levels get higher

相关标签:
2条回答
  • 2020-12-09 00:49

    Yes, you need to grab the raw PCM samples (like Kennis mentions). However, to calculate the overall volume levels, you want to grab the RMS (Root Mean Square) of the values. Also, you will likely want to pay attention to all the channels in the stream, not just the first channel (so you can accurately reflect the volume level for a stereo stream for example).

    There are some tricks (make sure you use multiplication of the same samples across channels, not addition). Then you will be adding them all together (again like Kennis is doing). If you want it an actual decibels, there is a log step that is required as well.

    There is an example as an answer to this other question.

    Relevant code:

    var rms = Math.sqrt(sum / (_buffer.length / 2));
    var decibel = 20 * (Math.log(rms) / Math.log(10));
    
    0 讨论(0)
  • 2020-12-09 01:01

    This approach will work in Chrome / Safari:

    +function(){
      
      var ctx = new AudioContext()
        , url = 'https://cf-media.sndcdn.com/OfjMZo27DlvH.128.mp3?Policy=eyJTdGF0ZW1lbnQiOlt7IlJlc291cmNlIjoiKjovL2NmLW1lZGlhLnNuZGNkbi5jb20vT2ZqTVpvMjdEbHZILjEyOC5tcDMiLCJDb25kaXRpb24iOnsiRGF0ZUxlc3NUaGFuIjp7IkFXUzpFcG9jaFRpbWUiOjE1MTUwNDM5Njd9fX1dfQ__&Signature=FfmL2qUssAKs3Z7EPoYo0Yq8-SAg8rKLPs65EasXwuVkfsOB4joFqeCvVR2elpaG-lJaV4hXpXFiRCDWXNOYyAtO4Oz~sexiPwIoSk8-jWiVbGQRS8TMmUmj7TJzxemMOIj7ugWJKk6PHsrUdgqs9woDpHzxmkGCzk6sfqJEIsdeZJ4rWUFAh4iGWn9M6b0xfzTgndAJmytkNj9raCpWCBVmdr5u-r9nt~q5uF1easNSW9oaFilM4s1Hq2ei~VJye8zW9bzvrGm8idVdy-tiPeMWAKcE8J2VuaS1Ret6jRTRaHTDuiNgA5sZvgTzNpEpKtWI7UmAWI5TrqNVSlxpgQ__&Key-Pair-Id=APKAJAGZ7VMH2PFPW6UQ'  
        , audio = new Audio(url)
        // 2048 sample buffer, 1 channel in, 1 channel out  
        , processor = ctx.createScriptProcessor(2048, 1, 1)
        , meter = document.getElementById('meter')
        , source
        
      audio.crossOrigin = 'anonymous'
    
      audio.addEventListener('canplaythrough', function(){
        source = ctx.createMediaElementSource(audio)
        source.connect(processor)
        source.connect(ctx.destination)
        processor.connect(ctx.destination)
        audio.play()
      }, false);
      
      // loop through PCM data and calculate average
      // volume for a given 2048 sample buffer
      processor.onaudioprocess = function(evt){
        var input = evt.inputBuffer.getChannelData(0)
          , len = input.length   
          , total = i = 0
          , rms
        while ( i < len ) total += Math.abs( input[i++] )
        rms = Math.sqrt( total / len )
        meter.style.width = ( rms * 100 ) + '%'
      }
      
    }()
    #meter {
      width: 0%;
      height: 15px;
      margin: 2px 0;
      background: green;
      -webkit-transition: width .05s;
    }
    <div id="meter"></div>

    The important stuff happens here:

    processor.onaudioprocess = function(evt){
      var input = evt.inputBuffer.getChannelData(0)
        , len = input.length   
        , total = i = 0
        , rms
      while ( i < len ) total += Math.abs( input[i++] )
      rms = Math.sqrt( total / len )
      meter.style.width = ( rms * 100 ) + '%' 
    }
    

    Basically, you grab the raw PCM data (values from -1 to 1) every 2048 samples and you loop through them, calculating the average signal level over the given period of time.

    You can then use that value to do your animations.

    Edit: Updated to use RMS, which as Jason pointed out is a more meaningful measurement.

    0 讨论(0)
提交回复
热议问题