博文索引目录:
1. 引言
2. 自画像功能展示及使用说明
3. 功能实现
- 3.1 交互一——GUI界面
- 3.2 交互二——音乐播放器
- 3.2.1 播放/暂停
- 3.2.2 切歌
- 3.2.3 倍速与音量
- 3.3 交互三——动态灯光背景
- 3.3.1 普通灯光
- 3.3.2 闪烁灯光
- 3.4 交互四——闪烁会动的眼睛
- 3.5 交互五——会唱歌的嘴巴
- 3.6 交互六——根据音量互动的彩虹喇叭
- 3.7 交互七——录音功能
- 3.8 自画像其他画线代码
4. 总结
1. 引言
这一次互动媒体技术的作品是利用用p5.js实现了自己的创意自画像,因为我非常喜欢音乐,所以本次创意自画像全部围绕音乐这个主题。因为太喜欢音乐了,所以做的时候一发不可收拾啦。接下来,让我带领你们进入奇妙的音乐世界吧~启程咯!
2. 自画像功能展示及使用说明
接下来我将详细展示我的自画像各功能的交互,由于交互较多,刚进入自画像的图片我采用了静态图,而后每一个功能我都使用动态图进行展示。
初始进入界面时:
可以在左上角小字看到,我是中国90后顶尖流行歌手陈明炜,身穿燕尾服,手拿金话筒。
通过GUI界面,可以修改背景颜色、灯光颜色和灯光样式:
操作简易的音乐播放器,可以选择想要演唱的歌曲,演唱歌曲时歌名会显示在右下方。我的嘴巴在演唱时会张合,如果暂停演唱,我的嘴巴就会闭合。(GIF图显示不出声音,如果需要听声音可以加载html文件或者看文件夹中的介绍视频)
在演唱过程中还能调节音量和音速。同时还可以切歌。
我的眼睛一直闪烁着,而且眼珠会随着鼠标位置的移动而移动。
彩虹喇叭获取电脑麦克风的音量,音量越大,扩张越大。
录音功能,即按下空格键开始录音,第二次按下停止录音,第三次按下可以保存音频文件。(可重复录制和保存)
需要说明的是,由于用到了本地声音资源的加载,涉及到跨域权限的问题,在项目运行时为了能听到声音,需要进行一些配置,具体配置请参考:
js加载跨域文件报错多种解决与配置方法
3. 功能实现
- 3.1 交互一——GUI界面
p5.js的GUI界面程序学习请参考GitHub代码:p5.js—GUI
代码如下所示,先设置界面的各个选项参数,然后在setup()函数中用createGui()创建界面,再通过addGlobals()将各设置添加到GUI界面中,如果在界面中选择改变一些变量的值,那么这些变量在draw()函数中绘制就会改变,从而从GUI能够改变一些参数的值。这里需要说明的是,为了在界面中呈现中文,我的每个界面选项的变量都用了中文,但在实际编程中还是不建议采用这种方法,虽然能运行,但太不规范了。
//界面
var gui;
//调整衣服、灯光颜色、灯光样式
var 背景颜色 = [255,168,211];
var 灯光颜色 = [255,0,0];
var 灯光样式 = ['点阵','闪动点阵','闪动方阵'];
//曲目选择栏
var 演唱曲目 = ['无','《我的名字》','《喜欢你》','《太空》','《Shape of you》','《玫瑰少年》'];
//音量
var 音量 =0.5;
//速度
var 速度=['1.0倍速','0.5倍速','2.0倍速'],speed;
//播放/暂停
var 是否开唱=['演唱','暂停'];
// 函数setup() : 准备阶段
function setup()
{
createCanvas(windowWidth, windowHeight);
background(背景颜色);
// 创建GUI界面
gui = createGui('中国90后顶尖流行歌手:陈明炜');
colorMode(RGB, 255);
//滑条最小、最大值和步长
sliderRange(0.0, 1.0, 0.1);
//为界面增加各选项
gui.addGlobals('背景颜色', '灯光颜色','灯光样式','演唱曲目','音量','速度','是否开唱');
......//其他代码
}
- 3.2 交互二——音乐播放器
在GUI界面中,一个重要的实现就是简易音乐播放器,它可以播放音乐,可以暂停或者继续播放,可以实现切歌功能,也可以改变倍速与音量。
- 3.2.1 播放/暂停
播放与暂停之间的切换由一个isplay变量实现,默认是不开唱的,如果界面中选择的是演唱,且演唱曲目是无,则开始播放音乐,并将isplay置为true;如果界面中选择的是暂停,就用pause()使音乐暂停,同时置isplay为false.
//默认不开唱
var isplay=false;
switch(是否开唱)
{
case '演唱':if(!isplay&&演唱曲目!='无')
{
song.play();isplay=true;}
break;
case '暂停':song.pause();isplay=false;
break;
}
- 3.2.2 切歌
切歌功能其实夹带在普通播放功能下,每帧通过判断当前所选择的演唱曲目是什么来进行操作,如果是“无”,就停止播放;如果是其他曲目,则先让原来的音乐暂停,再重新创建一个audio,最后让它自动播放。这里最重要的是一个条件判断,即当前演唱曲目与上一帧的曲目是否相同,如果相同,则不切换,只有不同时才代表切歌了。
//歌曲变量
var song;
//上一帧的曲目
var oldsong;
function setup()
{
......//其他代码
song = createAudio();
......//其他代码
}
// 函数draw():作画阶段
function draw()
{
......//其他代码
//更新当前所选的音乐
switch(演唱曲目)
{
case '无':
song.stop();
isplay=false;break;
case '《我的名字》':
if(演唱曲目!=oldsong)
{
song.pause();
song = createAudio('../music/我的名字.mp3');
song.autoplay(true);
}break;
case '《喜欢你》':
if(演唱曲目!=oldsong)
{
song.pause();
song = createAudio('../music/喜欢你.mp3');
song.autoplay(true);
}break;
case '《太空》':
if(演唱曲目!=oldsong)
{
song.pause();
song = createAudio('../music/太空.mp3');
song.autoplay(true);
}break;
case '《Shape of you》':
if(演唱曲目!=oldsong)
{
song.pause();
song = createAudio('../music/Shape of you.mp3');
song.autoplay(true);
}break;
case '《玫瑰少年》':
if(演唱曲目!=oldsong)
{
song.pause();
song = createAudio('../music/玫瑰少年.mp3');
song.autoplay(true);
}break;
}
oldsong=演唱曲目;
......//其他代码
- 3.2.3 倍速与音量
倍速与音量的设置也是非常简单,只需获取相应的值,用volume()与speed()进行设置即可。
//调整播放速度
switch(速度)
{
case '0.5倍速':speed=0.5;break;
case '1.0倍速':speed=1.0;break;
case '2.0倍速':speed=2.0;break;
}
song.volume(音量);
song.speed(speed);
- 3.3 交互三——动态灯光背景
这里的动态灯光效果用到了上一次互动媒体作业中我所临摹的灯光效果图,改进了参数以后的结果就是本次演示的结果,具体变换规律与数学原理请参考我的上一篇博文:
互动媒体技术——基于p5.js实现动态图形临摹与拓展:炫彩光影的千变万化!
- 3.3.1 普通灯光
这是原来的临摹图,灯光的中心在中心(200,200)处,本作品中只需将中心改到(windowWidth/2,windowHeight/2)处,并修改各区域所对应直线的斜率判断即可。
代码如下:
// 函数draw():作画阶段
function draw()
{
//屏幕中心点坐标
var xcen=windowWidth/2;
var ycen=windowHeight/2;
//程序运行的时间(单位:秒)
t=millis()/1000;
......//其他代码
//画8*8的点阵
for(i=0;i<8;i++)
for(j=0;j<8;j++)
{
fill(灯光颜色); stroke(灯光颜色);
var x=xpos+i*windowWidth/8; //实际画的时候点的x坐标
var y=(t*78)%windowHeight+ypos+j*windowHeight/8; //实际画的时候点的y坐标
//如果点运动到画布下界,则从上界开始重新往下运动
if(y>=windowHeight)
y-=windowHeight;
//找直线与边界的交点坐标
var linex,liney; //交点的x、y坐标
//区域1
if ( x<xcen && x>xcen/ycen*y )
{
linex=(xcen-x)/(y-ycen)*y+x;
liney=0;
}
//区域2
else if( x<xcen && x<=(windowHeight-y)*xcen/(windowHeight-ycen))
{
linex=0;
liney=(ycen-y)/(x-xcen)*x+y;
}
//区域3
else if ( x<xcen && x>(windowHeight-y)*xcen/(windowHeight-ycen))
{
linex=(xcen-x)/(y-ycen)*(y-windowHeight)+x;
liney=windowHeight;
}
//区域4
else if(x>xcen && x<(windowWidth-xcen)/(windowHeight-ycen)*(y-windowHeight)+windowHeight)
{
linex=(xcen-x)/(y-ycen)*(y-windowHeight)+x;
liney=windowHeight;
}
//区域5
else if ( x>xcen && x<=(xcen-windowWidth)/ycen*y+windowHeight)
{
linex=(x-xcen)/(ycen-y)*y+x;
liney=0;
}
//区域6
else
{
linex=windowWidth;
liney=(ycen-y)/(xcen-x)*(windowWidth-x)+y;
}
var times; //重复次数
switch(i) //每一列的“灯光”粗细不同
{
case 0: times=3;break;
case 1: times=5;break;
case 2: times=10;break;
case 3: times=