分享
 
 
 

掌上游戏机开发指南GBA探索日记(8)

王朝other·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

有了前几篇关于中断和Timer,DMA传输的介绍后,现在我们可以进入GBA声音播放的部分了.GBA一共有6个声道,从Sound 1-4加上两个Direct Sound A(and)B.GBA中对声音的播放应该是最困难的部分.至少我是这么认为,因为这里面涉及到太多的技术细节.所以我在这里只能告诉大家怎么在GBA中播放声音,至于内部的细节,我就无可奉告了.

如果你手上有任天堂的官方开发包AgbLib3.0,那么看看AgbLib3.0中有关声音的播放部分.任天堂公司在官方开发包里提供了个mediaPlayer2000来实现GBA声音的播放.那个mediaPlayer2000是个十分复杂的东西,需要配置很复杂的ini配置文件.光是看配置ini文件的帮助文件都够我们看几天了.为此,在官方开发包里面还专门附加了mediaPlyaer2000的帮助部分.不过最大的问题是,它的mediaPlayer2000播放声音的库文件无法在一般的GCC下在编译.或许是我所得到的官方开发包不完整(只有个AgbLib,GCC是另外自己搭配的),总之,那个mediaPlayer2000是不能用了.

前面的都是以官方开发包为基础而写的,内容是十分贴近AgbLib.但是这一节由于官方开发包里的mediaPlayer2000无法使用,所以我们就必须另开辟一条道路来走了.还好,这条路我已经走通了,大家也可以顺着这个方向前进.

这一部分关于声音播放的内容你也可以跳过前面的理论讲解.在后面我会直接把所有的声音播放的代码完整得公布在下一篇的探索日记中.如果你觉得麻烦,也可以直接看后面怎么使用这些播放库函数就可以了.

我们首先看看这张有关声道的内部结构图:

这里我们看到,Sound 1-4跟Direct Sound A和B有着不同的播放渠道.Direct Sound播放是需要通过DMA实现声音数据的传输.而传输速度就必须由Timer来控制.这也就是为什么我要在前面几节讲解DMA和Timer了.

我们这里主要看Direct Sound的声音播放.因为它的功能是最强大的.而Sound 1-4各个播放的声音数据都不同,而且使用起来很复杂,所以这里不讲了,如果你有兴趣,可以参考官方开发包.

Direct Sounds A and B 播放的是8位线性的音频数据

它们的数据入口就是两个寄存器SGFIFOA(B)_L和SGFIFOA(B)_H

每个Direct Sound一次可以接受4个字节的数据.

然后我们看看声音播放的控制寄存器

很复杂吧.其实我已经不只一次地给出这样的寄存器图表了.这些图片都是官方开发包里面的.它的说明都是很齐全的.不过我还是要说几句.

Direct Sound的播放一定要和Timer0或者1,DMA联系在一起.其中

Timer Selection for Direct Sound A或者B

就是指定该Direct Sound所使用的Timer了.而Timer只能是Timer 1或者Timer 0.

Output of Direct Sound A或者B

是选择每个Direct Sound左右声道的使用.其实这个选择没有多大用处.我试过,无论你选哪个,在GBA上播放的效果都差不多.所以我们一般都是把每个Direct Sound左右声道都开起.

Direct Sound FIFO A(B) Clear and Sequencer Reset

一般是初始化Direct Sound时候使用.FIFO是指先进先出接口.

下面让我们来做个实例来看看具体要做的步骤.

首先,我们要有个转换工具wav2gbac.exe. 它可以把我们电脑上的*.wav文件转换成一个*.h头文件.但是得注意,你的*.wav文件最好是8位音频,因为GBA上的Direct Sound只能播放8位的音频.即使8位以上的wav文件,但是播放出来还是只有8位的效果.

wav2gbac.exe这个工具可以在www.gbadev.org上下载.是个DOS下的程序.

我们在dos提示符下输入:

wav2gbac xxx.wav xxx.h

这样它就把xxx.wav音频数据转换到xxx.h里的一个大数组里了.

好了,我们已经得到转换后的音频数据.下面我们来看看如何写我们的声音播放函数.

void PlayDirectSoundA(u8 *sound, u16 sampleRate, u32 length)

{

//Stop any previous sample

*(vu16 *)REG_TM0CNT_H

= 0;

*(vu16 *)REG_TM0CNT_L = 0;

*(vu32 *)REG_DMA1SAD = 0;

*(vu16 *)REG_DMA1CNT_H = 0;

*(vu32 *)REG_DMA1DAD = 0;

//Output DirectSound A to right channel

*(vu16 *)REG_SOUNDCNT_H |= DSOUND_A_RIGHT_CHANNEL| DSOUND_A_TIMER_0 |

DSOUND_A_LEFT_CHANNEL | DSOUND_A_FIFO_RESET | DSOUND_A_OUTPUT_FULL;

//Enable all sound

*(vu16 *)REG_SOUNDCNT_X |= SOUND_MASTER_ENABLE;

//DMA1 Source Addresss

*(vu32 *)REG_DMA1SAD = (u32)sound;

//DMA1 Destination Address (REG_SGFIFOA)

*(vu32 *)REG_DMA1DAD = 0x40000A0;

//Write 32 bits into 0x040000A0 (REG_SGFIF0A) every VSync

*(vu32 *)REG_DMA1CNT =

DMA_DEST_FIXED | DMA_REPEATE | DMA_32 |

DMA_TIMEING_SYNC_TO_DISPLAY | DMA_ENABLE;

//Sample Rate

*(vu16 *)REG_TM0CNT_L = 65536 - (16777216/sampleRate);

//Enable the timer

*(vu16 *)REG_TM0CNT_H = TIMER_ENABLE | TIMER_IRQ;

}

这是个播放Direct Sound A声道的播放函数.

首先我们来看函数的参数,u8 *sound,u16 sampleRate,u32 length这些都是我们的声音转换工具wav2gbac.exe自动创建了的.你只要简单地把声音文件xxx.h的参数传递过来就可以了.

在播放声音之前,我们得先重至一次所需要的一切资源.这就是下面的代码完成的功能:

//Stop any previous sample

*(vu16 *)REG_TM0CNT_H

= 0;

*(vu16 *)REG_TM0CNT_L = 0;

*(vu32 *)REG_DMA1SAD = 0;

*(vu16 *)REG_DMA1CNT_H = 0;

*(vu32 *)REG_DMA1DAD = 0;

我使用了Timer0,DMA1作为我们播放Direct Sound A的辅助工具.这里的Timer,DMA都是可以自己选择的.但是需要注意的是Timer只能是Timer0或者Timer1,DMA也只能是DMA1或者DMA2.我们一般让Timer0,DMA1作为Direct Sound A的辅助控制,Timer1,DMA2作为Direct Sound B的辅助控制.

//Output DirectSound A to right channel

*(vu16 *)REG_SOUNDCNT_H |= DSOUND_A_RIGHT_CHANNEL| DSOUND_A_TIMER_0 |

DSOUND_A_LEFT_CHANNEL | DSOUND_A_FIFO_RESET | DSOUND_A_OUTPUT_FULL;

这是设置前面已经讲到的声音播放的控制寄存器.你可以根据前面的图表来自己设置.不过一般我们都使用上面代码的设置.如果你搞不清楚,在后面我会把完整的Direct Sound库函数给出来.下面是上面使用到的参数定义(其实就是C语言中的宏)

#define BIT00 1

#define BIT01 2

#define BIT02 4

#define BIT03 8

#define BIT04 16

#define BIT05 32

#define BIT06 64

#define BIT07 128

#define BIT08 256

#define BIT09 512

#define BIT10 1024

#define BIT11 2048

#define BIT12 4096

#define BIT13 8192

#define BIT14 16384

#define BIT15 32768

//SGCNT0_H

#define SOUND_OUTPUT_1_4

0

#define SOUND_OUTPUT_1_2

BIT00

#define SOUND_OUTPUT_FULL

BIT01

#define DSOUND_A_OUTPUT_HALF

0

#define DSOUND_A_OUTPUT_FULL

BIT02

#define DSOUND_B_OUTPUT_HALF

0

#define DSOUND_B_OUTPUT_FULL

BIT03

#define DSOUND_A_RIGHT_CHANNEL

BIT08

#define DSOUND_A_LEFT_CHANNEL

BIT09

#define DSOUND_A_TIMER_0

0

#define DSOUND_A_TIMER_1

BIT10

#define DSOUND_A_FIFO_RESET

BIT11

#define DSOUND_B_RIGHT_CHANNEL

BIT12

#define DSOUND_B_LEFT_CHANNEL

BIT13

#define DSOUND_B_TIMER_0

0

#define DSOUND_B_TIMER_1

BIT14

#define DSOUND_B_FIFO_RESET

BIT15

接下来,我们开起声音播放的总开关

#define SOUND_MASTER_ENABLE

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有