⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gbaapu.cpp

📁 一个任天堂掌上游戏机NDS的源代码
💻 CPP
字号:
/*************************************************************************** DSemu - The Next Generation                                             ** GBA PortAudio-emulated APU: Plugin Implementation [gbaapu.cpp]          ** Copyright Imran Nazar, 2005; released under the BSD public licence.     ** PortAudio used under the BSD license.                                   ***************************************************************************/#include <string>#include <math.h>#include "portaudio.h"#include "defs.h"#include "events.h"#include "gbaapu.h"#include "config.h"#include "font5x7.h"#include "log.h"#include "err.h"// Pi's used to generate the sine table, so define it if it's not already.#ifndef M_PI# define M_PI 3.14159265358979#endif//---Static private class members------------------------------------------// Every plugin has an INFO structure attached, with info about the plugin.PLUGININFO gbaAPU::pInfo={    PLUGIN_TYPE_APU,    0x00010001,    "GBA audio processor (PortAudio)",    "DSemu-ng"};gbaAPU::IOREG gbaAPU::reg[0x28];std::string gbaAPU::pluginName;#define REG(x) reg[REG_ ## x].data// IO read flags: 1=Readable, 2=Writable, 3=Bothint gbaAPU::rflags[0x28]={    3,3,3,0,3,0,3,0,3,3,3,0,3,0,3,0,    3,3,3,0,0,0,0,0,3,3,3,3,3,3,3,3,    3,3,0,0,0,0,0,0,};int gbaAPU::dmgChanged[4]={1,1,1,1};MMU32Plugin *gbaAPU::MMU;GUIPlugin *gbaAPU::GUI;gbaAPU *gbaAPU::cls;u16 *gbaAPU::ch2buf=NULL, *gbaAPU::ch2outbuf=NULL;int gbaAPU::ch2out;uint64_t gbaAPU::tsStart, gbaAPU::tsEnd;int gbaAPU::paused=1;PortAudioStream *gbaAPU::paStream;s16 gbaAPU::SinT[4096];//---Implementation--------------------------------------------------------// Fill the DMG soundwave buffersvoid gbaAPU::fillDMG(){    // Channel 2    u32 ticks;        dmgChanged[2-1]=1;    tsStart = tsEnd;    tsEnd = GUI->getTimestamp() >> 6;    ticks = (tsEnd - tsStart);    u32 posStart, posEnd, pos; int halfcyclen;    //    printf("sound register change, %d ticks of sound to output.\n", ticks);    if(ticks >= 4096)    {//	printf("That's more than 4kt, just fill the buf.\n");	posStart=0; posEnd=4095;	    } else {	posStart = tsStart&4095;	posEnd = tsEnd&4095;	if(posEnd<posStart) posEnd+=4096;//        printf("Filling from %d to %d.\n", posStart, posEnd);    }        if(posStart != posEnd)    {	int x=0;        pos = posStart;        halfcyclen = 2048-(REG(SND2CNT_H)&2047);//	printf("Filling %d cycles.\n", halfcyclen*2);//        halfcyclen = 512;        do {	    x++;	    memset(ch2buf+(pos&4095), (x&1)?0x7F:0x80, halfcyclen*2); pos+=halfcyclen;        } while(pos<posEnd);    }//    for(int i=0;i<4096;i++) ch2buf[i]=SinT[(i*3)&4095];//(i&1024)?32767:32768;}// PortAudio callback to dump the buffers to audio outputint gbaAPU::dump(void *in, void *out, unsigned long frames, PaTimestamp t, void *plg){    ((gbaAPU*)plg)->dumpDMG(in, out, frames, t);    return 0;}// Dump the DMG buffers to a 16-bit outputvoid gbaAPU::dumpDMG(void *in, void *out, unsigned long frames, PaTimestamp tstamp){    s16 *o = (s16*)out;        // Channel 2/*    	for(int i=0;i<64;i++)            for(int j=0;j<4096;j++)		ch2outbuf[(i*4096+j)>>3]=ch2buf[j];//	    memcpy(ch2outbuf+i*4096, ch2buf, 4096*2);*/      for(unsigned int i=0;i<frames;i+=8) o[i]=ch2buf[i*8];    //    GUI->eventPush(262144, EVENT_SOUND_DUMP, (vfptr)dump, (void*)cls);}// If the APU has to be paused, the stream will be stopped. Conversely, if// the APU has to start up, the stream will be started.void gbaAPU::togglePause(){    switch(paused)    {	case 0:            if(Pa_StopStream(paStream) != paNoError)                Logger::log(pName) << "Failed to stop PortAudio stream.";	    paused=1;	    break;	case 1:            if(Pa_StartStream(paStream) != paNoError)                Logger::log(pName) << "Failed to start PortAudio stream.";	    paused=0;	    break;    }}// Functions to read and write the APU's IO ports. These are registered// with the MMU, and then called automatically when the appropriate// operation occurs.// NOTE: If a register is unreadable, it returns all 1's.u8 gbaAPU::rdB(u32 a){//    char str[128];    if(reg[((a&0xFF)-0x60)>>1].flags)	return reg[((a&0xFF)-0x60)>>1].b[a&1];    else	return 0xFF;}u16 gbaAPU::rdH(u32 a){//    char str[128];    if(reg[((a&0xFF)-0x60)>>1].flags)        return reg[((a&0xFF)-0x60)>>1].data;    else	return 0xFFFF;}u32 gbaAPU::rdW(u32 a){//    char str[128];    u32 w;    w=(reg[((a&0xFF)-0x60)>>1].flags)?reg[((a&0xFF)-0x60)>>1].data:0xFFFF;    w|=(reg[(((a&0xFF)-0x60)>>1)+1].flags)?(reg[(((a&0xFF)-0x60)>>1)+1].data)<<16:0xFFFF0000;    return w;}// NOTE: Every time a change occurs to the sound card, the sound has// to be changed. So the buffers are re-filled.void gbaAPU::wrB(u32 a, u8  d){//    char str[128];    if(reg[((a&0xFF)-0x60)>>1].flags)    {	reg[((a&0xFF)-0x60)>>1].b[a&1]=d;	fillDMG();    }}void gbaAPU::wrH(u32 a, u16 d){//    char str[128];    if(reg[((a&0xFF)-0x60)>>1].flags)    {	reg[((a&0xFF)-0x60)>>1].data=d;	fillDMG();    }}void gbaAPU::wrW(u32 a, u32 d){//    char str[128];    if(reg[((a&0xFF)-0x60)>>1].flags)	reg[((a&0xFF)-0x60)>>1].data=d&65535;    if(reg[(((a&0xFF)-0x60)>>1)+1].flags)	reg[(((a&0xFF)-0x60)>>1)+1].data=d>>16;    if((reg[((a&0xFF)-0x60)>>1].flags) || (reg[(((a&0xFF)-0x60)>>1)+1].flags))	fillDMG();}// Initialise plugin: Init PortAudio, register with the MMU// A 16-bit 32kHz stream is opened, to make life easy.gbaAPU::gbaAPU(std::string name, REQPTR req, UNREQPTR unreq){    pName = std::string(name);    pClass = pName.substr(0, pName.find(".")+1);    pRequest = req;    pUnrequest = unreq;    pluginName = std::string(pName);    cls = this;        if(Pa_Initialize() != paNoError)	throw Exception(ERR_APU_INIT, pName, "PortAudio initialisation failed.");    if(Pa_OpenDefaultStream(&paStream,			    0,          // no input			    2,          // stereo out			    paInt16,    // Sample type/size, 16-bit signed int			    32768,      // Sample rate			    512,        // 1/64s per buffer			    0,          // default minimum number of buffers			    dump,       // Our audio out handler			    this) != paNoError)	 throw Exception(ERR_APU_INIT, pName, "Failed to open PortAudio stream.");    Logger::log(pName) << "PortAudio stream opened.";        MMU = (MMU32Plugin*)pRequest("GBA_CPU0.mmu");    GUI = (GUIPlugin*)pRequest("UI");    ch2buf = new u16[4096];    ch2outbuf = new u16[262144];    if(!ch2buf || !ch2outbuf)        throw Exception(ERR_APU_INIT, pName, "Unable to allocate Channel 2 buffer.");    memset(ch2buf, 0, 4096*2);        for(int i=0; i<0x28; ++i)    {	reg[i].data = 0;        reg[i].flags = rflags[i];    }        for(int i=0; i<5; ++i)        MMU->mmioReg(0x06+i, rdB, rdH, rdW, wrB, wrH, wrW);        Logger::log(pName) << "Registered with MMU.";    // Initialise the sine table    for(int i=0;i<4096;i++) SinT[i]=(s16)(sin((float)i*M_PI/2048.0)*32768.0);        Logger::log(pName) << "Initialised.";}// Shut down plugin: terminate PA, free up buffersgbaAPU::~gbaAPU(){    if(Pa_StopStream(paStream) != paNoError)	Logger::log(pName) << "Failed to stop PortAudio stream.";    else    {	if(Pa_CloseStream(paStream) != paNoError)            Logger::log(pName) << "Failed to close PortAudio stream.";    }    Pa_Terminate();    Logger::log(pName) << "PortAudio terminated.";	    if(ch2buf) { delete ch2buf; ch2buf = NULL; }    if(ch2outbuf) { delete ch2outbuf; ch2outbuf = NULL; }	    pUnrequest("GBA_CPU0.mmu",1); MMU=NULL;    pUnrequest("UI",0); GUI=NULL;        Logger::log(pName) << "Shutdown.";}// Reset plugin: stop the stream, clear registersvoid gbaAPU::reset(){    if(Pa_StopStream(paStream) != paNoError)	Logger::log(pName) << "Failed to stop PortAudio stream.";    paused=1;	    for(int i=0;i<0x28;++i) reg[i].data = 0;//    GUI->eventPush(262144, EVENT_SOUND_DUMP, (vfptr)dump, this);        Logger::log(pName) << "Reset";}// Provide plugin status: Not much really to givevoid gbaAPU::status(int opt1=0, int opt2=0){}//---Plugin architecture support-------------------------------------------// Retrieve Plugin class from outside// Parameters: plg   - Address of a pointer to a Plugin class to 'new'//             name  - FQPN of plugin as listed in INI file//             req   - Pointer to PluginRequest API function//             unreq - Pointer to PluginUnrequest API functionEXPORTFUNC void getPlugin(Plugin **plg,                          std::string name,                          REQPTR req, UNREQPTR unreq){   *plg = new gbaAPU(name, req, unreq);}// Provide plugin version informationPLUGININFO *gbaAPU::getinfo(){    return &pInfo;}// Release plugin from outsidevoid gbaAPU::release(){    // Delete the Test plugin that was 'new'd in getPlugin.    delete this;}/*** EOF: gbaapu.cpp *****************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -