绿豆宝贝 发表于 2015-7-17 14:44:50

使用Web音频API

Web音频API介绍以下为在线翻译提供哦!凑合者看看吧!
现代的移动应用程序和游戏的存在不能没有音频。 然而,很长一段时间,开发人员必须依赖外部浏览器插件来实现声音在他们的应用程序。 幸运的是,W3C引入了 网络音频API。 最新的规范草案状态仍在工作。 这是一个非常年轻的技术规范的第一个出现在2011年,可以发现在以下链接: http://www.w3.org/TR/2011/WD-webaudio-20111215/。 Tizen 2.0.0决赛WebKit引擎实现第一个规范发表在12月15日,2011年在工作草案状态。 这种技术设计是非常容易使用和非常强大的。
你不应该考虑 网络音频API在一个html音频标签。 音频标签提供了基本的功能,比如播放声音;Web音频API通过更多的功能。 工程师工作规范介绍了许多特性允许精确的声波操纵。 这听起来可用于创建专业的编辑器。 修改声音的数据可以作为源音频在html标记或被保存到文件中。 然而,第二个选项不是默认提供。 你必须压缩数据和使用文件API。 网络音频API仍然在发展,甚至现在我们可以看到惊人的使用的例子。
所有API函数的入口点是我们检索一个上下文对象通过调用其构造函数称为webkitAudioContext()(它仍然是一个工作草案,我们必须使用webkit的前缀)。 所有的功能封装在该对象。

[*]var context = new webkitAudioContext();

一个节点是什么以及如何使用它呢?
声音总是有它的源和目标。 源可以是一个解码/音乐声音文件数据API本身也可以合成。 演讲者的目的地是一个设备(s),接收声音数据和声音。
源和目标两个基本节点。 一个节点是一个基本的Web音频API元素都具有特定的功能。 有很多节点有不同的功能:GainNode操纵量水平,PannerNode模拟将声源在三维空间中,DelayNode推迟声音,AnalyserNode声波和许多数据,更多。 详细你可以阅读关于W3C网站上可用的节点: http://www.w3.org/TR/2011/WD-webaudio-20111215/。 你必须将源节点到目标节点连接到听到任何声音。 然而,您可以插入任何前面提到的节点。 连接一个节点到另一个你使用一个连接()函数的参数是另一个节点的传输数据。 最小连接两个节点称为路由图。 一个例子的路由图下图所示。

https://developer.tizen.org/sites/default/files/users/user-2059/3-routing-graph-1.png路由图

路由图可能更复杂。 在前面的示例中,我们显示只有一个路线。 在真实的应用程序中,它可以包含许多路线处理不同来源和最终加入到一个目标节点。 例如我们可能想打两个声音同时和两个独立的音量控制器。 下图演示了这种情况。

https://developer.tizen.org/sites/default/files/users/user-2059/3-routing-graph-2.png路由图有两个来源

加载和播放声音
现在有网络音频API是如何工作的基础知识,我们可以尝试加载和玩一些声音。 加载一个良好的数据我们可以使用几种方法,唯一的要求是在ArrayBuffer格式检索数据。 我们将展示如何得到这些数据使用XMLHttpRequest。 Tizen,通过XMLHttpRequest(通常称为AJAX),我们可以从不同的领域如果我们加载文件申报特殊访问权限在XML配置文件中。 我们需要设置域的应用程序访问。 然而,如果你想从一个内部加载声音文件Tizen设备内存可以使用Tizen Filesystem API。 此外,每个部件都有它的私有存储虚拟根的位置被称为“wgt-private”。 描述Tizen的文件系统API不是本文的主题。
AJAX请求在做一个AJAX请求,我们必须像URL设置一些属性,请求方法,请求类型和反应类型。 前三个参数我们设置在一个开放的XMLHttpRequest对象的()方法。 我们使用一个异步GET方法。 文件的URL可以是一个通往任何内部文件的三种格式(WAV,MP3和OGG)或一个外部文件的URL匹配访问模式。 在配置。 xml文件,我们可以添加一个访问标签告诉应用程序,它可以访问外部资源只匹配一个给定的模式。 如果我们想从任何域允许加载文件我们可以编写以下代码行。

[*]<access origin="*" subdomains="true"/>

如果我们想限制文件的加载一个明确的领域我们只是写如下:
[*]<access origin="http://example.com" subdomains="true"/>

让我们回到AJAX请求。 响应类型应该设置为一个arraybuffer因为二进制文件的数据。 下面的代码显示了AJAX请求加载声音文件从主应用程序目录。

[*]xhr = new XMLHttpRequest();
[*]xhr.open('GET', './sound.mp3', true);
[*]xhr.responseType = 'arraybuffer';
[*]xhr.onload = function () {
[*]    /* Processing response data - xhr.response */
[*]};
[*]xhr.onerror = function () {
[*]    /* Handling errors */
[*]};
[*]xhr.send();

解码文件数据现在有文件的数据我们已经解码。 正如前面提到的,我们可以在三种不同加载文件格式:WAV,MP3和OGG。 这些文件的数据必须转换为进一步使用PCM /原始格式。
我们使用decodeAudioData解码数据()函数从webkitAudioContext对象。 这需要三个参数。 第一个是二进制数据,我们得到了在xhr AJAX请求。 响应对象。 第二个参数是一个函数执行成功,第三个参数是一个函数执行错误。 当decodeAudioData()完成后,它调用成功解码音频数据的回调函数AudioBuffer类型作为参数。 下面的代码演示了解码过程。

[*]/* Decoding audio data. */
[*]var context = new webkitAudioContext();
[*]context.decodeAudioData(xhr.response, function onSuccess (buffer) {
[*]    if (! buffer) {
[*]      alert('Error decoding file data.');
[*]      return;
[*]    }
[*]}, function onError (error) {
[*]    alert('Error decoding file data.');
[*]});

声音我们的声音数据,但我们没有SourceNode对象,所以让我们做一个。 我们创造它通过调用createBufferSource()函数从上下文对象。

[*]var source = context.createBufferSource(); /* Create SourceNode. */

之后,我们必须分配AudioBuffer数据缓冲区SourceNode的财产。

[*]source.buffer = buffer; /* buffer variable is data of AudioBuffer type from the decodeAudioData() function. */

本文开始提到的,我们必须把SourceNode DestinationNode。

[*]source.connect(context.destination); /* Connect SourceNode to DestinationNode. */

现在,只是玩的声音立即给0作为noteOn()函数的参数。 这个参数延迟播放声音的给定的毫秒。

[*]source.noteOn(0); /* Play sound. */

Tizen 2.0.0 WebKit引擎实现了第一个W3C Web音频API规范。 在此规范玩声音我们使用noteOn()函数,但在目前规范的版本的弃用,取而代之的是一个开始()函数。
将节点添加到路由图现在我们只使用两个节点,SourceNode DestinationNode。 如果我们想要添加例如GainNode图吗? 所必须做的就是连接SourceNode GainNode和GainNode DestinationNode。 你可以连接你想要尽可能多的节点。 声音处理开始从最早的节点和结束最后一个节点的路由图。 让我们看看下面的代码。

[*]var gainNode = context.createGainNode(); /* In the newest Audio API specification it's createGain(). */
[*]source.connect(gainNode); /* Connect the SourceNode to the GainNode. */
[*]gainNode.connect(context.destination); /* Connect the GainNode to the DestinationNode. */

再一次,打你打电话声音noteOn SourceNode()函数。

[*]source.noteOn(0); /* Play sound that will be processed by the GainNode. */

如前所述,GainNode用于控制声音的音量级别。 这种类型的对象有一个获得属性,属性值。 属性的值是一个我们必须修改为了控制音量水平。

[*]gainNode.gain.value = 0.5; /* Decrease the volume level by half. */
[*]gainNode.gain.value = 2; /* Increase the volume level two times. */

样例应用程序
让我们看看本文的示例应用程序。 它使用两个库创建UI,使AJAX调用。 他们是jQuery 1.3.0 1.9.0和jQuery移动。 应用程序允许加载和播放声音/音乐从不同的来源。 首先,您可以运行文件存储在应用程序。 在这个演示应用程序文件都存储在一个”。 /声音的目录。 另一个来源是“音乐”目录放置在设备的内部内存Tizen。 最后一个从网上任何外部文件。 此外,你可以改变音量级别和三维空间模拟播放声音。 使应用程序简单我有限只移动声源的左边或者右边的侦听器。 下面的屏幕快照展示了应用程序的主屏幕。

https://developer.tizen.org/sites/default/files/users/user-2059/3-screen.png应用程序的主界面

在应用程序中使用的所有声音来自SoundJay网站 http://www.soundjay.com/。我将只讨论的部分代码,理解网络音频API至关重要。 其他部分,比如UI实现就会被忽略掉。入口点是一个应用程序模块,它有几个私有方法和一个公共接口使用以下方法:

[*]init()——初始化应用程序;调用onload事件,
[*]listFilesInMusicDir()——列出了所有的文件都存储在“音乐”目录,
[*]loadSound()——异步加载的声音和一个回调函数执行成功,
[*]playSound名字()——播放声音。

[*]var app = (function () {
[*]
[*]    /* ... */
[*]
[*]    return {
[*]      init                : _init,
[*]      listFilesInMusicDir : _listFilesInMusicDir,
[*]      loadSound         : _loadSound,
[*]      playSound         : _playSound
[*]    };
[*]}());
[*]
[*]window.onload = app.init;

这个模块有几个值得一提的私有变量:

[*]带有_file——数组保存所有文件的数据。 每个数组的元素是一个对象有以下属性:

[*]名称-内部文件名称
[*]uri uri或URL到文件,
[*]缓冲-解码音频缓冲区。
[*]_context——上下文对象初始化在init()函数,
[*]_source SourceNode——商店,
[*]_gainNode _pannerNode——对象获取和平移的声音。
大多数的这些对象初始化_init()方法。

[*]_context = new webkitAudioContext(); /* Create context object. */
[*]_source = null;
[*]/* Create gain and panner nodes. */
[*]_gainNode = _context.createGainNode(); // createGain()
[*]_pannerNode = _context.createPanner();
[*]/* Connect panner node to the gain node and later gain node to the
[*] * destination node. */
[*]_pannerNode.connect(_gainNode);
[*]_gainNode.connect(_context.destination);

注意到路由图的创建。 我们连接PannerNode GainNode,后来的GainNode DestinationNode。 稍后您将看到,在_playSound()方法中,我们把SourceNode PannerNode关闭图和玩耍的声音。在开始我们也将滑块绑定到增益和淘洗沙金的人节点的属性。

[*]/* onVolumeChangeListener changes volume of the sound. */
[*]onVolumeChangeListener = function () {
[*]    /* Slider's values range between 0 and 200 but the GainNode's default value equals 1. We have to divide slider's value by 100, but first we convert string value to the integer value. */
[*]    _gainNode.gain.value = parseInt(this.value, 10) / 100;
[*]};
[*]
[*]/* onPannerChangeListener changes sound's position in space. */
[*]onPannerChangeListener = function () {
[*]    /* setPosition() method takes 3 arguments x, y and z position of the sound in three dimensional space. We control only x axis. */
[*]    _pannerNode.setPosition(this.value, 0, 0);
[*]};

通过点击不同的UI元素我们负载加载完成后声音和玩。

[*]app.loadSound(file, function () {
[*]    app.playSound(soundName);
[*]});

现在,让我们检查最重要的功能:_loadSound()和_playSound()。_loadSound()函数接受三个参数。 第一个是一个文件对象名称和uri属性。 最后两个属性是成功和错误回调。 在一开始,我们设置默认参数的值和一个带有_file对象定义为一个空数组(如果不是预先设定的)。 接下来我们要做的就是检查是否已经是一个具有相同名称的文件加载。 如果它存在于带有_file数组,只需执行回调函数。

[*]/* Check if file with the same name is already in the list. */
[*]isLoaded = false;
[*]$.each(_files, function isFileAlreadyLoaded (i) {
[*]    if (_files[i].name === file.name) {
[*]      /* Set flag indicating that file is already loaded and stop 'each' function. */
[*]      isLoaded = true;
[*]      return false;
[*]    }
[*]});

如果文件没有加载之前,我们必须得到它的数据通过一个AJAX请求。

[*]/* Do AJAX request. */
[*]doXHRRequest = function () {
[*]    xhr = new XMLHttpRequest();
[*]    xhr.open('GET', file.uri, true);
[*]    xhr.responseType = 'arraybuffer';
[*]    xhr.onload = onRequestLoad;
[*]    xhr.onloadstart = tlib.view.showLoader;
[*]    xhr.onerror = onRequestError;
[*]    xhr.send();
[*]};

后文件的数据解码里面由decodeAudioData onRequestLoad函数()方法中,我们最终有一个缓冲区对象我们商店里面带有_file数组与文件名称和它的URI / URL。 解码完成后,我们回调函数执行成功或错误回调函数如果事情错了。

[*]/* When audio data is decoded add it to the files list. */
[*]onDecodeAudioDataSuccess = function (buffer) {
[*]    if (!buffer) {
[*]      errorCallback('Error decoding file ' + file.uri + ' data.');
[*]      return;
[*]    }
[*]    /* Add sound file to loaded sounds list when loading succeeded. */
[*]    _files.push({
[*]       name : file.name,
[*]       uri : file.uri,
[*]       buffer : buffer
[*]    });
[*]    /* Hide loading indicator. */
[*]    tlib.view.hideLoader();
[*]    /* Execute callback function. */
[*]    successCallback();
[*]};
[*]
[*]/* When loading file is finished try to decode its audio data. */
[*]onRequestLoad = function () {
[*]    /* Decode audio data. */
[*]    _context.decodeAudioData(xhr.response, onDecodeAudioDataSuccess, onDecodeAudioDataError);
[*]};

正如我们之前看到的,我们的应用程序的成功回调函数的函数执行playSound()函数,我们现在要讨论。 我们做的第一件事就是检查是否有已经播放声音。 如果是的,那么我们必须停止件通过调用noteOff()函数。 需要作为参数的毫秒数之后,应该停止。 件注意noteOff()函数是弃用最新版本的Web音频API规范。 停止一切听起来后,我们步行穿过一系列文件和寻求的名字我们给作为参数。 玩的声音我们要做的几个步骤,我们本文开始提到的,那就是:创建一个SoundNode对象,添加一个缓冲SoundObject,SourceNode连接到下一个节点的路由图和播放声音通过执行noteOn()方法。 下面的代码显示了这个过程。

[*]_playSound = function (name) {
[*]    /* Check whether any sound is being played. */
[*]    if (_source && _source.playbackState === _source.PLAYING_STATE) {
[*]      _source.noteOff(0); // stop()
[*]      _source = null;
[*]    }
[*]
[*]    $.each(_files, function (i, file) {
[*]      if (file.name === name) {
[*]            /* Create SourceNode and add buffer to it. */
[*]            _source = _context.createBufferSource();
[*]            _source.buffer = file.buffer;
[*]            /* Connect the SourceNode to the next node in the routing graph
[*]             * which is the PannerNode and play the sound. */
[*]            _source.connect(_pannerNode);
[*]            _source.noteOn(0); // start()
[*]
[*]            return false;
[*]      }
[*]    });
[*]};

总结我希望这篇文章帮助你理解Web音频API是如何工作的和熟悉的加载和玩声音的过程。 使用网络音频API你可以让应用程序中,您不需要把html音频声音元素在文档。 你可以玩和操纵听起来当某些行为发生。 它在游戏开发方面的一大优势。 您现在应该能够丰富任何应用程序用声音或使一个简单的音乐播放器。
文件附件下载:
soundplayer.zip

页: [1]
查看完整版本: 使用Web音频API