使用SVG开发音乐播放器(三)

已经有挺长一段时间没有更新了,原因略多啊。最近在弄毕业论文最后的资料整理,然后走出学校租房住了。 面试进了一家物联网公司,总的感觉还不错,就是暂时稍微忙了一些。

很坑的是现在住的地方是傻傻的长城宽带,刚开始我以为都是宽带差距不会很大,后来才知道我错了。 这个网络问题是在是有点多,个人也进了长宽吧看了看,长宽的网络鱼龙混杂啊。 我就成为了被选召的咸鱼。

之前又因为cocos2d给我的灵感,加入了新的机制。后来发现我之前的自定义标签模式根本不够结构化, 连我自己都不能满意,就下定决心完全重做这个框架。现在也算基本成型了, 这个例子因为用了之前的框架所以后续内容可能会晚一点再做了

今天要做的

好啦,闲话不多说,来说说我们今天做什么吧。

有很多音乐播放器都有着随音乐的播放而变动的图像,用视觉来表达音乐的节奏感。 就是那种看到让人更high的东西 有的是条形图有的是波纹图等。比如下面的就是千千静听的条形图:

我们今天要做的是一个被我自称水波效果的效果,灵感是最近打开了有挺久没完的PSP, 又看到了当年一直让我感觉很美的波纹背景。PSP的界面是这个样子的:

背景的波纹运动的即让人感觉很舒服也不会太抢眼球。还会随着用户的操作而进行很不错的交互, 细节做得真的很棒。虽然这次做得效果差的很远,但是也算是一次学习啦。

最终的效果

下面就是我们今天要做的最终的效果图啦,虽然实际的交互效果并不好

要先了解的知识

js如何获取音乐当前的数据

我们既然要用图形来表现音乐,首要的事情当然是在播放音乐时获取音乐相关的数据。之前的我还没有接触过js获取, 想过使用flash获取再传给js。直到我搜索到了AudioContext,才发现HTML5已经这么强。 这里有一篇文章详细的说明了如何通过AudioContext获取声音信号:

Web Audio API之手把手教你用web api处理声音信号

上面的教程比较详细,我就不做关于怎么获取数据的讲解了,照着自己做一两个例子就能了解了。 现在我们来布置一下我们的代码。

window.addEventListener('load', function(){
    var context1 = new (window.AudioContext || window.webkitAudioContext);
    var analyserfa=context1.createAnalyser();
    var source = context1.createMediaElementSource(music);
    source.connect(analyserfa);
    analyserfa.connect(context1.destination);

    var step = function(){
        var array =  new Uint8Array(1024);
        analyserfa.getByteFrequencyData(array);
        setTimeout(step,20);
    }
    step();
},false);

前面的代码是绑定AudioContext,后面的代码我们用setTimeout来每秒执行50次step方法。 step方法每次执行生成一个数组,并使用getByteFrequencyData将声音信号传进数组。 这时数组里就是我们的频谱数据了。

用SVG如何生成波浪

现在我们已经得到了声音信号了,接下来就是要画波浪了。我们先看看SVG的图形绘制:

突袭HTML5之SVG 2D入门2 - 图形绘制

文章中有提到path标签的用法,基本路径指令:

我们绘制曲线需要用到的就是贝塞尔曲线,想要深入了解贝塞尔曲线的话可以看看下面这篇文章

深度掌握SVG路径path的贝塞尔曲线指令 我基本是看着这位大大的文章成长的

实际上我自己对贝塞尔曲线并不熟,这里我也只使用了最简单的特殊版本三次贝塞尔曲线,也就是S指令。 那么特殊的贝塞尔曲线到底特殊在哪里呢,下面是在PS中钢笔画图的默认贝塞尔曲线:

我们可以发现,在不做调整的情况下PS中绘制贝塞尔曲线的两个控制点是对称的,这就是特殊的三次贝塞尔曲线( 控制点不是从目标点拉出来的两个,而是上一个点的右控制点和当前的左控制点)。 我们的波浪线在波峰和波谷处都是平行切高度一致的,所以只需要简单的贝塞尔曲线就可以完成。 比如下面的代码我们就可以绘制一个简短的波浪:

<svg>
    <path d="M0,0 S75,50,50,50 S125,0,100,0"></path>
</svg>

上面的代码画出来的曲线如上,S的四个参数分别是控制点X、控制点Y、目标点X、目标点Y。 不难看出点的X轴每次递增50,Y轴0和50之间跳动,控制点就在目标点左边25单位。 之后的波浪只需要按照这个规律下去就可以了。不过需要注意的是我们第一个曲线部分并不是真正的波浪。

现在我们可以开始写代码了

var build_path = function(w,h,by){
    var re = "M0,"+h/2;
    if(by)
        re = "M0,"+by + " L0,"+h/2;
    var hb = h/2;
    var wb = w/2.5;
    var i;
    for(i = 0;i < 30;i++){
        var x = (i+1)*w;
        var y = (i%2)?hb:-hb;
        re += " S"+(x-wb)+","+y+","+x+","+y;
    }
    if(by)
        re += "L"+i*w+","+by;
    return re;
}

上面的方法可以通过参数构建一个波浪线并向下填充,其中w是波长、h是波幅、by是向下填充的量。

然后我们要在界面中添加波浪,这里我添加了三个波浪var clip = back.use();
g.appendChild(clip);

var gz = g.add("g");

gz.clip(clip);
pts.push(gz.add("path",{fill:"rgba(255,255,255,0.15)",w:60,h:0.3,base:1,transform:"translate(0,350)"}));
pts.push(gz.add("path",{fill:"rgba(255,255,255,0.15)",w:40,h:0.15,base:1,transform:"translate(0,347)"}));
pts.push(gz.add("path",{fill:"rgba(255,255,255,0.15)",w:50,h:0.15,base:0,transform:"translate(0,354)"}));

在spanle的onload中加入上述代码,首先创建一个back的引用作为遮罩,这样波浪部分不会超出播放器。 然后创建三个波浪,w、h、base是自定义参数,之后我们会解析它来让三个波浪变得不同。

接下来我们把它加入到我们获取声音信号的step方法中去。

var step = function(){
    var array =  new Uint8Array(1024);
    analyserfa.getByteFrequencyData(array);
    array = arr_avg(array) * 2;

    for(var i = 0;i < pts.length;i++){
        var trans = pts[i].transform.baseVal[0].matrix;
        trans.e -= (array/30 + 0.8)*(pts[i].getAttribute("h"))*5 + (-(-pts[i].getAttribute("base"))||0);
        if(trans.e <= -400)
            trans.e += pts[i].getAttribute("w")*2;
        pts[i].setAttribute("d",build_path(pts[i].getAttribute("w"),array*pts[i].getAttribute("h"),200));
    }
    setTimeout(step,20);
}

上面首先先将我们获取到的数组取平均值,我们暂且可以将它理解为当前音量。然后再对其加上一个合适的系数来调整音量。 之后我们循环每一个波浪,先获取它的矩阵变换对象,可以控制它的位置,,之后再对矩阵变换进行详细的说明。 matrix.e控制了这个单位的水平位移,我们一直让它变小波浪就会一直向左移动。移动的速度和波幅相关并附带我们定义的base参数, 然后再做简单的位置范围控制,不要让波浪离开可视范围。最后调用我们做好的build_path方法构建路径, 使得我们的波浪的幅度随音量变化。

上面用到了一个取数组平均值的方法,方法内容如下:

var arr_avg = function(arr){
    var re = 0;
    for(var i in arr)
        re -= arr[i];
    return -re/arr.length;
}

就这样,到目前为止我们就完成了今天的内容,其实我总共花费了一天半左右才弄好

本次成果

现在的成果例子:例子

因为要重新弄框架的原因,这个系列可能会更晚一些再继续更了。

文章为原创内容并且是个人观点和见解,如有错误或问题欢迎指出
本文的地址为 :  http://evillcg.com/blog/item/1465121268/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值