From 5aa3368a5179a76f9944c3e4386ec17f0872251a Mon Sep 17 00:00:00 2001 From: dborth Date: Sun, 14 Sep 2008 21:03:59 +0000 Subject: [PATCH] It should compile now! --- Makefile | 190 +--- Makefile.gc | 140 +-- Makefile.wii | 143 +++ src/Sound.cpp | 2926 ++++++++++++++++++++++++------------------------- src/Util.cpp | 2391 ++++++++++++++++++++-------------------- src/memgzio.c | 60 +- src/memgzio.h | 5 + src/unzip.h | 2 +- 8 files changed, 2902 insertions(+), 2955 deletions(-) create mode 100644 Makefile.wii diff --git a/Makefile b/Makefile index 814703d..65a1cb6 100644 --- a/Makefile +++ b/Makefile @@ -1,183 +1,23 @@ -#--------------------------------------------------------------------------------- -# Generic makefile for Gamecube projects -# -# Tab stops set to 4 -# | | | | -# 0 1 2 3 -#--------------------------------------------------------------------------------- -# Clear the implicit built in rules -#--------------------------------------------------------------------------------- -.SUFFIXES: +.PHONY = all wii gc wii-clean gc-clean wii-run gc-run -HAVEDIST := $(wildcard w) +all: wii gc -#--------------------------------------------------------------------------------- -# TARGET is the name of the output -# BUILD is the directory where object files & intermediate files will be placed -# SOURCES is a list of directories containing source code -# INCLUDES is a list of directories containing extra header files -#--------------------------------------------------------------------------------- -TARGET := vba172 -BUILD := build -SOURCES := src/gb src src/fileio src/ngc -INCLUDES = -I$(DEVKITPRO)/libogc/include -I$(DEVKITPRO)/libfat/libogc/include src/gb src src/fileio src/ngc -LIBPATHS = -L$(DEVKITPRO)/libogc/lib/wii -L$(DEVKITPRO)/libfat/libogc/lib/wii +clean: wii-clean gc-clean -#--------------------------------------------------------------------------------- -# options for code generation -#--------------------------------------------------------------------------------- -MACHDEP = -DGEKKO -mcpu=750 -meabi -mhard-float -CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) -meabi \ - -DWORDS_BIGENDIAN -DPACKAGE=\"VisualBoyAdvance\" \ - -DVERSION=\"1.7.2\" -DC_CORE -DHAVE_ZUTIL_H \ - -DCHANFFS -DSDL -DWII_BUILD -LDFLAGS = $(MACHDEP) -mrvl -Wl,-Map,$(notdir $@).map -Wl,--cref -PREFIX := powerpc-gekko- +wii: + $(MAKE) -f Makefile.wii -#export PATH:=/c/devkitPPC_r11/bin:/bin +wii-clean: + $(MAKE) -f Makefile.wii clean -#--------------------------------------------------------------------------------- -# any extra libraries we wish to link with -#--------------------------------------------------------------------------------- -LIBS := -lm -lz -lfat -ldb -lwiiuse -lbte -logc +wii-run: + $(MAKE) -f Makefile.wii run -#--------------------------------------------------------------------------------- -# no real need to edit anything past this point unless you need to add additional -# rules for different file extensions -#--------------------------------------------------------------------------------- -ifneq ($(BUILD),$(notdir $(CURDIR))) -#--------------------------------------------------------------------------------- -export OUTPUT := $(CURDIR)/$(TARGET) -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) +gc: + $(MAKE) -f Makefile.gc -export CC := $(PREFIX)gcc -export CXX := $(PREFIX)g++ -export AR := $(PREFIX)ar -export OBJCOPY := $(PREFIX)objcopy -#--------------------------------------------------------------------------------- -# automatically build a list of object files for our project -#--------------------------------------------------------------------------------- -CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) -CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) -sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) -SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) -#--------------------------------------------------------------------------------- -# use CXX for linking C++ projects, CC for standard C -#--------------------------------------------------------------------------------- -ifeq ($(strip $(CPPFILES)),) - export LD := $(CC) -else - export LD := $(CXX) -endif +gc-clean: + $(MAKE) -f Makefile.gc clean -export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(sFILES:.s=.o) $(SFILES:.S=.o) - -#--------------------------------------------------------------------------------- -# build a list of include paths -#--------------------------------------------------------------------------------- -export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ - $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) - -#--------------------------------------------------------------------------------- -# build a list of library paths -#--------------------------------------------------------------------------------- -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) - -export OUTPUT := $(CURDIR)/$(TARGET) -.PHONY: $(BUILD) clean - -#--------------------------------------------------------------------------------- -$(BUILD): - @[ -d $@ ] || mkdir $@ - @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile -#--------------------------------------------------------------------------------- -clean: - @echo clean ... - @rm -fr $(BUILD) *.elf - -#--------------------------------------------------------------------------------- -run: - psoload $(TARGET).dol - -#--------------------------------------------------------------------------------- -reload: - psoload -r $(TARGET).dol - -#--------------------------------------------------------------------------------- -dist: - @echo Files : $(HAVEDIST) - ifeq ($(strip $(HAVEDIST)),) - rule: - @echo "No file" - else - rule2: A - @echo "Have File" - endif - -bindist: - @[ -f $(TARGET).7z ] || rm $(TARGET).7z 2>/dev/null - @7z a -mx=9 -m0=lzma $(TARGET).7z $(TARGET).dol - -#--------------------------------------------------------------------------------- -else - -DEPENDS := $(OFILES:.o=.d) - -#--------------------------------------------------------------------------------- -# main targets -#--------------------------------------------------------------------------------- -$(OUTPUT).dol: $(OUTPUT).elf - @echo "Output ... "$(notdir $@) - @$(OBJCOPY) -O binary $< $@ - -#--------------------------------------------------------------------------------- -$(OUTPUT).elf: $(OFILES) - @echo "Linking ... "$(notdir $@) - @$(LD) $^ $(LDFLAGS) $(LIBPATHS) $(LIBS) -o $@ - -#--------------------------------------------------------------------------------- -# Compile Targets for C/C++ -#--------------------------------------------------------------------------------- - -#--------------------------------------------------------------------------------- -%.o : %.cpp - @echo Compiling ... $(notdir $<) - @$(CXX) -MMD $(CFLAGS) -o $@ -c $< - -#--------------------------------------------------------------------------------- -%.o : %.c - @echo Compiling ... $(notdir $<) - @$(CC) -MMD $(CFLAGS) -o $@ -c $< - -#--------------------------------------------------------------------------------- -%.o : %.S - @echo Compiling ... $(notdir $<) - @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ - -#--------------------------------------------------------------------------------- -%.o : %.s - @echo Compiling ... $(notdir $<) - @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ - -#--------------------------------------------------------------------------------- -# canned command sequence for binary data -#--------------------------------------------------------------------------------- -define bin2o - cp $(<) $(*).tmp - $(OBJCOPY) -I binary -O elf32-powerpc -B powerpc \ - --rename-section .data=.rodata,readonly,data,contents,alloc \ - --redefine-sym _binary_$*_tmp_start=$*\ - --redefine-sym _binary_$*_tmp_end=$*_end\ - --redefine-sym _binary_$*_tmp_size=$*_size\ - $(*).tmp $(@) - echo "extern const u8" $(*)"[];" > $(*).h - echo "extern const u32" $(*)_size[]";" >> $(*).h - rm $(*).tmp -endef - --include $(DEPENDS) - -#--------------------------------------------------------------------------------- -endif -#--------------------------------------------------------------------------------- +gc-run: + $(MAKE) -f Makefile.gc run diff --git a/Makefile.gc b/Makefile.gc index d2650bd..c574338 100644 --- a/Makefile.gc +++ b/Makefile.gc @@ -1,15 +1,13 @@ #--------------------------------------------------------------------------------- -# Generic makefile for Gamecube projects -# -# Tab stops set to 4 -# | | | | -# 0 1 2 3 -#--------------------------------------------------------------------------------- # Clear the implicit built in rules #--------------------------------------------------------------------------------- .SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITPPC)),) +$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") +endif -HAVEDIST := $(wildcard w) +include $(DEVKITPPC)/gamecube_rules #--------------------------------------------------------------------------------- # TARGET is the name of the output @@ -17,29 +15,33 @@ HAVEDIST := $(wildcard w) # SOURCES is a list of directories containing source code # INCLUDES is a list of directories containing extra header files #--------------------------------------------------------------------------------- -TARGET := vba172 -BUILD := build +TARGET := vba172_gc +TARGETDIR := executables +BUILD := build_gc SOURCES := src/gb src src/fileio src/ngc -INCLUDES = -I$(DEVKITPRO)/libogc/include -I$(DEVKITPRO)/libfat/libogc/include src/gb src src/fileio src/ngc -LIBPATHS = -L$(DEVKITPRO)/libogc/lib/cube -L$(DEVKITPRO)/libfat/libogc/lib/cube +INCLUDES := src/gb src src/fileio src/ngc #--------------------------------------------------------------------------------- # options for code generation #--------------------------------------------------------------------------------- MACHDEP = -DGEKKO -mcpu=750 -meabi -mhard-float -CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) -meabi \ - -DWORDS_BIGENDIAN -DPACKAGE=\"VisualBoyAdvance\" \ - -DVERSION=\"1.7.2\" -DC_CORE -DHAVE_ZUTIL_H \ - -DCHANFFS -DSDL -DGC_BUILD -LDFLAGS = $(MACHDEP) -mogc -Wl,-Map,$(notdir $@).map -Wl,--cref -PREFIX := powerpc-gekko- - -#export PATH:=/c/devkitPPC_r11/bin:/bin +CFLAGS = -g -Os -Wall $(MACHDEP) $(INCLUDE) -meabi \ + -DNGC -DWORDS_BIGENDIAN -DPACKAGE=\"VisualBoyAdvance\" \ + -DVERSION=\"1.7.2\" -DC_CORE \ + -DCHANFFS -DSDL -DNO_DEFLATE +CXXFLAGS = $(CFLAGS) +LDFLAGS = $(MACHDEP) -mrvl -Wl,-Map,$(notdir $@).map -Wl,--cref #--------------------------------------------------------------------------------- # any extra libraries we wish to link with #--------------------------------------------------------------------------------- -LIBS := -logc -lz -lm -lfat -logc -lz -lm +LIBS := -lm -lz -lfat -ldb -logc + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(CURDIR) #--------------------------------------------------------------------------------- # no real need to edit anything past this point unless you need to add additional @@ -47,13 +49,14 @@ LIBS := -logc -lz -lm -lfat -logc -lz -lm #--------------------------------------------------------------------------------- ifneq ($(BUILD),$(notdir $(CURDIR))) #--------------------------------------------------------------------------------- -export OUTPUT := $(CURDIR)/$(TARGET) -export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) -export CC := $(PREFIX)gcc -export CXX := $(PREFIX)g++ -export AR := $(PREFIX)ar -export OBJCOPY := $(PREFIX)objcopy +export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + #--------------------------------------------------------------------------------- # automatically build a list of object files for our project #--------------------------------------------------------------------------------- @@ -61,6 +64,8 @@ CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C #--------------------------------------------------------------------------------- @@ -70,54 +75,47 @@ else export LD := $(CXX) endif -export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(sFILES:.s=.o) $(SFILES:.S=.o) +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) #--------------------------------------------------------------------------------- # build a list of include paths #--------------------------------------------------------------------------------- export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ - -I$(CURDIR)/$(BUILD) + -I$(CURDIR)/$(BUILD) \ + -I$(LIBOGC_INC) #--------------------------------------------------------------------------------- # build a list of library paths #--------------------------------------------------------------------------------- -export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + -L$(LIBOGC_LIB) -export OUTPUT := $(CURDIR)/$(TARGET) +export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET) .PHONY: $(BUILD) clean #--------------------------------------------------------------------------------- $(BUILD): - @[ -d $@ ] || mkdir $@ + @[ -d $@ ] || mkdir -p $@ + @[ -d $(TARGETDIR) ] || mkdir -p $(TARGETDIR) @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.gc + @rm -fr $(OUTPUT).elf + #--------------------------------------------------------------------------------- clean: @echo clean ... - @rm -fr $(BUILD) *.elf + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol #--------------------------------------------------------------------------------- run: - psoload $(TARGET).dol + psoload $(OUTPUT).dol #--------------------------------------------------------------------------------- reload: - psoload -r $(TARGET).dol + psoload -r $(OUTPUT).dol -#--------------------------------------------------------------------------------- -dist: - @echo Files : $(HAVEDIST) - ifeq ($(strip $(HAVEDIST)),) - rule: - @echo "No file" - else - rule2: A - @echo "Have File" - endif - -bindist: - @[ -f $(TARGET).7z ] || rm $(TARGET).7z 2>/dev/null - @7z a -mx=9 -m0=lzma $(TARGET).7z $(TARGET).dol #--------------------------------------------------------------------------------- else @@ -128,53 +126,15 @@ DEPENDS := $(OFILES:.o=.d) # main targets #--------------------------------------------------------------------------------- $(OUTPUT).dol: $(OUTPUT).elf - @echo "Output ... "$(notdir $@) - @$(OBJCOPY) -O binary $< $@ - -#--------------------------------------------------------------------------------- $(OUTPUT).elf: $(OFILES) - @echo "Linking ... "$(notdir $@) - @$(LD) $^ $(LDFLAGS) $(LIBPATHS) $(LIBS) -o $@ #--------------------------------------------------------------------------------- -# Compile Targets for C/C++ +# This rule links in binary data with the .jpg extension #--------------------------------------------------------------------------------- - +%.jpg.o : %.jpg #--------------------------------------------------------------------------------- -%.o : %.cpp - @echo Compiling ... $(notdir $<) - @$(CXX) -MMD $(CFLAGS) -o $@ -c $< - -#--------------------------------------------------------------------------------- -%.o : %.c - @echo Compiling ... $(notdir $<) - @$(CC) -MMD $(CFLAGS) -o $@ -c $< - -#--------------------------------------------------------------------------------- -%.o : %.S - @echo Compiling ... $(notdir $<) - @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ - -#--------------------------------------------------------------------------------- -%.o : %.s - @echo Compiling ... $(notdir $<) - @$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@ - -#--------------------------------------------------------------------------------- -# canned command sequence for binary data -#--------------------------------------------------------------------------------- -define bin2o - cp $(<) $(*).tmp - $(OBJCOPY) -I binary -O elf32-powerpc -B powerpc \ - --rename-section .data=.rodata,readonly,data,contents,alloc \ - --redefine-sym _binary_$*_tmp_start=$*\ - --redefine-sym _binary_$*_tmp_end=$*_end\ - --redefine-sym _binary_$*_tmp_size=$*_size\ - $(*).tmp $(@) - echo "extern const u8" $(*)"[];" > $(*).h - echo "extern const u32" $(*)_size[]";" >> $(*).h - rm $(*).tmp -endef + @echo $(notdir $<) + $(bin2o) -include $(DEPENDS) diff --git a/Makefile.wii b/Makefile.wii new file mode 100644 index 0000000..17c0ff8 --- /dev/null +++ b/Makefile.wii @@ -0,0 +1,143 @@ +#--------------------------------------------------------------------------------- +# Clear the implicit built in rules +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITPPC)),) +$(error "Please set DEVKITPPC in your environment. export DEVKITPPC=devkitPPC") +endif + +include $(DEVKITPPC)/wii_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +#--------------------------------------------------------------------------------- +TARGET := vba172_wii +TARGETDIR := executables +BUILD := build_wii +SOURCES := src/gb src src/fileio src/ngc +INCLUDES := src/gb src src/fileio src/ngc + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +MACHDEP = -DGEKKO -mcpu=750 -meabi -mhard-float +CFLAGS = -g -Os -Wall $(MACHDEP) $(INCLUDE) -meabi \ + -DNGC -DWORDS_BIGENDIAN -DPACKAGE=\"VisualBoyAdvance\" \ + -DVERSION=\"1.7.2\" -DC_CORE \ + -DCHANFFS -DSDL -DWII_BUILD -DNO_DEFLATE +CXXFLAGS = $(CFLAGS) +LDFLAGS = $(MACHDEP) -mrvl -Wl,-Map,$(notdir $@).map -Wl,--cref + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with +#--------------------------------------------------------------------------------- +LIBS := -lm -lz -lfat -ldb -lwiiuse -lbte -logc + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(CURDIR) + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +#--------------------------------------------------------------------------------- +# automatically build a list of object files for our project +#--------------------------------------------------------------------------------- +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) + export LD := $(CC) +else + export LD := $(CXX) +endif + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) \ + $(sFILES:.s=.o) $(SFILES:.S=.o) + +#--------------------------------------------------------------------------------- +# build a list of include paths +#--------------------------------------------------------------------------------- +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) \ + -I$(LIBOGC_INC) + +#--------------------------------------------------------------------------------- +# build a list of library paths +#--------------------------------------------------------------------------------- +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) \ + -L$(LIBOGC_LIB) + +export OUTPUT := $(CURDIR)/$(TARGETDIR)/$(TARGET) +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @[ -d $(TARGETDIR) ] || mkdir -p $(TARGETDIR) + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.wii + @rm -fr $(OUTPUT).elf + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol + +#--------------------------------------------------------------------------------- +run: + wiiload $(OUTPUT).dol + +#--------------------------------------------------------------------------------- +reload: + wiiload -r $(OUTPUT).dol + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT).dol: $(OUTPUT).elf +$(OUTPUT).elf: $(OFILES) + +#--------------------------------------------------------------------------------- +# This rule links in binary data with the .jpg extension +#--------------------------------------------------------------------------------- +%.jpg.o : %.jpg +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + $(bin2o) + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- diff --git a/src/Sound.cpp b/src/Sound.cpp index 4b49f16..3ad8906 100644 --- a/src/Sound.cpp +++ b/src/Sound.cpp @@ -1,1463 +1,1463 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team - -// This program 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, or(at your option) -// any later version. -// -// This program 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 this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include - -#include "GBA.h" -#include "Globals.h" -#include "Sound.h" -#include "Util.h" - -#define USE_TICKS_AS 380 -#define SOUND_MAGIC 0x60000000 -#define SOUND_MAGIC_2 0x30000000 -#define NOISE_MAGIC 5 - -extern bool stopState; - -u8 soundWavePattern[4][32] = { - {0x01,0x01,0x01,0x01, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff}, - {0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff}, - {0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff}, - {0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0x01,0x01,0x01,0x01, - 0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff} - }; - -int soundFreqRatio[8] = { - 1048576, // 0 - 524288, // 1 - 262144, // 2 - 174763, // 3 - 131072, // 4 - 104858, // 5 - 87381, // 6 - 74898 // 7 - }; - -int soundShiftClock[16]= { - 2, // 0 - 4, // 1 - 8, // 2 - 16, // 3 - 32, // 4 - 64, // 5 - 128, // 6 - 256, // 7 - 512, // 8 - 1024, // 9 - 2048, // 10 - 4096, // 11 - 8192, // 12 - 16384, // 13 - 1, // 14 - 1 // 15 - }; - -int soundVolume = 0; - -u8 soundBuffer[6][735]; -u16 soundFinalWave[1470]; - -int soundBufferLen = 1470; -int soundBufferTotalLen = 14700; -int soundQuality = 2; -int soundPaused = 1; -int soundPlay = 0; -int soundTicks = soundQuality * USE_TICKS_AS; -int SOUND_CLOCK_TICKS = soundQuality * USE_TICKS_AS; -u32 soundNextPosition = 0; - -int soundLevel1 = 0; -int soundLevel2 = 0; -int soundBalance = 0; -int soundMasterOn = 0; -int soundIndex = 0; -int soundBufferIndex = 0; -int soundDebug = 0; -bool soundOffFlag = false; - -int sound1On = 0; -int sound1ATL = 0; -int sound1Skip = 0; -int sound1Index = 0; -int sound1Continue = 0; -int sound1EnvelopeVolume = 0; -int sound1EnvelopeATL = 0; -int sound1EnvelopeUpDown = 0; -int sound1EnvelopeATLReload = 0; -int sound1SweepATL = 0; -int sound1SweepATLReload = 0; -int sound1SweepSteps = 0; -int sound1SweepUpDown = 0; -int sound1SweepStep = 0; -u8 *sound1Wave = soundWavePattern[2]; - -int sound2On = 0; -int sound2ATL = 0; -int sound2Skip = 0; -int sound2Index = 0; -int sound2Continue = 0; -int sound2EnvelopeVolume = 0; -int sound2EnvelopeATL = 0; -int sound2EnvelopeUpDown = 0; -int sound2EnvelopeATLReload = 0; -u8 *sound2Wave = soundWavePattern[2]; - -int sound3On = 0; -int sound3ATL = 0; -int sound3Skip = 0; -int sound3Index = 0; -int sound3Continue = 0; -int sound3OutputLevel = 0; -int sound3Last = 0; -u8 sound3WaveRam[0x20]; -int sound3Bank = 0; -int sound3DataSize = 0; -int sound3ForcedOutput = 0; - -int sound4On = 0; -int sound4Clock = 0; -int sound4ATL = 0; -int sound4Skip = 0; -int sound4Index = 0; -int sound4ShiftRight = 0x7f; -int sound4ShiftSkip = 0; -int sound4ShiftIndex = 0; -int sound4NSteps = 0; -int sound4CountDown = 0; -int sound4Continue = 0; -int sound4EnvelopeVolume = 0; -int sound4EnvelopeATL = 0; -int sound4EnvelopeUpDown = 0; -int sound4EnvelopeATLReload = 0; - -int soundControl = 0; - -int soundDSFifoAIndex = 0; -int soundDSFifoACount = 0; -int soundDSFifoAWriteIndex = 0; -bool soundDSAEnabled = false; -int soundDSATimer = 0; -u8 soundDSFifoA[32]; -u8 soundDSAValue = 0; - -int soundDSFifoBIndex = 0; -int soundDSFifoBCount = 0; -int soundDSFifoBWriteIndex = 0; -bool soundDSBEnabled = false; -int soundDSBTimer = 0; -u8 soundDSFifoB[32]; -u8 soundDSBValue = 0; - -int soundEnableFlag = 0x3ff; - -s16 soundFilter[4000]; -s16 soundRight[5] = { 0, 0, 0, 0, 0 }; -s16 soundLeft[5] = { 0, 0, 0, 0, 0 }; -int soundEchoIndex = 0; -bool soundEcho = false; -bool soundLowPass = false; -bool soundReverse = false; - -variable_desc soundSaveStruct[] = { - { &soundPaused, sizeof(int) }, - { &soundPlay, sizeof(int) }, - { &soundTicks, sizeof(int) }, - { &SOUND_CLOCK_TICKS, sizeof(int) }, - { &soundLevel1, sizeof(int) }, - { &soundLevel2, sizeof(int) }, - { &soundBalance, sizeof(int) }, - { &soundMasterOn, sizeof(int) }, - { &soundIndex, sizeof(int) }, - { &sound1On, sizeof(int) }, - { &sound1ATL, sizeof(int) }, - { &sound1Skip, sizeof(int) }, - { &sound1Index, sizeof(int) }, - { &sound1Continue, sizeof(int) }, - { &sound1EnvelopeVolume, sizeof(int) }, - { &sound1EnvelopeATL, sizeof(int) }, - { &sound1EnvelopeATLReload, sizeof(int) }, - { &sound1EnvelopeUpDown, sizeof(int) }, - { &sound1SweepATL, sizeof(int) }, - { &sound1SweepATLReload, sizeof(int) }, - { &sound1SweepSteps, sizeof(int) }, - { &sound1SweepUpDown, sizeof(int) }, - { &sound1SweepStep, sizeof(int) }, - { &sound2On, sizeof(int) }, - { &sound2ATL, sizeof(int) }, - { &sound2Skip, sizeof(int) }, - { &sound2Index, sizeof(int) }, - { &sound2Continue, sizeof(int) }, - { &sound2EnvelopeVolume, sizeof(int) }, - { &sound2EnvelopeATL, sizeof(int) }, - { &sound2EnvelopeATLReload, sizeof(int) }, - { &sound2EnvelopeUpDown, sizeof(int) }, - { &sound3On, sizeof(int) }, - { &sound3ATL, sizeof(int) }, - { &sound3Skip, sizeof(int) }, - { &sound3Index, sizeof(int) }, - { &sound3Continue, sizeof(int) }, - { &sound3OutputLevel, sizeof(int) }, - { &sound4On, sizeof(int) }, - { &sound4ATL, sizeof(int) }, - { &sound4Skip, sizeof(int) }, - { &sound4Index, sizeof(int) }, - { &sound4Clock, sizeof(int) }, - { &sound4ShiftRight, sizeof(int) }, - { &sound4ShiftSkip, sizeof(int) }, - { &sound4ShiftIndex, sizeof(int) }, - { &sound4NSteps, sizeof(int) }, - { &sound4CountDown, sizeof(int) }, - { &sound4Continue, sizeof(int) }, - { &sound4EnvelopeVolume, sizeof(int) }, - { &sound4EnvelopeATL, sizeof(int) }, - { &sound4EnvelopeATLReload, sizeof(int) }, - { &sound4EnvelopeUpDown, sizeof(int) }, - { &soundEnableFlag, sizeof(int) }, - { &soundControl, sizeof(int) }, - { &soundDSFifoAIndex, sizeof(int) }, - { &soundDSFifoACount, sizeof(int) }, - { &soundDSFifoAWriteIndex, sizeof(int) }, - { &soundDSAEnabled, sizeof(bool) }, - { &soundDSATimer, sizeof(int) }, - { &soundDSFifoA[0], 32 }, - { &soundDSAValue, sizeof(u8) }, - { &soundDSFifoBIndex, sizeof(int) }, - { &soundDSFifoBCount, sizeof(int) }, - { &soundDSFifoBWriteIndex, sizeof(int) }, - { &soundDSBEnabled, sizeof(int) }, - { &soundDSBTimer, sizeof(int) }, - { &soundDSFifoB[0], 32 }, - { &soundDSBValue, sizeof(int) }, - { &soundBuffer[0][0], 6*735 }, - { &soundFinalWave[0], 2*735 }, - { NULL, 0 } - }; - -variable_desc soundSaveStructV2[] = { - { &sound3WaveRam[0], 0x20 }, - { &sound3Bank, sizeof(int) }, - { &sound3DataSize, sizeof(int) }, - { &sound3ForcedOutput, sizeof(int) }, - { NULL, 0 } - }; - -void soundEvent(u32 address, u8 data) -{ - int freq = 0; - - switch(address) - { - case NR10: - data &= 0x7f; - sound1SweepATL = sound1SweepATLReload = 344 * ((data >> 4) & 7); - sound1SweepSteps = data & 7; - sound1SweepUpDown = data & 0x08; - sound1SweepStep = 0; - ioMem[address] = data; - break; - case NR11: - sound1Wave = soundWavePattern[data >> 6]; - sound1ATL = 172 * (64 - (data & 0x3f)); - ioMem[address] = data; - break; - case NR12: - sound1EnvelopeUpDown = data & 0x08; - sound1EnvelopeATLReload = 689 * (data & 7); - if((data & 0xF8) == 0) - sound1EnvelopeVolume = 0; - ioMem[address] = data; - break; - case NR13: - freq = (((int)(ioMem[NR14] & 7)) << 8) | data; - sound1ATL = 172 * (64 - (ioMem[NR11] & 0x3f)); - freq = 2048 - freq; - if(freq) - { - sound1Skip = SOUND_MAGIC / freq; - } - else - sound1Skip = 0; - ioMem[address] = data; - break; - case NR14: - data &= 0xC7; - freq = (((int)(data&7) << 8) | ioMem[NR13]); - freq = 2048 - freq; - sound1ATL = 172 * (64 - (ioMem[NR11] & 0x3f)); - sound1Continue = data & 0x40; - if(freq) - { - sound1Skip = SOUND_MAGIC / freq; - } - else - sound1Skip = 0; - if(data & 0x80) - { - ioMem[NR52] |= 1; - sound1EnvelopeVolume = ioMem[NR12] >> 4; - sound1EnvelopeUpDown = ioMem[NR12] & 0x08; - sound1ATL = 172 * (64 - (ioMem[NR11] & 0x3f)); - sound1EnvelopeATLReload = sound1EnvelopeATL = 689 * (ioMem[NR12] & 7); - sound1SweepATL = sound1SweepATLReload = 344 * ((ioMem[NR10] >> 4) & 7); - sound1SweepSteps = ioMem[NR10] & 7; - sound1SweepUpDown = ioMem[NR10] & 0x08; - sound1SweepStep = 0; - - sound1Index = 0; - sound1On = 1; - } - ioMem[address] = data; - break; - case NR21: - sound2Wave = soundWavePattern[data >> 6]; - sound2ATL = 172 * (64 - (data & 0x3f)); - ioMem[address] = data; - break; - case NR22: - sound2EnvelopeUpDown = data & 0x08; - sound2EnvelopeATLReload = 689 * (data & 7); - if((data & 0xF8) == 0) - sound2EnvelopeVolume = 0; - ioMem[address] = data; - break; - case NR23: - freq = (((int)(ioMem[NR24] & 7)) << 8) | data; - sound2ATL = 172 * (64 - (ioMem[NR21] & 0x3f)); - freq = 2048 - freq; - if(freq) - { - sound2Skip = SOUND_MAGIC / freq; - } - else - sound2Skip = 0; - ioMem[address] = data; - break; - case NR24: - data &= 0xC7; - freq = (((int)(data&7) << 8) | ioMem[NR23]); - freq = 2048 - freq; - sound2ATL = 172 * (64 - (ioMem[NR21] & 0x3f)); - sound2Continue = data & 0x40; - if(freq) - { - sound2Skip = SOUND_MAGIC / freq; - } - else - sound2Skip = 0; - if(data & 0x80) - { - ioMem[NR52] |= 2; - sound2EnvelopeVolume = ioMem[NR22] >> 4; - sound2EnvelopeUpDown = ioMem[NR22] & 0x08; - sound2ATL = 172 * (64 - (ioMem[NR21] & 0x3f)); - sound2EnvelopeATLReload = sound2EnvelopeATL = 689 * (ioMem[NR22] & 7); - - sound2Index = 0; - sound2On = 1; - } - break; - ioMem[address] = data; - case NR30: - data &= 0xe0; - if(!(data & 0x80)) - { - ioMem[NR52] &= 0xfb; - sound3On = 0; - } - if(((data >> 6) & 1) != sound3Bank) - memcpy(&ioMem[0x90], &sound3WaveRam[(((data >> 6) & 1) * 0x10)^0x10], - 0x10); - sound3Bank = (data >> 6) & 1; - sound3DataSize = (data >> 5) & 1; - ioMem[address] = data; - break; - case NR31: - sound3ATL = 172 * (256-data); - ioMem[address] = data; - break; - case NR32: - data &= 0xe0; - sound3OutputLevel = (data >> 5) & 3; - sound3ForcedOutput = (data >> 7) & 1; - ioMem[address] = data; - break; - case NR33: - freq = 2048 - (((int)(ioMem[NR34]&7) << 8) | data); - if(freq) - { - sound3Skip = SOUND_MAGIC_2 / freq; - } - else - sound3Skip = 0; - ioMem[address] = data; - break; - case NR34: - data &= 0xc7; - freq = 2048 - (((data &7) << 8) | (int)ioMem[NR33]); - if(freq) - { - sound3Skip = SOUND_MAGIC_2 / freq; - } - else - { - sound3Skip = 0; - } - sound3Continue = data & 0x40; - if((data & 0x80) && (ioMem[NR30] & 0x80)) - { - ioMem[NR52] |= 4; - sound3ATL = 172 * (256 - ioMem[NR31]); - sound3Index = 0; - sound3On = 1; - } - ioMem[address] = data; - break; - case NR41: - data &= 0x3f; - sound4ATL = 172 * (64 - (data & 0x3f)); - ioMem[address] = data; - break; - case NR42: - sound4EnvelopeUpDown = data & 0x08; - sound4EnvelopeATLReload = 689 * (data & 7); - if((data & 0xF8) == 0) - sound4EnvelopeVolume = 0; - ioMem[address] = data; - break; - case NR43: - freq = soundFreqRatio[data & 7]; - sound4NSteps = data & 0x08; - - sound4Skip = (freq << 8) / NOISE_MAGIC; - - sound4Clock = data >> 4; - - freq = freq / soundShiftClock[sound4Clock]; - - sound4ShiftSkip = (freq << 8) / NOISE_MAGIC; - ioMem[address] = data; - break; - case NR44: - data &= 0xc0; - sound4Continue = data & 0x40; - if(data & 0x80) - { - ioMem[NR52] |= 8; - sound4EnvelopeVolume = ioMem[NR42] >> 4; - sound4EnvelopeUpDown = ioMem[NR42] & 0x08; - sound4ATL = 172 * (64 - (ioMem[NR41] & 0x3f)); - sound4EnvelopeATLReload = sound4EnvelopeATL = 689 * (ioMem[NR42] & 7); - - sound4On = 1; - - sound4Index = 0; - sound4ShiftIndex = 0; - - freq = soundFreqRatio[ioMem[NR43] & 7]; - - sound4Skip = (freq << 8) / NOISE_MAGIC; - - sound4NSteps = ioMem[NR43] & 0x08; - - freq = freq / soundShiftClock[ioMem[NR43] >> 4]; - - sound4ShiftSkip = (freq << 8) / NOISE_MAGIC; - if(sound4NSteps) - sound4ShiftRight = 0x7fff; - else - sound4ShiftRight = 0x7f; - } - ioMem[address] = data; - break; - case NR50: - data &= 0x77; - soundLevel1 = data & 7; - soundLevel2 = (data >> 4) & 7; - ioMem[address] = data; - break; - case NR51: - soundBalance = (data & soundEnableFlag); - ioMem[address] = data; - break; - case NR52: - data &= 0x80; - data |= ioMem[NR52] & 15; - soundMasterOn = data & 0x80; - if(!(data & 0x80)) - { - sound1On = 0; - sound2On = 0; - sound3On = 0; - sound4On = 0; - } - ioMem[address] = data; - break; - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - case 0x98: - case 0x99: - case 0x9a: - case 0x9b: - case 0x9c: - case 0x9d: - case 0x9e: - case 0x9f: - sound3WaveRam[(sound3Bank*0x10)^0x10+(address&15)] = data; - break; - } -} - -void soundEvent(u32 address, u16 data) -{ - switch(address) - { - case SGCNT0_H: - data &= 0xFF0F; - soundControl = data & 0x770F; - ; - if(data & 0x0800) - { - soundDSFifoAWriteIndex = 0; - soundDSFifoAIndex = 0; - soundDSFifoACount = 0; - soundDSAValue = 0; - memset(soundDSFifoA, 0, 32); - } - soundDSAEnabled = (data & 0x0300) ? true : false; - soundDSATimer = (data & 0x0400) ? 1 : 0; - if(data & 0x8000) - { - soundDSFifoBWriteIndex = 0; - soundDSFifoBIndex = 0; - soundDSFifoBCount = 0; - soundDSBValue = 0; - memset(soundDSFifoB, 0, 32); - } - soundDSBEnabled = (data & 0x3000) ? true : false; - soundDSBTimer = (data & 0x4000) ? 1 : 0; - *((u16 *)&ioMem[address]) = data; - break; - case FIFOA_L: - case FIFOA_H: - soundDSFifoA[soundDSFifoAWriteIndex++] = data & 0xFF; - soundDSFifoA[soundDSFifoAWriteIndex++] = data >> 8; - soundDSFifoACount += 2; - soundDSFifoAWriteIndex &= 31; - *((u16 *)&ioMem[address]) = data; - break; - case FIFOB_L: - case FIFOB_H: - soundDSFifoB[soundDSFifoBWriteIndex++] = data & 0xFF; - soundDSFifoB[soundDSFifoBWriteIndex++] = data >> 8; - soundDSFifoBCount += 2; - soundDSFifoBWriteIndex &= 31; - *((u16 *)&ioMem[address]) = data; - break; - case 0x88: - data &= 0xC3FF; - *((u16 *)&ioMem[address]) = data; - break; - case 0x90: - case 0x92: - case 0x94: - case 0x96: - case 0x98: - case 0x9a: - case 0x9c: - case 0x9e: - *((u16 *)&sound3WaveRam[(sound3Bank*0x10)^0x10+(address&14)]) = data; - *((u16 *)&ioMem[address]) = data; - break; - } -} - -void soundChannel1() -{ - int vol = sound1EnvelopeVolume; - - int freq = 0; - int value = 0; - - if(sound1On && (sound1ATL || !sound1Continue)) - { - sound1Index += soundQuality*sound1Skip; - sound1Index &= 0x1fffffff; - - value = ((s8)sound1Wave[sound1Index>>24]) * vol; - } - - soundBuffer[0][soundIndex] = value; - - - if(sound1On) - { - if(sound1ATL) - { - sound1ATL-=soundQuality; - - if(sound1ATL <=0 && sound1Continue) - { - ioMem[NR52] &= 0xfe; - sound1On = 0; - } - } - - if(sound1EnvelopeATL) - { - sound1EnvelopeATL-=soundQuality; - - if(sound1EnvelopeATL<=0) - { - if(sound1EnvelopeUpDown) - { - if(sound1EnvelopeVolume < 15) - sound1EnvelopeVolume++; - } - else - { - if(sound1EnvelopeVolume) - sound1EnvelopeVolume--; - } - - sound1EnvelopeATL += sound1EnvelopeATLReload; - } - } - - if(sound1SweepATL) - { - sound1SweepATL-=soundQuality; - - if(sound1SweepATL<=0) - { - freq = (((int)(ioMem[NR14]&7) << 8) | ioMem[NR13]); - - int updown = 1; - - if(sound1SweepUpDown) - updown = -1; - - int newfreq = 0; - if(sound1SweepSteps) - { - newfreq = freq + updown * freq / (1 << sound1SweepSteps); - if(newfreq == freq) - newfreq = 0; - } - else - newfreq = freq; - - if(newfreq < 0) - { - sound1SweepATL += sound1SweepATLReload; - } - else if(newfreq > 2047) - { - sound1SweepATL = 0; - sound1On = 0; - ioMem[NR52] &= 0xfe; - } - else - { - sound1SweepATL += sound1SweepATLReload; - sound1Skip = SOUND_MAGIC/(2048 - newfreq); - - ioMem[NR13] = newfreq & 0xff; - ioMem[NR14] = (ioMem[NR14] & 0xf8) |((newfreq >> 8) & 7); - } - } - } - } -} - -void soundChannel2() -{ - // int freq = 0; - int vol = sound2EnvelopeVolume; - - int value = 0; - - if(sound2On && (sound2ATL || !sound2Continue)) - { - sound2Index += soundQuality*sound2Skip; - sound2Index &= 0x1fffffff; - - value = ((s8)sound2Wave[sound2Index>>24]) * vol; - } - - soundBuffer[1][soundIndex] = value; - - if(sound2On) - { - if(sound2ATL) - { - sound2ATL-=soundQuality; - - if(sound2ATL <= 0 && sound2Continue) - { - ioMem[NR52] &= 0xfd; - sound2On = 0; - } - } - - if(sound2EnvelopeATL) - { - sound2EnvelopeATL-=soundQuality; - - if(sound2EnvelopeATL <= 0) - { - if(sound2EnvelopeUpDown) - { - if(sound2EnvelopeVolume < 15) - sound2EnvelopeVolume++; - } - else - { - if(sound2EnvelopeVolume) - sound2EnvelopeVolume--; - } - sound2EnvelopeATL += sound2EnvelopeATLReload; - } - } - } -} - -void soundChannel3() -{ - int value = sound3Last; - - if(sound3On && (sound3ATL || !sound3Continue)) - { - sound3Index += soundQuality*sound3Skip; - if(sound3DataSize) - { - sound3Index &= 0x3fffffff; - value = sound3WaveRam[sound3Index>>25]; - } - else - { - sound3Index &= 0x1fffffff; - value = sound3WaveRam[sound3Bank*0x10 + (sound3Index>>25)]; - } - - if( (sound3Index & 0x01000000)) - { - value &= 0x0f; - } - else - { - value >>= 4; - } - - value -= 8; - //value *= 2; - value <<= 1; - - if(sound3ForcedOutput) - { - value = ((value >> 1) + value) >> 1; - } - else - { - switch(sound3OutputLevel) - { - case 0: - value = 0; - break; - case 1: - break; - case 2: - value = (value >> 1); - break; - case 3: - value = (value >> 2); - break; - } - } - sound3Last = value; - } - - soundBuffer[2][soundIndex] = value; - - if(sound3On) - { - if(sound3ATL) - { - sound3ATL-=soundQuality; - - if(sound3ATL <= 0 && sound3Continue) - { - ioMem[NR52] &= 0xfb; - sound3On = 0; - } - } - } -} - -void soundChannel4() -{ - int vol = sound4EnvelopeVolume; - - int value = 0; - - if(sound4Clock <= 0x0c) - { - if(sound4On && (sound4ATL || !sound4Continue)) - { - sound4Index += soundQuality*sound4Skip; - sound4ShiftIndex += soundQuality*sound4ShiftSkip; - - if(sound4NSteps) - { - while(sound4ShiftIndex > 0x1fffff) - { - sound4ShiftRight = (((sound4ShiftRight << 6) ^ - (sound4ShiftRight << 5)) & 0x40) | - (sound4ShiftRight >> 1); - sound4ShiftIndex -= 0x200000; - } - } - else - { - while(sound4ShiftIndex > 0x1fffff) - { - sound4ShiftRight = (((sound4ShiftRight << 14) ^ - (sound4ShiftRight << 13)) & 0x4000) | - (sound4ShiftRight >> 1); - - sound4ShiftIndex -= 0x200000; - } - } - - sound4Index &= 0x1fffff; - sound4ShiftIndex &= 0x1fffff; - - value = ((sound4ShiftRight & 1)*2-1) * vol; - } - else - { - value = 0; - } - } - - soundBuffer[3][soundIndex] = value; - - if(sound4On) - { - if(sound4ATL) - { - sound4ATL-=soundQuality; - - if(sound4ATL <= 0 && sound4Continue) - { - ioMem[NR52] &= 0xfd; - sound4On = 0; - } - } - - if(sound4EnvelopeATL) - { - sound4EnvelopeATL-=soundQuality; - - if(sound4EnvelopeATL <= 0) - { - if(sound4EnvelopeUpDown) - { - if(sound4EnvelopeVolume < 15) - sound4EnvelopeVolume++; - } - else - { - if(sound4EnvelopeVolume) - sound4EnvelopeVolume--; - } - sound4EnvelopeATL += sound4EnvelopeATLReload; - } - } - } -} - -void soundDirectSoundA() -{ - soundBuffer[4][soundIndex] = soundDSAValue; -} - -void soundDirectSoundATimer() -{ - if(soundDSAEnabled) - { - if(soundDSFifoACount <= 16) - { - CPUCheckDMA(3, 2); - if(soundDSFifoACount <= 16) - { - soundEvent(FIFOA_L, (u16)0); - soundEvent(FIFOA_H, (u16)0); - soundEvent(FIFOA_L, (u16)0); - soundEvent(FIFOA_H, (u16)0); - soundEvent(FIFOA_L, (u16)0); - soundEvent(FIFOA_H, (u16)0); - soundEvent(FIFOA_L, (u16)0); - soundEvent(FIFOA_H, (u16)0); - } - } - - soundDSAValue = (soundDSFifoA[soundDSFifoAIndex]); - soundDSFifoAIndex = (++soundDSFifoAIndex) & 31; - soundDSFifoACount--; - } - else - soundDSAValue = 0; -} - -void soundDirectSoundB() -{ - soundBuffer[5][soundIndex] = soundDSBValue; -} - -void soundDirectSoundBTimer() -{ - if(soundDSBEnabled) - { - if(soundDSFifoBCount <= 16) - { - CPUCheckDMA(3, 4); - if(soundDSFifoBCount <= 16) - { - soundEvent(FIFOB_L, (u16)0); - soundEvent(FIFOB_H, (u16)0); - soundEvent(FIFOB_L, (u16)0); - soundEvent(FIFOB_H, (u16)0); - soundEvent(FIFOB_L, (u16)0); - soundEvent(FIFOB_H, (u16)0); - soundEvent(FIFOB_L, (u16)0); - soundEvent(FIFOB_H, (u16)0); - } - } - - soundDSBValue = (soundDSFifoB[soundDSFifoBIndex]); - soundDSFifoBIndex = (++soundDSFifoBIndex) & 31; - soundDSFifoBCount--; - } - else - { - soundDSBValue = 0; - } -} - -void soundTimerOverflow(int timer) -{ - if(soundDSAEnabled && (soundDSATimer == timer)) - { - soundDirectSoundATimer(); - } - if(soundDSBEnabled && (soundDSBTimer == timer)) - { - soundDirectSoundBTimer(); - } -} - -#ifndef max -#define max(a,b) (a)<(b)?(b):(a) -#endif - -void soundMix() -{ - int res = 0; - int cgbRes = 0; - int ratio = ioMem[0x82] & 3; - int dsaRatio = ioMem[0x82] & 4; - int dsbRatio = ioMem[0x82] & 8; - - if(soundBalance & 16) - { - cgbRes = ((s8)soundBuffer[0][soundIndex]); - } - if(soundBalance & 32) - { - cgbRes += ((s8)soundBuffer[1][soundIndex]); - } - if(soundBalance & 64) - { - cgbRes += ((s8)soundBuffer[2][soundIndex]); - } - if(soundBalance & 128) - { - cgbRes += ((s8)soundBuffer[3][soundIndex]); - } - - if((soundControl & 0x0200) && (soundEnableFlag & 0x100)) - { - if(!dsaRatio) - res = ((s8)soundBuffer[4][soundIndex])>>1; - else - res = ((s8)soundBuffer[4][soundIndex]); - } - - if((soundControl & 0x2000) && (soundEnableFlag & 0x200)) - { - if(!dsbRatio) - res += ((s8)soundBuffer[5][soundIndex])>>1; - else - res += ((s8)soundBuffer[5][soundIndex]); - } - - res = (res * 170); - cgbRes = (cgbRes * 52 * soundLevel1); - - switch(ratio) - { - case 0: - case 3: // prohibited, but 25% - cgbRes >>= 2; - break; - case 1: - cgbRes >>= 1; - break; - case 2: - break; - } - - res += cgbRes; - - if(soundEcho) - { - res *= 2; - res += soundFilter[soundEchoIndex]; - res /= 2; - soundFilter[soundEchoIndex++] = res; - } - - if(soundLowPass) - { - soundLeft[4] = soundLeft[3]; - soundLeft[3] = soundLeft[2]; - soundLeft[2] = soundLeft[1]; - soundLeft[1] = soundLeft[0]; - soundLeft[0] = res; - res = (soundLeft[4] + 2*soundLeft[3] + 8*soundLeft[2] + 2*soundLeft[1] + - soundLeft[0])/14; - } - - switch(soundVolume) - { - case 0: - case 1: - case 2: - case 3: - res *= (soundVolume+1); - break; - case 4: - res >>= 2; - break; - case 5: - res >>= 1; - break; - } - - if(res > 32767) - res = 32767; - if(res < -32768) - res = -32768; - - if(soundReverse) - soundFinalWave[++soundBufferIndex] = res; - else - soundFinalWave[soundBufferIndex++] = res; - - res = 0; - cgbRes = 0; - - if(soundBalance & 1) - { - cgbRes = ((s8)soundBuffer[0][soundIndex]); - } - if(soundBalance & 2) - { - cgbRes += ((s8)soundBuffer[1][soundIndex]); - } - if(soundBalance & 4) - { - cgbRes += ((s8)soundBuffer[2][soundIndex]); - } - if(soundBalance & 8) - { - cgbRes += ((s8)soundBuffer[3][soundIndex]); - } - - if((soundControl & 0x0100) && (soundEnableFlag & 0x100)) - { - if(!dsaRatio) - res = ((s8)soundBuffer[4][soundIndex])>>1; - else - res = ((s8)soundBuffer[4][soundIndex]); - } - - if((soundControl & 0x1000) && (soundEnableFlag & 0x200)) - { - if(!dsbRatio) - res += ((s8)soundBuffer[5][soundIndex])>>1; - else - res += ((s8)soundBuffer[5][soundIndex]); - } - - res = (res * 170); - cgbRes = (cgbRes * 52 * soundLevel1); - - switch(ratio) - { - case 0: - case 3: // prohibited, but 25% - cgbRes >>= 2; - break; - case 1: - cgbRes >>= 1; - break; - case 2: - break; - } - - res += cgbRes; - - if(soundEcho) - { - res *= 2; - res += soundFilter[soundEchoIndex]; - res /= 2; - soundFilter[soundEchoIndex++] = res; - - if(soundEchoIndex >= 4000) - soundEchoIndex = 0; - } - - if(soundLowPass) - { - soundRight[4] = soundRight[3]; - soundRight[3] = soundRight[2]; - soundRight[2] = soundRight[1]; - soundRight[1] = soundRight[0]; - soundRight[0] = res; - res = (soundRight[4] + 2*soundRight[3] + 8*soundRight[2] + 2*soundRight[1] + - soundRight[0])/14; - } - - switch(soundVolume) - { - case 0: - case 1: - case 2: - case 3: - res *= (soundVolume+1); - break; - case 4: - res >>= 2; - break; - case 5: - res >>= 1; - break; - } - - if(res > 32767) - res = 32767; - if(res < -32768) - res = -32768; - - if(soundReverse) - soundFinalWave[-1+soundBufferIndex++] = res; - else - soundFinalWave[soundBufferIndex++] = res; -} - -void soundTick() -{ - if(systemSoundOn) - { - if(soundMasterOn && !stopState) - { - soundChannel1(); - soundChannel2(); - soundChannel3(); - soundChannel4(); - soundDirectSoundA(); - soundDirectSoundB(); - soundMix(); - } - else - { - soundFinalWave[soundBufferIndex++] = 0; - soundFinalWave[soundBufferIndex++] = 0; - } - - soundIndex++; - - if(2*soundBufferIndex >= soundBufferLen) - { - if(systemSoundOn) - { - if(soundPaused) - { - soundResume(); - } - - systemWriteDataToSoundBuffer(); - } - soundIndex = 0; - soundBufferIndex = 0; - } - } -} - -void soundShutdown() -{ - systemSoundShutdown(); -} - -void soundPause() -{ - systemSoundPause(); - soundPaused = 1; -} - -void soundResume() -{ - systemSoundResume(); - soundPaused = 0; -} - -void soundEnable(int channels) -{ - int c = channels & 0x0f; - - soundEnableFlag |= ((channels & 0x30f) |c | (c << 4)); - if(ioMem) - soundBalance = (ioMem[NR51] & soundEnableFlag); -} - -void soundDisable(int channels) -{ - int c = channels & 0x0f; - - soundEnableFlag &= (~((channels & 0x30f)|c|(c<<4))); - if(ioMem) - soundBalance = (ioMem[NR51] & soundEnableFlag); -} - -int soundGetEnable() -{ - return (soundEnableFlag & 0x30f); -} - -void soundReset() -{ - systemSoundReset(); - - soundPaused = 1; - soundPlay = 0; - SOUND_CLOCK_TICKS = soundQuality * USE_TICKS_AS; - soundTicks = SOUND_CLOCK_TICKS; - soundNextPosition = 0; - soundMasterOn = 1; - soundIndex = 0; - soundBufferIndex = 0; - soundLevel1 = 7; - soundLevel2 = 7; - - sound1On = 0; - sound1ATL = 0; - sound1Skip = 0; - sound1Index = 0; - sound1Continue = 0; - sound1EnvelopeVolume = 0; - sound1EnvelopeATL = 0; - sound1EnvelopeUpDown = 0; - sound1EnvelopeATLReload = 0; - sound1SweepATL = 0; - sound1SweepATLReload = 0; - sound1SweepSteps = 0; - sound1SweepUpDown = 0; - sound1SweepStep = 0; - sound1Wave = soundWavePattern[2]; - - sound2On = 0; - sound2ATL = 0; - sound2Skip = 0; - sound2Index = 0; - sound2Continue = 0; - sound2EnvelopeVolume = 0; - sound2EnvelopeATL = 0; - sound2EnvelopeUpDown = 0; - sound2EnvelopeATLReload = 0; - sound2Wave = soundWavePattern[2]; - - sound3On = 0; - sound3ATL = 0; - sound3Skip = 0; - sound3Index = 0; - sound3Continue = 0; - sound3OutputLevel = 0; - sound3Last = 0; - sound3Bank = 0; - sound3DataSize = 0; - sound3ForcedOutput = 0; - - sound4On = 0; - sound4Clock = 0; - sound4ATL = 0; - sound4Skip = 0; - sound4Index = 0; - sound4ShiftRight = 0x7f; - sound4NSteps = 0; - sound4CountDown = 0; - sound4Continue = 0; - sound4EnvelopeVolume = 0; - sound4EnvelopeATL = 0; - sound4EnvelopeUpDown = 0; - sound4EnvelopeATLReload = 0; - - sound1On = 0; - sound2On = 0; - sound3On = 0; - sound4On = 0; - - int addr = 0x90; - - while(addr < 0xA0) - { - ioMem[addr++] = 0x00; - ioMem[addr++] = 0xff; - } - - addr = 0; - while(addr < 0x20) - { - sound3WaveRam[addr++] = 0x00; - sound3WaveRam[addr++] = 0xff; - } - - memset(soundFinalWave, 0, soundBufferLen); - - memset(soundFilter, 0, sizeof(soundFilter)); - soundEchoIndex = 0; -} - -bool soundInit() -{ - if(systemSoundInit()) - { - memset(soundBuffer[0], 0, 735*2); - memset(soundBuffer[1], 0, 735*2); - memset(soundBuffer[2], 0, 735*2); - memset(soundBuffer[3], 0, 735*2); - - memset(soundFinalWave, 0, soundBufferLen); - - soundPaused = true; - return true; - } - return false; -} - -void soundSetQuality(int quality) -{ - if(soundQuality != quality && systemCanChangeSoundQuality()) - { - if(!soundOffFlag) - soundShutdown(); - soundQuality = quality; - soundNextPosition = 0; - if(!soundOffFlag) - soundInit(); - SOUND_CLOCK_TICKS = USE_TICKS_AS * soundQuality; - soundIndex = 0; - soundBufferIndex = 0; - } - else if(soundQuality != quality) - { - soundNextPosition = 0; - SOUND_CLOCK_TICKS = USE_TICKS_AS * soundQuality; - soundIndex = 0; - soundBufferIndex = 0; - } -} - -void soundSaveGame(gzFile gzFile) -{ - utilWriteData(gzFile, soundSaveStruct); - utilWriteData(gzFile, soundSaveStructV2); - - utilGzWrite(gzFile, &soundQuality, sizeof(int)); -} - -void soundReadGame(gzFile gzFile, int version) -{ - utilReadData(gzFile, soundSaveStruct); - if(version >= SAVE_GAME_VERSION_3) - { - utilReadData(gzFile, soundSaveStructV2); - } - else - { - sound3Bank = (ioMem[NR30] >> 6) & 1; - sound3DataSize = (ioMem[NR30] >> 5) & 1; - sound3ForcedOutput = (ioMem[NR32] >> 7) & 1; - // nothing better to do here... - memcpy(&sound3WaveRam[0x00], &ioMem[0x90], 0x10); - memcpy(&sound3WaveRam[0x10], &ioMem[0x90], 0x10); - } - soundBufferIndex = soundIndex * 2; - - int quality = 1; - utilGzRead(gzFile, &quality, sizeof(int)); - soundSetQuality(quality); - - sound1Wave = soundWavePattern[ioMem[NR11] >> 6]; - sound2Wave = soundWavePattern[ioMem[NR21] >> 6]; -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program 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, or(at your option) +// any later version. +// +// This program 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 this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include + +#include "GBA.h" +#include "Globals.h" +#include "Sound.h" +#include "Util.h" + +#define USE_TICKS_AS 380 +#define SOUND_MAGIC 0x60000000 +#define SOUND_MAGIC_2 0x30000000 +#define NOISE_MAGIC 5 + +extern bool stopState; + +u8 soundWavePattern[4][32] = { + {0x01,0x01,0x01,0x01, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff}, + {0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff}, + {0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff}, + {0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0x01,0x01,0x01,0x01, + 0xff,0xff,0xff,0xff, + 0xff,0xff,0xff,0xff} + }; + +int soundFreqRatio[8] = { + 1048576, // 0 + 524288, // 1 + 262144, // 2 + 174763, // 3 + 131072, // 4 + 104858, // 5 + 87381, // 6 + 74898 // 7 + }; + +int soundShiftClock[16]= { + 2, // 0 + 4, // 1 + 8, // 2 + 16, // 3 + 32, // 4 + 64, // 5 + 128, // 6 + 256, // 7 + 512, // 8 + 1024, // 9 + 2048, // 10 + 4096, // 11 + 8192, // 12 + 16384, // 13 + 1, // 14 + 1 // 15 + }; + +int soundVolume = 0; + +u8 soundBuffer[6][735]; +u16 soundFinalWave[1470]; + +int soundBufferLen = 1470; +int soundBufferTotalLen = 14700; +int soundQuality = 2; +int soundPaused = 1; +int soundPlay = 0; +int soundTicks = soundQuality * USE_TICKS_AS; +int SOUND_CLOCK_TICKS = soundQuality * USE_TICKS_AS; +u32 soundNextPosition = 0; + +int soundLevel1 = 0; +int soundLevel2 = 0; +int soundBalance = 0; +int soundMasterOn = 0; +int soundIndex = 0; +int soundBufferIndex = 0; +int soundDebug = 0; +bool soundOffFlag = false; + +int sound1On = 0; +int sound1ATL = 0; +int sound1Skip = 0; +int sound1Index = 0; +int sound1Continue = 0; +int sound1EnvelopeVolume = 0; +int sound1EnvelopeATL = 0; +int sound1EnvelopeUpDown = 0; +int sound1EnvelopeATLReload = 0; +int sound1SweepATL = 0; +int sound1SweepATLReload = 0; +int sound1SweepSteps = 0; +int sound1SweepUpDown = 0; +int sound1SweepStep = 0; +u8 *sound1Wave = soundWavePattern[2]; + +int sound2On = 0; +int sound2ATL = 0; +int sound2Skip = 0; +int sound2Index = 0; +int sound2Continue = 0; +int sound2EnvelopeVolume = 0; +int sound2EnvelopeATL = 0; +int sound2EnvelopeUpDown = 0; +int sound2EnvelopeATLReload = 0; +u8 *sound2Wave = soundWavePattern[2]; + +int sound3On = 0; +int sound3ATL = 0; +int sound3Skip = 0; +int sound3Index = 0; +int sound3Continue = 0; +int sound3OutputLevel = 0; +int sound3Last = 0; +u8 sound3WaveRam[0x20]; +int sound3Bank = 0; +int sound3DataSize = 0; +int sound3ForcedOutput = 0; + +int sound4On = 0; +int sound4Clock = 0; +int sound4ATL = 0; +int sound4Skip = 0; +int sound4Index = 0; +int sound4ShiftRight = 0x7f; +int sound4ShiftSkip = 0; +int sound4ShiftIndex = 0; +int sound4NSteps = 0; +int sound4CountDown = 0; +int sound4Continue = 0; +int sound4EnvelopeVolume = 0; +int sound4EnvelopeATL = 0; +int sound4EnvelopeUpDown = 0; +int sound4EnvelopeATLReload = 0; + +int soundControl = 0; + +int soundDSFifoAIndex = 0; +int soundDSFifoACount = 0; +int soundDSFifoAWriteIndex = 0; +bool soundDSAEnabled = false; +int soundDSATimer = 0; +u8 soundDSFifoA[32]; +u8 soundDSAValue = 0; + +int soundDSFifoBIndex = 0; +int soundDSFifoBCount = 0; +int soundDSFifoBWriteIndex = 0; +bool soundDSBEnabled = false; +int soundDSBTimer = 0; +u8 soundDSFifoB[32]; +u8 soundDSBValue = 0; + +int soundEnableFlag = 0x3ff; + +s16 soundFilter[4000]; +s16 soundRight[5] = { 0, 0, 0, 0, 0 }; +s16 soundLeft[5] = { 0, 0, 0, 0, 0 }; +int soundEchoIndex = 0; +bool soundEcho = false; +bool soundLowPass = false; +bool soundReverse = false; + +variable_desc soundSaveStruct[] = { + { &soundPaused, sizeof(int) }, + { &soundPlay, sizeof(int) }, + { &soundTicks, sizeof(int) }, + { &SOUND_CLOCK_TICKS, sizeof(int) }, + { &soundLevel1, sizeof(int) }, + { &soundLevel2, sizeof(int) }, + { &soundBalance, sizeof(int) }, + { &soundMasterOn, sizeof(int) }, + { &soundIndex, sizeof(int) }, + { &sound1On, sizeof(int) }, + { &sound1ATL, sizeof(int) }, + { &sound1Skip, sizeof(int) }, + { &sound1Index, sizeof(int) }, + { &sound1Continue, sizeof(int) }, + { &sound1EnvelopeVolume, sizeof(int) }, + { &sound1EnvelopeATL, sizeof(int) }, + { &sound1EnvelopeATLReload, sizeof(int) }, + { &sound1EnvelopeUpDown, sizeof(int) }, + { &sound1SweepATL, sizeof(int) }, + { &sound1SweepATLReload, sizeof(int) }, + { &sound1SweepSteps, sizeof(int) }, + { &sound1SweepUpDown, sizeof(int) }, + { &sound1SweepStep, sizeof(int) }, + { &sound2On, sizeof(int) }, + { &sound2ATL, sizeof(int) }, + { &sound2Skip, sizeof(int) }, + { &sound2Index, sizeof(int) }, + { &sound2Continue, sizeof(int) }, + { &sound2EnvelopeVolume, sizeof(int) }, + { &sound2EnvelopeATL, sizeof(int) }, + { &sound2EnvelopeATLReload, sizeof(int) }, + { &sound2EnvelopeUpDown, sizeof(int) }, + { &sound3On, sizeof(int) }, + { &sound3ATL, sizeof(int) }, + { &sound3Skip, sizeof(int) }, + { &sound3Index, sizeof(int) }, + { &sound3Continue, sizeof(int) }, + { &sound3OutputLevel, sizeof(int) }, + { &sound4On, sizeof(int) }, + { &sound4ATL, sizeof(int) }, + { &sound4Skip, sizeof(int) }, + { &sound4Index, sizeof(int) }, + { &sound4Clock, sizeof(int) }, + { &sound4ShiftRight, sizeof(int) }, + { &sound4ShiftSkip, sizeof(int) }, + { &sound4ShiftIndex, sizeof(int) }, + { &sound4NSteps, sizeof(int) }, + { &sound4CountDown, sizeof(int) }, + { &sound4Continue, sizeof(int) }, + { &sound4EnvelopeVolume, sizeof(int) }, + { &sound4EnvelopeATL, sizeof(int) }, + { &sound4EnvelopeATLReload, sizeof(int) }, + { &sound4EnvelopeUpDown, sizeof(int) }, + { &soundEnableFlag, sizeof(int) }, + { &soundControl, sizeof(int) }, + { &soundDSFifoAIndex, sizeof(int) }, + { &soundDSFifoACount, sizeof(int) }, + { &soundDSFifoAWriteIndex, sizeof(int) }, + { &soundDSAEnabled, sizeof(bool) }, + { &soundDSATimer, sizeof(int) }, + { &soundDSFifoA[0], 32 }, + { &soundDSAValue, sizeof(u8) }, + { &soundDSFifoBIndex, sizeof(int) }, + { &soundDSFifoBCount, sizeof(int) }, + { &soundDSFifoBWriteIndex, sizeof(int) }, + { &soundDSBEnabled, sizeof(int) }, + { &soundDSBTimer, sizeof(int) }, + { &soundDSFifoB[0], 32 }, + { &soundDSBValue, sizeof(int) }, + { &soundBuffer[0][0], 6*735 }, + { &soundFinalWave[0], 2*735 }, + { NULL, 0 } + }; + +variable_desc soundSaveStructV2[] = { + { &sound3WaveRam[0], 0x20 }, + { &sound3Bank, sizeof(int) }, + { &sound3DataSize, sizeof(int) }, + { &sound3ForcedOutput, sizeof(int) }, + { NULL, 0 } + }; + +void soundEvent(u32 address, u8 data) +{ + int freq = 0; + + switch(address) + { + case NR10: + data &= 0x7f; + sound1SweepATL = sound1SweepATLReload = 344 * ((data >> 4) & 7); + sound1SweepSteps = data & 7; + sound1SweepUpDown = data & 0x08; + sound1SweepStep = 0; + ioMem[address] = data; + break; + case NR11: + sound1Wave = soundWavePattern[data >> 6]; + sound1ATL = 172 * (64 - (data & 0x3f)); + ioMem[address] = data; + break; + case NR12: + sound1EnvelopeUpDown = data & 0x08; + sound1EnvelopeATLReload = 689 * (data & 7); + if((data & 0xF8) == 0) + sound1EnvelopeVolume = 0; + ioMem[address] = data; + break; + case NR13: + freq = (((int)(ioMem[NR14] & 7)) << 8) | data; + sound1ATL = 172 * (64 - (ioMem[NR11] & 0x3f)); + freq = 2048 - freq; + if(freq) + { + sound1Skip = SOUND_MAGIC / freq; + } + else + sound1Skip = 0; + ioMem[address] = data; + break; + case NR14: + data &= 0xC7; + freq = (((int)(data&7) << 8) | ioMem[NR13]); + freq = 2048 - freq; + sound1ATL = 172 * (64 - (ioMem[NR11] & 0x3f)); + sound1Continue = data & 0x40; + if(freq) + { + sound1Skip = SOUND_MAGIC / freq; + } + else + sound1Skip = 0; + if(data & 0x80) + { + ioMem[NR52] |= 1; + sound1EnvelopeVolume = ioMem[NR12] >> 4; + sound1EnvelopeUpDown = ioMem[NR12] & 0x08; + sound1ATL = 172 * (64 - (ioMem[NR11] & 0x3f)); + sound1EnvelopeATLReload = sound1EnvelopeATL = 689 * (ioMem[NR12] & 7); + sound1SweepATL = sound1SweepATLReload = 344 * ((ioMem[NR10] >> 4) & 7); + sound1SweepSteps = ioMem[NR10] & 7; + sound1SweepUpDown = ioMem[NR10] & 0x08; + sound1SweepStep = 0; + + sound1Index = 0; + sound1On = 1; + } + ioMem[address] = data; + break; + case NR21: + sound2Wave = soundWavePattern[data >> 6]; + sound2ATL = 172 * (64 - (data & 0x3f)); + ioMem[address] = data; + break; + case NR22: + sound2EnvelopeUpDown = data & 0x08; + sound2EnvelopeATLReload = 689 * (data & 7); + if((data & 0xF8) == 0) + sound2EnvelopeVolume = 0; + ioMem[address] = data; + break; + case NR23: + freq = (((int)(ioMem[NR24] & 7)) << 8) | data; + sound2ATL = 172 * (64 - (ioMem[NR21] & 0x3f)); + freq = 2048 - freq; + if(freq) + { + sound2Skip = SOUND_MAGIC / freq; + } + else + sound2Skip = 0; + ioMem[address] = data; + break; + case NR24: + data &= 0xC7; + freq = (((int)(data&7) << 8) | ioMem[NR23]); + freq = 2048 - freq; + sound2ATL = 172 * (64 - (ioMem[NR21] & 0x3f)); + sound2Continue = data & 0x40; + if(freq) + { + sound2Skip = SOUND_MAGIC / freq; + } + else + sound2Skip = 0; + if(data & 0x80) + { + ioMem[NR52] |= 2; + sound2EnvelopeVolume = ioMem[NR22] >> 4; + sound2EnvelopeUpDown = ioMem[NR22] & 0x08; + sound2ATL = 172 * (64 - (ioMem[NR21] & 0x3f)); + sound2EnvelopeATLReload = sound2EnvelopeATL = 689 * (ioMem[NR22] & 7); + + sound2Index = 0; + sound2On = 1; + } + break; + ioMem[address] = data; + case NR30: + data &= 0xe0; + if(!(data & 0x80)) + { + ioMem[NR52] &= 0xfb; + sound3On = 0; + } + if(((data >> 6) & 1) != sound3Bank) + memcpy(&ioMem[0x90], &sound3WaveRam[(((data >> 6) & 1) * 0x10)^0x10], + 0x10); + sound3Bank = (data >> 6) & 1; + sound3DataSize = (data >> 5) & 1; + ioMem[address] = data; + break; + case NR31: + sound3ATL = 172 * (256-data); + ioMem[address] = data; + break; + case NR32: + data &= 0xe0; + sound3OutputLevel = (data >> 5) & 3; + sound3ForcedOutput = (data >> 7) & 1; + ioMem[address] = data; + break; + case NR33: + freq = 2048 - (((int)(ioMem[NR34]&7) << 8) | data); + if(freq) + { + sound3Skip = SOUND_MAGIC_2 / freq; + } + else + sound3Skip = 0; + ioMem[address] = data; + break; + case NR34: + data &= 0xc7; + freq = 2048 - (((data &7) << 8) | (int)ioMem[NR33]); + if(freq) + { + sound3Skip = SOUND_MAGIC_2 / freq; + } + else + { + sound3Skip = 0; + } + sound3Continue = data & 0x40; + if((data & 0x80) && (ioMem[NR30] & 0x80)) + { + ioMem[NR52] |= 4; + sound3ATL = 172 * (256 - ioMem[NR31]); + sound3Index = 0; + sound3On = 1; + } + ioMem[address] = data; + break; + case NR41: + data &= 0x3f; + sound4ATL = 172 * (64 - (data & 0x3f)); + ioMem[address] = data; + break; + case NR42: + sound4EnvelopeUpDown = data & 0x08; + sound4EnvelopeATLReload = 689 * (data & 7); + if((data & 0xF8) == 0) + sound4EnvelopeVolume = 0; + ioMem[address] = data; + break; + case NR43: + freq = soundFreqRatio[data & 7]; + sound4NSteps = data & 0x08; + + sound4Skip = (freq << 8) / NOISE_MAGIC; + + sound4Clock = data >> 4; + + freq = freq / soundShiftClock[sound4Clock]; + + sound4ShiftSkip = (freq << 8) / NOISE_MAGIC; + ioMem[address] = data; + break; + case NR44: + data &= 0xc0; + sound4Continue = data & 0x40; + if(data & 0x80) + { + ioMem[NR52] |= 8; + sound4EnvelopeVolume = ioMem[NR42] >> 4; + sound4EnvelopeUpDown = ioMem[NR42] & 0x08; + sound4ATL = 172 * (64 - (ioMem[NR41] & 0x3f)); + sound4EnvelopeATLReload = sound4EnvelopeATL = 689 * (ioMem[NR42] & 7); + + sound4On = 1; + + sound4Index = 0; + sound4ShiftIndex = 0; + + freq = soundFreqRatio[ioMem[NR43] & 7]; + + sound4Skip = (freq << 8) / NOISE_MAGIC; + + sound4NSteps = ioMem[NR43] & 0x08; + + freq = freq / soundShiftClock[ioMem[NR43] >> 4]; + + sound4ShiftSkip = (freq << 8) / NOISE_MAGIC; + if(sound4NSteps) + sound4ShiftRight = 0x7fff; + else + sound4ShiftRight = 0x7f; + } + ioMem[address] = data; + break; + case NR50: + data &= 0x77; + soundLevel1 = data & 7; + soundLevel2 = (data >> 4) & 7; + ioMem[address] = data; + break; + case NR51: + soundBalance = (data & soundEnableFlag); + ioMem[address] = data; + break; + case NR52: + data &= 0x80; + data |= ioMem[NR52] & 15; + soundMasterOn = data & 0x80; + if(!(data & 0x80)) + { + sound1On = 0; + sound2On = 0; + sound3On = 0; + sound4On = 0; + } + ioMem[address] = data; + break; + case 0x90: + case 0x91: + case 0x92: + case 0x93: + case 0x94: + case 0x95: + case 0x96: + case 0x97: + case 0x98: + case 0x99: + case 0x9a: + case 0x9b: + case 0x9c: + case 0x9d: + case 0x9e: + case 0x9f: + sound3WaveRam[(sound3Bank*0x10)^0x10+(address&15)] = data; + break; + } +} + +void soundEvent(u32 address, u16 data) +{ + switch(address) + { + case SGCNT0_H: + data &= 0xFF0F; + soundControl = data & 0x770F; + ; + if(data & 0x0800) + { + soundDSFifoAWriteIndex = 0; + soundDSFifoAIndex = 0; + soundDSFifoACount = 0; + soundDSAValue = 0; + memset(soundDSFifoA, 0, 32); + } + soundDSAEnabled = (data & 0x0300) ? true : false; + soundDSATimer = (data & 0x0400) ? 1 : 0; + if(data & 0x8000) + { + soundDSFifoBWriteIndex = 0; + soundDSFifoBIndex = 0; + soundDSFifoBCount = 0; + soundDSBValue = 0; + memset(soundDSFifoB, 0, 32); + } + soundDSBEnabled = (data & 0x3000) ? true : false; + soundDSBTimer = (data & 0x4000) ? 1 : 0; + *((u16 *)&ioMem[address]) = data; + break; + case FIFOA_L: + case FIFOA_H: + soundDSFifoA[soundDSFifoAWriteIndex++] = data & 0xFF; + soundDSFifoA[soundDSFifoAWriteIndex++] = data >> 8; + soundDSFifoACount += 2; + soundDSFifoAWriteIndex &= 31; + *((u16 *)&ioMem[address]) = data; + break; + case FIFOB_L: + case FIFOB_H: + soundDSFifoB[soundDSFifoBWriteIndex++] = data & 0xFF; + soundDSFifoB[soundDSFifoBWriteIndex++] = data >> 8; + soundDSFifoBCount += 2; + soundDSFifoBWriteIndex &= 31; + *((u16 *)&ioMem[address]) = data; + break; + case 0x88: + data &= 0xC3FF; + *((u16 *)&ioMem[address]) = data; + break; + case 0x90: + case 0x92: + case 0x94: + case 0x96: + case 0x98: + case 0x9a: + case 0x9c: + case 0x9e: + *((u16 *)&sound3WaveRam[(sound3Bank*0x10)^0x10+(address&14)]) = data; + *((u16 *)&ioMem[address]) = data; + break; + } +} + +void soundChannel1() +{ + int vol = sound1EnvelopeVolume; + + int freq = 0; + int value = 0; + + if(sound1On && (sound1ATL || !sound1Continue)) + { + sound1Index += soundQuality*sound1Skip; + sound1Index &= 0x1fffffff; + + value = ((s8)sound1Wave[sound1Index>>24]) * vol; + } + + soundBuffer[0][soundIndex] = value; + + + if(sound1On) + { + if(sound1ATL) + { + sound1ATL-=soundQuality; + + if(sound1ATL <=0 && sound1Continue) + { + ioMem[NR52] &= 0xfe; + sound1On = 0; + } + } + + if(sound1EnvelopeATL) + { + sound1EnvelopeATL-=soundQuality; + + if(sound1EnvelopeATL<=0) + { + if(sound1EnvelopeUpDown) + { + if(sound1EnvelopeVolume < 15) + sound1EnvelopeVolume++; + } + else + { + if(sound1EnvelopeVolume) + sound1EnvelopeVolume--; + } + + sound1EnvelopeATL += sound1EnvelopeATLReload; + } + } + + if(sound1SweepATL) + { + sound1SweepATL-=soundQuality; + + if(sound1SweepATL<=0) + { + freq = (((int)(ioMem[NR14]&7) << 8) | ioMem[NR13]); + + int updown = 1; + + if(sound1SweepUpDown) + updown = -1; + + int newfreq = 0; + if(sound1SweepSteps) + { + newfreq = freq + updown * freq / (1 << sound1SweepSteps); + if(newfreq == freq) + newfreq = 0; + } + else + newfreq = freq; + + if(newfreq < 0) + { + sound1SweepATL += sound1SweepATLReload; + } + else if(newfreq > 2047) + { + sound1SweepATL = 0; + sound1On = 0; + ioMem[NR52] &= 0xfe; + } + else + { + sound1SweepATL += sound1SweepATLReload; + sound1Skip = SOUND_MAGIC/(2048 - newfreq); + + ioMem[NR13] = newfreq & 0xff; + ioMem[NR14] = (ioMem[NR14] & 0xf8) |((newfreq >> 8) & 7); + } + } + } + } +} + +void soundChannel2() +{ + // int freq = 0; + int vol = sound2EnvelopeVolume; + + int value = 0; + + if(sound2On && (sound2ATL || !sound2Continue)) + { + sound2Index += soundQuality*sound2Skip; + sound2Index &= 0x1fffffff; + + value = ((s8)sound2Wave[sound2Index>>24]) * vol; + } + + soundBuffer[1][soundIndex] = value; + + if(sound2On) + { + if(sound2ATL) + { + sound2ATL-=soundQuality; + + if(sound2ATL <= 0 && sound2Continue) + { + ioMem[NR52] &= 0xfd; + sound2On = 0; + } + } + + if(sound2EnvelopeATL) + { + sound2EnvelopeATL-=soundQuality; + + if(sound2EnvelopeATL <= 0) + { + if(sound2EnvelopeUpDown) + { + if(sound2EnvelopeVolume < 15) + sound2EnvelopeVolume++; + } + else + { + if(sound2EnvelopeVolume) + sound2EnvelopeVolume--; + } + sound2EnvelopeATL += sound2EnvelopeATLReload; + } + } + } +} + +void soundChannel3() +{ + int value = sound3Last; + + if(sound3On && (sound3ATL || !sound3Continue)) + { + sound3Index += soundQuality*sound3Skip; + if(sound3DataSize) + { + sound3Index &= 0x3fffffff; + value = sound3WaveRam[sound3Index>>25]; + } + else + { + sound3Index &= 0x1fffffff; + value = sound3WaveRam[sound3Bank*0x10 + (sound3Index>>25)]; + } + + if( (sound3Index & 0x01000000)) + { + value &= 0x0f; + } + else + { + value >>= 4; + } + + value -= 8; + //value *= 2; + value <<= 1; + + if(sound3ForcedOutput) + { + value = ((value >> 1) + value) >> 1; + } + else + { + switch(sound3OutputLevel) + { + case 0: + value = 0; + break; + case 1: + break; + case 2: + value = (value >> 1); + break; + case 3: + value = (value >> 2); + break; + } + } + sound3Last = value; + } + + soundBuffer[2][soundIndex] = value; + + if(sound3On) + { + if(sound3ATL) + { + sound3ATL-=soundQuality; + + if(sound3ATL <= 0 && sound3Continue) + { + ioMem[NR52] &= 0xfb; + sound3On = 0; + } + } + } +} + +void soundChannel4() +{ + int vol = sound4EnvelopeVolume; + + int value = 0; + + if(sound4Clock <= 0x0c) + { + if(sound4On && (sound4ATL || !sound4Continue)) + { + sound4Index += soundQuality*sound4Skip; + sound4ShiftIndex += soundQuality*sound4ShiftSkip; + + if(sound4NSteps) + { + while(sound4ShiftIndex > 0x1fffff) + { + sound4ShiftRight = (((sound4ShiftRight << 6) ^ + (sound4ShiftRight << 5)) & 0x40) | + (sound4ShiftRight >> 1); + sound4ShiftIndex -= 0x200000; + } + } + else + { + while(sound4ShiftIndex > 0x1fffff) + { + sound4ShiftRight = (((sound4ShiftRight << 14) ^ + (sound4ShiftRight << 13)) & 0x4000) | + (sound4ShiftRight >> 1); + + sound4ShiftIndex -= 0x200000; + } + } + + sound4Index &= 0x1fffff; + sound4ShiftIndex &= 0x1fffff; + + value = ((sound4ShiftRight & 1)*2-1) * vol; + } + else + { + value = 0; + } + } + + soundBuffer[3][soundIndex] = value; + + if(sound4On) + { + if(sound4ATL) + { + sound4ATL-=soundQuality; + + if(sound4ATL <= 0 && sound4Continue) + { + ioMem[NR52] &= 0xfd; + sound4On = 0; + } + } + + if(sound4EnvelopeATL) + { + sound4EnvelopeATL-=soundQuality; + + if(sound4EnvelopeATL <= 0) + { + if(sound4EnvelopeUpDown) + { + if(sound4EnvelopeVolume < 15) + sound4EnvelopeVolume++; + } + else + { + if(sound4EnvelopeVolume) + sound4EnvelopeVolume--; + } + sound4EnvelopeATL += sound4EnvelopeATLReload; + } + } + } +} + +void soundDirectSoundA() +{ + soundBuffer[4][soundIndex] = soundDSAValue; +} + +void soundDirectSoundATimer() +{ + if(soundDSAEnabled) + { + if(soundDSFifoACount <= 16) + { + CPUCheckDMA(3, 2); + if(soundDSFifoACount <= 16) + { + soundEvent(FIFOA_L, (u16)0); + soundEvent(FIFOA_H, (u16)0); + soundEvent(FIFOA_L, (u16)0); + soundEvent(FIFOA_H, (u16)0); + soundEvent(FIFOA_L, (u16)0); + soundEvent(FIFOA_H, (u16)0); + soundEvent(FIFOA_L, (u16)0); + soundEvent(FIFOA_H, (u16)0); + } + } + + soundDSAValue = (soundDSFifoA[soundDSFifoAIndex]); + soundDSFifoAIndex = (++soundDSFifoAIndex) & 31; + soundDSFifoACount--; + } + else + soundDSAValue = 0; +} + +void soundDirectSoundB() +{ + soundBuffer[5][soundIndex] = soundDSBValue; +} + +void soundDirectSoundBTimer() +{ + if(soundDSBEnabled) + { + if(soundDSFifoBCount <= 16) + { + CPUCheckDMA(3, 4); + if(soundDSFifoBCount <= 16) + { + soundEvent(FIFOB_L, (u16)0); + soundEvent(FIFOB_H, (u16)0); + soundEvent(FIFOB_L, (u16)0); + soundEvent(FIFOB_H, (u16)0); + soundEvent(FIFOB_L, (u16)0); + soundEvent(FIFOB_H, (u16)0); + soundEvent(FIFOB_L, (u16)0); + soundEvent(FIFOB_H, (u16)0); + } + } + + soundDSBValue = (soundDSFifoB[soundDSFifoBIndex]); + soundDSFifoBIndex = (++soundDSFifoBIndex) & 31; + soundDSFifoBCount--; + } + else + { + soundDSBValue = 0; + } +} + +void soundTimerOverflow(int timer) +{ + if(soundDSAEnabled && (soundDSATimer == timer)) + { + soundDirectSoundATimer(); + } + if(soundDSBEnabled && (soundDSBTimer == timer)) + { + soundDirectSoundBTimer(); + } +} + +#ifndef max +#define max(a,b) (a)<(b)?(b):(a) +#endif + +void soundMix() +{ + int res = 0; + int cgbRes = 0; + int ratio = ioMem[0x82] & 3; + int dsaRatio = ioMem[0x82] & 4; + int dsbRatio = ioMem[0x82] & 8; + + if(soundBalance & 16) + { + cgbRes = ((s8)soundBuffer[0][soundIndex]); + } + if(soundBalance & 32) + { + cgbRes += ((s8)soundBuffer[1][soundIndex]); + } + if(soundBalance & 64) + { + cgbRes += ((s8)soundBuffer[2][soundIndex]); + } + if(soundBalance & 128) + { + cgbRes += ((s8)soundBuffer[3][soundIndex]); + } + + if((soundControl & 0x0200) && (soundEnableFlag & 0x100)) + { + if(!dsaRatio) + res = ((s8)soundBuffer[4][soundIndex])>>1; + else + res = ((s8)soundBuffer[4][soundIndex]); + } + + if((soundControl & 0x2000) && (soundEnableFlag & 0x200)) + { + if(!dsbRatio) + res += ((s8)soundBuffer[5][soundIndex])>>1; + else + res += ((s8)soundBuffer[5][soundIndex]); + } + + res = (res * 170); + cgbRes = (cgbRes * 52 * soundLevel1); + + switch(ratio) + { + case 0: + case 3: // prohibited, but 25% + cgbRes >>= 2; + break; + case 1: + cgbRes >>= 1; + break; + case 2: + break; + } + + res += cgbRes; + + if(soundEcho) + { + res *= 2; + res += soundFilter[soundEchoIndex]; + res /= 2; + soundFilter[soundEchoIndex++] = res; + } + + if(soundLowPass) + { + soundLeft[4] = soundLeft[3]; + soundLeft[3] = soundLeft[2]; + soundLeft[2] = soundLeft[1]; + soundLeft[1] = soundLeft[0]; + soundLeft[0] = res; + res = (soundLeft[4] + 2*soundLeft[3] + 8*soundLeft[2] + 2*soundLeft[1] + + soundLeft[0])/14; + } + + switch(soundVolume) + { + case 0: + case 1: + case 2: + case 3: + res *= (soundVolume+1); + break; + case 4: + res >>= 2; + break; + case 5: + res >>= 1; + break; + } + + if(res > 32767) + res = 32767; + if(res < -32768) + res = -32768; + + if(soundReverse) + soundFinalWave[++soundBufferIndex] = res; + else + soundFinalWave[soundBufferIndex++] = res; + + res = 0; + cgbRes = 0; + + if(soundBalance & 1) + { + cgbRes = ((s8)soundBuffer[0][soundIndex]); + } + if(soundBalance & 2) + { + cgbRes += ((s8)soundBuffer[1][soundIndex]); + } + if(soundBalance & 4) + { + cgbRes += ((s8)soundBuffer[2][soundIndex]); + } + if(soundBalance & 8) + { + cgbRes += ((s8)soundBuffer[3][soundIndex]); + } + + if((soundControl & 0x0100) && (soundEnableFlag & 0x100)) + { + if(!dsaRatio) + res = ((s8)soundBuffer[4][soundIndex])>>1; + else + res = ((s8)soundBuffer[4][soundIndex]); + } + + if((soundControl & 0x1000) && (soundEnableFlag & 0x200)) + { + if(!dsbRatio) + res += ((s8)soundBuffer[5][soundIndex])>>1; + else + res += ((s8)soundBuffer[5][soundIndex]); + } + + res = (res * 170); + cgbRes = (cgbRes * 52 * soundLevel1); + + switch(ratio) + { + case 0: + case 3: // prohibited, but 25% + cgbRes >>= 2; + break; + case 1: + cgbRes >>= 1; + break; + case 2: + break; + } + + res += cgbRes; + + if(soundEcho) + { + res *= 2; + res += soundFilter[soundEchoIndex]; + res /= 2; + soundFilter[soundEchoIndex++] = res; + + if(soundEchoIndex >= 4000) + soundEchoIndex = 0; + } + + if(soundLowPass) + { + soundRight[4] = soundRight[3]; + soundRight[3] = soundRight[2]; + soundRight[2] = soundRight[1]; + soundRight[1] = soundRight[0]; + soundRight[0] = res; + res = (soundRight[4] + 2*soundRight[3] + 8*soundRight[2] + 2*soundRight[1] + + soundRight[0])/14; + } + + switch(soundVolume) + { + case 0: + case 1: + case 2: + case 3: + res *= (soundVolume+1); + break; + case 4: + res >>= 2; + break; + case 5: + res >>= 1; + break; + } + + if(res > 32767) + res = 32767; + if(res < -32768) + res = -32768; + + if(soundReverse) + soundFinalWave[-1+soundBufferIndex++] = res; + else + soundFinalWave[soundBufferIndex++] = res; +} + +void soundTick() +{ + if(systemSoundOn) + { + if(soundMasterOn && !stopState) + { + soundChannel1(); + soundChannel2(); + soundChannel3(); + soundChannel4(); + soundDirectSoundA(); + soundDirectSoundB(); + soundMix(); + } + else + { + soundFinalWave[soundBufferIndex++] = 0; + soundFinalWave[soundBufferIndex++] = 0; + } + + soundIndex++; + + if(2*soundBufferIndex >= soundBufferLen) + { + if(systemSoundOn) + { + if(soundPaused) + { + soundResume(); + } + + systemWriteDataToSoundBuffer(); + } + soundIndex = 0; + soundBufferIndex = 0; + } + } +} + +void soundShutdown() +{ + systemSoundShutdown(); +} + +void soundPause() +{ + systemSoundPause(); + soundPaused = 1; +} + +void soundResume() +{ + systemSoundResume(); + soundPaused = 0; +} + +void soundEnable(int channels) +{ + int c = channels & 0x0f; + + soundEnableFlag |= ((channels & 0x30f) |c | (c << 4)); + if(ioMem) + soundBalance = (ioMem[NR51] & soundEnableFlag); +} + +void soundDisable(int channels) +{ + int c = channels & 0x0f; + + soundEnableFlag &= (~((channels & 0x30f)|c|(c<<4))); + if(ioMem) + soundBalance = (ioMem[NR51] & soundEnableFlag); +} + +int soundGetEnable() +{ + return (soundEnableFlag & 0x30f); +} + +void soundReset() +{ + systemSoundReset(); + + soundPaused = 1; + soundPlay = 0; + SOUND_CLOCK_TICKS = soundQuality * USE_TICKS_AS; + soundTicks = SOUND_CLOCK_TICKS; + soundNextPosition = 0; + soundMasterOn = 1; + soundIndex = 0; + soundBufferIndex = 0; + soundLevel1 = 7; + soundLevel2 = 7; + + sound1On = 0; + sound1ATL = 0; + sound1Skip = 0; + sound1Index = 0; + sound1Continue = 0; + sound1EnvelopeVolume = 0; + sound1EnvelopeATL = 0; + sound1EnvelopeUpDown = 0; + sound1EnvelopeATLReload = 0; + sound1SweepATL = 0; + sound1SweepATLReload = 0; + sound1SweepSteps = 0; + sound1SweepUpDown = 0; + sound1SweepStep = 0; + sound1Wave = soundWavePattern[2]; + + sound2On = 0; + sound2ATL = 0; + sound2Skip = 0; + sound2Index = 0; + sound2Continue = 0; + sound2EnvelopeVolume = 0; + sound2EnvelopeATL = 0; + sound2EnvelopeUpDown = 0; + sound2EnvelopeATLReload = 0; + sound2Wave = soundWavePattern[2]; + + sound3On = 0; + sound3ATL = 0; + sound3Skip = 0; + sound3Index = 0; + sound3Continue = 0; + sound3OutputLevel = 0; + sound3Last = 0; + sound3Bank = 0; + sound3DataSize = 0; + sound3ForcedOutput = 0; + + sound4On = 0; + sound4Clock = 0; + sound4ATL = 0; + sound4Skip = 0; + sound4Index = 0; + sound4ShiftRight = 0x7f; + sound4NSteps = 0; + sound4CountDown = 0; + sound4Continue = 0; + sound4EnvelopeVolume = 0; + sound4EnvelopeATL = 0; + sound4EnvelopeUpDown = 0; + sound4EnvelopeATLReload = 0; + + sound1On = 0; + sound2On = 0; + sound3On = 0; + sound4On = 0; + + int addr = 0x90; + + while(addr < 0xA0) + { + ioMem[addr++] = 0x00; + ioMem[addr++] = 0xff; + } + + addr = 0; + while(addr < 0x20) + { + sound3WaveRam[addr++] = 0x00; + sound3WaveRam[addr++] = 0xff; + } + + memset(soundFinalWave, 0, soundBufferLen); + + memset(soundFilter, 0, sizeof(soundFilter)); + soundEchoIndex = 0; +} + +bool soundInit() +{ + if(systemSoundInit()) + { + memset(soundBuffer[0], 0, 735*2); + memset(soundBuffer[1], 0, 735*2); + memset(soundBuffer[2], 0, 735*2); + memset(soundBuffer[3], 0, 735*2); + + memset(soundFinalWave, 0, soundBufferLen); + + soundPaused = true; + return true; + } + return false; +} + +void soundSetQuality(int quality) +{ + if(soundQuality != quality && systemCanChangeSoundQuality()) + { + if(!soundOffFlag) + soundShutdown(); + soundQuality = quality; + soundNextPosition = 0; + if(!soundOffFlag) + soundInit(); + SOUND_CLOCK_TICKS = USE_TICKS_AS * soundQuality; + soundIndex = 0; + soundBufferIndex = 0; + } + else if(soundQuality != quality) + { + soundNextPosition = 0; + SOUND_CLOCK_TICKS = USE_TICKS_AS * soundQuality; + soundIndex = 0; + soundBufferIndex = 0; + } +} + +void soundSaveGame(gzFile gzFile) +{ + utilWriteData(gzFile, soundSaveStruct); + utilWriteData(gzFile, soundSaveStructV2); + + utilGzWrite(gzFile, &soundQuality, sizeof(int)); +} + +void soundReadGame(gzFile gzFile, int version) +{ + utilReadData(gzFile, soundSaveStruct); + if(version >= SAVE_GAME_VERSION_3) + { + utilReadData(gzFile, soundSaveStructV2); + } + else + { + sound3Bank = (ioMem[NR30] >> 6) & 1; + sound3DataSize = (ioMem[NR30] >> 5) & 1; + sound3ForcedOutput = (ioMem[NR32] >> 7) & 1; + // nothing better to do here... + memcpy(&sound3WaveRam[0x00], &ioMem[0x90], 0x10); + memcpy(&sound3WaveRam[0x10], &ioMem[0x90], 0x10); + } + soundBufferIndex = soundIndex * 2; + + int quality = 1; + utilGzRead(gzFile, &quality, sizeof(int)); + soundSetQuality(quality); + + sound1Wave = soundWavePattern[ioMem[NR11] >> 6]; + sound2Wave = soundWavePattern[ioMem[NR21] >> 6]; +} diff --git a/src/Util.cpp b/src/Util.cpp index 2823e54..d6f94f3 100644 --- a/src/Util.cpp +++ b/src/Util.cpp @@ -1,1196 +1,1195 @@ -// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. -// Copyright (C) 1999-2003 Forgotten -// Copyright (C) 2004 Forgotten and the VBA development team - -// This program 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, or(at your option) -// any later version. -// -// This program 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 this program; if not, write to the Free Software Foundation, -// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include "sdfileio.h" -#include -#include -#include -#include - -extern "C" - { -#include - } - -#if 0 -#include "unrarlib.h" -#endif - -#include "System.h" -#include "NLS.h" -#include "Util.h" -#include "Flash.h" -#include "GBA.h" -#include "Globals.h" -#include "RTC.h" -#include "Port.h" - - -extern "C" - { -#include "memgzio.h" - } - -#ifndef _MSC_VER -#define _stricmp strcasecmp -#endif // ! _MSC_VER - -static int (*utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL; -static int (*utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL; -static int (*utilGzCloseFunc)(gzFile) = NULL; - -bool utilWritePNGFile(const char *fileName, int w, int h, u8 *pix) -{ -#if 0 - u8 writeBuffer[512 * 3]; - - FILE* fp = gen_fopen(fileName,"wb"); - - if(!fp) - { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); - return false; - } - - png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, - NULL, - NULL, - NULL); - if(!png_ptr) - { - gen_fclose(fp); - return false; - } - - png_infop info_ptr = png_create_info_struct(png_ptr); - - if(!info_ptr) - { - png_destroy_write_struct(&png_ptr,NULL); - gen_fclose(fp); - return false; - } - - if(setjmp(png_ptr->jmpbuf)) - { - png_destroy_write_struct(&png_ptr,NULL); - gen_fclose(fp); - return false; - } - - png_init_io(png_ptr,fp); - - png_set_IHDR(png_ptr, - info_ptr, - w, - h, - 8, - PNG_COLOR_TYPE_RGB, - PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, - PNG_FILTER_TYPE_DEFAULT); - - png_write_info(png_ptr,info_ptr); - - u8 *b = writeBuffer; - - int sizeX = w; - int sizeY = h; - - switch(systemColorDepth) - { - case 16: - { - u16 *p = (u16 *)(pix+(w+2)*2); // skip first black line - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - u16 v = *p++; - - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B - } - p++; // skip black pixel for filters - p++; // skip black pixel for filters - png_write_row(png_ptr,writeBuffer); - - b = writeBuffer; - } - } - break; - case 24: - { - u8 *pixU8 = (u8 *)pix; - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - if(systemRedShift < systemBlueShift) - { - *b++ = *pixU8++; // R - *b++ = *pixU8++; // G - *b++ = *pixU8++; // B - } - else - { - int blue = *pixU8++; - int green = *pixU8++; - int red = *pixU8++; - - *b++ = red; - *b++ = green; - *b++ = blue; - } - } - png_write_row(png_ptr,writeBuffer); - - b = writeBuffer; - } - } - break; - case 32: - { - u32 *pixU32 = (u32 *)(pix+4*(w+1)); - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - u32 v = *pixU32++; - - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B - } - pixU32++; - - png_write_row(png_ptr,writeBuffer); - - b = writeBuffer; - } - } - break; - } - - png_write_end(png_ptr, info_ptr); - - png_destroy_write_struct(&png_ptr, &info_ptr); - - gen_fclose(fp); - -#endif - return true; -} - -void utilPutDword(u8 *p, u32 value) -{ - *p++ = value & 255; - *p++ = (value >> 8) & 255; - *p++ = (value >> 16) & 255; - *p = (value >> 24) & 255; -} - -void utilPutWord(u8 *p, u16 value) -{ - *p++ = value & 255; - *p = (value >> 8) & 255; -} - -void utilWriteBMP(char *buf, int w, int h, u8 *pix) -{ - u8 *b = (u8 *)buf; - - int sizeX = w; - int sizeY = h; - - switch(systemColorDepth) - { - case 16: - { - u16 *p = (u16 *)(pix+(w+2)*(h)*2); // skip first black line - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - u16 v = *p++; - - *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - } - p++; // skip black pixel for filters - p++; // skip black pixel for filters - p -= 2*(w+2); - } - } - break; - case 24: - { - u8 *pixU8 = (u8 *)pix+3*w*(h-1); - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - if(systemRedShift > systemBlueShift) - { - *b++ = *pixU8++; // B - *b++ = *pixU8++; // G - *b++ = *pixU8++; // R - } - else - { - int red = *pixU8++; - int green = *pixU8++; - int blue = *pixU8++; - - *b++ = blue; - *b++ = green; - *b++ = red; - } - } - pixU8 -= 2*3*w; - } - } - break; - case 32: - { - u32 *pixU32 = (u32 *)(pix+4*(w+1)*(h)); - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - u32 v = *pixU32++; - - *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - } - pixU32++; - pixU32 -= 2*(w+1); - } - } - break; - } -} - -bool utilWriteBMPFile(const char *fileName, int w, int h, u8 *pix) -{ - u8 writeBuffer[512 * 3]; - - FILE* fp = gen_fopen(fileName,"wb"); - - if(!fp) - { - systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); - return false; - } - - struct - { - u8 ident[2]; - u8 filesize[4]; - u8 reserved[4]; - u8 dataoffset[4]; - u8 headersize[4]; - u8 width[4]; - u8 height[4]; - u8 planes[2]; - u8 bitsperpixel[2]; - u8 compression[4]; - u8 datasize[4]; - u8 hres[4]; - u8 vres[4]; - u8 colors[4]; - u8 importantcolors[4]; - // u8 pad[2]; - } - bmpheader; - memset(&bmpheader, 0, sizeof(bmpheader)); - - bmpheader.ident[0] = 'B'; - bmpheader.ident[1] = 'M'; - - u32 fsz = sizeof(bmpheader) + w*h*3; - utilPutDword(bmpheader.filesize, fsz); - utilPutDword(bmpheader.dataoffset, 0x36); - utilPutDword(bmpheader.headersize, 0x28); - utilPutDword(bmpheader.width, w); - utilPutDword(bmpheader.height, h); - utilPutDword(bmpheader.planes, 1); - utilPutDword(bmpheader.bitsperpixel, 24); - utilPutDword(bmpheader.datasize, 3*w*h); - - gen_fwrite(&bmpheader, 1, sizeof(bmpheader), fp); - - u8 *b = writeBuffer; - - int sizeX = w; - int sizeY = h; - - switch(systemColorDepth) - { - case 16: - { - u16 *p = (u16 *)(pix+(w+2)*(h)*2); // skip first black line - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - u16 v = *p++; - - *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - } - p++; // skip black pixel for filters - p++; // skip black pixel for filters - p -= 2*(w+2); - gen_fwrite(writeBuffer, 1, 3*w, fp); - - b = writeBuffer; - } - } - break; - case 24: - { - u8 *pixU8 = (u8 *)pix+3*w*(h-1); - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - if(systemRedShift > systemBlueShift) - { - *b++ = *pixU8++; // B - *b++ = *pixU8++; // G - *b++ = *pixU8++; // R - } - else - { - int red = *pixU8++; - int green = *pixU8++; - int blue = *pixU8++; - - *b++ = blue; - *b++ = green; - *b++ = red; - } - } - pixU8 -= 2*3*w; - gen_fwrite(writeBuffer, 1, 3*w, fp); - - b = writeBuffer; - } - } - break; - case 32: - { - u32 *pixU32 = (u32 *)(pix+4*(w+1)*(h)); - for(int y = 0; y < sizeY; y++) - { - for(int x = 0; x < sizeX; x++) - { - u32 v = *pixU32++; - - *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B - *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G - *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R - } - pixU32++; - pixU32 -= 2*(w+1); - - gen_fwrite(writeBuffer, 1, 3*w, fp); - - b = writeBuffer; - } - } - break; - } - - gen_fclose(fp); - - return true; -} - -static int utilReadInt2(FILE* f) -{ - int res = 0; - int c = gen_fgetc(f); - if(c == EOF) - return -1; - res = c; - c = gen_fgetc(f); - if(c == EOF) - return -1; - return c + (res<<8); -} - -static int utilReadInt3(FILE* f) -{ - int res = 0; - int c = gen_fgetc(f); - if(c == EOF) - return -1; - res = c; - c = gen_fgetc(f); - if(c == EOF) - return -1; - res = c + (res<<8); - c = gen_fgetc(f); - if(c == EOF) - return -1; - return c + (res<<8); -} - -void utilApplyIPS(const char *ips, u8 **r, int *s) -{ - // from the IPS spec at http://zerosoft.zophar.net/ips.htm - FILE* f = gen_fopen(ips, "rb"); - if(!f) - return; - u8 *rom = *r; - int size = *s; - if(gen_fgetc(f) == 'P' && - gen_fgetc(f) == 'A' && - gen_fgetc(f) == 'T' && - gen_fgetc(f) == 'C' && - gen_fgetc(f) == 'H') - { - int b; - int offset; - int len; - for(;;) - { - // read offset - offset = utilReadInt3(f); - // if offset == EOF, end of patch - if(offset == 0x454f46) - break; - // read length - len = utilReadInt2(f); - if(!len) - { - // len == 0, RLE block - len = utilReadInt2(f); - // byte to fill - int c = gen_fgetc(f); - if(c == -1) - break; - b = (u8)c; - } - else - b= -1; - // check if we need to reallocate our ROM - if((offset + len) >= size) - { - size *= 2; - rom = (u8 *)realloc(rom, size); - *r = rom; - *s = size; - } - if(b == -1) - { - // normal block, just read the data - //if(gen_fread(&rom[offset], 1, len, f) != (size_t)len) - if(gen_fread(&rom[offset], 1, len, f) != (int)len) - break; - } - else - { - // fill the region with the given byte - while(len--) - { - rom[offset++] = b; - } - } - } - } - // close the file - gen_fclose(f); -} - -extern bool cpuIsMultiBoot; - -bool utilIsGBAImage(const char * file) -{ - cpuIsMultiBoot = false; - if(strlen(file) > 4) - { - char * p = strrchr(file,'.'); - - if(p != NULL) - { - if(_stricmp(p, ".gba") == 0) - return true; - if(_stricmp(p, ".agb") == 0) - return true; - if(_stricmp(p, ".bin") == 0) - return true; - if(_stricmp(p, ".elf") == 0) - return true; - if(_stricmp(p, ".mb") == 0) - { - cpuIsMultiBoot = true; - return true; - } - } - } - - return false; -} - -bool utilIsGBImage(const char * file) -{ - if(strlen(file) > 4) - { - char * p = strrchr(file,'.'); - - if(p != NULL) - { - if(_stricmp(p, ".gb") == 0) - return true; - if(_stricmp(p, ".gbc") == 0) - return true; - if(_stricmp(p, ".cgb") == 0) - return true; - if(_stricmp(p, ".sgb") == 0) - return true; - } - } - - return false; -} - -bool utilIsZipFile(const char *file) -{ - if(strlen(file) > 4) - { - char * p = strrchr(file,'.'); - - if(p != NULL) - { - if(_stricmp(p, ".zip") == 0) - return true; - } - } - - return false; -} - -#if 0 -bool utilIsRarFile(const char *file) -{ - if(strlen(file) > 4) - { - char * p = strrchr(file,'.'); - - if(p != NULL) - { - if(_stricmp(p, ".rar") == 0) - return true; - } - } - - return false; -} -#endif - -bool utilIsGzipFile(const char *file) -{ - if(strlen(file) > 3) - { - char * p = strrchr(file,'.'); - - if(p != NULL) - { - if(_stricmp(p, ".gz") == 0) - return true; - if(_stricmp(p, ".z") == 0) - return true; - } - } - - return false; -} - -void utilGetBaseName(const char *file, char *buffer) -{ - strcpy(buffer, file); - - if(utilIsGzipFile(file)) - { - char *p = strrchr(buffer, '.'); - - if(p) - *p = 0; - } -} - -IMAGE_TYPE utilFindType(const char *file) -{ - char buffer[2048]; - - if(utilIsZipFile(file)) - { - unzFile unz = unzOpen(file); - - if(unz == NULL) - { - systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file); - return IMAGE_UNKNOWN; - } - - int r = unzGoToFirstFile(unz); - - if(r != UNZ_OK) - { - unzClose(unz); - systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); - return IMAGE_UNKNOWN; - } - - IMAGE_TYPE found = IMAGE_UNKNOWN; - - unz_file_info info; - - while(true) - { - r = unzGetCurrentFileInfo(unz, - &info, - buffer, - sizeof(buffer), - NULL, - 0, - NULL, - 0); - - if(r != UNZ_OK) - { - unzClose(unz); - systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); - return IMAGE_UNKNOWN; - } - - if(utilIsGBAImage(buffer)) - { - found = IMAGE_GBA; - break; - } - - if(utilIsGBImage(buffer)) - { - found = IMAGE_GB; - break; - } - - r = unzGoToNextFile(unz); - - if(r != UNZ_OK) - break; - } - unzClose(unz); - - if(found == IMAGE_UNKNOWN) - { - systemMessage(MSG_NO_IMAGE_ON_ZIP, - N_("No image found on ZIP file %s"), file); - return found; - } - return found; -#if 0 - } - else if(utilIsRarFile(file)) - { - IMAGE_TYPE found = IMAGE_UNKNOWN; - - ArchiveList_struct *rarList = NULL; - if(urarlib_list((void *)file, (ArchiveList_struct *)&rarList)) - { - ArchiveList_struct *p = rarList; - - while(p) - { - if(utilIsGBAImage(p->item.Name)) - { - found = IMAGE_GBA; - break; - } - - if(utilIsGBImage(p->item.Name)) - { - found = IMAGE_GB; - break; - } - p = p->next; - } - - urarlib_freelist(rarList); - } - return found; -#endif - } - else - { - if(utilIsGzipFile(file)) - utilGetBaseName(file, buffer); - else - strcpy(buffer, file); - - if(utilIsGBAImage(buffer)) - return IMAGE_GBA; - if(utilIsGBImage(buffer)) - return IMAGE_GB; - } - return IMAGE_UNKNOWN; -} - -static int utilGetSize(int size) -{ - int res = 1; - while(res < size) - res <<= 1; - return res; -} - -static u8 *utilLoadFromZip(const char *file, - bool (*accept)(const char *), - u8 *data, - int &size) -{ - char buffer[2048]; - - unzFile unz = unzOpen(file); - - if(unz == NULL) - { - systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file); - return NULL; - } - int r = unzGoToFirstFile(unz); - - if(r != UNZ_OK) - { - unzClose(unz); - systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); - return NULL; - } - - bool found = false; - - unz_file_info info; - - while(true) - { - r = unzGetCurrentFileInfo(unz, - &info, - buffer, - sizeof(buffer), - NULL, - 0, - NULL, - 0); - - if(r != UNZ_OK) - { - unzClose(unz); - systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); - return NULL; - } - - if(accept(buffer)) - { - found = true; - break; - } - - r = unzGoToNextFile(unz); - - if(r != UNZ_OK) - break; - } - - if(!found) - { - unzClose(unz); - systemMessage(MSG_NO_IMAGE_ON_ZIP, - N_("No image found on ZIP file %s"), file); - return NULL; - } - - int fileSize = info.uncompressed_size; - if(size == 0) - size = fileSize; - r = unzOpenCurrentFile(unz); - - if(r != UNZ_OK) - { - unzClose(unz); - systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), buffer); - return NULL; - } - - u8 *image = data; - - if(image == NULL) - { - image = (u8 *)malloc(utilGetSize(size)); - if(image == NULL) - { - unzCloseCurrentFile(unz); - unzClose(unz); - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "data"); - return NULL; - } - size = fileSize; - } - int read = fileSize <= size ? fileSize : size; - r = unzReadCurrentFile(unz, - image, - read); - - unzCloseCurrentFile(unz); - unzClose(unz); - - if(r != (int)read) - { - systemMessage(MSG_ERROR_READING_IMAGE, - N_("Error reading image %s"), buffer); - if(data == NULL) - free(image); - return NULL; - } - - size = fileSize; - - return image; -} - -static u8 *utilLoadGzipFile(const char *file, - bool (*accept)(const char *), - u8 *data, - int &size) -{ - FILE* f = gen_fopen(file, "rb"); - - if(f == NULL) - { - systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); - return NULL; - } - - gen_fseek(f, -4, SEEK_END); - int fileSize = gen_fgetc(f) | (gen_fgetc(f) << 8) | (gen_fgetc(f) << 16) | (gen_fgetc(f) << 24); - gen_fclose(f); - if(size == 0) - size = fileSize; - - gzFile gz = gzopen(file, "rb"); - - if(gz == NULL) - { - // should not happen, but who knows? - systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); - return NULL; - } - - u8 *image = data; - - if(image == NULL) - { - image = (u8 *)malloc(utilGetSize(size)); - if(image == NULL) - { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "data"); - gen_fclose(f); - return NULL; - } - size = fileSize; - } - int read = fileSize <= size ? fileSize : size; - int r = gzread(gz, image, read); - gzclose(gz); - - if(r != (int)read) - { - systemMessage(MSG_ERROR_READING_IMAGE, - N_("Error reading image %s"), file); - if(data == NULL) - free(image); - return NULL; - } - - size = fileSize; - - return image; -} - -#if 0 -static u8 *utilLoadRarFile(const char *file, - bool (*accept)(const char *), - u8 *data, - int &size) -{ - char buffer[2048]; - - ArchiveList_struct *rarList = NULL; - if(urarlib_list((void *)file, (ArchiveList_struct *)&rarList)) - { - ArchiveList_struct *p = rarList; - - bool found = false; - while(p) - { - if(accept(p->item.Name)) - { - strcpy(buffer, p->item.Name); - found = true; - break; - } - p = p->next; - } - if(found) - { - void *memory = NULL; - unsigned long lsize = 0; - size = p->item.UnpSize; - int r = urarlib_get((void *)&memory, &lsize, buffer, (void *)file, ""); - if(!r) - { - systemMessage(MSG_ERROR_READING_IMAGE, - N_("Error reading image %s"), buffer); - urarlib_freelist(rarList); - return NULL; - } - u8 *image = (u8 *)memory; - if(data != NULL) - { - memcpy(image, data, size); - } - urarlib_freelist(rarList); - return image; - } - systemMessage(MSG_NO_IMAGE_ON_ZIP, - N_("No image found on RAR file %s"), file); - urarlib_freelist(rarList); - return NULL; - } - // nothing found - return NULL; -} -#endif - -u8 *utilLoad(const char *file, - bool (*accept)(const char *), - u8 *data, - int &size) -{ - if(utilIsZipFile(file)) - { - return utilLoadFromZip(file, accept, data, size); - } - if(utilIsGzipFile(file)) - { - return utilLoadGzipFile(file, accept, data, size); - } -#if 0 - if(utilIsRarFile(file)) - { - return utilLoadRarFile(file, accept, data, size); - } -#endif - - u8 *image = data; - - FILE* f = gen_fopen(file, "rb"); - - if(!f) - { - systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); - return NULL; - } - - gen_fseek(f,0,SEEK_END); - int fileSize = ftell(f); - - gen_fseek(f,0,SEEK_SET); - if(size == 0) - size = fileSize; - - if(image == NULL) - { - image = (u8 *)malloc(utilGetSize(size)); - if(image == NULL) - { - systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), - "data"); - gen_fclose(f); - return NULL; - } - size = fileSize; - } - int read = fileSize <= size ? fileSize : size; - int r = gen_fread(image, 1, read, f); - gen_fclose(f); - - if(r != (int)read) - { - systemMessage(MSG_ERROR_READING_IMAGE, - N_("Error reading image %s"), file); - if(data == NULL) - free(image); - return NULL; - } - - size = fileSize; - - return image; -} - -void utilWriteInt(gzFile gzFile, int i) -{ - utilGzWrite(gzFile, &i, sizeof(int)); -} - -int utilReadInt(gzFile gzFile) -{ - int i = 0; - utilGzRead(gzFile, &i, sizeof(int)); - return i; -} - -void utilReadData(gzFile gzFile, variable_desc* data) -{ - while(data->address) - { - utilGzRead(gzFile, data->address, data->size); - data++; - } -} - -void utilWriteData(gzFile gzFile, variable_desc *data) -{ - while(data->address) - { - utilGzWrite(gzFile, data->address, data->size); - data++; - } -} - -gzFile utilGzOpen(const char *file, const char *mode) -{ - utilGzWriteFunc = (int (*)(void *,void * const, unsigned int))gzwrite; - utilGzReadFunc = gzread; - utilGzCloseFunc = gzclose; - - return gzopen(file, mode); -} - -gzFile utilMemGzOpen(char *memory, int available, char *mode) -{ - utilGzWriteFunc = memgzwrite; - utilGzReadFunc = memgzread; - utilGzCloseFunc = memgzclose; - - return memgzopen(memory, available, mode); -} - -int utilGzWrite(gzFile file, const voidp buffer, unsigned int len) -{ - return utilGzWriteFunc(file, buffer, len); -} - -int utilGzRead(gzFile file, voidp buffer, unsigned int len) -{ - return utilGzReadFunc(file, buffer, len); -} - -int utilGzClose(gzFile file) -{ - return utilGzCloseFunc(file); -} - -long utilGzMemTell(gzFile file) -{ - return memtell(file); -} - -void utilGBAFindSave(const u8 *data, const int size) -{ - u32 *p = (u32 *)data; - u32 *end = (u32 *)(data + size); - int saveType = 0; - int flashSize = 0x10000; - bool rtcFound = false; - - while(p < end) - { - u32 d = READ32LE(p); - - if(d == 0x52504545) - { - if(memcmp(p, "EEPROM_", 7) == 0) - { - if(saveType == 0) - saveType = 1; - } - } - else if (d == 0x4D415253) - { - if(memcmp(p, "SRAM_", 5) == 0) - { - if(saveType == 0) - saveType = 2; - } - } - else if (d == 0x53414C46) - { - if(memcmp(p, "FLASH1M_", 8) == 0) - { - if(saveType == 0) - { - saveType = 3; - flashSize = 0x20000; - } - } - else if(memcmp(p, "FLASH", 5) == 0) - { - if(saveType == 0) - { - saveType = 3; - flashSize = 0x10000; - } - } - } - else if (d == 0x52494953) - { - if(memcmp(p, "SIIRTC_V", 8) == 0) - rtcFound = true; - } - p++; - } - // if no matches found, then set it to NONE - if(saveType == 0) - { - saveType = 5; - } - rtcEnable(rtcFound); - cpuSaveType = saveType; - flashSetSize(flashSize); -} +// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator. +// Copyright (C) 1999-2003 Forgotten +// Copyright (C) 2004 Forgotten and the VBA development team + +// This program 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, or(at your option) +// any later version. +// +// This program 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 this program; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#include "sdfileio.h" +#include +#include +#include +#include + +extern "C" + { +#include + } + +#if 0 +#include "unrarlib.h" +#endif + +#include "System.h" +#include "NLS.h" +#include "Util.h" +#include "Flash.h" +#include "GBA.h" +#include "Globals.h" +#include "RTC.h" +#include "Port.h" + +extern "C" + { +#include "memgzio.h" + } + +#ifndef _MSC_VER +#define _stricmp strcasecmp +#endif // ! _MSC_VER + +static int (*utilGzWriteFunc)(gzFile, const voidp, unsigned int) = NULL; +static int (*utilGzReadFunc)(gzFile, voidp, unsigned int) = NULL; +static int (*utilGzCloseFunc)(gzFile) = NULL; + +bool utilWritePNGFile(const char *fileName, int w, int h, u8 *pix) +{ +#if 0 + u8 writeBuffer[512 * 3]; + + FILE* fp = gen_fopen(fileName,"wb"); + + if(!fp) + { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); + return false; + } + + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, + NULL, + NULL); + if(!png_ptr) + { + gen_fclose(fp); + return false; + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + + if(!info_ptr) + { + png_destroy_write_struct(&png_ptr,NULL); + gen_fclose(fp); + return false; + } + + if(setjmp(png_ptr->jmpbuf)) + { + png_destroy_write_struct(&png_ptr,NULL); + gen_fclose(fp); + return false; + } + + png_init_io(png_ptr,fp); + + png_set_IHDR(png_ptr, + info_ptr, + w, + h, + 8, + PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + png_write_info(png_ptr,info_ptr); + + u8 *b = writeBuffer; + + int sizeX = w; + int sizeY = h; + + switch(systemColorDepth) + { + case 16: + { + u16 *p = (u16 *)(pix+(w+2)*2); // skip first black line + for(int y = 0; y < sizeY; y++) + { + for(int x = 0; x < sizeX; x++) + { + u16 v = *p++; + + *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R + *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G + *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B + } + p++; // skip black pixel for filters + p++; // skip black pixel for filters + png_write_row(png_ptr,writeBuffer); + + b = writeBuffer; + } + } + break; + case 24: + { + u8 *pixU8 = (u8 *)pix; + for(int y = 0; y < sizeY; y++) + { + for(int x = 0; x < sizeX; x++) + { + if(systemRedShift < systemBlueShift) + { + *b++ = *pixU8++; // R + *b++ = *pixU8++; // G + *b++ = *pixU8++; // B + } + else + { + int blue = *pixU8++; + int green = *pixU8++; + int red = *pixU8++; + + *b++ = red; + *b++ = green; + *b++ = blue; + } + } + png_write_row(png_ptr,writeBuffer); + + b = writeBuffer; + } + } + break; + case 32: + { + u32 *pixU32 = (u32 *)(pix+4*(w+1)); + for(int y = 0; y < sizeY; y++) + { + for(int x = 0; x < sizeX; x++) + { + u32 v = *pixU32++; + + *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R + *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G + *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B + } + pixU32++; + + png_write_row(png_ptr,writeBuffer); + + b = writeBuffer; + } + } + break; + } + + png_write_end(png_ptr, info_ptr); + + png_destroy_write_struct(&png_ptr, &info_ptr); + + gen_fclose(fp); + +#endif + return true; +} + +void utilPutDword(u8 *p, u32 value) +{ + *p++ = value & 255; + *p++ = (value >> 8) & 255; + *p++ = (value >> 16) & 255; + *p = (value >> 24) & 255; +} + +void utilPutWord(u8 *p, u16 value) +{ + *p++ = value & 255; + *p = (value >> 8) & 255; +} + +void utilWriteBMP(char *buf, int w, int h, u8 *pix) +{ + u8 *b = (u8 *)buf; + + int sizeX = w; + int sizeY = h; + + switch(systemColorDepth) + { + case 16: + { + u16 *p = (u16 *)(pix+(w+2)*(h)*2); // skip first black line + for(int y = 0; y < sizeY; y++) + { + for(int x = 0; x < sizeX; x++) + { + u16 v = *p++; + + *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B + *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G + *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R + } + p++; // skip black pixel for filters + p++; // skip black pixel for filters + p -= 2*(w+2); + } + } + break; + case 24: + { + u8 *pixU8 = (u8 *)pix+3*w*(h-1); + for(int y = 0; y < sizeY; y++) + { + for(int x = 0; x < sizeX; x++) + { + if(systemRedShift > systemBlueShift) + { + *b++ = *pixU8++; // B + *b++ = *pixU8++; // G + *b++ = *pixU8++; // R + } + else + { + int red = *pixU8++; + int green = *pixU8++; + int blue = *pixU8++; + + *b++ = blue; + *b++ = green; + *b++ = red; + } + } + pixU8 -= 2*3*w; + } + } + break; + case 32: + { + u32 *pixU32 = (u32 *)(pix+4*(w+1)*(h)); + for(int y = 0; y < sizeY; y++) + { + for(int x = 0; x < sizeX; x++) + { + u32 v = *pixU32++; + + *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B + *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G + *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R + } + pixU32++; + pixU32 -= 2*(w+1); + } + } + break; + } +} + +bool utilWriteBMPFile(const char *fileName, int w, int h, u8 *pix) +{ + u8 writeBuffer[512 * 3]; + + FILE* fp = gen_fopen(fileName,"wb"); + + if(!fp) + { + systemMessage(MSG_ERROR_CREATING_FILE, N_("Error creating file %s"), fileName); + return false; + } + + struct + { + u8 ident[2]; + u8 filesize[4]; + u8 reserved[4]; + u8 dataoffset[4]; + u8 headersize[4]; + u8 width[4]; + u8 height[4]; + u8 planes[2]; + u8 bitsperpixel[2]; + u8 compression[4]; + u8 datasize[4]; + u8 hres[4]; + u8 vres[4]; + u8 colors[4]; + u8 importantcolors[4]; + // u8 pad[2]; + } + bmpheader; + memset(&bmpheader, 0, sizeof(bmpheader)); + + bmpheader.ident[0] = 'B'; + bmpheader.ident[1] = 'M'; + + u32 fsz = sizeof(bmpheader) + w*h*3; + utilPutDword(bmpheader.filesize, fsz); + utilPutDword(bmpheader.dataoffset, 0x36); + utilPutDword(bmpheader.headersize, 0x28); + utilPutDword(bmpheader.width, w); + utilPutDword(bmpheader.height, h); + utilPutDword(bmpheader.planes, 1); + utilPutDword(bmpheader.bitsperpixel, 24); + utilPutDword(bmpheader.datasize, 3*w*h); + + gen_fwrite(&bmpheader, 1, sizeof(bmpheader), fp); + + u8 *b = writeBuffer; + + int sizeX = w; + int sizeY = h; + + switch(systemColorDepth) + { + case 16: + { + u16 *p = (u16 *)(pix+(w+2)*(h)*2); // skip first black line + for(int y = 0; y < sizeY; y++) + { + for(int x = 0; x < sizeX; x++) + { + u16 v = *p++; + + *b++ = ((v >> systemBlueShift) & 0x01f) << 3; // B + *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G + *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R + } + p++; // skip black pixel for filters + p++; // skip black pixel for filters + p -= 2*(w+2); + gen_fwrite(writeBuffer, 1, 3*w, fp); + + b = writeBuffer; + } + } + break; + case 24: + { + u8 *pixU8 = (u8 *)pix+3*w*(h-1); + for(int y = 0; y < sizeY; y++) + { + for(int x = 0; x < sizeX; x++) + { + if(systemRedShift > systemBlueShift) + { + *b++ = *pixU8++; // B + *b++ = *pixU8++; // G + *b++ = *pixU8++; // R + } + else + { + int red = *pixU8++; + int green = *pixU8++; + int blue = *pixU8++; + + *b++ = blue; + *b++ = green; + *b++ = red; + } + } + pixU8 -= 2*3*w; + gen_fwrite(writeBuffer, 1, 3*w, fp); + + b = writeBuffer; + } + } + break; + case 32: + { + u32 *pixU32 = (u32 *)(pix+4*(w+1)*(h)); + for(int y = 0; y < sizeY; y++) + { + for(int x = 0; x < sizeX; x++) + { + u32 v = *pixU32++; + + *b++ = ((v >> systemBlueShift) & 0x001f) << 3; // B + *b++ = ((v >> systemGreenShift) & 0x001f) << 3; // G + *b++ = ((v >> systemRedShift) & 0x001f) << 3; // R + } + pixU32++; + pixU32 -= 2*(w+1); + + gen_fwrite(writeBuffer, 1, 3*w, fp); + + b = writeBuffer; + } + } + break; + } + + gen_fclose(fp); + + return true; +} + +static int utilReadInt2(FILE* f) +{ + int res = 0; + int c = gen_fgetc(f); + if(c == EOF) + return -1; + res = c; + c = gen_fgetc(f); + if(c == EOF) + return -1; + return c + (res<<8); +} + +static int utilReadInt3(FILE* f) +{ + int res = 0; + int c = gen_fgetc(f); + if(c == EOF) + return -1; + res = c; + c = gen_fgetc(f); + if(c == EOF) + return -1; + res = c + (res<<8); + c = gen_fgetc(f); + if(c == EOF) + return -1; + return c + (res<<8); +} + +void utilApplyIPS(const char *ips, u8 **r, int *s) +{ + // from the IPS spec at http://zerosoft.zophar.net/ips.htm + FILE* f = gen_fopen(ips, "rb"); + if(!f) + return; + u8 *rom = *r; + int size = *s; + if(gen_fgetc(f) == 'P' && + gen_fgetc(f) == 'A' && + gen_fgetc(f) == 'T' && + gen_fgetc(f) == 'C' && + gen_fgetc(f) == 'H') + { + int b; + int offset; + int len; + for(;;) + { + // read offset + offset = utilReadInt3(f); + // if offset == EOF, end of patch + if(offset == 0x454f46) + break; + // read length + len = utilReadInt2(f); + if(!len) + { + // len == 0, RLE block + len = utilReadInt2(f); + // byte to fill + int c = gen_fgetc(f); + if(c == -1) + break; + b = (u8)c; + } + else + b= -1; + // check if we need to reallocate our ROM + if((offset + len) >= size) + { + size *= 2; + rom = (u8 *)realloc(rom, size); + *r = rom; + *s = size; + } + if(b == -1) + { + // normal block, just read the data + //if(gen_fread(&rom[offset], 1, len, f) != (size_t)len) + if(gen_fread(&rom[offset], 1, len, f) != (int)len) + break; + } + else + { + // fill the region with the given byte + while(len--) + { + rom[offset++] = b; + } + } + } + } + // close the file + gen_fclose(f); +} + +extern bool cpuIsMultiBoot; + +bool utilIsGBAImage(const char * file) +{ + cpuIsMultiBoot = false; + if(strlen(file) > 4) + { + char * p = strrchr(file,'.'); + + if(p != NULL) + { + if(_stricmp(p, ".gba") == 0) + return true; + if(_stricmp(p, ".agb") == 0) + return true; + if(_stricmp(p, ".bin") == 0) + return true; + if(_stricmp(p, ".elf") == 0) + return true; + if(_stricmp(p, ".mb") == 0) + { + cpuIsMultiBoot = true; + return true; + } + } + } + + return false; +} + +bool utilIsGBImage(const char * file) +{ + if(strlen(file) > 4) + { + char * p = strrchr(file,'.'); + + if(p != NULL) + { + if(_stricmp(p, ".gb") == 0) + return true; + if(_stricmp(p, ".gbc") == 0) + return true; + if(_stricmp(p, ".cgb") == 0) + return true; + if(_stricmp(p, ".sgb") == 0) + return true; + } + } + + return false; +} + +bool utilIsZipFile(const char *file) +{ + if(strlen(file) > 4) + { + char * p = strrchr(file,'.'); + + if(p != NULL) + { + if(_stricmp(p, ".zip") == 0) + return true; + } + } + + return false; +} + +#if 0 +bool utilIsRarFile(const char *file) +{ + if(strlen(file) > 4) + { + char * p = strrchr(file,'.'); + + if(p != NULL) + { + if(_stricmp(p, ".rar") == 0) + return true; + } + } + + return false; +} +#endif + +bool utilIsGzipFile(const char *file) +{ + if(strlen(file) > 3) + { + char * p = strrchr(file,'.'); + + if(p != NULL) + { + if(_stricmp(p, ".gz") == 0) + return true; + if(_stricmp(p, ".z") == 0) + return true; + } + } + + return false; +} + +void utilGetBaseName(const char *file, char *buffer) +{ + strcpy(buffer, file); + + if(utilIsGzipFile(file)) + { + char *p = strrchr(buffer, '.'); + + if(p) + *p = 0; + } +} + +IMAGE_TYPE utilFindType(const char *file) +{ + char buffer[2048]; + + if(utilIsZipFile(file)) + { + unzFile unz = unzOpen(file); + + if(unz == NULL) + { + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file); + return IMAGE_UNKNOWN; + } + + int r = unzGoToFirstFile(unz); + + if(r != UNZ_OK) + { + unzClose(unz); + systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); + return IMAGE_UNKNOWN; + } + + IMAGE_TYPE found = IMAGE_UNKNOWN; + + unz_file_info info; + + while(true) + { + r = unzGetCurrentFileInfo(unz, + &info, + buffer, + sizeof(buffer), + NULL, + 0, + NULL, + 0); + + if(r != UNZ_OK) + { + unzClose(unz); + systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); + return IMAGE_UNKNOWN; + } + + if(utilIsGBAImage(buffer)) + { + found = IMAGE_GBA; + break; + } + + if(utilIsGBImage(buffer)) + { + found = IMAGE_GB; + break; + } + + r = unzGoToNextFile(unz); + + if(r != UNZ_OK) + break; + } + unzClose(unz); + + if(found == IMAGE_UNKNOWN) + { + systemMessage(MSG_NO_IMAGE_ON_ZIP, + N_("No image found on ZIP file %s"), file); + return found; + } + return found; +#if 0 + } + else if(utilIsRarFile(file)) + { + IMAGE_TYPE found = IMAGE_UNKNOWN; + + ArchiveList_struct *rarList = NULL; + if(urarlib_list((void *)file, (ArchiveList_struct *)&rarList)) + { + ArchiveList_struct *p = rarList; + + while(p) + { + if(utilIsGBAImage(p->item.Name)) + { + found = IMAGE_GBA; + break; + } + + if(utilIsGBImage(p->item.Name)) + { + found = IMAGE_GB; + break; + } + p = p->next; + } + + urarlib_freelist(rarList); + } + return found; +#endif + } + else + { + if(utilIsGzipFile(file)) + utilGetBaseName(file, buffer); + else + strcpy(buffer, file); + + if(utilIsGBAImage(buffer)) + return IMAGE_GBA; + if(utilIsGBImage(buffer)) + return IMAGE_GB; + } + return IMAGE_UNKNOWN; +} + +static int utilGetSize(int size) +{ + int res = 1; + while(res < size) + res <<= 1; + return res; +} + +static u8 *utilLoadFromZip(const char *file, + bool (*accept)(const char *), + u8 *data, + int &size) +{ + char buffer[2048]; + + unzFile unz = unzOpen(file); + + if(unz == NULL) + { + systemMessage(MSG_CANNOT_OPEN_FILE, N_("Cannot open file %s"), file); + return NULL; + } + int r = unzGoToFirstFile(unz); + + if(r != UNZ_OK) + { + unzClose(unz); + systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); + return NULL; + } + + bool found = false; + + unz_file_info info; + + while(true) + { + r = unzGetCurrentFileInfo(unz, + &info, + buffer, + sizeof(buffer), + NULL, + 0, + NULL, + 0); + + if(r != UNZ_OK) + { + unzClose(unz); + systemMessage(MSG_BAD_ZIP_FILE, N_("Bad ZIP file %s"), file); + return NULL; + } + + if(accept(buffer)) + { + found = true; + break; + } + + r = unzGoToNextFile(unz); + + if(r != UNZ_OK) + break; + } + + if(!found) + { + unzClose(unz); + systemMessage(MSG_NO_IMAGE_ON_ZIP, + N_("No image found on ZIP file %s"), file); + return NULL; + } + + int fileSize = info.uncompressed_size; + if(size == 0) + size = fileSize; + r = unzOpenCurrentFile(unz); + + if(r != UNZ_OK) + { + unzClose(unz); + systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), buffer); + return NULL; + } + + u8 *image = data; + + if(image == NULL) + { + image = (u8 *)malloc(utilGetSize(size)); + if(image == NULL) + { + unzCloseCurrentFile(unz); + unzClose(unz); + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "data"); + return NULL; + } + size = fileSize; + } + int read = fileSize <= size ? fileSize : size; + r = unzReadCurrentFile(unz, + image, + read); + + unzCloseCurrentFile(unz); + unzClose(unz); + + if(r != (int)read) + { + systemMessage(MSG_ERROR_READING_IMAGE, + N_("Error reading image %s"), buffer); + if(data == NULL) + free(image); + return NULL; + } + + size = fileSize; + + return image; +} + +static u8 *utilLoadGzipFile(const char *file, + bool (*accept)(const char *), + u8 *data, + int &size) +{ + FILE* f = gen_fopen(file, "rb"); + + if(f == NULL) + { + systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); + return NULL; + } + + gen_fseek(f, -4, SEEK_END); + int fileSize = gen_fgetc(f) | (gen_fgetc(f) << 8) | (gen_fgetc(f) << 16) | (gen_fgetc(f) << 24); + gen_fclose(f); + if(size == 0) + size = fileSize; + + gzFile gz = gzopen(file, "rb"); + + if(gz == NULL) + { + // should not happen, but who knows? + systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); + return NULL; + } + + u8 *image = data; + + if(image == NULL) + { + image = (u8 *)malloc(utilGetSize(size)); + if(image == NULL) + { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "data"); + gen_fclose(f); + return NULL; + } + size = fileSize; + } + int read = fileSize <= size ? fileSize : size; + int r = gzread(gz, image, read); + gzclose(gz); + + if(r != (int)read) + { + systemMessage(MSG_ERROR_READING_IMAGE, + N_("Error reading image %s"), file); + if(data == NULL) + free(image); + return NULL; + } + + size = fileSize; + + return image; +} + +#if 0 +static u8 *utilLoadRarFile(const char *file, + bool (*accept)(const char *), + u8 *data, + int &size) +{ + char buffer[2048]; + + ArchiveList_struct *rarList = NULL; + if(urarlib_list((void *)file, (ArchiveList_struct *)&rarList)) + { + ArchiveList_struct *p = rarList; + + bool found = false; + while(p) + { + if(accept(p->item.Name)) + { + strcpy(buffer, p->item.Name); + found = true; + break; + } + p = p->next; + } + if(found) + { + void *memory = NULL; + unsigned long lsize = 0; + size = p->item.UnpSize; + int r = urarlib_get((void *)&memory, &lsize, buffer, (void *)file, ""); + if(!r) + { + systemMessage(MSG_ERROR_READING_IMAGE, + N_("Error reading image %s"), buffer); + urarlib_freelist(rarList); + return NULL; + } + u8 *image = (u8 *)memory; + if(data != NULL) + { + memcpy(image, data, size); + } + urarlib_freelist(rarList); + return image; + } + systemMessage(MSG_NO_IMAGE_ON_ZIP, + N_("No image found on RAR file %s"), file); + urarlib_freelist(rarList); + return NULL; + } + // nothing found + return NULL; +} +#endif + +u8 *utilLoad(const char *file, + bool (*accept)(const char *), + u8 *data, + int &size) +{ + if(utilIsZipFile(file)) + { + return utilLoadFromZip(file, accept, data, size); + } + if(utilIsGzipFile(file)) + { + return utilLoadGzipFile(file, accept, data, size); + } +#if 0 + if(utilIsRarFile(file)) + { + return utilLoadRarFile(file, accept, data, size); + } +#endif + + u8 *image = data; + + FILE* f = gen_fopen(file, "rb"); + + if(!f) + { + systemMessage(MSG_ERROR_OPENING_IMAGE, N_("Error opening image %s"), file); + return NULL; + } + + gen_fseek(f,0,SEEK_END); + int fileSize = ftell(f); + + gen_fseek(f,0,SEEK_SET); + if(size == 0) + size = fileSize; + + if(image == NULL) + { + image = (u8 *)malloc(utilGetSize(size)); + if(image == NULL) + { + systemMessage(MSG_OUT_OF_MEMORY, N_("Failed to allocate memory for %s"), + "data"); + gen_fclose(f); + return NULL; + } + size = fileSize; + } + int read = fileSize <= size ? fileSize : size; + int r = gen_fread(image, 1, read, f); + gen_fclose(f); + + if(r != (int)read) + { + systemMessage(MSG_ERROR_READING_IMAGE, + N_("Error reading image %s"), file); + if(data == NULL) + free(image); + return NULL; + } + + size = fileSize; + + return image; +} + +void utilWriteInt(gzFile gzFile, int i) +{ + utilGzWrite(gzFile, &i, sizeof(int)); +} + +int utilReadInt(gzFile gzFile) +{ + int i = 0; + utilGzRead(gzFile, &i, sizeof(int)); + return i; +} + +void utilReadData(gzFile gzFile, variable_desc* data) +{ + while(data->address) + { + utilGzRead(gzFile, data->address, data->size); + data++; + } +} + +void utilWriteData(gzFile gzFile, variable_desc *data) +{ + while(data->address) + { + utilGzWrite(gzFile, data->address, data->size); + data++; + } +} + +gzFile utilGzOpen(const char *file, const char *mode) +{ + utilGzWriteFunc = (int (*)(void *,void * const, unsigned int))gzwrite; + utilGzReadFunc = gzread; + utilGzCloseFunc = gzclose; + + return gzopen(file, mode); +} + +gzFile utilMemGzOpen(char *memory, int available, char *mode) +{ +// utilGzWriteFunc = memgzwrite; + utilGzReadFunc = memgzread; + utilGzCloseFunc = memgzclose; + + return memgzopen(memory, available, mode); +} + +int utilGzWrite(gzFile file, const voidp buffer, unsigned int len) +{ + return utilGzWriteFunc(file, buffer, len); +} + +int utilGzRead(gzFile file, voidp buffer, unsigned int len) +{ + return utilGzReadFunc(file, buffer, len); +} + +int utilGzClose(gzFile file) +{ + return utilGzCloseFunc(file); +} + +long utilGzMemTell(gzFile file) +{ + return memtell(file); +} + +void utilGBAFindSave(const u8 *data, const int size) +{ + u32 *p = (u32 *)data; + u32 *end = (u32 *)(data + size); + int saveType = 0; + int flashSize = 0x10000; + bool rtcFound = false; + + while(p < end) + { + u32 d = READ32LE(p); + + if(d == 0x52504545) + { + if(memcmp(p, "EEPROM_", 7) == 0) + { + if(saveType == 0) + saveType = 1; + } + } + else if (d == 0x4D415253) + { + if(memcmp(p, "SRAM_", 5) == 0) + { + if(saveType == 0) + saveType = 2; + } + } + else if (d == 0x53414C46) + { + if(memcmp(p, "FLASH1M_", 8) == 0) + { + if(saveType == 0) + { + saveType = 3; + flashSize = 0x20000; + } + } + else if(memcmp(p, "FLASH", 5) == 0) + { + if(saveType == 0) + { + saveType = 3; + flashSize = 0x10000; + } + } + } + else if (d == 0x52494953) + { + if(memcmp(p, "SIIRTC_V", 8) == 0) + rtcFound = true; + } + p++; + } + // if no matches found, then set it to NONE + if(saveType == 0) + { + saveType = 5; + } + rtcEnable(rtcFound); + cpuSaveType = saveType; + flashSetSize(flashSize); +} diff --git a/src/memgzio.c b/src/memgzio.c index eef6b2c..7a235ea 100644 --- a/src/memgzio.c +++ b/src/memgzio.c @@ -10,7 +10,7 @@ */ /* @(#) $Id: memgzio.c,v 1.3 2004/01/17 23:07:32 kxu Exp $ */ - +#include #include #include #include @@ -70,15 +70,15 @@ typedef struct mem_stream mem_stream; -local gzFile gz_open OF((char *memory, const int available, const char *mode)); -local int do_flush OF((gzFile file, int flush)); -local int get_byte OF((mem_stream *s)); -local void check_header OF((mem_stream *s)); -local int destroy OF((mem_stream *s)); -local void putLong OF((MEMFILE *file, uLong x)); -local uLong getLong OF((mem_stream *s)); +gzFile gz_open OF((char *memory, const int available, const char *mode)); +int do_flush OF((gzFile file, int flush)); +int get_byte OF((mem_stream *s)); +void check_header OF((mem_stream *s)); +int destroy OF((mem_stream *s)); +void putLong OF((MEMFILE *file, uLong x)); +uLong getLong OF((mem_stream *s)); -local MEMFILE *memOpen(char *memory, int available, char mode) +MEMFILE *memOpen(char *memory, int available, char mode) { MEMFILE *f; @@ -119,7 +119,7 @@ local MEMFILE *memOpen(char *memory, int available, char mode) return f; } -local size_t memWrite(const void *buffer, size_t size, size_t count, +size_t memWrite(const void *buffer, size_t size, size_t count, MEMFILE *file) { size_t total = size*count; @@ -140,7 +140,7 @@ local size_t memWrite(const void *buffer, size_t size, size_t count, return total; } -local size_t memRead(void *buffer, size_t size, size_t count, +size_t memRead(void *buffer, size_t size, size_t count, MEMFILE *file) { size_t total = size*count; @@ -164,7 +164,7 @@ local size_t memRead(void *buffer, size_t size, size_t count, return total; } -local int memPutc(int c, MEMFILE *file) +int memPutc(int c, MEMFILE *file) { if(file->mode != 'w') { @@ -183,17 +183,17 @@ local int memPutc(int c, MEMFILE *file) return c; } -local long memTell(MEMFILE *f) +long memTell(MEMFILE *f) { return (f->next - f->memory) - 8; } -local int memError(MEMFILE *f) +int memError(MEMFILE *f) { return f->error; } -local int memClose(MEMFILE *f) +int memClose(MEMFILE *f) { if(f->mode == 'w') { @@ -203,7 +203,7 @@ local int memClose(MEMFILE *f) return 0; } -local int memPrintf(MEMFILE *f, const char *format, ...) +int memPrintf(MEMFILE *f, const char *format, ...) { char buffer[80]; va_list list; @@ -225,7 +225,7 @@ local int memPrintf(MEMFILE *f, const char *format, ...) can be checked to distinguish the two cases (if errno is zero, the zlib error is Z_MEM_ERROR). */ -local gzFile gz_open (memory, available, mode) +gzFile gz_open (memory, available, mode) char *memory; const int available; const char *mode; @@ -313,7 +313,7 @@ const char *mode; } s->stream.avail_out = Z_BUFSIZE; - errno = 0; + //errno = 0; s->file = memOpen(memory, available, s->mode); if (s->file == NULL) @@ -325,8 +325,8 @@ const char *mode; { /* Write a very simple .gz header: */ - memPrintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], - Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + //memPrintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + // Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); s->startpos = 10L; /* We use 10L instead of ftell(s->file) to because ftell causes an * fflush on some systems. This version of the library doesn't use @@ -359,13 +359,13 @@ const char *mode; for end of file. IN assertion: the stream s has been sucessfully opened for reading. */ -local int get_byte(s) +int get_byte(s) mem_stream *s; { if (s->z_eof) return EOF; if (s->stream.avail_in == 0) { - errno = 0; +// errno = 0; s->stream.avail_in = memRead(s->inbuf, 1, Z_BUFSIZE, s->file); if (s->stream.avail_in == 0) { @@ -388,7 +388,7 @@ mem_stream *s; s->stream.avail_in is zero for the first time, but may be non-zero for concatenated .gz files. */ -local void check_header(s) +void check_header(s) mem_stream *s; { int method; /* method byte */ @@ -449,7 +449,7 @@ mem_stream *s; * Cleanup then free the given mem_stream. Return a zlib error code. Try freeing in the reverse order of allocations. */ -local int destroy (s) +int destroy (s) mem_stream *s; { int err = Z_OK; @@ -520,7 +520,7 @@ unsigned len; if (n > s->stream.avail_out) n = s->stream.avail_out; if (n > 0) { - zmemcpy(s->stream.next_out, s->stream.next_in, n); +// zmemcpy(s->stream.next_out, s->stream.next_in, n); next_out += n; s->stream.next_out = next_out; s->stream.next_in += n; @@ -541,7 +541,7 @@ unsigned len; if (s->stream.avail_in == 0 && !s->z_eof) { - errno = 0; +// errno = 0; s->stream.avail_in = memRead(s->inbuf, 1, Z_BUFSIZE, s->file); if (s->stream.avail_in == 0) { @@ -637,7 +637,7 @@ unsigned len; Flushes all pending output into the compressed file. The parameter flush is as in the deflate() function. */ -local int do_flush (file, flush) +int do_flush (file, flush) gzFile file; int flush; { @@ -682,7 +682,7 @@ int flush; /* =========================================================================== Outputs a long in LSB order to the given file */ -local void putLong (file, x) +void putLong (file, x) MEMFILE *file; uLong x; { @@ -698,7 +698,7 @@ uLong x; Reads a long in LSB order from the given mem_stream. Sets z_err in case of error. */ -local uLong getLong (s) +uLong getLong (s) mem_stream *s; { uLong x = (uLong)get_byte(s); @@ -719,7 +719,7 @@ mem_stream *s; int ZEXPORT memgzclose (file) gzFile file; { - int err; +// int err; mem_stream *s = (mem_stream*)file; if (s == NULL) return Z_STREAM_ERROR; diff --git a/src/memgzio.h b/src/memgzio.h index 2ca74cb..f2c2513 100644 --- a/src/memgzio.h +++ b/src/memgzio.h @@ -8,14 +8,19 @@ /* memgzio.c - IO on .gz files in memory * Adapted from original gzio.c from zlib library by Forgotten */ +/* #ifndef HAVE_ZUTIL_H #include "../win32/include/zlib/zutil.h" #else #include #endif +*/ + +#include gzFile ZEXPORT memgzopen(char *memory, int, const char *); int ZEXPORT memgzread(gzFile, voidp, unsigned); int ZEXPORT memgzwrite(gzFile, const voidp, unsigned); int ZEXPORT memgzclose(gzFile); long ZEXPORT memtell(gzFile); + diff --git a/src/unzip.h b/src/unzip.h index 97bdbe0..5ef98c5 100644 --- a/src/unzip.h +++ b/src/unzip.h @@ -66,7 +66,7 @@ extern "C" #endif #ifndef _ZLIB_H -#include "zlib.h" +#include #endif #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)