Sound.js是辅助pixi.js的一个微型库,允许你为游戏和交互式应用程序加载、播放和生成音效和音乐。它非常小——不到800行代码,没有依赖关系。
它的核心是由两个简短独立的功能组成的:makeSound和soundEffect。makeSound功能帮助您加载和播放声音文件(mp3、wav、ogg和webm)。soundEffect函数帮助您从纯代码中生成各种各样的声音和音乐效果。这两个函数是完全模块化的,没有依赖关系,因此您可以将它们的任何部分复制并粘贴到您自己的项目中。事实上,你可以在不到150行的代码中,通过单独使用soundEffect函数,为你的项目创建所有的声音和音乐。
如果需要,sound.js还有一个sounds对象,它有一个有用的load方法,可以很容易地加载和访问声音文件。
安装配置
只需要链接到带有< script >标记的sound.js文件:
<script src="sound.js"></script>
或者只是将sound.js文件中您需要的任何函数复制/粘贴到您自己的项目代码中。
加载声音文件
加载声音文件的最佳方式是使用sounds
对象的load
方法。在sound.load
方法的数组中列出每个声音文件的路径和名称。然后给sounds.whenLoaded
分配一个回调函数。
//加载音效 sounds.load([ "sounds/shoot.wav", "sounds/music.wav", "sounds/bounce.mp3" ]); //设置加载音效文件的回调函数 //每次加载一个文件,就像PIXI.js加载资源文件一样 sounds.onProgress = function (progress, res) { console.log('Total ' + progress + ' file(s) loaded.'); console.log('File ' + res.url + ' just finished loading.'); }; //音效何时运行 sounds.whenLoaded = setup;
声音加载后,setup
功能将运行。使用setup
功能初始化您的声音。
function setup() { //此处初始化声音 }
当然,你可以给这个函数取任何你喜欢的名字,不是非要叫setup。
初始化加载的声音
使用sounds.load
方法加载声音文件后,您可以将其作为sounds
对象的属性进行访问,如下所示:
sounds["sounds/music.wav"]
为变量赋你想要使用的声音的值,方便以后引用:
var shoot = sounds["sounds/shoot.wav"], music = sounds["sounds/music.wav"], bounce = sounds["sounds/bounce.mp3"];
你现在有三个声音对象,shoot
,music
和bounce
,你可以播放和控制。
播放和控制加载的声音
您可以播放、暂停、循环和重新启动声音,以及设置它们的音量和扬声器声相设置。你也可以淡入或淡出声音。方法如下:
//播放声音 music.play(); //声音循环 music.loop = true //设置音量 //1是全音量,2是双倍音量,0.5是半音量,等等。 music.volume = 0.7; //暂停声音。要恢复暂停的声音,请再次调用`play` music.pause(); //从特定时间开始播放(秒) music.playFrom(10) //-1是全左扬声器,0是中间扬声器,1是全右扬声器 //扬声器 music.pan = -0.8; //在3秒内淡出声音 music.fadeOut(3); //在2秒内淡入声音 music.fadeIn(2); //在1秒钟内将声音淡化到“0.3”的音量 music.fade(0.3, 1);
更改回放速率
使用playbackRate
来更改声音播放的速度。值为0.5将使声音以半速播放。值为2将使它以双倍速度播放。1是正常速度。
music.playbackRate = 0.5
改变声音的回放速度不会影响其音高。
添加回声
使用setEcho
方法设置声音的可选回声效果。setEcho
有三个参数:delay
、feedback
和filter
。
bounce.setEcho(0.2,0.3,1000);
delay、feedback是以秒为单位的时间。delay决定声音重复之前需要多长时间。feedback决定了每次重复的强度——feedback值越高,回声持续的时间越长。filter是一个可选的赫兹值,用于滤除高于该值的频率。它通过每次重复来改变回声的音调,以获得更加有机的效果。将filter设置为0以禁用它。如果您需要关闭声音的回声效果,请将声音的echo
属性设置为false
bounce.echo = false
添加混响
使用setReverb
设置声音的混响效果。setReverb
接受3个参数:duration
、decay
和reverse
。
music.setReverb(2,2,false);
duration、decay是决定混响效果有多明显的时间,以秒为单位。给他们大数值来模拟大空间,给他们小数值来模拟小空间。第三个参数reverse是一个布尔值,它确定混响效果是否应该反转。对于正常混响设置为false,或者对于怪异的反向混响设置为true。如果以后需要禁用混响效果,请将声音的reverse属性设置为false。
这就是声音文件的工作方式。但是Sound.js也可以让你从头开始制作自己的音乐和音效。
产生音效和音乐
使用多功能soundEffect
功能,使用十三个低级别参数创建几乎无限多样的音效。这里有一个使用它的模型,包括每个参数的描述。
soundEffect( frequencyValue, //声音的频率音调,单位为赫兹 attack, //淡入声音的时间,以秒为单位 decay, //声音消失的时间,以秒为单位 type, //波形类型:“正弦”、“三角形”、“正方形”、“锯齿”:"sine", "triangle", "square", "sawtooth" volumeValue, //声音的最大音量 panValue, //扬声器声相。左:-1,中间:0,右:1 wait, //播放声音前等待的时间(秒) pitchBendAmount, //将声音的音调降下来的赫兹数 reverse, //如果“反向”为真,音高将向上弯曲 randomValue, //一个范围,单位为赫兹,在此范围内可以随机化音高 dissonance, //以赫兹为单位的值。在目标音高上下创建2个不和谐的频率 echo, //一个数组:[延迟时间秒,反馈时间秒,过滤值秒] reverb, //一个数组:[持续时间秒,十亿分之一秒,反向] timeout //声音的最大持续时间,以秒为单位 );
(注意:由于浏览器的特性,音效混响目前是实验性的。在未来,它可能会稳定下来,但在此之前,使用它会给你带来危险!)使用soundEffect函数的策略是修改所有这些参数,并为游戏开发自己的自定义音效库。把它想象成一个巨大的音板,上面有14个彩色闪烁的拨号盘,你可以玩玩。把自己想象成一个疯狂的科学家,14是你的幸运数字!
(注意:最后一个参数timeout是声音的最大持续时间。它的默认值是2 (2秒),这对于大多数声音效果
来说通常是足够长的,但是如果您要创建更长的声音,请将其设置为更高的数字。)
译者注:在调试这14个参数的时候,注意调试幅度小一些,因为播放一些极端参数的音效会伤害你电脑的扬声器!亲测血泪史……
射击音
这里有一个如何使用soundEffect
功能来创建一个典型的激光射击声音的例子。
function shootSound() { soundEffect( 1046.5, //frequency 0, //attack 0.3, //decay "sawtooth", //waveform 1, //Volume -0.8, //pan 0, //wait before playing 1200, //pitch bend amount false, //reverse bend 0, //random pitch range 25, //dissonance [0.2, 0.2, 2000], //echo array: [delay, feedback, filter] undefined //reverb array: [duration, decay, reverse?] ); }
“sawtooth”波形设置使声音变得尖锐刺耳。音高pitchBendAmount是1200,这意味着声音的音高下降1200赫兹。从头到尾。这听起来就像你看过的每部科幻电影里的每一束激光。25的不协调值dissonance意味着两个额外的泛音被添加到声音中,高于和低于主频率25赫兹。那些额外的弦外之音给音调增加了一种尖锐的复杂性。
因为soundEffect函数被封装在一个自定义的shootSound函数中,所以您可以在应用程序代码中随时
播放该效果,如下所示:
shootSound();
它将立即播放。
跳跃声
让我们看看另一个例子。这里有一个jumpSound
函数,它可以产生一个典型的平台游戏角色跳跃声音。
function jumpSound() { soundEffect( 523.25, //frequency 0.05, //attack 0.2, //decay "sine", //waveform 3, //volume 0.8, //pan 0, //wait before playing 600, //pitch bend amount true, //reverse 100, //random pitch range 0, //dissonance undefined, //echo array: [delay, feedback, filter] undefined //reverb array: [duration, decay, reverse?] ); }
jumpSound的jumpSound为0.05,这意味着声音会很快淡入。它太快了,以至于你听不到,但是它稍微减弱了声音的开始。reverse的值为true,这意味着音调向上弯曲而不是向下。(这很有意义,因为跳跃的角色会向上跳。)randomValue是100。这意味着音调将在目标频率上下100赫兹的范围内随机变化,因此声音的音调每次都略有不同。这增加了声音的有机趣味性,让游戏世界充满活力。
爆炸声
你可以通过调整这些相同的参数来创造一个完全不同的爆炸音效。
function explosionSound() { soundEffect( 16, //frequency 0, //attack 1, //decay "sawtooth", //waveform 1, //volume 0, //pan 0, //wait before playing 0, //pitch bend amount false, //reverse 0, //random pitch range 50, //dissonance undefined, //echo array: [delay, feedback, filter] undefined //reverb array: [duration, decay, reverse?] ); }
制作音乐
但这不仅仅是为了音效!您可以使用soundEffect
创建音符,并以设定的间隔播放它们。这里有一个叫做bonusSound
的函数,它在一个升调序列中演奏三个音符(D、A和高D)。这是典型的音乐主题,当游戏角色获得一些奖励点数时,你可能会听到,比如拿起星星或硬币。(当你听到这个声音时,你可能会想起1985年!)
译者注:说起85年,那必然是超级玛丽 😮
function bonusSound() { //D soundEffect(587.33, 0, 0.2, "square", 1, 0, 0); //A soundEffect(880, 0, 0.2, "square", 1, 0, 0.1); //High D soundEffect(1174.66, 0, 0.3, "square", 1, 0, 0.2); }
让它工作的关键是最后一个参数:wait值。第一个声音的wait值是0,这意味着该声音将立即播放。第二个声音的wait值是0.1,这意味着它将在延迟100毫秒后播放。最后一个声音的wait值是0.2,这将使它在200毫秒内播放。这意味着所有三个音符以100毫秒的间隔依次播放。
只需多做一点工作,你就可以使用wait参数来构建一个简单的音乐序列器,并构建你自己的迷你音乐音效库来播放音符。
高级声音加载和解码配置
(注意:这是高级的东西,你可能不需要知道!)
如果您已经在使用自己的自定义文件和资源加载系统,并且只想从预加载的音频文件生成声音对象,该怎么办?您可以借助makeSound的可选第三和第四个参数来实现这一点:
var anySound = makeSound(source, loadHandler, loadTheSound?, xhrObject);
loadTheSoun?是一个布尔值(true/false),如果为假,则阻止加载声音文件。因此,如果您正在处理一个已经加载的声音文件,请将其设置为false。
xhrObject,可选的第四个参数,是用来加载声音的XHR对象。同样,如果您使用自己的自定义资源加载系统,请提供您用来加载声音文件的XHR对象。如果您提供xhr参数,makeSound将跳过文件加载步骤(因为您已经这样做了),但仍然为您解码音频缓冲区。(注意:如果您使用另一个文件加载库加载声音文件,请确保您的声音文件是使用XHRresponseType = “arraybuffer”)
例如,您可以使用这种高级配置来解码已经使用您自己的自定义加载系统加载的声音:
var soundSprite = makeSound(source, decodeHandler.bind(this), false, xhr);
当文件完成解码后,您的自定义解码器将运行,这将告诉您文件已经完成解码。
如果您要创建多个这样的声音,请使用计数器变量来跟踪您需要解码的声音数量,以及已经解码的声音数量。当两组计数器相同时,您将知道您的所有声音文件已经完成解码,并且您可以继续应用程序的其余部分。
//这是所有声音都被解码后运行的代码 let finsihLoadingState = () = { //...继续运行应用程序... }; //计算声音文件和声音文件数量的变量 //已经解码的。如果这两个数字在 //某个时候,我们知道所有的声音都被解码了,我们 //可以调用“完成加载状态”函数 let soundsToDecode = 0, soundsDecoded = 0; //首先,创建一个我们想要检查的声音文件的列表 let soundExtensions = ["wav", "mp3", "ogg", "webm"]; //解码每个声音文件时,将运行`decodeHandler` let decodeHandler = () => { //解码后再计数1个声音 soundsDecoded += 1; //如果解码的声音与要解码的声音数量相匹配, //然后我们知道所有的声音都已经解码,我们可以调用 //` Finish LoadingState ` if (soundsToDecode === soundsDecoded) { finishLoadingState(); } }; //遍历加载程序的所有资源,寻找声音文件 Object.keys(this.loader.resources).forEach(resource => { //查找资产的文件扩展名 let extension = resource.split(".").pop(); //如果其中一个资源文件扩展名与声音文件匹配 //扩展名,那么我们知道我们有一个声音文件 if(soundExtensions.indexOf(extension) !== -1){ //再计算一个声音进行解码 soundsToDecode += 1; //为声音的“xhr”对象和“url”创建别名(其 //文件名) let xhr = this.loader.resources[resource].xhr, url = this.loader.resources[resource].url; //使用“sound.js”创建声音精灵 //`makeSound '函数。注意第四个参数是加载的 //sound的“xhr”对象。将第三个参数设置为“false” //表示“生成声音”不会尝试加载声音 //再次。当声音被解码后,“解码处理程序” //(见上文!)将被运行 let soundSprite = makeSound(url, decodeHandler.bind(this), false, xhr); //获取声音文件名 soundSprite.name = this.loader.resources[resource].name; //将声音对象添加到河西的“声音对象”对象中 this.soundObjects[soundSprite.name] = soundSprite; } }); //如果没有声音文件,我们可以跳过解码步骤 //直接调用“完成加载状态” if (soundsToDecode === 0) { finishLoadingState(); }