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

📄 sound.cpp

📁 一个gba的模拟器源代码
💻 CPP
字号:
//---------------------------------------------------------------------------
#include <vcl.h>
#include <mmsystem.h>
#pragma hdrstop
#include <stdlib.h>
#include <dsound.h>

#include "Sound.h"
#include "rom.h"

static CRITICAL_SECTION cs;
static HWAVEOUT dev=NULL;
static HANDLE bufs[2];
static unsigned char* bufPtr[2];
static HANDLE bufHdr[2];
static int curBlock=0;
static int ready;
static int bufPos,bufCycles,bufLVal,bufRVal;
static WAVEHDR* wh;
static int sampleCycles=(8192*1024)/22050;

void CALLBACK WaveCallback(HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
   WAVEHDR *wh;
   HGLOBAL hg;   MMRESULT res;   if(uMsg == WOM_DONE)   {       EnterCriticalSection( &cs );       wh = (WAVEHDR *)dwParam1;       waveOutUnprepareHeader(dev, wh, sizeof (WAVEHDR));       //Deallocate the buffer memory       hg = GlobalHandle(wh->lpData);       GlobalUnlock(hg);       GlobalFree(hg);       //Deallocate the header memory       hg = GlobalHandle(wh);       GlobalUnlock(hg);       GlobalFree(hg);       ready++;       LeaveCriticalSection( &cs );   }}

LPDIRECTSOUND lpDS;
LPDIRECTSOUNDBUFFER lpBuf;
LPDIRECTSOUNDNOTIFY lpDSNot;
HANDLE sndEv[2];
unsigned char buf[2048];
int bufIndx=0;
static int playing;
static int left;

void CreateSoundBuffer();

void EnableDirectSound(HWND hWnd)
{
    DirectSoundCreate(NULL,&lpDS,NULL);
    lpDS->SetCooperativeLevel(hWnd,DSSCL_NORMAL);
    CreateSoundBuffer();
}

void EnableSound(HWND hWnd)
{
    if (soundEnable) return;
    if (!waveOutGetNumDevs())
    {
        MessageBox(NULL,"No audio devices present","Error",
            MB_OK|MB_ICONSTOP);
        return;
    }
    soundEnable=1;
    ready=3; bufPos=0;
    bufCycles=0; bufLVal=0; bufRVal=0;
//    EnableDirectSound(hWnd);
//    return;
    WAVEFORMATEX outFormatex;
    outFormatex.wFormatTag=WAVE_FORMAT_PCM;
    outFormatex.wBitsPerSample=8;
    outFormatex.nChannels=2;
    outFormatex.nSamplesPerSec=22050;
    outFormatex.nAvgBytesPerSec=44100;
    outFormatex.nBlockAlign=2;
    if (waveOutOpen(&dev,WAVE_MAPPER,&outFormatex,(DWORD)
        WaveCallback,0,CALLBACK_FUNCTION)!=MMSYSERR_NOERROR)
    {
        MessageBox(NULL,"Could not open audio device","Error",
            MB_OK|MB_ICONSTOP);
        return;
    }
    waveOutReset(dev);
    InitializeCriticalSection(&cs);
    bufs[curBlock]=GlobalAlloc(GMEM_MOVEABLE,2048);
    bufPtr[curBlock]=(unsigned char *)GlobalLock(bufs[curBlock]);
    bufHdr[curBlock]=GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,sizeof(WAVEHDR));
    wh=(WAVEHDR*)GlobalLock(bufHdr[curBlock]);
    wh->dwBufferLength=2048;
    wh->lpData=bufPtr[curBlock];
}

void DisableSound()
{
    if (!soundEnable)
        return;
    if(dev)
    {        while (ready<2)            Sleep(50);        waveOutReset(dev);      //reset the device        waveOutClose(dev);      //close the device        dev=NULL;    }    DeleteCriticalSection(&cs);    soundEnable=0;
}

void CreateSoundBuffer()
{
    DSBUFFERDESC d;
    WAVEFORMATEX wf;
    char *ptr;
    unsigned long n;
    wf.wFormatTag=WAVE_FORMAT_PCM;
    wf.nChannels=2;
    wf.nSamplesPerSec=22050;
    wf.nAvgBytesPerSec=22050*2;
    wf.nBlockAlign=2;
    wf.wBitsPerSample=8;
    wf.cbSize=0;
    memset(&d,0,sizeof(d));
    d.dwSize=sizeof(d);
    d.dwFlags=DSBCAPS_CTRLPOSITIONNOTIFY|DSBCAPS_GLOBALFOCUS;
    d.dwBufferBytes=4096;
    d.lpwfxFormat=&wf;
    lpDS->CreateSoundBuffer(&d,&lpBuf,NULL);
    sndEv[0]=CreateEvent(NULL,FALSE,FALSE,NULL);
    sndEv[1]=CreateEvent(NULL,FALSE,FALSE,NULL);
    DSBPOSITIONNOTIFY pn[2];
    pn[0].dwOffset=0;
    pn[0].hEventNotify=sndEv[0];
    pn[1].dwOffset=d.dwBufferBytes/2;
    pn[1].hEventNotify=sndEv[1];
    lpBuf->QueryInterface(IID_IDirectSoundNotify,(void**)&lpDSNot);
    lpDSNot->SetNotificationPositions(2,pn);
    bufIndx=0;
    playing=0;
    left=2;
}

void DirectSoundOutput(int l,int r)
{
    buf[bufIndx++]=l;
    buf[bufIndx++]=r;
    if (bufIndx>=2048)
    {
        bufIndx=0;
        int i;
        if (playing)
        {
            i=MsgWaitForMultipleObjects(2,sndEv,FALSE,INFINITE,0);
            i-=WAIT_OBJECT_0;
        }
        else
            i=1;
        if (i==0)
        {
            short *ptr1,*ptr2;
            unsigned long len1,len2;
            lpBuf->Lock(2048,2048,(void**)&ptr1,&len1,
                (void**)&ptr2,&len2,0);
            memcpy(ptr1,buf,len1);
            lpBuf->Unlock(ptr1,len1,ptr2,len2);
        }
        else
        {
            short *ptr1,*ptr2;
            unsigned long len1,len2;
            lpBuf->Lock(0,2048,(void**)&ptr1,&len1,
                (void**)&ptr2,&len2,0);
            memcpy(ptr1,buf,len1);
            lpBuf->Unlock(ptr1,len1,ptr2,len2);
        }
        if (!playing)
        {
            lpBuf->Play(0,0,DSBPLAY_LOOPING);
            playing=1;
        }
    }
}

void SoundDoOut(int l,int r,int cycles)
{
    bufLVal+=l*cycles;
    bufRVal+=r*cycles;
    bufCycles+=cycles;
    if (bufCycles>=sampleCycles)
    {
//        DirectSoundOutput(bufRVal/sampleCycles,bufLVal/sampleCycles);
//        bufCycles=0;
//        bufLVal=0; bufRVal=0;
//        return;
        bufPtr[curBlock][bufPos]=bufRVal/sampleCycles;
        bufPtr[curBlock][bufPos+1]=bufLVal/sampleCycles;
        bufCycles=0;
        bufPos+=2;
        bufLVal=0; bufRVal=0;
        if (bufPos>=2048)
        {
            while (!ready)
                Sleep(3);
            ready--;
            waveOutPrepareHeader(dev,wh,sizeof(WAVEHDR));
            waveOutWrite(dev,wh,sizeof(WAVEHDR));
            curBlock=(curBlock+1)&1;
            bufs[curBlock]=GlobalAlloc(GMEM_MOVEABLE,2048);
            bufPtr[curBlock]=(unsigned char *)GlobalLock(bufs[curBlock]);
            bufHdr[curBlock]=GlobalAlloc(GMEM_MOVEABLE|GMEM_ZEROINIT,sizeof(WAVEHDR));
            wh=(WAVEHDR*)GlobalLock(bufHdr[curBlock]);
            wh->dwBufferLength=2048;
            wh->lpData=bufPtr[curBlock];
            bufPos=0;
        }
    }
}

void SoundOutBits(int l,int r,int cycles)
{
    if (!soundEnable) return;
    while ((bufCycles+cycles)>sampleCycles)
    {
        int left=sampleCycles-bufCycles;
        SoundDoOut(l,r,left);
        cycles-=left;
    }
    SoundDoOut(l,r,cycles);
}

int snd1Enable,snd1Freq,snd1Vol,snd1Len,snd1SwpCnt=0;
int snd1EnvCnt=0,snd1Bit=0,snd1ValL=0,snd1ValR=0,snd1Cnt=0;
int snd2Enable,snd2Freq,snd2Vol,snd2Len;
int snd2EnvCnt=0,snd2Bit=0,snd2ValL=0,snd2ValR=0,snd2Cnt=0;
int snd3Enable,snd3Freq,snd3Len,snd3Bit=0,snd3Cnt=0;
int snd3ValL=0,snd3ValR=0;
int snd4Enable,snd4Freq,snd4Vol,snd4Len;
int snd4EnvCnt=0,snd4Bit=0,snd4ValL=0,snd4ValR=0,snd4Cnt=0;
extern int sndRegChange;

static int bit[4][8]={{1,0,0,0,0,0,0},{1,1,0,0,0,0,0,0},
    {1,1,1,1,0,0,0,0},{1,1,1,1,1,1,0,0}};
static int vol[16]={0,8,17,25,34,42,51,59,68,76,85,93,102,110,119,127};

#define HZ(x) ((8192*1024)/(x))

void SoundUpdate(int cycles)
{
    static int swpClk=0;
    static int envClk=0;
    static int lenClk=0;
    static int freqClk=0;
    static int freq4Clk=0;
    int l=0,r=0;

    if (!soundEnable) return;
    if (!restrictSpeed) return;
    if (sndRegChange)
    {
        snd1Freq=hiRam[0x13]|((hiRam[0x14]&7)<<8);
        snd2Freq=hiRam[0x18]|((hiRam[0x19]&7)<<8);
        snd3Freq=hiRam[0x1d]|((hiRam[0x1e]&7)<<8);
        switch(hiRam[0x22]&7)
        {
            case 0: snd4Freq=((512*1024)*2)>>((hiRam[0x22]>>4)+1); break;
            case 1: snd4Freq=(512*1024)>>((hiRam[0x22]>>4)+1); break;
            case 2: snd4Freq=((512*1024)/2)>>((hiRam[0x22]>>4)+1); break;
            case 3: snd4Freq=((512*1024)/3)>>((hiRam[0x22]>>4)+1); break;
            case 4: snd4Freq=((512*1024)/4)>>((hiRam[0x22]>>4)+1); break;
            case 5: snd4Freq=((512*1024)/5)>>((hiRam[0x22]>>4)+1); break;
            case 6: snd4Freq=((512*1024)/6)>>((hiRam[0x22]>>4)+1); break;
            case 7: snd4Freq=((512*1024)/7)>>((hiRam[0x22]>>4)+1); break;
        }
        snd4Freq=HZ(snd4Freq);
        snd3Enable=(hiRam[0x1a]&0x80)?1:0;
        snd1Vol=hiRam[0x12]>>4;
        if (hiRam[0x14]&0x80)
        {
            snd1Len=64-(hiRam[0x11]&63);
            snd1Cnt=0;
            hiRam[0x14]&=0x7f;
            snd1Enable=1;
        }
        snd2Vol=hiRam[0x17]>>4;
        if (hiRam[0x19]&0x80)
        {
            snd2Len=64-(hiRam[0x16]&63);
            snd2Cnt=0;
            hiRam[0x19]&=0x7f;
            snd2Enable=1;
        }
        if (hiRam[0x1e]&0x80)
        {
            snd3Len=(256-((int)((unsigned char)hiRam[0x1b])))<<7;
            snd3Cnt=0;
            hiRam[0x1e]&=0x7f;
        }
        snd4Vol=hiRam[0x21]>>4;
        if (hiRam[0x23]&0x80)
        {
            snd4Len=64-(hiRam[0x20]&63);
            hiRam[0x23]&=0x7f;
            snd4Enable=1;
        }
        sndRegChange=0;
    }
    if ((snd1Enable)&&(hiRam[0x10]&0x70))
    {
        swpClk+=cycles;
        if (swpClk>=HZ(128))
        {
            swpClk-=HZ(128);
            snd1SwpCnt++;
            if (snd1SwpCnt>=((hiRam[0x10]>>4)&7))
            {
                snd1SwpCnt=0;
                if (hiRam[0x10]&8)
                {
                    snd1Freq-=snd1Freq>>(hiRam[0x10]&7);
                    if (snd1Freq<0) snd1Freq=0;
                }
                else
                {
                    snd1Freq+=snd1Freq>>(hiRam[0x10]&7);
                    if (snd1Freq>2047)
                    {
                        snd1Freq=2047;
                        snd1Enable=0;
                    }
                }
            }
        }
    }
    envClk+=cycles;
    if (envClk>=HZ(64))
    {
        envClk-=HZ(64);
        if ((snd1Enable)&&(hiRam[0x12]&7))
        {
            snd1EnvCnt++;
            if (snd1EnvCnt>=(hiRam[0x12]&7))
            {
                snd1EnvCnt=0;
                if (hiRam[0x12]&8)
                {
                    snd1Vol++;
                    if (snd1Vol>0xf) snd1Vol=0xf;
                    hiRam[0x12]=(hiRam[0x12]&0xf)|(snd1Vol<<4);
                }
                else
                {
                    snd1Vol--;
                    if (snd1Vol<0) snd1Vol=0;
                    hiRam[0x12]=(hiRam[0x12]&0xf)|(snd1Vol<<4);
                }
            }
        }
        if ((snd2Enable)&&(hiRam[0x17]&7))
        {
            snd2EnvCnt++;
            if (snd2EnvCnt>=(hiRam[0x17]&7))
            {
                snd2EnvCnt=0;
                if (hiRam[0x17]&8)
                {
                    snd2Vol++;
                    if (snd2Vol>0xf) snd2Vol=0xf;
                    hiRam[0x17]=(hiRam[0x17]&0xf)|(snd2Vol<<4);
                }
                else
                {
                    snd2Vol--;
                    if (snd2Vol<0) snd2Vol=0;
                    hiRam[0x17]=(hiRam[0x17]&0xf)|(snd2Vol<<4);
                }
            }
        }
        if ((snd4Enable)&&(hiRam[0x21]&7))
        {
            snd4EnvCnt++;
            if (snd4EnvCnt>=(hiRam[0x21]&7))
            {
                snd4EnvCnt=0;
                if (hiRam[0x21]&8)
                {
                    snd4Vol++;
                    if (snd4Vol>0xf) snd4Vol=0xf;
                    hiRam[0x21]=(hiRam[0x21]&0xf)|(snd4Vol<<4);
                }
                else
                {
                    snd4Vol--;
                    if (snd4Vol<0) snd4Vol=0;
                    hiRam[0x21]=(hiRam[0x21]&0xf)|(snd4Vol<<4);
                }
            }
        }
    }
    lenClk+=cycles;
    if (lenClk>=HZ(256))
    {
        lenClk-=HZ(256);
        if (snd1Enable)
        {
            snd1Len--;
            if ((snd1Len<=0)&&(hiRam[0x14]&0x40))
                snd1Enable=0;
        }
        if (snd2Enable)
        {
            snd2Len--;
            if ((snd2Len<=0)&&(hiRam[0x19]&0x40))
                snd2Enable=0;
        }
        if (snd3Enable)
        {
            snd3Len--;
            if ((snd3Len<=0)&&(hiRam[0x1e]&0x40))
            {
                snd3Enable=0;
                hiRam[0xff1a]&=0x7f;
            }
        }
        if (snd4Enable)
        {
            snd4Len--;
            if ((snd4Len<=0)&&(hiRam[0x23]&0x40))
                snd4Enable=0;
        }
    }
    hiRam[0x13]=snd1Freq&0xff;
    hiRam[0x14]=(hiRam[0x14]&0xf8)|((snd1Freq>>8)&7);
    freqClk+=cycles;
    if (freqClk>=4)
    {
        int n=freqClk>>2;
        freqClk-=n<<2;
        if (snd1Enable)
        {
            snd1Cnt+=n;
            while (snd1Cnt>=((2048-snd1Freq)<<4))
                snd1Cnt-=((2048-snd1Freq)<<4);
        }
        if (snd2Enable)
        {
            snd2Cnt+=n;
            while (snd2Cnt>=((2048-snd2Freq)<<4))
                snd2Cnt-=((2048-snd2Freq)<<4);
        }
        if (snd3Enable)
        {
            snd3Cnt+=n;
            while (snd3Cnt>=((2048-snd3Freq)<<5))
                snd3Cnt-=((2048-snd3Freq)<<5);
        }
    }
    if (snd1Enable)
    {
        int stage=(snd1Cnt/(2048-snd1Freq))>>1;
        if (stage>7) stage=7;
        snd1Bit=bit[hiRam[0x11]>>6][stage];
    }
    if (hiRam[0x25]&1) l+=snd1Bit?vol[snd1Vol]:-vol[snd1Vol];
    if (hiRam[0x25]&0x10) r+=snd1Bit?vol[snd1Vol]:-vol[snd1Vol];
    if (snd2Enable)
    {
        int stage=(snd2Cnt/(2048-snd2Freq))>>1;
        if (stage>7) stage=7;
        snd2Bit=bit[hiRam[0x16]>>6][stage];
    }
    if (hiRam[0x25]&2) l+=snd2Bit?vol[snd2Vol]:-vol[snd2Vol];
    if (hiRam[0x25]&0x20) r+=snd2Bit?vol[snd2Vol]:-vol[snd2Vol];
    if (snd3Enable)
    {
        int stage=snd3Cnt/(2048-snd3Freq);
        if (stage>31) stage=31;
        snd3Bit=hiRam[0x30+(stage>>1)];
        if (stage&1)
            snd3Bit&=0xf;
        else
            snd3Bit>>=4;
        switch ((hiRam[0x1c]>>5)&3)
        {
            case 0: snd3Bit=8; break;
            case 1: break;
            case 2: snd3Bit=8|(snd3Bit>>1); break;
            case 3: snd3Bit=0xc|(snd3Bit>>2); break;
        }
    }
    if (hiRam[0x25]&4) l+=(snd3Bit<<4)-0x80;
    if (hiRam[0x25]&0x40) r+=(snd3Bit<<4)-0x80;
    if (snd4Enable)
    {
        freq4Clk+=cycles;
        if (freq4Clk>=snd4Freq)
        {
            freq4Clk=freq4Clk%snd4Freq;
            snd4Bit=rand()&1;
        }
    }
    if (hiRam[0x25]&8) l+=snd4Bit?vol[snd4Vol]:-vol[snd4Vol];
    if (hiRam[0x25]&0x80) r+=snd4Bit?vol[snd4Vol]:-vol[snd4Vol];
    l>>=2;
    if (l<-128) l=-128;
    if (l>127) l=127;
    l+=0x80;
    r>>=2;
    if (r<-128) r=-128;
    if (r>127) r=127;
    r+=0x80;
    SoundOutBits(l,r,cycles);
}

void SoundSetCycles(int n)
{
    sampleCycles=n;
}

//---------------------------------------------------------------------------
#pragma package(smart_init)

⌨️ 快捷键说明

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