博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
掌上游戏机开发指南GBA探索日记(8)(转)
阅读量:2450 次
发布时间:2019-05-10

本文共 5364 字,大约阅读时间需要 17 分钟。

掌上游戏机开发指南GBA探索日记(8)(转)[@more@]

  有了前几篇关于中断和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无法使用,所以我们就必须另开辟一条道路来走了.还好,这条路我已经走通了,大家也可以顺着这个方向前进.

  

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

  

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

  
 
2005.1.5.17.59.46.1.gif

  这里我们看到,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

  
 
2005.1.5.17.59.56.2.gif

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

  

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

  
2005.1.5.18.0.5.3.gif

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

  

  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 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/8225414/viewspace-951681/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/8225414/viewspace-951681/

你可能感兴趣的文章
android应用开发_学习开发Android应用-无需经验
查看>>
freecodecamp_我们使用freeCodeCamp课程创建了本地免费编码学校。 这是我们学到的东西。
查看>>
Docker Remove Image:如何删除Docker镜像示例
查看>>
函数式编程 java_学习Java函数式编程-完整课程
查看>>
github 图像ai项目_如何在Github项目存储库中添加社交媒体图像
查看>>
国外开放知识图谱_什么是开放图谱,如何在我的网站上使用它?
查看>>
ntp时间同步会同步时区吗_如何处理时区并使软件与国际客户同步
查看>>
什么是JAMstack?如何开始?
查看>>
firebase使用_如何使用ReactJS和Firebase构建TodoApp
查看>>
nsfw_如何使用机器学习设置NSFW内容检测
查看>>
react中使用构建缓存_如何使用React构建客户支持实时聊天小部件
查看>>
reactjs生命周期_如何在ReactJS中了解组件的生命周期方法
查看>>
graphql和rest_如何使用GraphQL使您的网站整洁和可维护
查看>>
flutter dart_Dart和Flutter的简化介绍
查看>>
hbuilder自述文件_为什么创建自述文件已成为我最喜欢的开发部分
查看>>
从ES5到ESNext-这是自2015年以来添加到JavaScript的所有功能
查看>>
GraphQL中的突变简介:它们是什么以及如何使用它们
查看>>
如何使用Blazor和Google Cloud Firestore执行CRUD操作
查看>>
emberjs_如何与Circle CI,EmberJS和GitHub进行持续集成
查看>>
协作型过滤_公司如何使用协作过滤来准确了解您想要的内容
查看>>