在播放器上的浏览器上播放wav字节数据

时间:2017-05-24 11:47:06

标签: javascript html5 audio

有人可以帮我解决这个问题我有点困惑,我从数据库获取wav数据,我可以设法使用此功能在浏览器上播放这个wav数据:

function playWave(byteArray) {
    var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
    var myAudioBuffer = audioCtx.createBuffer(1, byteArray.length, 8000);
    var nowBuffering = myAudioBuffer.getChannelData(0);
    for (var i = 0; i < byteArray.length; i++) {
        nowBuffering[i] = byteArray[i];
    }

    var source = audioCtx.createBufferSource();
    source.buffer = myAudioBuffer;
    source.connect(audioCtx.destination);
    source.start();
}

一切正常,我只需要一个GUI播放器来播放/暂停/停止并最终绘制频谱。

首先,我尝试使用HTML5的音频标签,但您需要在src参数中放置一个有效的网址:

<audio controls="controls">
  Your browser does not support the &lt;audio&gt; tag. 
  <source src="../m/example.mp3" />
</audio> 

是否可以将src参数更改为可以放置和播放字节数组的方法?是否有任何球员可以处理这种情况?我只是想以一定的速率(8000Hz)在播放器(播放/暂停/停止)上播放数据库中的wav,这似乎是一个简单的问题,但我发现没有文章或文档在互联网上谈论它。我在互联网上找到的唯一玩家,你需要提供一个有效的文件。

2 个答案:

答案 0 :(得分:0)

我为音频播放对话框制作了一个角度控制器,它是:

App.controller("PlaySoundDialogCtrl", function ($scope, $rootScope, $http, $interval, $mdDialog, $mdMedia, url) {

$scope.url = url;
$scope.error = "";
$scope.audioData = null;
$scope.resampleRate = 44100;
$scope.playing = false;
$scope.source = null;
$scope.buffer = null;
$scope.startedAt = 0;
$scope.pausedAt = 0;
$scope.duration = 0;
$scope.currentTime = 0;
$scope.timeChunks = [];
window.AudioContext = window.AudioContext ||
    window.webkitAudioContext ||
    window.mozAudioContext ||
    window.oAudioContext ||
    window.msAudioContext;
$scope.audioCtx = new AudioContext();

$http.get($scope.url, {responseType: "arraybuffer"}).
      success(function(data) {
        $scope.audioData = data;
        $scope.playByteArray(data);
      }).
      error(function(data, status) {
        $scope.error = "errors.sound-error";
      });

$scope.playByteArray = function(byteArray) {
  var data = new DataView(byteArray);
  var audio = new Int16Array(data.byteLength / Int16Array.BYTES_PER_ELEMENT);
  var len = audio.length;
  for(var jj = 0; jj < len; ++jj) {
    audio[jj] = data.getInt16(jj * Int16Array.BYTES_PER_ELEMENT, true);
  }

  var mono = new Float32Array(audio.length);
  var channelCounter = 0;
  for(var i = 0; i < audio.length; ) {
    mono[channelCounter] = (audio[i] > 0 ? audio[i]/32767 : audio[i]/-32768);
    i = i+1;
    channelCounter++;
  }

  $scope.buffer = $scope.audioCtx.createBuffer(1, mono.length, $scope.resampleRate);
  $scope.buffer.getChannelData(0).set(mono);
  $scope.duration = $scope.buffer.duration;
  for(var i = 0; i < 20; i++) {
    $scope.timeChunks.push(($scope.duration/20)*i);
  }
  window.setTimeout(function() {$scope.play();}, 100);
}

$scope.play = function() {
  var offset = $scope.pausedAt;

  $scope.source = $scope.audioCtx.createBufferSource();
  $scope.source.connect($scope.audioCtx.destination);
  $scope.source.buffer = $scope.buffer;
  $scope.source.start(0, offset);
  $scope.startedAt = $scope.audioCtx.currentTime - offset;
  $scope.pausedAt = 0;
  $scope.playing = true;
  $scope.playInterval = $interval(function() {
    $scope.currentTime = $scope.getCurrentTime();
    if($scope.currentTime > $scope.duration) {
      $scope.stop();
      $interval.cancel($scope.playInterval);
      $scope.currentTime = 0;
    }
  }, 500);
}

$scope.timeWatch = $scope.$watch("currentTime", function() {
  var all = $(".timeRanger").innerWidth();
  var leftOffset = Math.floor(((all-30)/$scope.duration)*$scope.currentTime);
  if($(".playerTooltip").length) {
    $(".playerTooltip")[0].style.setProperty("left", leftOffset+"px", "important");
  }
});

$scope.stop = function() {
  if($scope.source != null) {
    $scope.source.disconnect();
    $scope.source.stop(0);
    $scope.source = null;
  }
  $scope.pausedAt = 0;
  $scope.startedAt = 0;
  $scope.playing = false;
  if(angular.isDefined($scope.playInterval)) $interval.cancel($scope.playInterval);
}

$scope.pause = function() {
  var elapsed = $scope.audioCtx.currentTime - $scope.startedAt;
  $scope.stop();
  $scope.pausedAt = elapsed;
}

$scope.jump = function() {
  $scope.pause();
  $scope.pausedAt = $scope.currentTime;
  $scope.play();
}

$scope.getCurrentTime = function() {
    if($scope.pausedAt) {
        return $scope.pausedAt;
    }
    if($scope.startedAt) {
        return $scope.audioCtx.currentTime - $scope.startedAt;
    }
    return 0;
}

$scope.cancel = function() {
    $scope.stop();
    $mdDialog.cancel();
}

$scope.stopInterval = function() {
  if(angular.isDefined($scope.playInterval)) $interval.cancel($scope.playInterval);
}

$scope.$on('$destroy',function() {
  if(angular.isDefined($scope.playInterval)) $interval.cancel($scope.playInterval);
  if(angular.isDefined($scope.timeWatch)) $scope.timeWatch();
});

}).filter('secToTime', function() {
  return function(item) {
    var minutes = Math.floor(item/60);
    item -= minutes*60;
    item = Math.floor(item);
    if(item < 10) item = "0"+item;
    return minutes+":"+item;
  };
});

和视图部分:

<div class="row text-center">
      {{currentTime | secToTime}}
        <button type="button" class="btn btn-primary" ng-click="pause()" ng-show="playing">Pause</button>
        <button type="button" class="btn btn-primary" ng-click="play()" ng-show="!playing">Play</button><br />
        <div class="timeRanger">
          <input type="range" min="0" max="{{duration}}" step="1" ng-mousedown="stopInterval()" ng-mouseup="jump()" ng-model="currentTime" />
          <div class="tooltip playerTooltip top fade in" tooltip-animation-class="fade" style="top: -33px; left: 0;">
            <div class="tooltip-arrow"></div>
            <div class="tooltip-inner">{{currentTime | secToTime}}</div>
          </div>
        </div>

        <!--<button type="button" class="btn btn-primary" ng-click="jump(t)" ng-repeat="t in timeChunks">{{t | secToTime}}</button>-->
      </div>

答案 1 :(得分:0)

正确转换byteArray后,您应该可以使用Blob。然后,您可以创建一个blob对象URL,并在src元素上将其设置为source

// Create blob from Uint8Array & Object URL.
const blob = new Blob([getByteArray()], { type: 'audio/wav' });
const url = URL.createObjectURL(blob);

// Get DOM elements.
const audio = document.getElementById('audio');
const source = document.getElementById('source');

// Insert blob object URL into audio element & play.
source.src = url;
audio.load();
audio.play();

// Get data from database/server, hardcoded here for simplicity.
function getByteArray() {
  const data = [82, 73, 70, 70, 222, 37, 0, 0, 87, 65, 86, 69, 102, 109, 116, 32, 16, 0, 0, 0, 1, 0, 1, 0, 68, 172, 0, 0, 136, 88, 1, 0, 2, 0, 16, 0, 100, 97, 116, 97, 186, 37, 0, 0, 0, 0, 255, 12, 2, 27, 254, 40, 2, 55, 254, 68, 1, 83, 0, 83, 0, 69, 0, 55, 255, 40, 2, 27, 253, 12, 3, 255, 254, 240, 0, 227, 1, 213, 255, 198, 1, 185, 255, 170, 1, 175, 255, 188, 1, 203, 255, 216, 1, 231, 255, 244, 2, 3, 254, 16];

  // Convert byteArray into Uint8Array.
  return new Uint8Array(data);
}
<audio controls="controls" id="audio" loop>
  Your browser does not support the &lt;audio&gt; tag. 
  <source id="source" src="" type="audio/wav" />
</audio>

☝️这会在点击时播放声音!