Ajax – ntzyz's blog https://archive.ntzyz.io Mon, 18 Sep 2017 11:59:40 +0000 zh-CN hourly 1 https://wordpress.org/?v=5.8 [HTML] AudioContext 折腾笔记 01 https://archive.ntzyz.io/2016/12/17/html-audiocontext-01/ https://archive.ntzyz.io/2016/12/17/html-audiocontext-01/#respond Sat, 17 Dec 2016 11:14:24 +0000 https://ntzyz.io/?p=753 继续阅读[HTML] AudioContext 折腾笔记 01]]> p.indent { text-indent: 2em; }

前天尝试了一波那个什么 MediaSourceExtension,结果发现那套API目前限制蛮大的,而且对我来说没什么帮助(audio/x-wav 完全不正常支持,audio/mpeg 也只能在 Chrome 上使用)于是只能放弃折腾了 QAQ

昨天突然想起之前写 nanoPlayer 的时候,使用了一个叫 Audio Context 的接口,nanoPlayer 用了这个 API 里的 createAnalyser 方法,来获得音频的频率数据,进而实现了一个频谱可视化功能。之前就注意到了这个接口中有个自定义 AudioBufferSource 的方法,可以指定若干 Float32Array 并交给浏览器播放,应该是蛮有意思的。

这里就实现一个可制定频率的正弦波音频吧,如果这个实现起来没有什么难度的话,就准备试试浏览器端解码 WAV 音频。

首先是 HTML,我们要准备一个文本框来获得指定的频率,两个按钮分别控制播放的开始与停止:



  
    
    
    
    
  

然后初始化若干变量:

let ctx = new AudioContext();
let frames = ctx.sampleRate;
let start = document.querySelector('button[start]');
let stop = document.querySelector('button[stop]');
let last = null;

其中 ctx.sampleRate 是 AudioContext 的采样率,这里直接将一秒钟的采样数作为帧数,产生一段持续时间为一秒的 AudioSourceBuffer 就足够了,还有 last 是用来保存上一次的 AudioSource,可以随时调用 stop 方法来终止播放。

然后就是为 start 按钮增加一个点击事件:根据文本框里的数值产生一段指定频率的音频采样:

start.onclick = (e) => {
  if (last) last.stop();

  let freq = document.querySelector('#freq').value;
  // 初始化一个单声道,采样率和 AudioCotnext 一致,持续时间为 1 sec 的 AudioBuffer
  let audioBuffer = ctx.createBuffer(1, ctx.sampleRate, ctx.sampleRate);
  // 获得其中第一个声道的数据源,类型是 Float32Array
  let nowBuffering = audioBuffer.getChannelData(0);
  // 填充数据,取值范围是 [-1, 1],直接用正弦函数就行了
  for (let i = 0; i < frames; ++i) {
    nowBuffering[i] = Math.sin((Math.PI * 2 * freq) * (i / ctx.sampleRate));
  }
  // 初始化一个 AudioBufferSource,并将上面的 AudioBuffer 与之绑定,并输出到 AudioContext
  let source = ctx.createBufferSource();
  source.loop = true;
  source.buffer = audioBuffer;
  source.connect(ctx.destination);
  // 开始回放
  source.start();
  // 保存以备后续使用
  last = source;
}

当然还需要对停止按钮绑定一个事件,来停止回放:

stop.onclick = (e) => {
  if (last) last.stop();
  last = null;
};

以上就是所有代码啦,效果的话,我在这里直接放个demo就行:


]]>
https://archive.ntzyz.io/2016/12/17/html-audiocontext-01/feed/ 0
[HTML] MediaSource 折腾笔记 01 https://archive.ntzyz.io/2016/12/16/html-fuck-mediasource-01/ https://archive.ntzyz.io/2016/12/16/html-fuck-mediasource-01/#respond Thu, 15 Dec 2016 17:26:26 +0000 https://ntzyz.io/?p=735 继续阅读[HTML] MediaSource 折腾笔记 01]]> p.indent { text-indent: 2em; }

MediaSource 是 HTML5 中的一个实验性特性,用于给 `HTMLMediaElement` 对象提供数据源。这里的数据源通常是使用 `XMLHttpRequest` 获得的数据。在 XHR 取得数据后,我们可以使用 JavaScript 对数据进行一些操作,比如提取 ID3、修改封装类型等等。 某 bilibili 开源的 Flv.js 就是使用这个特性实现的在 HTML5 环境下播放 H264 + AAC 格式的 FLV 视频。

最近在写 `Nano Player` 的时候遇到了两个比较尴尬的问题:1、ID3 信息必须手动指定;2、网易云音乐上下载的 MP3 由于某些原因必须缓冲 2MB 才能播放(详见MP3缓冲2MB才开始播放的解决方法)。于是想到是不是可以用这个 MediaSource 来暴改 MP3 呢?我也不知道

不管怎样,要用这个 MSE 来解决问题,首先就是要用它来播放文件(如果获得的数据直接喂给 MSE 都不能播放那还讨论个什么鬼)

创建若干变量并初始化:

let mediaSource = new MediaSource();
let audio = new Audio();
let media = 'audio.mp3';

audio.src = URL.createObjectURL(mediaSource);
audio.controls = 'controls';

然后是对 `sourceopen` 事件添加监听。当 `sourceopen` 事件触发后,我们需要创建一个 `sourceBuffer`,随后使用 `XMLHttpRequest` 获得媒体文件的内容,并附加到这个 `sourceBuffer` 内。当以上工作完成后,调用 `play` 方法播放音频:

mediaSource.addEventListener('sourceopen', () => {
  let sourceBuffer = mediaSource.addSourceBuffer('audio/mpeg');

  let xhr = new XMLHttpRequest();
  xhr.open('GET', media);
  xhr.responseType = 'arraybuffer';
  xhr.onreadystatechange = () => {
    if (xhr.readyState === xhr.DONE && xhr.status === 200) {
      sourceBuffer.addEventListener('updateend', () => {
        mediaSource.endOfStream();
        audio.play();
      });
      sourceBuffer.appendBuffer(xhr.response);
    }
  };
  xhr.send();
});

最后,为了方便检查,将 `audio` 添加到 `body` 中:

document.querySelector('body').appendChild(audio);

嗯,以上的这些代码就能实现一个本来只要三行代码就完成的工作了。具体效果可以看这里:MSE Playground 01

下面需要解决的问题是,为什么刚开始尝试使用的 M4A 格式无法正常播放,这个坑死人了我哪知道只能 MP3 啊浪费了两个多小时……


由于目前来看,MediaSource 的表现在各个浏览器中并不一致,同时支持的格式就目前而言还是十分有限,这个系列估计就这一篇了吧 23333(逃

参考链接:

  1. Media Source Extensions
  2. MediaSource – Web APIs | MDN
  3. Media Source Extensions for Audio
  4. HTML5 Media – types and codecs examples + canPlayType(type) test
  5. html5 video tag codecs attribute
  6. nickdesaulniers/netfix: Let’s build a Netflix
]]>
https://archive.ntzyz.io/2016/12/16/html-fuck-mediasource-01/feed/ 0
没事儿干写了个新的 Blog 框架 https://archive.ntzyz.io/2016/07/30/the-new-blog-project/ https://archive.ntzyz.io/2016/07/30/the-new-blog-project/#comments Fri, 29 Jul 2016 16:02:00 +0000 https://blog.ntzyz.io/?p=691 继续阅读没事儿干写了个新的 Blog 框架]]> p.indent { text-indent: 2em; }

JavaScript 自己也看了一段时间了,Node.js 相关的内容也随手糊过一点了,但是总是没有一个像样的作品,这样是不行的。

所以就必须想点办法,搞个大新闻,把脑子里的知识运用一番,顺带学学新的姿势,提高自己的水平。不编了好吧我承认是自己在家无聊了QAQ

在基佬集线器上逛逛的话,会发现很多人都自己撸过一个简单的 Blog 框架,毕竟这种简单的网页应用逻辑简单,同时实现的参考啊也很多,比如 PHP 就有 WordPress, Node.js 就有 Hexo,等等。所以我也就学着做个玩玩咯~

花了大概一天吧,撸出了现在的这个最简单的 Blog Framework,虽然还没想到取什么名字。前段框架使用了 Vue.js,并且才用了 Materialize 提供的部分样式和组件。后端使用了 Express.js,数据存储则按照国际惯例选择了 MySQL(MariaDB)。全站数据使用 Ajax 获得,并完全在浏览器端渲染,同时除了博客名称以外没有任何触发刷新的组件。整体风格自认为是极简风格,实际上是自己没本事搞出什么好看的设计。

现在这个框架准确的说还在开发阶段,需要解决的问题是评论以及管理页面。当然部分代码需要优化优化,写得实在是太随性了。

样例页面可以在这里查看,里面的内容大多是从这里搬运过去的。源代码则可以前往GitHub来查看(顺便请允许我无耻的求个 Star QwQ)。

卧槽我这个 Framework 国内访问速度真他喵快啊

]]>
https://archive.ntzyz.io/2016/07/30/the-new-blog-project/feed/ 3