赞
踩
目录
由于瘟疫肆虐,我在家中宅了好几天,简直不能太无聊。一个偶然的机会,我在抖音上面发现了一个类似钢琴的APP,然后就试着用App inventor做一个可以实现音乐功能的软件,暂且可以把它叫做木琴。经过3次的修改,最终成了下面的样子。让我们来一起看看吧!
基本界面如下图所示:
功能介绍:
记得上次做的是蓝牙相关的实践,用的是汉语的界面,这次尝试用英文试一下!
首先创建前两个键,用按钮来实现:
1. 从面板(palette)的user interface组中拖出一个按钮。
BackgroundColor属性:为红色;
Text属性:为“C”;
Width属性:为“Fill parent”,使其占满屏幕;
2. 重复上述步骤创建第二个按钮,名为Button2,放在Button1下面。Width及Height属性值同Button1,但BackgroundColor属性设为红色,Text属性设置为“D”。如下图:
3.其他键位的设计完全按照上面的步骤来实现,在此就不一一说明了。
木琴不能没有声音,所以我创建一个Sound组件,名字为Sound1。MinimumInterval(最小间隔)属性设置为0(默认值为500毫秒)。这可以让我们的演奏要多快有多快,而不必等半秒钟(500毫秒)。
下载1.wav和2.wav,并加载到项目中,注意这里的声音文件必须保持原有文件名。
当某个按钮被点击时,用程序来实现播放声音的行为,即:如果Button1被点击,则播放1.wav,如果Button2被点击,播放2.wav。
若要切换到块编辑器,如下图所示,进行以下设置:
点击按钮时播放声音
对Button2进行同样设置,如图(只改了文件名),代码几乎完全重复。
重复的代码提示我们最好是创建一个过程。用join块将数字(如1)与文本“.wav”连接起来,创造出正规的文件名(如“1.wav”)。下面是创建这个过程的步骤:
1. 在块编辑器中打开Procedures抽屉,拖出“to procedure”块;
2. 单击procedure将过程名改为playNote;
3. 点击procedure块左上角的蓝色方块呼出内部组件,将一个input x块插入“inputs”块;
4. 将input x块中的x改为number;
5. 将set Sound1.Source to块从Button1.Click事件处理程序中拖出,放在PlayNote过程内“do”的右边,Sound1.Play块也将随之移动;
6. 将1.wav块拖入垃圾桶;
7. 从Text抽屉中拖出join块放到set Sound1.Source to的插槽内;
8. 将鼠标悬停在playNote的number参数上,呼出并拖动get number块,并将其放入join块的第一个插槽中;
9. 从Text抽屉中拖出空文本块,放在join块的第二个插槽中;
现在,当Button1被点击时,过程PlayNote将以数字1为参数被调用。该过程将Sound1.Source属性设为“1.wav”,并播放该声音。
创建一个Button2.Click块,调用参数为2的PlayNote过程。(可以复制现有的PlayNote块,将其移动到Button2.Click块内,并将参数更改为2;也可以复制整个Button1.Click块,然后将Button1改为Button2,再将参数1改为2。)程序如图所示。
图 创建一个过程来演奏音符
此时在手机上测试程序并不能成功:第一次按键时,弹出错误提示:“Error 703:Unable to play 1.wav”(不能播放1.wav);第二次再按同一个键时,才听到声音。
原因:Android系统是在程序运行时才加载声音文件(只需加载一次),加载过程需要一点时间。第一次按键,当call Sound1 play块开始执行时,set Sound1.Source to块的加载任务尚未完成,因此系统给出错误提示;等到第二次按键时,声音文件已经加载完成,因此可以正常播放。
解决方法:直到程序启动之后,我们也没有对Sound1.Source进行设置,因此没有对声音做初始化。我们必须在程序启动时直接加载声音文件,如图所示。
图 在应用启动时加载声音文件
两个按钮已经实现了演奏音符的功能,现在需要回到组件设计器,加载其余六个声音文件3.wav、4.wav、5.wav、6.wav、7.wav和8.wav,并添加其余六个音符。首先创建六个新Button组件,重复此前的步骤,
图 在组件设计器中放置其余的声音按钮
回到块编辑器中,为每个新按钮创建Click块并以相应的参数调用PlayNote过程。同样,在Screen.Initialize中加载新的声音文件,如图所示。
对按钮单击事件编程,使得键盘与音调相对应
为了实现回放功能,需要记录弹奏的音符并加以保存。除了要记录弹奏的音高(声音文件),还要记录两个音符之间的时间长度,否则将无法表现两个连续快弹音符与两个间隔10秒的音符之间的差别。
实现原理:维护两个列表,每弹奏一个音符,两个列表中都会各自添加一条记录:
在设计器中添加一个Clock组件及“播放”和“重置”按钮,按钮放在HorizontalArrangement中:
1. 拖入一个Clock组件,它将出现在“不可见组件”区域,取消勾选TimerEnabled属性。
2. 从layout组中拖出一个HorizontalArrangement组件放在按钮下面,Width属性设为“Fill parent”;
3. 从User Interface组中拖动一个按钮,改名为PlayButton,Text属性设为“播放”;
4. 拖出另一个按钮并放在PlayButton右侧,改名为ResetButton,Text属性设为“重置”。
图 记录并回放声音的组件被添加到设计器中
实现原理:维护两个列表:notes与times,每次用户按下一个按钮,就向列表中添加一项:
1. 从Variables抽屉中拖出一个initialize global name to块来定义一个新的变量;
2. 单击“name”将变量命名为“notes”;
3. 打开Lists抽屉,拖动一个make a list块,将其放置在变量notes的插槽中;
这样就定义了一个名为“notes”的空列表。重复上述步骤定义另一个变量,命名为“times”。块的样子如图所示。
图 设置变量来记录音符
每演奏一个音符,需要保存两项数据:声音文件名(保存到notes列表),以及演奏瞬间的时刻(保存到times列表)。用Clock1.Now块来记录时刻,它返回当前时刻的时间值,精确到毫秒。这些数据可以通过Sound1.Source和Clock1.Now块获得,将分别被添加到notes及times列表中。
添加一个Sound1.Vibrate块,通过振动来告知用户按键生效了。实现逻辑如下:
为用户的“重置”操作提供反馈
实现原理:
变量count用来跟踪notes列表中当前正在播放的音符的索引(位置);
新过程 PlayBackNote,用来播放当前音符,并移动到下一个音符;
图 回放被记录下来的音符
自我调用-----数学递归
1. 在第一次调用PlayBackNote时,count= 1:
Sound1.Source被设置为在notes中的第1项,即1.wav;
调用Sound1.Play,播放1.wav;
2. 第二次调用PlayBackNote时,count=2:
Sound1.Source被设置为notes中的第2项,即3.wav;
调用Sound1.Play,播放3.wav;
3. 第三次调用PlayBackNote时,count=3:
Sound1.Source被设置为notes中的第3项,即6.wav;
调用Sound1.Play,播放6.wav;
实现原理:
延迟的设定与两个音符之间的时间差有关,用clock来为这个时间差计时。创建Clock1.Timer事件并编写事件处理程序,来说明计时结束时将发生的事情。
图 在音符之间加入延迟
块的功能
现在假设两个列表中记录了以下内容:
notes:1.wav,3.wav,6.wav
如图所示,在PlayButton.Click中设置count为1,并调用PlayBackNote。
1. 第一次调用PlayBackNote时,count= 1:
Sound1.Source被设置为notes中的第1项,即“1.wav”;
调用Sound1.Play播放1.wav;
Clock1.Timer开始计时,间隔1秒之后,计时结束,定时器暂时禁用,并调用PlayBackNote。
2. 第二次调用PlayBackNote时,count= 2 :
Sound1.Source被设置为notes中的第2项,即“3.wav”;
调用Sound1.Play播放3.wav;
Clock1.Timer计时开始,间隔3秒之后,定时器暂时禁用,并调用PlayBackNote。
3. 第三次调用PlayBackNote时,count= 3 :
Sound1.Source被设置为notes中的第3项,即“6.wav”;
调用Sound1.Play来播放6.wav;
本次实践的最大收获是:编写一个能自我调用的过程不仅是可能的,有时也是必要的。递归就可以实现,在编写递归过程时,一定要确保为程序的退出设定一个基本条件,否则程序将陷入无限循环。好了今天就分享的这里吧,有问题可以通过下方留言。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。