您的位置:首页 > 其它

音频引擎FMOD学习记录02:控制暂停/继续,调节音量,设置声效

2015-02-01 21:45 856 查看
这是本系列的第二篇,本文针对上一篇的入门示例进行了简单扩展。

入门示例(第一篇)戳这里http://blog.csdn.net/fengyhack/article/details/43318575

扩展内容包括:

1.控制暂停/继续

2.调节音量大小

3.激活/关闭声音特效

首先贴几张运行时截图吧

初始状态:播放中,音量50%,未开启任何特效



按下按键'P'暂停播放



暂停状态时再按'P'继续播放

每按一次'A'/'B'音量增加/减少10%,按4次'A'增加到90%



按下‘E'开启回声效果,按下'D'开启扭曲(类似“破音”)效果

其他特效包括OSCILLATOR,FLANGE, CHORUS, CONVOLUTIONREVERB等

本示例只提供ECHO和DISTORTION两种,其他类似。

当前状态:播放中,音量40%,已开启回声与扭曲效果



如需取消刚才设置的特效,只需再次按下'E'或'D'

按下'Q'键,退出播放循环



下面将源代码贴上来然后做一个简单分析(代码注释比较详细呢^_^)

#include <fmod.hpp> // FMOD_...
#include <stdio.h>
#include <stdlib.h> // system()
#include <ctype.h> // isprint()
#pragma comment(lib,"fmod_vc.lib") // FMOD_xxx...
#pragma warning(disable:4996)

int main(void)
{
/*
下述的双冒号::表示全局作用域
这样做是为了区分系统system与FMOD::System system
参数color: 前景色/背景色
参数title: 标题
*/
::system("color 2e");
::system("title Simple FMOD demo CREATED by fengyhack");

const char* fileName = "1.mp3";
float volume = 0.5f;  // 初始音量50%

FMOD::System* system = NULL;
FMOD::Sound* sound = NULL;
FMOD::Channel* channel = NULL;
FMOD::DSP* dspEcho = NULL;  // 回声
FMOD::DSP* dspDisto = NULL; // 扭曲
System_Create(&system);
system->init(10, FMOD_INIT_NORMAL, NULL); // 第一个参数10表示最多10个混音
system->createSound(fileName, FMOD_LOOP_NORMAL | FMOD_2D, NULL, &sound);
system->createDSPByType(FMOD_DSP_TYPE_ECHO, &dspEcho);
system->createDSPByType(FMOD_DSP_TYPE_DISTORTION, &dspDisto);

/*
为什么在初步设置前先不要播放声音?
下面的playSound()函数第3个参数true表示"暂停"状态
在设置完毕后再恢复"播放"状态,这种设置是必要的!!!
如果不这样做,那么在设置自定义状态之前
系统就已经按照默认状态开始播放了(这不是我们想要的)
*/
system->playSound(sound, NULL, true, &channel);

// 现在设置初始状态如音量等
channel->setVolume(volume);
dspEcho->setBypass(true);
dspDisto->setBypass(true);
channel->addDSP(0, dspEcho);
channel->addDSP(0, dspDisto);
/*
在设置了音量、添加声效之后再打开"播放"开关
setPaused(false)表示取消刚才的"暂停"状态
这样系统一开始播放时就是按照我们之前做的自定义设置来进行的
*/
channel->setPaused(false);

char key = 0;
bool paused = false;
bool dsp_echo = false;
bool dsp_disto = false;
while (true)
{
/*
这个循环是为了让主函数永不结束(除非输入'Q'键)
这样FMOD就有机会继续执行任务(播放声音)
否则主函数会继续执行下一语句,直接退出
实际情况不应该是这样,这里仅仅作为一个示例罢了
实际情况应该是有一个前台任务在执行,在后台播放声音
*/

// !!!!!!!!!! 请务必在每一帧(frmae)中执行update()
system->update();

::system("cls"); // 清屏
printf("------------ CMMOAND ------------\n");
if (paused) // 暂停或继续
{
printf("| P/p: resume\n");
}
else
{
printf("| P/p: pause\n");
}
if (dsp_echo) // 回声效果
{
printf("| E/e: disable echo effect\n");
}
else
{
printf("| E/e: enable echo effect\n");
}
if (dsp_disto)  // 扭曲("破音")
{
printf("| D/d: disable distortion\n");
}
else
{
printf("| D/d: enable distortion\n");
}
printf("| ---- Sound vloume: %.2f\n", volume);
printf("| A/a: volume +0.1 (max 1.0)\n");  // 音量增10%
printf("| B/b: vloume -0.1 (min 0.1)\n");  // 音量减10%
printf("| Q/q: stop and quit\n");  // 退出
printf("---------------------------------\n");
printf("Input your command:");

key = getchar();
if (isprint(key)) // 是否为可打印字符
{
/*
再次执行getchar()以“吃掉”输入字符之后的回车符
例如输入 X <ENTER>
那么key=X然后吃掉<ENTER>
如果不这么做,下一次循环执行key=getchar()
结果为key=<ENTER> ('\n')
*/
getchar();
}

if (key == 'q' || key == 'Q') break;

switch (key)
{
case 'P':
case 'p':
/*
如何设置get和set的先后顺序?
与update()有什么关系?
*/
channel->setPaused(!paused);
channel->getPaused(&paused);
break;
case 'E':
case 'e':
dspEcho->getBypass(&dsp_echo);
dspEcho->setBypass(!dsp_echo);
break;
case 'D':
case 'd':
dspDisto->getBypass(&dsp_disto);
dspDisto->setBypass(!dsp_disto);
break;
case 'A':
case 'a':
volume += 0.1f;
if (volume > 1.0) volume = 1.0f;
channel->setVolume(volume);
break;
case 'B':
case 'b':
volume -= 0.1f;
if (volume < 0.1) volume = 0.1f;
channel->setVolume(volume);
break;
default:
break;
}
}

sound->release();
system->close();

::system("cls");
::system("color 2f");
printf("====================================\n");
printf("= Copyleft (LF) 2015, fengyhack\n");
printf("= For more details, see\n");
printf("= http://blog.csdn.net/fengyhack\n"); printf("= Or you can contact me by\n");
printf("= Email: fengyhack@163.com\n");
printf("====================================\n");

printf("Press ENTER to exit the program...");
getchar();
return 0;
}

注意!!!

因为我们在程序中创建了一个FMOD::System类型变量*system

二这个变量的名字取得“不好”,因为它和系统函数system()冲突了

为了解决这个麻烦,最好将变量取为别的名字,例如fmodSystem等

其次,代码中的输出提示为英文,注释为中文,这种风格也不太好

但是注释是新手写给新手看的,因此采用中文(说白了就是鄙人英文不太好||$_$)

本文原创,博文地址

http://blog.csdn.net/fengyhack/article/details/43375857
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: