分享
 
 
 

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

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

这一节我们讨论如何正常结束声音播放的问题。不要觉得这是个小问题,当初这个小问题难倒了我们所有研究GBA的爱好者。我总觉得这一点似乎是GBA设计上的缺陷,但是最后我们可以通过使用VBlank中断还解决这个问题。本篇结束的时候,我还会给出完整声音播放的代码。这样,你甚至不必了解声音播放的细节就可以实现声音的播放功能了。

由于声音播放使用的DMA不能根据WORD COUNT来控制传输的数据量,同时又不能在传输完毕的时候产生DMA中断,所以我们无法知道什么时候DMA把我们的音频数据传输完毕。这样,我们必须自己另外加一计时器,来计算什么时候声音播放结束。当然,你可以使用Timer来做,但是另外再设置个Timer似乎就麻烦了点,而且Timer的精度过高,也不好计算长时间的声音播放。依照官方开发包中的做法,我们就拿VBlank中断作为声音播放的计时器。

VBlank中断是在硬件扫描屏幕V方向扫描线的时候产生的硬件中断。它是严格的每秒59.78次(接近60次/s)

下面我们来看看这段修改后的播放声音的代码。需要注意拿他和前一节的播放代码来比较一下,看看他们之间有什么不同。

这个PlayDirectSoundA的播发函数多了一个参数u32 time.它就是用来控制声音结束的时间参数。它的单位是秒(对于一般的声音播放来说,秒单位应该是足够精确了)。

soundATime = time * 59.727;

这条代码是将实际播放时间的秒数转换成一共要产生VBlank的中断数。前面说过,我们将使用VBlank来判断我们的声音是否播放结束。而VBlank中断的频率是59.727Hz,也就是说一秒中要产生59.727次。比如说如果我们的这段声音要播放5秒钟,那么播放过程中一共要产生5*59.727次VBlank中断。这样,我们只要使用一个计数器,每次VBlank中断产生的时候计数器自加1,当它等于5*59.727的时候,那么声音也就应该结束了。

其它的代码就差不多和前一节的PlayDirectSoundA差不多了。

////////////////////////////////////PlayDirectSoundA/////////////////////////////////////

// time是播发时间,单位是秒数

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

{

//Stop any previous sample

soundAPlaying = 0;

*(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;

//Set sound A's current sound

soundA = sound;

//Set the length, looping, etc

soundALength = length;

// 讲time秒转换成V-Blank中断次数,V-Blank中断是59.727Hz

soundATime = time * 59.727;

soundACurrent = 0;

soundASampleRate = sampleRate;

//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;

//The sound is playing

soundAPlaying = 1;

}

在这里我们增加了一个函数UpdateDirectSoundA.它的作用是判断Direct Sound A是否播放完毕的函数.它的代码很简单.每调用它一次,当前计数器soundACurrent自加1,同时判断是否播放完毕.

/////////////////////////////////////UpdateDirectSoundA////////////////////////////////

void UpdateDirectSoundA(void)

{

// if now is not playing sound A,return

if(!soundAPlaying)

return;

// Increase the Current timer

soundACurrent +=1;

// If sound A play time is up,close the sound A

if(soundACurrent = soundATime)

CloseDirectSoundA();

}

需要注意的是,这个函数的调用必须是放在VBlank中断的响应函数里.比如像下面一样,把它的调用放在Interrupt中处理VBlank的部分里.这样我们才能保证它是每1/59.727秒被调用一次.

关于中断的部分,请看看前面的有关中断的部分.

void Interrupts(void)

{

u16 Int_Flag;

REG_IME = 0x00;

// Disable interrupts

Int_Flag = REG_IF;

// Read the interrupt flags

if((REG_IF & 1) == 1)

{

UpdateDirectSoundA();

}

REG_IF = Int_Flag;

// Write back the interrupt flags

REG_IME = 1;

// Re-Enable interrups

}

好了.这个如何控制声音播放结束的问题总算解决了.其实我们也可以使用Timer用同样的原理来控制声音播放的结束,不过至少我觉得Timer的中断产生频率太快,完全没有必要.下面我将把我播放声音的全部代码公布出来,你可以将它拷贝到libsound.c和libsound.h,然后就可以使用了.

随便在结束本节之前再说几句,我们关于GBA的基础部分也就结束.但是我们对于GBA开发的探索还没有结束.后面的GBA探索日记将介绍一些实际游戏开发过程中需要的技术,比如汉字显示,Tile模式下写点等问题.不过这些问题就和我们一直走的官方开发包没有关系(无论是日本人还是老美根本不会去考虑汉字显示的问题),但是这些技术在实际开发过程中是很有用的.特别是汉字显示和Tile下写点这两个问题,是很多朋友都在做的,现在应该说是比较成熟的,所以在后面的两篇日记里,我也将它们公布出来,希望对大家有所帮助.

//*************************************

//

文件名: libsound.h

//

GBA中Direct Sound处理函数或宏

//

tangl_99 创建于2003.2.7

//*************************************

#ifndef _SOUND_H

#define _SOUND_H

//////////////////////////Necessary Includes/////////////////////////////

//////////////////////////////Definitions/////////////////////////////////

#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

#define TIMER_CASCADE

BIT02

#define TIMER_IRQ

BIT06

#define TIMER_ENABLE

BIT07

#define DMA_ENABLE

0x80000000

#define DMA_INTERUPT_ENABLE

0x40000000

#define DMA_TIMEING_IMMEDIATE

0x00000000

#define DMA_TIMEING_VBLANK

0x10000000

#define DMA_TIMEING_HBLANK

0x20000000

#define DMA_TIMEING_SYNC_TO_DISPLAY

0x30000000

#define DMA_16

0x00000000

#define DMA_32

0x04000000

#define DMA_REPEATE

0x02000000

#define DMA_SOURCE_INCREMENT

0x00000000

#define DMA_SOURCE_DECREMENT

0x00800000

#define DMA_SOURCE_FIXED

0x01000000

#define DMA_DEST_INCREMENT

0x00000000

#define DMA_DEST_DECREMENT

0x00200000

#define DMA_DEST_FIXED

0x00400000

#define DMA_DEST_RELOAD

0x00600000

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
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- 王朝網路 版權所有