36.Flight Music
As well as being useful for working with triangles, the sine function can also be used for generating sounds. If you take an ever increasing number and pass it to the sine function, you get back this graph:
正弦函数不仅对处理三角形非常实用,它也可以被用于生成声音。倘若你将一个不断增加的数字序列作为参数传递给正弦函数,你将得到如下图像:
If you treat this as a sound wave, then you get a dull tone that we recognise as an electronic beep, since it’s used so often by electronic devices. Here’s an example of a sine wave on youtube.
如果你将其视为一个声音波形的话,你将得到一个沉闷的音调,就像我们熟知的电子蜂鸣声一样,因为它经常被电子设备所使用。这儿是youtube网站的一个正弦波示例。
We saw in our last post that for our monkeys-throwing-bananas game, we can work out how long the banana will be in flight for. We can use this information to construct a sound that’s exactly as long as the time the banana will spend in the air:
我们在上一篇关于猴子扔香蕉游戏的帖子中了解到,我们可以计算出香蕉将要飞行多长时间。我们可以利用这个信息来创建一个声音,它的长度完全等同于香蕉在空中飞行的时间:
double lengthInSecs = timePerFrame * (impactTime - 5);
short[] soundWave = new short[(int)(lengthInSecs * 44000.0)];
The sound will play at 44000 samples per second, so we need to multiply the number of seconds by 44000 to get the number of samples. The length of the sound in seconds will be the time it takes to execute one frame in Greenfoot, multiplied by the number of frames before impact (“impactTime”, above — which we saw how to calculate last post). I subtract 5 frames off the total, to make sure that the sound is finished before we need to play the impact sound.
声音在每秒钟将会播放个44000样本,于是我们需要用44000乘以秒数来获取样本的数量。在greenfoot的每一帧中,声音的长度(以秒为单位)将会作为时间值去乘以碰撞之前经过的帧的数量(就是“impactTime”,我们在上一篇帖子中知道了如何去计算)。我在总数上减去了5帧,以便确保飞行声音在我们需要播放碰撞声音前结束。
Just playing a simple sine wave for the sound of the flight is dull and incongruous. We can greatly improve the suitability of the sound if we vary the frequency of the sine wave during the flight. If we change the frequency in proportion to the height of the banana, we get a sound that starts low, increases in pitch as the banana reaches the apex of its flight, then decreases again as it comes back down. This creates a more familiar flight sound (such as you hear in cartoons). The gist is something like this — the sine wave gets more frequent (the peaks get closer together, horizontally), the higher the projectile is in the air:
仅仅播放一个简单的正弦波作为飞行的声音是单调的不和谐的。如果我们在飞行过程中改变正弦波的频率,则可以几大地改善声音的适应性。如果我们按照香蕉高度的比例来改变声波频率,我们将得到这样一个声音:开始时较低,然后逐渐升高音调直到香蕉飞行高度达到顶峰,接下来随着香蕉下落而重新降低音调。这将创建一个更加熟悉的飞行声音(正如我们在动画片中听到的)。大意是这样的—抛射物在空中越高,声音正弦波则越紧密(在水平方向波峰变得更加靠近了):
What this means is that instead of using a steadily-increasing number to feed to the sine wave function, you increase the number faster when the banana is higher. Here’s some code that does just that, using the height calculation from our previous post:
这意味着你不能使用一个稳定增长的数字作为参数传递给正弦函数,而是当香蕉变得高一些时要让数字增加得快一些。这里有一些代码实现这个功能,使用到了前一篇帖子中的高度计算代码:
double a = 0;
for (int i = 0; i < soundWave.length; i++)
{
// t is the frame number:
double t = (double)i / (timePerFrame * 44000.0);
a += 0.25 + (t * vy - 0.5 * g * t * (t - 1)) / 3200.0;
soundWave[i] = (short)(8000 * Math.sin(a));
}
There are three constants in this code that I fiddled with until they sounded right (literally!). The 0.25 and the 3200 on the middle line of the loop adjust the amount that the height of the projectile affects the frequency of the sine wave. The 8000 in the last line is simply the volume of the sound (the height of the sine wave).
这段代码中有三个常量,我不断的调整它们的值,直到它们听起来比较正确。循环代码中间一行的0.25和3200用来调节抛射物高度影响正弦波频率的量。最后一行的8000只是声音的音量(即正弦波的高)。
You can play with the finished game (including a couple of simple AI players) over on the Greenfoot site. Don’t forget to listen to the flight sounds!
你可以到greenfoot官网玩以一下完成后的游戏(包括了一些简单的AI玩家)。不要忘了听一下飞行音乐哦!