最近在学习声音可视化的内容,所以就试图用processing做了一下超爱的网易云音乐的动效,没想到还真的实现啦,就放上来大家一同学习学习~~。教程中借用了王菲演唱的《我和我的祖国》专辑封面作为素材,歌超好听,欢迎大家去收听呀。
我们先从看起来最简单的动感音阶这个动效进行尝试吧,未来可能还会出后续动效的小教程,欢迎关注呀。
序: 圆形唱片
首先我们要在画布中央导入专辑图片,并将专辑图片变为圆形。用过PS的同学,在此时可能很快就浮现出一个词:蒙版。我们这次用的方式就是蒙版。
首先要准备一张蒙版图片。然后将唱片图片和蒙版图片放入工程文件中,再导入程序之中。
PImage album, masking; //初始化两个图片变量,album和masking
int r = 200; //唱片圆形半径
void setup() {
size(800, 800); //设置画布
background(0); //设置背景颜色
imageMode(CENTER); //图片导入模式为中点
album = loadImage("album.jpg"); //导入album.jpg图片
masking = loadImage("masking.jpg"); //导入masking.jpg图片
album.resize(2*r, 2*r); //将图片长宽放缩为两倍半径
masking.resize(2*r, 2*r);
masking.filter(INVERT); //将蒙版反相,黑色蒙住,白色漏出
album.mask(masking); //唱片为底图,加上蒙版
}
void draw() {
translate(width/2, height/2); //将坐标原点放在画布中心
image(album, 0, 0); //绘制圆形图片
}
现在我们需要将唱片旋转起来啦。原理是将坐标轴转动起来。设定一个theta变量,每次循环增加一点。
float theta = 0.0; //唱片旋转角度
void draw() {
translate(width/2, height/2); //将坐标原点放在画布中心
rotate(theta);
image(album, 0, 0);
theta += 0.02;
}
渐变背景
旋转唱片已经实现了,我们可以再对比一下网易云音乐的效果,可以发现背景是透明渐变的。我们可以从唱片中提取颜色来实现渐变效果。
首先我们设置两个颜色变量。一个变量从唱片图片中提取颜色,另一个设置为白色,来制造渐变效果。
color c1, c2; //动效颜色
c1 = album.get(0, 0); //提取唱片中的颜色
c2 = color(360, 1, 100, 1); //白色透明
颜色从上到下为:唱片颜色 - 白 - 唱片颜色,所以我们将底图分为上下两部分。先绘制上半部分。
for (int y = -height/2; y < 0; y++) { //循环
float n = map(y, -height/2, 0, 0, 1); //0-1间取值,根据y得到映射值n
color newc = lerpColor(c1, c2, n); //渐变颜色提取,n取值为0-1
stroke(newc); //设置线的颜色
line(-width/2, y, width/2, y); //画线
}
绘制下半部分后,再得加一个透明白色正方形。
//设置渐变背景
void backGround() {
for (int y = -height/2; y < 0; y++) { //循环
float n = map(y, -height/2, 0, 0, 1); //0-1间取值,根据y得到映射值n
color newc = lerpColor(c1, c2, n); //渐变颜色提取,n取值为0-1
stroke(newc); //设置线的颜色
line(-width/2, y, width/2, y); //画线
}
for (int y = height/2; y >= 0; y--) {
float n = map(y, height/2, 0, 0, 1);
color newc = lerpColor(c1, c2, n);
stroke(newc);
line(-width/2, y, width/2, y);
}
//设置透明白色正方形
noStroke();
fill(360, 40);
rect(-width/2, -height/2, width, height);
}
音乐可视化动效:动感音阶
在绘制动效之前,我们需要导入Minim音频库。通过建立Minim对象,载入音频文件或者建立声音输入与输出。首先我们需要在“速写本 - 引用库文件 - 添加库文件”中搜索Minim点击Install。
点击“速写本 - 引用库文件 - 添加库文件 - 第三方贡献库 - Minim”我们可以得到以下几行代码。我们这次只需要最开始的一行代码。
import ddf.minim.*; //这次只用得到这行代码
import ddf.minim.analysis.*;
import ddf.minim.effects.*;
import ddf.minim.signals.*;
import ddf.minim.spi.*;
import ddf.minim.ugens.*;
一般编写音频相关的代码,需要参考下面的范例。
import ddf.minim.*;
AudioPlayer player; //建立音频播放器
Minim minim; //定义音频对象
void setup() {
minim = new Minim(this);
player = minim.loadFile("music.mp3", 1024); //调取音频文件,指定缓存的采样频率为1024
player.play(); //播放文件
}
void draw(){
}
//需要注意的是,在推出程序钱,必须关闭Minim获得的所有I/O类,然后关闭Minim范本。
void stop(){
player.close(); //关闭播放器
minim.stop(); //停止音频
super.stop();
}
我们可以通过上图看动态音效的效果,围绕圆形唱片根据音乐绘制线。这里也要用到循环。每画一条线就旋转一个角度继续画。我们旋转角度后每次都要将坐标轴重置为没有旋转的位置,所以要运用到pushMatrix();和popMatrix();
translate(width/2, height/2); //原始点到画布中央
for (int i=0; i<player.left.size(); i+=15) {
float rTheta = map(i, 0, player.left.size()-1, 0, 2*PI); //动态音效绘制线旋转的角度
pushMatrix(); //把原点数据和旋转数据放入矩阵堆栈中
rotate(rTheta); //旋转一个角度
line(0, r, 0, r + player.left.get(i)*100); //player.left.get(i)为-1 - 1,所以要乘以一个数放大
popMatrix(); //释放堆栈
}
这里我们可以看到线会往内部,会影响视觉效果,所以我们将player.left.get(i)加上绝对值,保证它能够大于0。
再将线条设置为提取的颜色就可以啦!!
其实绘制圆形图片应当有更简单高效的方法,但是奈何我试不出来/(ㄒoㄒ)/~~,希望有厉害的同学能够和我分享分享方法,十分感谢~~~。
最后附上所有的代码~~~
主代码
import ddf.minim.*;
AudioPlayer player; //建立音频播放器
Minim minim; //定义音频对象
PImage album, masking;
int r = 200; //唱片圆形半径
float albumTheta = 0.0; 坐标轴旋转角度
color c1, c2; //动效颜色
void setup() {
size(800, 800); //设置画布
colorMode(HSB, 360, 100, 100, 100);
myAlbum(); //***导入圆形唱片图片
minim = new Minim(this);
player = minim.loadFile("yunian.mp3", 1024); //调取音频文件,指定缓存的采样频率为1024
player.play(); //播放文件
}
void draw() {
translate(width/2, height/2); //将坐标原点放在画布中心
background(360); //设置背景颜色
backGround(); //***设置渐变背景
rotate(albumTheta); //坐标轴旋转
image(album, 0, 0); //绘制圆形图片
//绘制动态音效
stroke(c1); //线颜色
strokeWeight(4); //线粗
for (int i=0; i<player.left.size(); i+=6) {
float rTheta = map(i, 0, player.left.size()-1, 0, 2*PI); //旋转角度
pushMatrix(); //把原点数据和旋转数据放入矩阵堆栈中
rotate(rTheta);
line(0, r+10, 0, r + 10 + abs(player.left.get(i))*200);
popMatrix(); //释放堆栈
}
albumTheta += 0.02; //坐标轴旋转角度增加
}
void stop() {
player.close(); //关闭播放器
minim.stop(); //停止音频
super.stop();
}
myAlbum();导入圆形专辑图片
//导入圆形唱片图片
void myAlbum() {
imageMode(CENTER); //图片导入模式为中点
album = loadImage("album.jpg"); //导入album.jpg图片
masking = loadImage("masking.jpg"); //导入masking.jpg图片
album.resize(2*r, 2*r); //将图片长宽放缩为两倍半径
masking.resize(2*r, 2*r);
c1 = album.get(0, 0); //提取唱片中的颜色
c2 = color(360, 1, 100, 1); //白色透明
masking.filter(INVERT); //将蒙版反相,黑色蒙住,白色漏出
album.mask(masking); //唱片为底图,加上蒙版
}
backGround();设置渐变背景
//设置渐变背景
void backGround() {
for (int y = -height/2; y < 0; y++) { //循环
float n = map(y, -height/2, 0, 0, 1); //0-1间取值,根据y得到映射值n
color newc = lerpColor(c1, c2, n); //渐变颜色提取,n取值为0-1
stroke(newc); //设置线的颜色
line(-width/2, y, width/2, y); //画线
}
for (int y = height/2; y >= 0; y--) {
float n = map(y, height/2, 0, 0, 1);
color newc = lerpColor(c1, c2, n);
stroke(newc);
line(-width/2, y, width/2, y);
}
noStroke();
fill(360, 40);
rect(-width/2, -height/2, width, height);
}