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

这是本系列的第二篇,本文针对上一篇的入门示例进行了简单扩展。

入门示例(第一篇)戳这里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: [email protected]\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

猜你喜欢

转载自blog.csdn.net/von_Ryan_Hack/article/details/43375857