From b603bcb9e06637bbb72d35ae1edb5c252f39ca51 Mon Sep 17 00:00:00 2001 From: cyberwarriorx Date: Mon, 6 Nov 2006 18:49:01 +0000 Subject: [PATCH] -Added NDS Sound emulation(spu.c/spu.h) -Fixed a few odd bugs -Added a new sound core system(pretty much taken right out of yabause) -Added Wav file write core -Added dummy core(it's currently set as the default) -Added Direct Sound core(windows port only) -There's still a number of issues with sound. I really don't understand what's causing them. --- trunk/desmume/configure.ac | 2 +- trunk/desmume/src/MMU.c | 46 +- trunk/desmume/src/Makefile.am | 16 +- trunk/desmume/src/NDSSystem.c | 5 + trunk/desmume/src/NDSSystem.h | 1 + trunk/desmume/src/SPU.c | 1313 +++++++++++++++++++++++++ trunk/desmume/src/SPU.h | 94 ++ trunk/desmume/src/windows/Makefile.am | 1 + trunk/desmume/src/windows/main.c | 16 +- 9 files changed, 1474 insertions(+), 20 deletions(-) create mode 100644 trunk/desmume/src/SPU.c create mode 100644 trunk/desmume/src/SPU.h diff --git a/trunk/desmume/configure.ac b/trunk/desmume/configure.ac index a1c713bef..40b35b4c4 100644 --- a/trunk/desmume/configure.ac +++ b/trunk/desmume/configure.ac @@ -63,7 +63,7 @@ case $target in AC_SUBST([UI_DIR]) ;; *mingw*) - LIBS="$LIBS -mwindows" + LIBS="$LIBS -ldxguid -ldxerr8 -ldsound -mwindows" UI_DIR=windows AC_SUBST([UI_DIR]) ;; diff --git a/trunk/desmume/src/MMU.c b/trunk/desmume/src/MMU.c index 1283b156a..131891424 100644 --- a/trunk/desmume/src/MMU.c +++ b/trunk/desmume/src/MMU.c @@ -331,6 +331,7 @@ u8 FASTCALL MMU_read8(u32 proc, u32 adr) return (unsigned char)cflash_read(adr); adr &= 0x0FFFFFFF; + switch(adr) { case 0x027FFCDC : @@ -366,7 +367,7 @@ u16 FASTCALL MMU_read16(u32 proc, u32 adr) return (unsigned short)cflash_read(adr); adr &= 0x0FFFFFFF; - + if((adr>>24)==4) { /* Adress is an IO register */ @@ -554,9 +555,19 @@ void FASTCALL MMU_write8(u32 proc, u32 adr, u8 val) cflash_write(adr,val); return; } - + adr &= 0x0FFFFFFF; - + + // This is bad, remove it + if(proc == ARMCPU_ARM7) + { + if ((adr>=0x04000400)&&(adr<0x0400051D)) + { + SPU_WriteByte(adr, val); + return; + } + } + switch(adr) { /* TODO: EEEK ! Controls for VRAMs A, B, C, D are missing ! */ @@ -687,8 +698,7 @@ void FASTCALL MMU_write8(u32 proc, u32 adr, u8 val) } } break; - -#ifdef LOG_CARD +#ifdef LOG_CARD case 0x040001A0 : /* TODO (clear): ??? */ case 0x040001A1 : case 0x040001A2 : @@ -727,9 +737,19 @@ void FASTCALL MMU_write16(u32 proc, u32 adr, u16 val) cflash_write(adr,val); return; } - + adr &= 0x0FFFFFFF; + // This is bad, remove it + if(proc == ARMCPU_ARM7) + { + if ((adr>=0x04000400)&&(adr<0x0400051D)) + { + SPU_WriteWord(adr, val); + return; + } + } + if((adr >> 24) == 4) { /* Adress is an IO register */ @@ -1310,9 +1330,19 @@ void FASTCALL MMU_write32(u32 proc, u32 adr, u32 val) cflash_write(adr,val); return; } - + adr &= 0x0FFFFFFF; - + + // This is bad, remove it + if(proc == ARMCPU_ARM7) + { + if ((adr>=0x04000400)&&(adr<0x0400051D)) + { + SPU_WriteLong(adr, val); + return; + } + } + if((adr>>24)==4) { switch(adr) diff --git a/trunk/desmume/src/Makefile.am b/trunk/desmume/src/Makefile.am index e9a706a48..7b3455db7 100644 --- a/trunk/desmume/src/Makefile.am +++ b/trunk/desmume/src/Makefile.am @@ -1,17 +1,17 @@ SUBDIRS = . $(UI_DIR) noinst_LIBRARIES = libdesmume.a libdesmume_a_SOURCES = \ - armcpu.c armcpu.h \ + armcpu.c armcpu.h ARM9.h \ arm_instructions.c arm_instructions.h \ bios.c bios.h cp15.c cp15.h \ + cflash.c cflash.h fs.h \ + debug.c debug.h \ Disassembler.c Disassembler.h \ FIFO.c FIFO.h \ - debug.c debug.h \ - MMU.c MMU.h NDSSystem.c NDSSystem.h \ - thumb_instructions.c thumb_instructions.h \ - mc.c mc.h \ GPU.c GPU.h \ - ARM9.h \ - cflash.c cflash.h fs.h \ - saves.c saves.h + mc.c mc.h \ + MMU.c MMU.h NDSSystem.c NDSSystem.h \ + saves.c saves.h \ + SPU.c SPU.h \ + thumb_instructions.c thumb_instructions.h libdesmume_a_LIBADD = fs-$(desmume_arch).$(OBJEXT) diff --git a/trunk/desmume/src/NDSSystem.c b/trunk/desmume/src/NDSSystem.c index 03e9202ed..303214b62 100644 --- a/trunk/desmume/src/NDSSystem.c +++ b/trunk/desmume/src/NDSSystem.c @@ -39,6 +39,10 @@ void NDS_Init(void) { armcpu_new(&NDS_ARM7,1); armcpu_new(&NDS_ARM9,0); +// if (SPU_Init(SNDCORE_FILEWRITE, 735) != 0) + if (SPU_Init(SNDCORE_DUMMY, 735) != 0) + return -1; + //ARM7 BIOS IRQ HANDLER MMU_writeWord(1, 0x00, 0xE25EF002); MMU_writeWord(1, 0x04, 0xEAFFFFFE); @@ -75,6 +79,7 @@ void NDS_DeInit(void) { NDS_FreeROM(); nds.nextHBlank = 3168; + SPU_DeInit(); Screen_DeInit(); MMU_DeInit(); } diff --git a/trunk/desmume/src/NDSSystem.h b/trunk/desmume/src/NDSSystem.h index a4e135dab..9cd927a8e 100644 --- a/trunk/desmume/src/NDSSystem.h +++ b/trunk/desmume/src/NDSSystem.h @@ -26,6 +26,7 @@ #include "MMU.h" #include "GPU.h" +#include "SPU.h" #include "mem.h" diff --git a/trunk/desmume/src/SPU.c b/trunk/desmume/src/SPU.c new file mode 100644 index 000000000..5ab0cd9f3 --- /dev/null +++ b/trunk/desmume/src/SPU.c @@ -0,0 +1,1313 @@ +/* Copyright (C) 2006 Theo Berkau + + Ideas borrowed from Stephane Dallongeville's SCSP core + + This file is part of DeSmuME + + DeSmuME is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DeSmuME is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DeSmuME; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "debug.h" +#include "ARM9.h" +#include "MMU.h" +#include "SPU.h" + +#include "armcpu.h" + +SPU_struct *SPU=NULL; + +static SoundInterface_struct *SNDCore=NULL; +extern SoundInterface_struct *SNDCoreList[]; + +#define CHANSTAT_STOPPED 0 +#define CHANSTAT_PLAY 1 + +#define ARM7_REG_8(a) (MMU.ARM7_REG[a]) + +#define ARM7_REG_16(a) (((u16 *)(MMU.ARM7_REG+addr))[0]) +#define ARM7_REG_32(a) (((u32 *)(MMU.ARM7_REG+addr))[0]) + +int indextbl[8] = +{ + -1, -1, -1, -1, 2, 4, 6, 8 +}; + +int adpcmtbl[89] = +{ + 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x0010, + 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F, 0x0022, 0x0025, + 0x0029, 0x002D, 0x0032, 0x0037, 0x003C, 0x0042, 0x0049, 0x0050, 0x0058, + 0x0061, 0x006B, 0x0076, 0x0082, 0x008F, 0x009D, 0x00AD, 0x00BE, 0x00D1, + 0x00E6, 0x00FD, 0x0117, 0x0133, 0x0151, 0x0173, 0x0198, 0x01C1, 0x01EE, + 0x0220, 0x0256, 0x0292, 0x02D4, 0x031C, 0x036C, 0x03C3, 0x0424, 0x048E, + 0x0502, 0x0583, 0x0610, 0x06AB, 0x0756, 0x0812, 0x08E0, 0x09C3, 0x0ABD, + 0x0BD0, 0x0CFF, 0x0E4C, 0x0FBA, 0x114C, 0x1307, 0x14EE, 0x1706, 0x1954, + 0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B, 0x364B, 0x3BB9, + 0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF +}; + +s16 wavedutytbl[8][8] = { +{ -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF }, +{ -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF }, +{ -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF }, +{ -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF }, +{ -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF }, +{ -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF }, +{ -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF }, +{ -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF } +}; + +FILE *spufp=NULL; + +////////////////////////////////////////////////////////////////////////////// + +int SPU_Init(int coreid, int buffersize) +{ + int i; + + if ((SPU = (SPU_struct *)malloc(sizeof(SPU_struct))) == NULL) + return -1; + + SPU_Reset(); + + // Allocate memory for sound buffer + if ((SPU->sndbuf = malloc(buffersize * 4 * 2)) == NULL) + return -1; + + if ((SPU->outbuf = malloc(buffersize * 2 * 2)) == NULL) + return -1; + + memset(SPU->sndbuf, 0, buffersize * 4 * 2); + memset(SPU->outbuf, 0, buffersize * 2 * 2); + + SPU->bufsize = buffersize; + + // So which core do we want? + if (coreid == SNDCORE_DEFAULT) + coreid = 0; // Assume we want the first one + + // Go through core list and find the id + for (i = 0; SNDCoreList[i] != NULL; i++) + { + if (SNDCoreList[i]->id == coreid) + { + // Set to current core + SNDCore = SNDCoreList[i]; + break; + } + } + + if (SNDCore == NULL) + return -1; + + if (SNDCore->Init(buffersize * 2) == -1) + { + // Since it failed, instead of it being fatal, we'll just use the dummy + // core instead + SNDCore = &SNDDummy; + SNDCore->Init(buffersize * 2); + } + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_Reset(void) +{ + int i; + + memset((void *)SPU, 0, sizeof(SPU_struct)); + + // Reset Registers + for (i = 0x400; i < 0x51D; i++) + ARM7_REG_8(i) = 0; +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_DeInit(void) +{ + if (SPU->sndbuf) + free(SPU->sndbuf); + + if (SPU->outbuf) + free(SPU->outbuf); + + if (SNDCore) + SNDCore->DeInit(); + + if (SPU) + free(SPU); +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_KeyOn(int channel) +{ + channel_struct *chan = &SPU->chan[channel]; + + chan->sampinc = (16777216 / (0x10000 - (double)chan->timer)) / 44100; + +// LOG("Channel %d key on: vol = %d, datashift = %d, hold = %d, pan = %d, waveduty = %d, repeat = %d, format = %d, source address = %07X, timer = %04X, loop start = %04X, length = %06X, MMU.ARM7_REG[0x501] = %02X\n", channel, chan->vol, chan->datashift, chan->hold, chan->pan, chan->waveduty, chan->repeat, chan->format, chan->addr, chan->timer, chan->loopstart, chan->length, ARM7_REG_8(0x501)); + switch(chan->format) + { + case 0: // 8-bit + chan->buf8 = &MMU.MMU_MEM[1][(chan->addr>>20)&0xFF][(chan->addr & MMU.MMU_MASK[1][(chan->addr >> 20) & 0xFF])]; + chan->loopstart = chan->loopstart << 2; + chan->length = (chan->length << 2) + chan->loopstart; + chan->sampcnt = 0; + break; + case 1: // 16-bit + chan->buf16 = (u16 *)&MMU.MMU_MEM[1][(chan->addr>>20)&0xFF][(chan->addr & MMU.MMU_MASK[1][(chan->addr >> 20) & 0xFF])]; + chan->loopstart = chan->loopstart << 1; + chan->length = (chan->length << 1) + chan->loopstart; + chan->sampcnt = 0; + break; + case 2: // ADPCM + { + u32 temp; + + chan->buf8 = &MMU.MMU_MEM[1][(chan->addr>>20)&0xFF][(chan->addr & MMU.MMU_MASK[1][(chan->addr >> 20) & 0xFF])]; + chan->pcm16b = (s16)((chan->buf8[1] << 8) | chan->buf8[0]); + chan->index = chan->buf8[2] & 0x7F; + chan->lastsampcnt = 7; + chan->sampcnt = 8; + chan->loopstart = chan->loopstart << 3; + chan->length = (chan->length << 3) + chan->loopstart; + break; + } + case 3: // PSG + { + break; + } + default: break; + } +} + +////////////////////////////////////////////////////////////////////////////// + +u8 SPU_ReadByte(u32 addr) +{ + addr &= 0xFFF; + + if (addr < 0x500) + { + switch (addr & 0xF) + { + case 0x0: +// LOG("Sound Channel %d Volume read\n", (addr >> 4) & 0xF); + return ARM7_REG_8(addr); + case 0x1: + { +// LOG("Sound Channel %d Data Shift/Hold read\n",(addr >> 4) & 0xF); + return ARM7_REG_8(addr); + } + case 0x2: +// LOG("Sound Channel %d Panning read\n",(addr >> 4) & 0xF); + return ARM7_REG_8(addr); + case 0x3: +// LOG("Sound Channel %d Wave Duty/Repeat/Format/Start read: %02X\n", (addr >> 4) & 0xF, ARM7_REG_8(addr)); + return ARM7_REG_8(addr); + case 0x4: + case 0x5: + case 0x6: + case 0x7: +// LOG("Sound Channel %d Data Source Register read: %08X\n",(addr >> 4) & 0xF, addr); + return ARM7_REG_8(addr); + case 0x8: +// LOG("Sound Channel Timer(Low byte) read: %08X\n", addr); + return ARM7_REG_8(addr); + case 0x9: +// LOG("Sound Channel Timer(High byte) read: %08X\n", addr); + return ARM7_REG_8(addr); + case 0xA: +// LOG("Sound Channel Loop Start(Low byte) read: %08X\n", addr); + return ARM7_REG_8(addr); + case 0xB: +// LOG("Sound Channel Loop Start(High byte) read: %08X\n", addr); + return ARM7_REG_8(addr); + case 0xC: + case 0xD: + case 0xE: + case 0xF: +// LOG("Sound Channel %d Length Register read: %08X\n",(addr >> 4) & 0xF, addr); + return ARM7_REG_8(addr); + default: break; + } + } + else + { + switch (addr & 0x1F) + { + case 0x000: + case 0x001: +// LOG("Sound Control Register read: %08X\n", addr); + return ARM7_REG_8(addr); + case 0x004: + case 0x005: +// LOG("Sound Bias Register read: %08X\n", addr); + return ARM7_REG_8(addr); + case 0x008: +// LOG("Sound Capture 0 Control Register read\n"); + return ARM7_REG_8(addr); + case 0x009: +// LOG("Sound Capture 1 Control Register read\n"); + return ARM7_REG_8(addr); + default: break; + } + } + + return ARM7_REG_8(addr); +} + +////////////////////////////////////////////////////////////////////////////// + +u16 SPU_ReadWord(u32 addr) +{ + addr &= 0xFFF; + + if (addr < 0x500) + { + switch (addr & 0xF) + { + case 0x0: +// LOG("Sound Channel %d Volume/data shift/hold word read\n", (addr >> 4) & 0xF); + return ARM7_REG_16(addr); + case 0x2: + { + channel_struct *chan=&SPU->chan[(addr >> 4) & 0xF]; +// LOG("Sound Channel %d Panning/Wave Duty/Repeat Mode/Format/Start word read\n", (addr >> 4) & 0xF); + return ARM7_REG_16(addr); + } + case 0x4: + case 0x6: +// LOG("Sound Channel %d Data Source Register word read: %08X\n",(addr >> 4) & 0xF, addr); + return ARM7_REG_16(addr); + case 0x8: +// LOG("Sound Channel %d Timer Register word read\n", (addr >> 4) & 0xF); + return ARM7_REG_16(addr); + case 0xA: +// LOG("Sound Channel %d Loop start Register word read\n", (addr >> 4) & 0xF); + return ARM7_REG_16(addr); + case 0xC: + case 0xE: +// LOG("Sound Channel %d Length Register word read: %08X\n",(addr >> 4) & 0xF, addr); + return ARM7_REG_16(addr); + default: break; + } + } + else + { + switch (addr & 0x1F) + { + case 0x000: +// LOG("Sound Control Register word read\n"); + return ARM7_REG_16(addr); + case 0x004: +// LOG("Sound Bias Register word read\n"); + return ARM7_REG_16(addr); + case 0x008: +// LOG("Sound Capture 0/1 Control Register word read\n"); + return ARM7_REG_16(addr); + default: break; + } + } + + return ARM7_REG_16(addr); +} + +////////////////////////////////////////////////////////////////////////////// + +u32 SPU_ReadLong(u32 addr) +{ + addr &= 0xFFF; + + if (addr < 0x500) + { + switch (addr & 0xF) + { + case 0x0: +// LOG("Sound Channel %d Control Register long read\n", (addr >> 4) & 0xF); + return ARM7_REG_32(addr); + case 0x4: +// LOG("Sound Channel %d Data Source Register long read\n"); + return ARM7_REG_32(addr); + case 0x8: +// LOG("Sound Channel %d Timer/Loop Start Register long read\n", (addr >> 4) & 0xF); + return ARM7_REG_32(addr); + case 0xC: +// LOG("Sound Channel %d Length Register long read\n", (addr >> 4) & 0xF); + return ARM7_REG_32(addr); + default: + return ARM7_REG_32(addr); + } + } + else + { + switch (addr & 0x1F) + { + case 0x000: +// LOG("Sound Control Register long read\n"); + return ARM7_REG_32(addr); + case 0x004: +// LOG("Sound Bias Register long read\n"); + return ARM7_REG_32(addr); + case 0x008: +// LOG("Sound Capture 0/1 Control Register long read: %08X\n"); + return ARM7_REG_32(addr); + default: + return ARM7_REG_32(addr); + } + } + + return ARM7_REG_32(addr); +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_WriteByte(u32 addr, u8 val) +{ + addr &= 0xFFF; + + if (addr < 0x500) + { + switch (addr & 0xF) + { + case 0x0: + SPU->chan[(addr >> 4) & 0xF].vol = val & 0x7F; +// LOG("Sound Channel %d Volume write: %02X\n", (addr >> 4) & 0xF, val); + ARM7_REG_8(addr) = val; + return; + case 0x1: + { + channel_struct *chan=&SPU->chan[(addr >> 4) & 0xF]; + +// LOG("Sound Channel %d Data Shift/Hold write: %02X\n",(addr >> 4) & 0xF, val); + chan->datashift = val & 0x3; + if (chan->datashift == 3) + chan->datashift = 4; + chan->hold = (val >> 7) & 0x1; + ARM7_REG_8(addr) = val; + return; + } + case 0x2: +// LOG("Sound Channel %d Panning write: %02X\n",(addr >> 4) & 0xF, val); + SPU->chan[(addr >> 4) & 0xF].pan = val & 0x7F; + ARM7_REG_8(addr) = val; + return; + case 0x3: + { + channel_struct *chan=&SPU->chan[(addr >> 4) & 0xF]; +// LOG("Sound Channel %d Wave Duty/Repeat/Format/Start write: %08X - %02X. ARM7 PC = %08X\n", (addr >> 4) & 0xF, addr, val, NDS_ARM7.instruct_adr); + + chan->waveduty = val & 0x7; + chan->repeat = (val >> 3) & 0x3; + chan->format = (val >> 5) & 0x3; + chan->status = (val >> 7) & 0x1; + + if (SPU->chan[(addr >> 4) & 0xF].status) + SPU_KeyOn((addr >> 4) & 0xF); + ARM7_REG_8(addr) = val; + return; + } + case 0x4: + case 0x5: + case 0x6: + case 0x7: +// LOG("Sound Channel %d Data Source Register write: %08X %02X\n",(addr >> 4) & 0xF, addr, val); + ARM7_REG_8(addr) = val; + return; + case 0x8: +// LOG("Sound Channel Timer(Low byte) write: %08X - %02X\n", addr, val); + ARM7_REG_8(addr) = val; + return; + case 0x9: +// LOG("Sound Channel Timer(High byte) write: %08X - %02X\n", addr, val); + ARM7_REG_8(addr) = val; + return; + case 0xA: +// LOG("Sound Channel Loop Start(Low byte) write: %08X - %02X\n", addr, val); + ARM7_REG_8(addr) = val; + return; + case 0xB: +// LOG("Sound Channel Loop Start(High byte) write: %08X - %02X\n", addr, val); + ARM7_REG_8(addr) = val; + return; + case 0xC: + case 0xD: + case 0xE: + case 0xF: +// LOG("Sound Channel %d Length Register write: %08X %02X\n",(addr >> 4) & 0xF, addr, val); + ARM7_REG_8(addr) = val; + return; + default: + LOG("Unsupported Sound Register byte write: %08X %02X\n", addr, val); + ARM7_REG_8(addr) = val; + break; + } + } + else + { + switch (addr & 0x1F) + { + case 0x000: + case 0x001: +// LOG("Sound Control Register write: %08X %02X\n", addr, val); + ARM7_REG_8(addr) = val; + return; + case 0x004: + case 0x005: +// LOG("Sound Bias Register write: %08X %02X\n", addr, val); + ARM7_REG_8(addr) = val; + return; + case 0x008: +// LOG("Sound Capture 0 Control Register write: %02X\n", val); + ARM7_REG_8(addr) = val; + return; + case 0x009: +// LOG("Sound Capture 1 Control Register write: %02X\n", val); + ARM7_REG_8(addr) = val; + return; + default: break; + } + } + + ARM7_REG_8(addr) = val; +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_WriteWord(u32 addr, u16 val) +{ + addr &= 0xFFF; + + if (addr < 0x500) + { + switch (addr & 0xF) + { + case 0x0: + { + channel_struct *chan=&SPU->chan[(addr >> 4) & 0xF]; +// LOG("Sound Channel %d Volume/data shift/hold write: %04X\n", (addr >> 4) & 0xF, val); + chan->vol = val & 0x7F; + chan->datashift = (val >> 8) & 0x3; + if (chan->datashift == 3) + chan->datashift = 4; + chan->hold = (val >> 15) & 0x1; + ARM7_REG_16(addr) = val; + return; + } + case 0x2: + { + channel_struct *chan=&SPU->chan[(addr >> 4) & 0xF]; +// LOG("Sound Channel %d Panning/Wave Duty/Repeat Mode/Format/Start write: %04X\n", (addr >> 4) & 0xF, val); + + chan->pan = val & 0x7F; + chan->waveduty = (val >> 8) & 0x7; + chan->repeat = (val >> 11) & 0x3; + chan->format = (val >> 13) & 0x3; + chan->status = (val >> 15) & 0x1; + if (chan->status) + SPU_KeyOn((addr >> 4) & 0xF); + + ARM7_REG_16(addr) = val; + return; + } + case 0x4: + case 0x6: +// LOG("Sound Channel %d Data Source Register write: %08X %04X\n",(addr >> 4) & 0xF, addr, val); + ARM7_REG_16(addr) = val; + return; + case 0x8: + { + channel_struct *chan = &SPU->chan[(addr >> 4) & 0xF]; +// LOG("Sound Channel %d Timer Register write: %04X\n", (addr >> 4) & 0xF, val); + chan->timer = val & 0xFFFF; + chan->sampinc = (16777216 / (0x10000 - (double)chan->timer)) / 44100; + ARM7_REG_16(addr) = val; + return; + } + case 0xA: +// LOG("Sound Channel %d Loop start Register write: %04X\n", (addr >> 4) & 0xF, val); + SPU->chan[(addr >> 4) & 0xF].loopstart = val; + ARM7_REG_16(addr) = val; + return; + case 0xC: + case 0xE: +// LOG("Sound Channel %d Length Register write: %08X %04X\n",(addr >> 4) & 0xF, addr, val); + ARM7_REG_16(addr) = val; + return; + default: +// LOG("Unsupported Sound Register word write: %08X %02X\n", addr, val); + ARM7_REG_16(addr) = val; + break; + } + } + else + { + switch (addr & 0x1F) + { + case 0x000: +// LOG("Sound Control Register write: %04X\n", val); + ARM7_REG_16(addr) = val; + return; + case 0x004: +// LOG("Sound Bias Register write: %04X\n", val); + ARM7_REG_16(addr) = val; + return; + case 0x008: +// LOG("Sound Capture 0/1 Control Register write: %04X\n", val); + ARM7_REG_16(addr) = val; + return; + default: break; + } + } + + ARM7_REG_16(addr) = val; +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_WriteLong(u32 addr, u32 val) +{ + addr &= 0xFFF; + + if (addr < 0x500) + { + switch (addr & 0xF) + { + case 0x0: + { + channel_struct *chan=&SPU->chan[(addr >> 4) & 0xF]; +// LOG("Sound Channel %d long write: %08X\n", (addr >> 4) & 0xF, val); + chan->vol = val & 0x7F; + chan->datashift = (val >> 8) & 0x3; + if (chan->datashift == 3) + chan->datashift = 4; + chan->hold = (val >> 15) & 0x1; + chan->pan = (val >> 16) & 0x7F; + chan->waveduty = (val >> 24) & 0x7; + chan->repeat = (val >> 27) & 0x3; + chan->format = (val >> 29) & 0x3; + chan->status = (val >> 31) & 0x1; + if (SPU->chan[(addr >> 4) & 0xF].status) + SPU_KeyOn((addr >> 4) & 0xF); + ARM7_REG_32(addr) = val; + return; + } + case 0x4: +// LOG("Sound Channel %d Data Source Register long write: %08X\n", (addr >> 4) & 0xF, val); + SPU->chan[(addr >> 4) & 0xF].addr = val & 0x7FFFFFF; + ARM7_REG_32(addr) = val; + return; + case 0x8: + { + channel_struct *chan = &SPU->chan[(addr >> 4) & 0xF]; + +// LOG("Sound Channel %d Timer/Loop Start Register write: - %08X\n", (addr >> 4) & 0xF, val); + chan->timer = val & 0xFFFF; + chan->loopstart = val >> 16; + chan->sampinc = (16777216 / (0x10000 - (double)chan->timer)) / 44100; + ARM7_REG_32(addr) = val; + return; + } + case 0xC: +// LOG("Sound Channel %d Length Register long write: %08X\n", (addr >> 4) & 0xF, val); + SPU->chan[(addr >> 4) & 0xF].length = val & 0x3FFFFF; + ARM7_REG_32(addr) = val; + return; + default: break; + } + } + else + { + switch (addr & 0x1F) + { + case 0x000: +// LOG("Sound Control Register write: %08X\n", val); + ARM7_REG_32(addr) = val; + return; + case 0x004: +// LOG("Sound Bias Register write: %08X\n", val); + ARM7_REG_32(addr) = val; + return; + case 0x008: +// LOG("Sound Capture 0/1 Control Register write: %08X\n", val); + ARM7_REG_32(addr) = val; + return; + default: break; + } + } + + ARM7_REG_32(addr) = val; +} + +////////////////////////////////////////////////////////////////////////////// + +static INLINE void Fetch8BitData(channel_struct *chan, s32 *data) +{ + *data = (s32)chan->buf8[(int)chan->sampcnt] << 8; +} + +////////////////////////////////////////////////////////////////////////////// + +static INLINE void Fetch16BitData(channel_struct *chan, s32 *data) +{ + *data = (s32)chan->buf16[(int)chan->sampcnt]; +} + +////////////////////////////////////////////////////////////////////////////// + +static INLINE int MinMax(int val, int min, int max) +{ + if (val < min) + return min; + else if (val > max) + return max; + + return val; +} + +////////////////////////////////////////////////////////////////////////////// + +static INLINE void FetchADPCMData(channel_struct *chan, s32 *data) +{ + u8 data4bit; + int diff; + int i; + + if (chan->lastsampcnt == (int)chan->sampcnt) + { + // No sense decoding, just return the last sample + *data = (s32)chan->pcm16b; + return; + } + + for (i = chan->lastsampcnt+1; i < (int)chan->sampcnt+1; i++) + { + if (i & 0x1) + data4bit = (chan->buf8[i >> 1] >> 4) & 0xF; + else + data4bit = chan->buf8[i >> 1] & 0xF; + + diff = ((data4bit & 0x7) * 2 + 1) * adpcmtbl[chan->index] / 8; + if (data4bit & 0x8) + diff = -diff; + + chan->pcm16b = (s16)MinMax(chan->pcm16b+diff, -0x8000, 0x7FFF); + chan->index = MinMax(chan->index+indextbl[data4bit & 0x7], 0, 88); + } + + chan->lastsampcnt = chan->sampcnt; + *data = (s32)chan->pcm16b; +} + +////////////////////////////////////////////////////////////////////////////// + +static INLINE void FetchPSGData(channel_struct *chan, s32 *data) +{ + *data = (s32)wavedutytbl[chan->waveduty][((int)chan->sampcnt) & 0x7]; +} + +////////////////////////////////////////////////////////////////////////////// + +static INLINE void MixL(channel_struct *chan, s32 data) +{ + if (data) + { + data = (data * chan->vol / 127) >> chan->datashift; + SPU->sndbuf[SPU->bufpos<<1] += data; + } +} + +////////////////////////////////////////////////////////////////////////////// + +static INLINE void MixR(channel_struct *chan, s32 data) +{ + if (data) + { + data = (data * chan->vol / 127) >> chan->datashift; + SPU->sndbuf[(SPU->bufpos<<1)+1] += data; + } +} + +////////////////////////////////////////////////////////////////////////////// + +static INLINE void MixLR(channel_struct *chan, s32 data) +{ + if (data) + { + data = ((data * chan->vol) / 127) >> chan->datashift; + SPU->sndbuf[SPU->bufpos<<1] += data * (127 - chan->pan) / 127; + SPU->sndbuf[(SPU->bufpos<<1)+1] += data * chan->pan / 127; + } +} + +////////////////////////////////////////////////////////////////////////////// + +static INLINE void TestForLoop(channel_struct *chan) +{ + chan->sampcnt += chan->sampinc; + + if (chan->sampcnt > (double)chan->length) + { + // Do we loop? Or are we done? + if (chan->repeat == 1) + chan->sampcnt = (double)chan->loopstart; // Is this correct? + else + { + chan->status = CHANSTAT_STOPPED; + MMU.ARM7_REG[0x403 + ((((u32)chan-(u32)SPU->chan) / sizeof(channel_struct)) * 0x10)] &= 0x7F; + SPU->bufpos = SPU->buflength; + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +static INLINE void TestForLoop2(channel_struct *chan) +{ + chan->sampcnt += chan->sampinc; + + if (chan->sampcnt > (double)chan->length) + { + // Do we loop? Or are we done? + if (chan->repeat == 1) + { + chan->sampcnt = (double)chan->loopstart; // Is this correct? + chan->pcm16b = (s16)((chan->buf8[1] << 8) | chan->buf8[0]); + chan->index = chan->buf8[2] & 0x7F; + chan->lastsampcnt = 7; + } + else + { + chan->status = CHANSTAT_STOPPED; + MMU.ARM7_REG[0x403 + ((((u32)chan-(u32)SPU->chan) / sizeof(channel_struct)) * 0x10)] &= 0x7F; + SPU->bufpos = SPU->buflength; + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_ChanUpdateNothing(channel_struct *chan) +{ +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_ChanUpdate8LR(channel_struct *chan) +{ + for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) + { + s32 data; + + // fetch data from source address + Fetch8BitData(chan, &data); + + MixLR(chan, data); + + // check to see if we're passed the length and need to loop, etc. + TestForLoop(chan); + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_ChanUpdate8L(channel_struct *chan) +{ + for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) + { + s32 data; + + // fetch data from source address + Fetch8BitData(chan, &data); + + MixL(chan, data); + + // check to see if we're passed the length and need to loop, etc. + TestForLoop(chan); + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_ChanUpdate8R(channel_struct *chan) +{ + for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) + { + s32 data; + + // fetch data from source address + Fetch8BitData(chan, &data); + + MixR(chan, data); + + // check to see if we're passed the length and need to loop, etc. + TestForLoop(chan); + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_ChanUpdate16LR(channel_struct *chan) +{ + for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) + { + s32 data; + + // fetch data from source address + Fetch16BitData(chan, &data); + + MixLR(chan, data); + + // check to see if we're passed the length and need to loop, etc. + TestForLoop(chan); + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_ChanUpdate16L(channel_struct *chan) +{ + for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) + { + s32 data; + + // fetch data from source address + Fetch16BitData(chan, &data); + + MixL(chan, data); + + // check to see if we're passed the length and need to loop, etc. + TestForLoop(chan); + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_ChanUpdate16R(channel_struct *chan) +{ + for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) + { + s32 data; + + // fetch data from source address + Fetch16BitData(chan, &data); + + MixR(chan, data); + + // check to see if we're passed the length and need to loop, etc. + TestForLoop(chan); + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_ChanUpdateADPCMLR(channel_struct *chan) +{ + for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) + { + s32 data; + + // fetch data from source address + FetchADPCMData(chan, &data); + + MixLR(chan, data); + + // check to see if we're passed the length and need to loop, etc. + TestForLoop2(chan); + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_ChanUpdateADPCML(channel_struct *chan) +{ + for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) + { + s32 data; + + // fetch data from source address + FetchADPCMData(chan, &data); + + MixL(chan, data); + + // check to see if we're passed the length and need to loop, etc. + TestForLoop2(chan); + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_ChanUpdateADPCMR(channel_struct *chan) +{ + for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) + { + s32 data; + + // fetch data from source address + FetchADPCMData(chan, &data); + + MixR(chan, data); + + // check to see if we're passed the length and need to loop, etc. + TestForLoop2(chan); + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_ChanUpdatePSGLR(channel_struct *chan) +{ + for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) + { + s32 data; + + // fetch data from source address + FetchPSGData(chan, &data); + + MixLR(chan, data); + + chan->sampcnt += chan->sampinc; + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_ChanUpdatePSGL(channel_struct *chan) +{ + for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) + { + s32 data; + + // fetch data from source address + FetchPSGData(chan, &data); + + MixL(chan, data); + + chan->sampcnt += chan->sampinc; + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_ChanUpdatePSGR(channel_struct *chan) +{ + for (; SPU->bufpos < SPU->buflength; SPU->bufpos++) + { + s32 data; + + // fetch data from source address + FetchPSGData(chan, &data); + + MixR(chan, data); + + chan->sampcnt += chan->sampinc; + } +} + +////////////////////////////////////////////////////////////////////////////// + +void (*SPU_ChanUpdate[4][3])(channel_struct *chan) = { + { // 8-bit PCM + SPU_ChanUpdate8L, + SPU_ChanUpdate8LR, + SPU_ChanUpdate8R + }, + { // 16-bit PCM + SPU_ChanUpdate16L, + SPU_ChanUpdate16LR, + SPU_ChanUpdate16R + }, + { // IMA-ADPCM + SPU_ChanUpdateADPCML, + SPU_ChanUpdateADPCMLR, + SPU_ChanUpdateADPCMR + }, + { // PSG/White Noise + SPU_ChanUpdatePSGL, + SPU_ChanUpdatePSGLR, + SPU_ChanUpdatePSGR + } +}; + +////////////////////////////////////////////////////////////////////////////// + +void SPU_MixAudio(int length) +{ + channel_struct *chan; + int i; + + memset(SPU->sndbuf, 0, length*4*2); + + // If Master Enable isn't set, don't output audio + if (!(MMU.ARM7_REG[0x501] & 0x80)) + return; + + for(chan = &(SPU->chan[0]); chan < &(SPU->chan[16]); chan++) + { + if (chan->status != CHANSTAT_PLAY) + continue; + + SPU->bufpos = 0; + SPU->buflength = length; + + // Mix audio + if (chan->pan == 0) + SPU_ChanUpdate[chan->format][0](chan); + else if (chan->pan == 127) + SPU_ChanUpdate[chan->format][2](chan); + else + SPU_ChanUpdate[chan->format][1](chan); + } + + // convert from 32-bit->16-bit + for (i = 0; i < length*2; i++) + { + if (SPU->sndbuf[i] > 0x7FFF) + SPU->outbuf[i] = 0x7FFF; + else if (SPU->sndbuf[i] < -0x8000) + SPU->outbuf[i] = -0x8000; + else + SPU->outbuf[i] = (s16)SPU->sndbuf[i]; + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SPU_Emulate(void) +{ + u32 audiosize; + + // Check to see how much free space there is + // If there is some, fill up the buffer + audiosize = SNDCore->GetAudioSpace(); + + if (audiosize > 0) + { + if (audiosize > SPU->bufsize) + audiosize = SPU->bufsize; + SPU_MixAudio(audiosize); + SNDCore->UpdateAudio(SPU->outbuf, audiosize); + } +} + +////////////////////////////////////////////////////////////////////////////// +// Dummy Sound Interface +////////////////////////////////////////////////////////////////////////////// + +int SNDDummyInit(int buffersize); +void SNDDummyDeInit(); +void SNDDummyUpdateAudio(s16 *buffer, u32 num_samples); +u32 SNDDummyGetAudioSpace(); +void SNDDummyMuteAudio(); +void SNDDummyUnMuteAudio(); +void SNDDummySetVolume(int volume); + +SoundInterface_struct SNDDummy = { +SNDCORE_DUMMY, +"Dummy Sound Interface", +SNDDummyInit, +SNDDummyDeInit, +SNDDummyUpdateAudio, +SNDDummyGetAudioSpace, +SNDDummyMuteAudio, +SNDDummyUnMuteAudio, +SNDDummySetVolume +}; + +////////////////////////////////////////////////////////////////////////////// + +int SNDDummyInit(int buffersize) +{ + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + +void SNDDummyDeInit() +{ +} + +////////////////////////////////////////////////////////////////////////////// + +void SNDDummyUpdateAudio(s16 *buffer, u32 num_samples) +{ +} + +////////////////////////////////////////////////////////////////////////////// + +u32 SNDDummyGetAudioSpace() +{ + return 735; +} + +////////////////////////////////////////////////////////////////////////////// + +void SNDDummyMuteAudio() +{ +} + +////////////////////////////////////////////////////////////////////////////// + +void SNDDummyUnMuteAudio() +{ +} + +////////////////////////////////////////////////////////////////////////////// + +void SNDDummySetVolume(int volume) +{ +} + +////////////////////////////////////////////////////////////////////////////// +// File Write Interface +////////////////////////////////////////////////////////////////////////////// + +int SNDFileInit(int buffersize); +void SNDFileDeInit(); +void SNDFileUpdateAudio(s16 *buffer, u32 num_samples); +u32 SNDFileGetAudioSpace(); +void SNDFileMuteAudio(); +void SNDFileUnMuteAudio(); +void SNDFileSetVolume(int volume); + +SoundInterface_struct SNDFile = { +SNDCORE_FILEWRITE, +"File Write Sound Interface", +SNDFileInit, +SNDFileDeInit, +SNDFileUpdateAudio, +SNDFileGetAudioSpace, +SNDFileMuteAudio, +SNDFileUnMuteAudio, +SNDFileSetVolume +}; + +////////////////////////////////////////////////////////////////////////////// + +typedef struct { + char id[4]; + u32 size; +} chunk_struct; + +typedef struct { + chunk_struct riff; + char rifftype[4]; +} waveheader_struct; + +typedef struct { + chunk_struct chunk; + u16 compress; + u16 numchan; + u32 rate; + u32 bytespersec; + u16 blockalign; + u16 bitspersample; +} fmt_struct; + +////////////////////////////////////////////////////////////////////////////// + +int SNDFileInit(int buffersize) +{ + waveheader_struct waveheader; + fmt_struct fmt; + chunk_struct data; + + if ((spufp = fopen("ndsaudio.wav", "wb")) == NULL) + return -1; + + // Do wave header + memcpy(waveheader.riff.id, "RIFF", 4); + waveheader.riff.size = 0; // we'll fix this after the file is closed + memcpy(waveheader.rifftype, "WAVE", 4); + fwrite((void *)&waveheader, 1, sizeof(waveheader_struct), spufp); + + // fmt chunk + memcpy(fmt.chunk.id, "fmt ", 4); + fmt.chunk.size = 16; // we'll fix this at the end + fmt.compress = 1; // PCM + fmt.numchan = 2; // Stereo + fmt.rate = 44100; + fmt.bitspersample = 16; + fmt.blockalign = fmt.bitspersample / 8 * fmt.numchan; + fmt.bytespersec = fmt.rate * fmt.blockalign; + fwrite((void *)&fmt, 1, sizeof(fmt_struct), spufp); + + // data chunk + memcpy(data.id, "data", 4); + data.size = 0; // we'll fix this at the end + fwrite((void *)&data, 1, sizeof(chunk_struct), spufp); + + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + +void SNDFileDeInit() +{ + if (spufp) + { + long length = ftell(spufp); + + // Let's fix the riff chunk size and the data chunk size + fseek(spufp, sizeof(waveheader_struct)-0x8, SEEK_SET); + length -= 0x4; + fwrite((void *)&length, 1, 4, spufp); + + fseek(spufp, sizeof(waveheader_struct)+sizeof(fmt_struct)+0x4, SEEK_SET); + length -= sizeof(waveheader_struct)+sizeof(fmt_struct); + fwrite((void *)&length, 1, 4, spufp); + fclose(spufp); + } +} + +////////////////////////////////////////////////////////////////////////////// + +void SNDFileUpdateAudio(s16 *buffer, u32 num_samples) +{ + if (spufp) + fwrite((void *)buffer, num_samples*2, 2, spufp); +} + +////////////////////////////////////////////////////////////////////////////// + +u32 SNDFileGetAudioSpace() +{ + return 735; +} + +////////////////////////////////////////////////////////////////////////////// + +void SNDFileMuteAudio() +{ +} + +////////////////////////////////////////////////////////////////////////////// + +void SNDFileUnMuteAudio() +{ +} + +////////////////////////////////////////////////////////////////////////////// + +void SNDFileSetVolume(int volume) +{ +} + +////////////////////////////////////////////////////////////////////////////// + diff --git a/trunk/desmume/src/SPU.h b/trunk/desmume/src/SPU.h new file mode 100644 index 000000000..33e1bdc29 --- /dev/null +++ b/trunk/desmume/src/SPU.h @@ -0,0 +1,94 @@ +/* Copyright (C) 2006 Theo Berkau + + This file is part of DeSmuME + + DeSmuME is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + DeSmuME is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with DeSmuME; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef SPU_H +#define SPU_H + +#include "types.h" + +#define SNDCORE_DEFAULT -1 +#define SNDCORE_DUMMY 0 +#define SNDCORE_FILEWRITE 1 + +typedef struct +{ + int id; + const char *Name; + int (*Init)(int buffersize); + void (*DeInit)(); + void (*UpdateAudio)(s16 *buffer, u32 num_samples); + u32 (*GetAudioSpace)(); + void (*MuteAudio)(); + void (*UnMuteAudio)(); + void (*SetVolume)(int volume); +} SoundInterface_struct; + +extern SoundInterface_struct SNDDummy; +extern SoundInterface_struct SNDFile; + +typedef struct +{ + u8 vol; + u8 datashift; + u8 hold; + u8 pan; + u8 waveduty; + u8 repeat; + u8 format; + u8 status; + u32 addr; + u16 timer; + u16 loopstart; + u32 length; + s8 *buf8; + s16 *buf16; + double sampcnt; + double sampinc; + // ADPCM specific + int lastsampcnt; + s16 pcm16b; + int index; +} channel_struct; + +typedef struct +{ +// u8 mvol; +// u8 lout; +// u8 rout; + BOOL enable; + u32 bufpos; + u32 buflength; + s32 *sndbuf; + s16 *outbuf; + u32 bufsize; + channel_struct chan[16]; +} SPU_struct; + +extern SPU_struct *SPU; + +int SPU_Init(int coreid, int buffersize); +void SPU_Reset(void); +void SPU_DeInit(void); +void SPU_KeyOn(int channel); +void SPU_WriteByte(u32 addr, u8 val); +void SPU_WriteWord(u32 addr, u16 val); +void SPU_WriteLong(u32 addr, u32 val); +void SPU_Emulate(void); + +#endif diff --git a/trunk/desmume/src/windows/Makefile.am b/trunk/desmume/src/windows/Makefile.am index bfd4e7241..4ea77f53d 100644 --- a/trunk/desmume/src/windows/Makefile.am +++ b/trunk/desmume/src/windows/Makefile.am @@ -6,6 +6,7 @@ desmume_SOURCES = \ main.cpp mapView.c mapView.h memView.c memView.h \ oamView.c oamView.h palView.c palView.h \ resource.h \ + snddx.c snddx.h \ tileView.c tileView.h yopyop_private.h \ ConfigKeys.c ConfigKeys.h desmume_LDADD = ../libdesmume.a yopyop_private.o diff --git a/trunk/desmume/src/windows/main.c b/trunk/desmume/src/windows/main.c index a757da703..a251176b2 100644 --- a/trunk/desmume/src/windows/main.c +++ b/trunk/desmume/src/windows/main.c @@ -40,6 +40,7 @@ #include "../saves.h" #include "../cflash.h" #include "ConfigKeys.h" +#include "snddx.h" #ifdef RENDER3D #include "OGLRender.h" @@ -72,6 +73,13 @@ HMENU menu; const DWORD tabkey[48]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,VK_SPACE,VK_UP,VK_DOWN,VK_LEFT,VK_RIGHT,VK_TAB,VK_SHIFT,VK_DELETE,VK_INSERT,VK_HOME,VK_END,0x0d}; DWORD ds_up,ds_down,ds_left,ds_right,ds_a,ds_b,ds_x,ds_y,ds_l,ds_r,ds_select,ds_start,ds_debug; +SoundInterface_struct *SNDCoreList[] = { +&SNDDummy, +&SNDFile, +&SNDDIRECTX, +NULL +}; + DWORD WINAPI run( LPVOID lpParameter) { u64 count; @@ -107,6 +115,8 @@ DWORD WINAPI run( LPVOID lpParameter) while(execute) { cycles = NDS_exec((560190<<1)-cycles,FALSE); + SPU_Emulate(); + ++nbframe; QueryPerformanceCounter((LARGE_INTEGER *)&count); if(nextcount<=count) @@ -229,11 +239,13 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM case WM_DESTROY: execute = FALSE; finished = TRUE; + NDS_DeInit(); PostQuitMessage (0); // send a WM_QUIT to the message queue return 0; case WM_CLOSE: execute = FALSE; finished = TRUE; + NDS_DeInit(); PostMessage(hwnd, WM_QUIT, 0, 0); return 0; case WM_DROPFILES: @@ -301,7 +313,7 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM if(wParam==tabkey[ds_debug]){ ((u16 *)MMU.ARM7_REG)[0x136>>1] &= 0xFFFB; return 0; } - break; + return 0; /*case 0x1E : MMU.ARM7_REG[0x136] &= 0xFE; break; @@ -728,7 +740,5 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM return DefWindowProc (hwnd, message, wParam, lParam); } - NDS_DeInit(); - return 0; }