掌上游戏机开发指南GBA探索日记(9)(转)[@more@] 这一节我们讨论如何正常结束声音播放的问题。不要觉得这是个小问题,当初这个小问题难倒了我们所有研究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
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/8225414/viewspace-951688/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/8225414/viewspace-951688/
掌上游戏机开发指南GBA探索日记(9)(转)相关推荐
- 掌上游戏机开发指南——GBA程序开发入门
1.GBA简介 Game Boy Advanced(GBA)是日本任天堂公司于2001年推出的一款32位掌上游戏机.它着重于游戏机的便携式,并且以2D游戏为主(3D游戏依然不错).GBA有十分高效硬件 ...
- 将前端技术栈移植到掌上游戏机
https://juejin.im/post/5df89b96518825125b21d0f6 前端工程师,我们编写的代码只能活在浏览器.小程序或者 Node 进程里,这似乎已经成为了一种常识.但这就 ...
- 新的掌上游戏机,首款防作弊的开放式硬件设备以及更多游戏新闻
您好,开放游戏迷! 在本周的版本中,我们将介绍GCW-ZERO手持式控制台,第一个防作弊的开放式硬件设备以及更多内容. 公开游戏摘要:2015年3月15日至21日 手持式控制台:GCW-ZERO 查看 ...
- 如果有一天,掌上游戏机的屏幕可以卷起来……
随着智能手机以及手机游戏的发展,已经把当年像PSP.PSV这样火爆一时的掌上游戏机彻底钉在了历史的长河底下,现在还剩下的掌机就都是那种把当年的小霸王游戏或者仙剑1代这种像素游戏装进去的掌上红白机,怀旧 ...
- 【DIY】手把手教你爆改一台手机制作掌上游戏机
开头声明: 此篇文章为本人原创,首发于酷安,转载请标明出处 这个游戏机的创意并非本人原创,创意来自B站UP主极客湾,在B站搜索"自制掌机"就可以看见相关视频视频转送门 这是一篇混合 ...
- GBA探索日记(-)
GBA探索日记(-) mode0-2的BG与VRAM GBA的VRAM总共96KB,在mode3-5中,VRAM跟计算机的显示内存一样.屏幕上一个点对应一个显示内存地址. 可以看看下面两个函数,都是在 ...
- 1 分钟 Serverless 部署掌上游戏机,“一行命令”找回小时候的乐趣!
简介:夏日大作战,体验极速部署的乐趣! 来源 | 阿里云开发者公众号 Serverless 以其快速交付.智能弹性.高可用性.低成本等核心价值成为云计算中一股新生力量,获得无数开发者的青睐. 为了让更 ...
- 任天堂3D掌上游戏机3DS正式发布
本文转自掌上数码 http://www.pocketdigi.com/201006/201.html 在周二的E3视频游戏展上,任天堂推出了裸眼可玩3D游戏和看3D电影的3D掌上游戏机--3DS,有蓝 ...
- C#在Linux上的开发指南
本人才疏学浅,在此记录自己用C#在Linux上开发的一点经验,写下这篇指南.(给想要在Linux上开发C#程序的朋友提供建议) 目前在Linux上跑的网站:http://douxiubar.com | ...
最新文章
- 要在某一房间中两台计算机之间实现网络通信,大学计算机计算思维导论期末考试综述.doc...
- 【性能优化实战】java嵌入式开发pos
- 018_switch语句
- 分布式、高并发、多线程,到底有什么区别?
- uva 10271——Chopsticks
- React Hooks的使用(三)——useRef、useImperativeHandle、useLayoutEffect解析、自定义Hook
- 树叶贴画机器人_洪山广场举办“落叶节”,树叶树枝拼贴出冬日风景
- MATLAB调用USB摄像头实现过程
- GOF之结构型模式Ⅱ(重点)
- 关于跨域问题的解决办法
- 静态方法获取spring的bean实例
- tesseract win 训练
- winpython anaconda_Windows:安装 Anaconda《 Python:基础 》
- kafka--Struct Streaming--kafka案例
- 京东app优惠券python抓取_备战双十一,scrapy框架爬取京东优惠券信息
- 自制中文编程语言一(语言设计一)
- 英文的pdf文件怎么翻译成中文
- android电视播放器字幕,android播放视频显示字幕
- 王者荣耀同一微信号多个服务器,王者荣耀微信怎么切换账号?打不上省排?那就换个荣耀战区好了...
- kali的vmtool工具安装
热门文章
- nvm管理node版本 node/npm不是内部或外部命令,也不是可运行的程序
- 程序员的叹息 (来自堕落兽人)
- python3 32位安装_【转载】python3安装scrapy之windows32位爬坑
- 8条战术教你正确分析游戏性能问题
- Git分布式版本控制和远程库创建运用、git常用指令【尚硅谷笔记】
- 2018天猫双11各类目品牌成交额top10排行榜
- 如何在手机TIM中使用QQ打卡
- jquery绑定点击事件形参_jquery click事件的可选参数data的作用
- BUG++:“expect ‘:‘ at 0, actual =“问题处理
- c语言抽签系统_C语言程序设计50例(经典收藏)